Skip to content

Commit 0539237

Browse files
committed
feat(secret): react to secret changed
1 parent fdf8673 commit 0539237

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

src/charm.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
ConfigChangedEvent,
3535
EventBase,
3636
InstallEvent,
37+
SecretChangedEvent,
3738
StartEvent,
3839
StopEvent,
3940
UpdateStatusEvent,
@@ -245,6 +246,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
245246
self.framework.observe(
246247
self.on[PLANNER_INTEGRATION_NAME].relation_broken, self._on_planner_relation_broken
247248
)
249+
self.framework.observe(self.on.secret_changed, self._on_secret_changed)
248250
self.framework.observe(self.on.check_runners_action, self._on_check_runners_action)
249251
self.framework.observe(self.on.flush_runners_action, self._on_flush_runners_action)
250252
self.framework.observe(self.on.update_status, self._on_update_status)
@@ -394,6 +396,14 @@ def _on_config_changed(self, _: ConfigChangedEvent) -> None:
394396
self._manager_client.flush_runner()
395397
self.unit.status = ActiveStatus()
396398

399+
@catch_charm_errors
400+
def _on_secret_changed(self, _: SecretChangedEvent) -> None:
401+
"""Handle secret content rotation (e.g. GitHub App private key)."""
402+
logger.info("Secret changed, reconciling")
403+
state = self._setup_state()
404+
self._reconcile(state)
405+
self._manager_client.flush_runner()
406+
397407
@catch_action_errors
398408
def _on_check_runners_action(self, event: ActionEvent) -> None:
399409
"""Handle the action of checking of runner state.

tests/unit/test_charm.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,49 @@ def test__on_config_changed_no_flush(
342342
harness.charm._manager_client.flush_runner.assert_not_called()
343343

344344

345+
def test_on_secret_changed_flushes_runners(monkeypatch: pytest.MonkeyPatch):
346+
"""
347+
arrange: Charm configured with a GitHub App private key secret.
348+
act: Update the secret content (triggers secret-changed event).
349+
assert: Runners are flushed and service is reconciled.
350+
"""
351+
harness = Harness(GithubRunnerCharm)
352+
secret_id = harness.add_user_secret(content={"private-key": "old-pem"})
353+
harness.update_config({GITHUB_APP_PRIVATE_KEY_SECRET_ID_CONFIG_NAME: secret_id})
354+
harness.begin()
355+
state_mock = MagicMock()
356+
monkeypatch.setattr("charm.manager_service", MagicMock())
357+
harness.charm._manager_client = MagicMock(spec=GitHubRunnerManagerClient)
358+
harness.charm._setup_state = MagicMock(return_value=state_mock)
359+
harness.charm._check_image_ready = MagicMock(return_value=True)
360+
361+
harness.set_secret_content(secret_id, {"private-key": "new-pem"})
362+
363+
harness.charm._manager_client.flush_runner.assert_called_once()
364+
365+
366+
def test_on_secret_changed_reconciles_on_any_secret(monkeypatch: pytest.MonkeyPatch):
367+
"""
368+
arrange: Charm configured with a GitHub App private key secret.
369+
act: Update an unrelated secret's content.
370+
assert: Runners are still flushed (holistic reconcile on any secret change).
371+
"""
372+
harness = Harness(GithubRunnerCharm)
373+
secret_id = harness.add_user_secret(content={"private-key": "pem-data"})
374+
unrelated_secret_id = harness.add_user_secret(content={"some-key": "some-value"})
375+
harness.update_config({GITHUB_APP_PRIVATE_KEY_SECRET_ID_CONFIG_NAME: secret_id})
376+
harness.begin()
377+
state_mock = MagicMock()
378+
monkeypatch.setattr("charm.manager_service", MagicMock())
379+
harness.charm._manager_client = MagicMock(spec=GitHubRunnerManagerClient)
380+
harness.charm._setup_state = MagicMock(return_value=state_mock)
381+
harness.charm._check_image_ready = MagicMock(return_value=True)
382+
383+
harness.set_secret_content(unrelated_secret_id, {"some-key": "new-value"})
384+
385+
harness.charm._manager_client.flush_runner.assert_called_once()
386+
387+
345388
def test_on_stop_busy_flush_and_cleanup_service(harness: Harness, monkeypatch: pytest.MonkeyPatch):
346389
"""
347390
arrange: Set up charm with Openstack mode and runner scaler mock.

0 commit comments

Comments
 (0)