feat(forgejo-package-prune): protect image tags running live in the cluster
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Adds collect_live_cluster_versions() — enumerates pod container images via
kubectl and protects any forgejo.coulomb.social/coulomb/<name>:<tag>. Closes the
gap where CI-deployed apps (e.g. state-hub) pin a live tag absent from Helm
values. On by default (--no-protect-live to skip); emits protection_notes +
live_protection in the JSON summary so consumers can detect reduced coverage.
Verified against production: protects state-hub/vergabe/issue-core live tags.

ACTIVITY-WP-0020 T07 (partial — see workplan note re multi-cluster coverage).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-07-16 14:44:03 +02:00
parent 6f7ca31a6d
commit e9e631fbf4
2 changed files with 89 additions and 0 deletions

View file

@ -64,5 +64,35 @@ image:
self.assertEqual(protected_plans, {("vergabe-teilnahme", "old-prod")})
def test_collect_live_cluster_versions_protects_forgejo_tags(self) -> None:
images = "\n".join([
"forgejo.coulomb.social/coulomb/state-hub:f2e042a",
"forgejo.coulomb.social/coulomb/vergabe-teilnahme:064d295",
"registry.k8s.io/pause:3.9", # unrelated registry → ignored
"gitea.coulomb.social/coulomb/old-app:x", # non-forgejo → ignored
"",
])
with mock.patch.object(prune.shutil, "which", return_value="/usr/bin/kubectl"), \
mock.patch.object(
prune.subprocess, "run",
return_value=mock.Mock(stdout=images, returncode=0),
):
protected, notes = prune.collect_live_cluster_versions()
self.assertEqual(notes, [])
self.assertEqual(
protected,
{
("container", "state-hub", "f2e042a"),
("container", "vergabe-teilnahme", "064d295"),
},
)
def test_collect_live_cluster_versions_skips_without_kubectl(self) -> None:
with mock.patch.object(prune.shutil, "which", return_value=None):
protected, notes = prune.collect_live_cluster_versions()
self.assertEqual(protected, set())
self.assertTrue(notes and "kubectl not found" in notes[0])
if __name__ == "__main__":
unittest.main()