Repository navigation
Migrate the workload-default and HelmRelease mutation ClusterPolicies to MutatingPolicy #4997
Description
🤖 Generated by the Agentic Engineer (interactive Claude Code session)
Evidence and problem
Kyverno 1.20 is planned to remove ClusterPolicy (#4984). These 11 mutation policies set workload defaults and HelmRelease settings at admission; each must exist as a MutatingPolicy (policies.kyverno.io) before 1.20 is installed:
k8s/bases/infrastructure/cluster-policies/best-practices/:add-recommended-labels,add-resource-defaults,add-security-context,insert-pod-antiaffinity,disable-default-sa-automount,propagate-reloader-to-flagger-primary,set-observability-dns-ndots,spread-podsk8s/bases/infrastructure/cluster-policies/flux/:helm-release-enable-tests,helm-release-install-crds,helm-release-remediation-retries
Only add-security-context has a Kyverno CLI test today; the other ten have none. disable-default-sa-automount and propagate-reloader-to-flagger-primary also mutate existing resources (targets), so the capability check below matters most for them.
Double application
During the deploy that swaps them, the old and new policy can both act on one request for a moment. A mutation that only sets a value where it is absent, or sets the same value again, gives the same object when applied twice. The implementer confirms that per policy (a list append, such as an inserted affinity term, may not hold), and any policy for which it is not true is split into its own PR with an explicit handover.
How every migration batch works
- Test first. Of the 49
ClusterPolicymanifests, 28 are named in notests/**/kyverno-test.yaml(counted 2026-10-17 by policy name). Before rewriting a policy, add a Kyverno CLI test that pins its current behaviour — at least one resource it must act on and one it must leave alone — and see it pass against theClusterPolicy. The same test, pointed at the new kind, must pass unchanged in its expected results. - Keep the action. Each rewritten policy keeps its failure action as recorded in
tests/policy-failure-actions.json(Enforce stays Enforce, Audit stays Audit), its match scope and its exclusions. - No gap in enforcement. Add the new policy and delete the
ClusterPolicyin the same PR, so Flux applies the replacement before it prunes the old one. Kinds whose two versions could both act on the same request (mutation or generation) say how double application is avoided. - Confirm the capability first. For each rule, confirm the replacement kind can express it at Kyverno 1.19.1 (the running version). A rule it cannot express is recorded on Migrate Kyverno ClusterPolicy and Policy before Kyverno 1.20 removes them #4984 and blocks only that policy, not the batch.
- Validate with
kyverno test ./testsandscripts/validate-kyverno-fixture-evaluation.sh(CI's⚖️ Validate cluster policiesstep), the layer builds inplatform/AGENTS.md, and after deploy a read-only check that each new policy reports ready and the old one is gone.
Acceptance criteria
- Every policy listed above has a CLI test that passed against the
ClusterPolicybefore the rewrite, covering a resource it mutates and one it leaves alone. - Each is a
MutatingPolicywith the same scope, exclusions and resulting object, and the oldClusterPolicyis deleted in the same PR. - Double application is shown to be harmless for each policy, as described above.
-
kyverno test ./testsand the fixture-evaluation check pass in CI. - After deploy, each new policy reports ready, no
ClusterPolicyof these names remains, and a workload created after the deploy carries the same defaults as one created before it.
Priority High, Effort High, Service class Risk reduction. These defaults supply labels, resource requests, security contexts and spreading to every workload; losing them would weaken every new Pod without any error. Effort includes ten missing tests, the rewrite, review and one production deploy. No prerequisite. Part of #4984.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Effort
Projects
- StatusShow more project fields🫴 Ready
Activity
chore: agent-claim #4997 nonce=39fb6f973316998a3d823bdbef2403d5