Skip to content

Commit 9e6e040

Browse files
fix private key generation (#78)
* fix private key generation * add missing _on_upgrade * linting * fix race condition in privkey generation (#76) * fix race condition in privkey generation * fix static checks in other libs * tox fmt * update LIBPATCH --------- Co-authored-by: Luca Bello <[email protected]>
1 parent b170b67 commit 9e6e040

File tree

4 files changed

+57
-10
lines changed

4 files changed

+57
-10
lines changed

lib/charms/observability_libs/v1/cert_handler.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666

6767
LIBID = "b5cd5cd580f3428fa5f59a8876dcbe6a"
6868
LIBAPI = 1
69-
LIBPATCH = 2
69+
LIBPATCH = 3
7070

7171

7272
def is_ip_address(value: str) -> bool:
@@ -192,14 +192,11 @@ def _on_certificates_relation_joined(self, _) -> None:
192192
def _generate_privkey(self):
193193
# Generate priv key unless done already
194194
# TODO figure out how to go about key rotation.
195-
relation = self.charm.model.get_relation(self.certificates_relation_name)
196195

197-
if not relation:
196+
if not (relation := self.charm.model.get_relation(self.certificates_relation_name)):
198197
return
199198

200-
private_key = relation.data[self.charm.unit].get("private-key", None)
201-
202-
if not private_key:
199+
if not self.private_key:
203200
private_key = generate_private_key()
204201
secret = self.charm.unit.add_secret({"private-key": private_key.decode()})
205202
secret.grant(relation)

tests/integration/helpers.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright 2024 Canonical Ltd.
2+
# See LICENSE file for licensing details.
3+
4+
"""Helper functions for writing tests."""
5+
6+
import subprocess
7+
8+
from pytest_operator.plugin import OpsTest
9+
10+
11+
def get_secret(ops_test: OpsTest, app_name: str, path: str) -> str:
12+
return subprocess.check_output(
13+
[
14+
"juju",
15+
"ssh",
16+
"--model",
17+
ops_test.model_full_name,
18+
"--container",
19+
"httpbin",
20+
f"{app_name}/0",
21+
"cat",
22+
path,
23+
]
24+
).decode()

tests/integration/test_cert_handler_v1.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@
88

99
import pytest
1010
import yaml
11+
from helpers import get_secret
1112
from pytest_operator.plugin import OpsTest
1213

1314
logger = logging.getLogger(__name__)
1415

1516
METADATA = yaml.safe_load(Path("./tests/integration/tester-charm/metadata.yaml").read_text())
1617
APP_NAME = METADATA["name"]
1718

19+
KEY_PATH = "/home/ubuntu/secrets/server.key"
20+
CERT_PATH = "/home/ubuntu/secrets/server.cert"
21+
CA_CERT_PATH = "/home/ubuntu/secrets/ca.cert"
22+
1823

1924
@pytest.mark.abort_on_fail
2025
async def test_cert_handler_v1(
@@ -52,7 +57,7 @@ async def test_cert_handler_v1(
5257
await ops_test.model.wait_for_idle(apps=apps, status="active", wait_for_exact_units=1)
5358

5459
# Check the certs files are in the filesystem
55-
for path in ["/tmp/server.key", "/tmp/server.cert", "/tmp/ca.cert"]:
60+
for path in [KEY_PATH, CERT_PATH, CA_CERT_PATH]:
5661
assert 0 == subprocess.check_call(
5762
[
5863
"juju",
@@ -65,3 +70,20 @@ async def test_cert_handler_v1(
6570
f"ls {path}",
6671
]
6772
)
73+
74+
75+
@pytest.mark.abort_on_fail
76+
async def test_secrets_does_not_change_after_refresh(ops_test: OpsTest, tester_charm: Path):
77+
paths = [KEY_PATH, CERT_PATH, CA_CERT_PATH]
78+
secrets = {paths[0]: "", paths[1]: "", paths[2]: ""}
79+
80+
for path in paths:
81+
secrets[path] = get_secret(ops_test, APP_NAME, path)
82+
83+
await ops_test.model.applications[APP_NAME].refresh(path=tester_charm)
84+
await ops_test.model.wait_for_idle(
85+
status="active", raise_on_error=False, timeout=600, idle_period=30
86+
)
87+
88+
for path in paths:
89+
assert secrets[path] == get_secret(ops_test, APP_NAME, path)

tests/integration/tester-charm/src/charm.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515
VALID_LOG_LEVELS = ["info", "debug", "warning", "error", "critical"]
1616

17-
KEY_PATH = "/tmp/server.key"
18-
CERT_PATH = "/tmp/server.cert"
19-
CA_CERT_PATH = "/tmp/ca.cert"
17+
KEY_PATH = "/home/ubuntu/secrets/server.key"
18+
CERT_PATH = "/home/ubuntu/secrets/server.cert"
19+
CA_CERT_PATH = "/home/ubuntu/secrets/ca.cert"
2020

2121

2222
class TesterCharm(ops.CharmBase):
@@ -34,6 +34,10 @@ def __init__(self, *args):
3434
self.framework.observe(self.cert_handler.on.cert_changed, self._on_server_cert_changed)
3535
self.framework.observe(self.on["httpbin"].pebble_ready, self._on_httpbin_pebble_ready)
3636
self.framework.observe(self.on.config_changed, self._on_config_changed)
37+
self.framework.observe(self.on.upgrade_charm, self._on_upgrade_charm)
38+
39+
def _on_upgrade_charm(self, _):
40+
self._update_cert()
3741

3842
def _on_server_cert_changed(self, _):
3943
self._update_cert()

0 commit comments

Comments
 (0)