Skip to content

Let the static guards admit a reviewed MutatingPolicy shape #5096

Description

@devantler

🤖 Generated by the Agentic Engineer

Evidence and problem

Two static guards refuse any MutatingPolicy in the production render, by design, because neither can evaluate CEL mutations:

  • the Crossplane egress-policy contract rule reject-cel-policy-producers (scripts/tests/crossplane-egress-policy-rules.yaml) rejects every policies.kyverno.io MutatingPolicy/GeneratingPolicy (only a policy-report DeletingPolicy is excepted, Prune stale Kyverno results after policies stop matching #2573);
  • scripts/guard-consumer-discovery-conservation.sh refuses a render that holds any MutatingPolicy, MutatingAdmissionPolicy or GeneratingPolicy, because it cannot prove such a mutation preserves consumer identity.

Measured on #5095 (2026-10-19), the first mutation migration for #4997: the policy itself is correct (its CLI test passes unchanged before and after), but 🧪 Validate Manifests and 🛡️ Validate Repository Guards fail on these two refusals. So none of the eleven mutation policies in #4997 can move to MutatingPolicy before Kyverno 1.20 removes ClusterPolicy (#4984) until the guards can tell a safe mutation from an unsafe one.

Audience and outcome

The platform operator: the mutation defaults keep working across the Kyverno 1.20 upgrade, and the guards keep refusing any mutation that could strip egress policy or change a consumer's identity.

Smallest useful change

Replace each blanket refusal with an allow-list of reviewed shapes, not a list of exceptions: a MutatingPolicy passes only when its matchConstraints.resourceRules name exactly the reviewed kinds (for #5095: helm.toolkit.fluxcd.io helmreleases) and none of the carrier kinds the guards protect, and its mutations are a JSON patch limited to reviewed paths. Everything else stays refused. Each guard keeps its negative controls, plus a new one proving a MutatingPolicy on a protected kind or path is still refused.

Acceptance criteria

Size: medium. Blocks #4997.

Activity

  1. moved this to 📥 Backlog in 🌊 Project Boardon Oct 19, 2026
  2. devantler commented on Oct 19, 2026

    @devantler
    ContributorAuthor

    🤖 Generated by the Agentic Engineer

    Scope note, 19 October: this also blocks a second started item, and it needs the GeneratingPolicy case too.

    Both refusals named above cover GeneratingPolicy as well as MutatingPolicy, read at platform main 5ed390f:

    • reject-cel-policy-producers in scripts/tests/crossplane-egress-policy-rules.yaml rejects GeneratingPolicy, MutatingPolicy and every DeletingPolicy except the policy-report one.
    • scripts/guard-consumer-discovery-conservation.sh counts every MutatingPolicy, MutatingAdmissionPolicy and GeneratingPolicy in a production render and refuses any non-zero count.

    The next step on devantler-tech/kyverno-policies#1 (item 3) registers the catalog's auto-vpa in the platform. The catalog's registered form is policies/best-practices/auto-vpa-generating-policy.yaml: three policies.kyverno.io/v1 GeneratingPolicy objects, one each for Deployment, DaemonSet and StatefulSet, that generate a VerticalPodAutoscaler. Once it is in the platform's production render, both guards refuse it for the same reason they refuse #5095 today.

    Suggested scope addition: the allow-list should name a reviewed GeneratingPolicy shape as well. That shape matches only apps deployments/daemonsets/statefulsets and generates only autoscaling.k8s.io VerticalPodAutoscaler, never a carrier kind. Add a negative control that a GeneratingPolicy generating any protected carrier kind is still refused. If one change is too big, split it into a sibling issue so each guard change is reviewed alone. Either way, one guard change now unblocks two started items: #4997 (through #5095) and kyverno-policies#1.

    Not picked up in this run: the board is above its WIP ceiling and this is Backlog work that is not a critical obligation.

  3. moved this from 📥 Backlog to 👀 In Review in 🌊 Project Boardon Oct 19, 2026
  4. moved this from 👀 In Review to ✅ Done in 🌊 Project Boardon Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Fields

    No fields configured for Security.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions