#17793·kyverno

[Bug] [CLI] kyverno test mutates the trigger resource for MutatingPolicy targetMatchConstraints

Author: Elvand-LieCreated Sep 30, 2026Updated Sep 30, 2026

Kyverno CLI version

Current main: c51c8f6fd10824a2560819553b78ac0d4f80a652.

Description

kyverno test evaluates a MutatingPolicy with active targetMatchConstraints against the trigger itself before evaluating its selected targets. This can apply the target mutation to the trigger, or produce a schema error when the mutation is valid only for the target kind.

The trigger should drive matching and evaluation; the selected target should receive the mutation. A trigger that is not selected as a target should remain unchanged.

Steps to reproduce

Save these files in one directory and run kyverno test .. policy.yaml

yaml
apiVersion: policies.kyverno.io/v1beta1
kind: MutatingPolicy
metadata:
  name: mutate-existing-deployment-from-secret
spec:
  evaluation:
    mutateExisting:
      enabled: true
  matchConstraints:
    resourceRules:
    - apiGroups: [""]
      apiVersions: ["v1"]
      operations: ["CREATE"]
      resources: ["secrets"]
  targetMatchConstraints:
    resourceRules:
    - apiGroups: ["apps"]
      apiVersions: ["v1"]
      operations: ["CREATE", "UPDATE"]
      resources: ["deployments"]
  mutations:
  - patchType: ApplyConfiguration
    applyConfiguration:
      expression: >
        Object{
          metadata: Object.metadata{
            labels: Object.metadata.labels{
              mutated: "true"
            }
          },
          spec: Object.spec{
            replicas: 3
          }
        }

trigger.yaml

yaml
apiVersion: v1
kind: Secret
metadata:
  name: test-secret
  namespace: test-ns
type: Opaque
data:
  key: dmFsdWU=

target.yaml

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deploy
  namespace: test-ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx

kyverno-test.yaml

yaml
apiVersion: cli.kyverno.io/v1alpha1
kind: Test
metadata:
  name: secret-trigger-deployment-target
policies:
- policy.yaml
resources:
- trigger.yaml
results:
- isMutatingPolicy: true
  kind: Deployment
  policy: mutate-existing-deployment-from-secret
  resources:
  - test-ns/test-deploy
  result: pass
targetResources:
- target.yaml

Actual and expected behavior

The YAML result row checks the Deployment only, so kyverno test can report success even when the trigger also undergoes inline mutation evaluation. Inspecting the CLI engine responses is necessary to assert trigger immutability.

The intended Deployment target should receive the label and replicas change. The Secret should receive neither a patched resource nor a failed target-shaped mutation rule. Removing the spec part of the mutation leaves a metadata-only variant that exposes the illicit trigger label directly.

Root cause

cmd/cli/kubectl-kyverno/processor/policy_processor.go calls eng.Handle(context.TODO(), request, nil) for the trigger. Both MutatingPolicy admission handlers instead use NoTargetMatchConstraintPolicy(), which excludes policies with active target constraints from inline mutation. The CLI's subsequent target Evaluate loop is separate.

The same processor is shared by kyverno apply; this issue does not request adding mutate-existing target processing to apply.

Regression evidence

The direct runTest regression uses the checked-in test/cli/test-mutating-policy/mutate-existing fixture (Deployment trigger, ConfigMap target):

Predicate Trigger response Target Regression
Current main's nil Two responses; the first patches Deployment test-ns/test-deploy with mutated=true ConfigMap test-ns/test-configmap receives mutated=true FAIL
NoTargetMatchConstraintPolicy() One target-processing response; no inline trigger patch Same target mutation succeeds PASS
Restored fix after negative control Same as fixed Same target mutation succeeds PASS

For the Secret-to-Deployment manifests above, the YAML test reports Pass on both builds. A supplementary kyverno apply policy.yaml --resource trigger.yaml -o out.yaml exercise of the same processor on current main reports .spec: field not declared in schema because it attempts the Deployment-shaped patch on the Secret. Removing spec from the mutation produces an output Secret with metadata.labels.mutated: "true", despite Secrets not being selected as targets. These apply observations are separate from the direct runTest regression; they do not establish mutate-existing target support in apply.

This report is limited to the CLI path. Admission already excludes these policies from inline mutation.