Skip to content

fix(cli): normalize nil map fields in YAML resources

Description

This PR fixes an issue where the Kyverno CLI fails to validate resources with nil map fields (e.g., annotations: with no value) against policies.

Problem

Some Helm library charts generate YAML manifests with nil map values, which while technically non-standard YAML, are accepted by Kubernetes. For example:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    metadata:
      labels:
        app: my-app
      annotations:  # <-- nil value, no map entries
    spec:
      containers:
      - name: app
        image: nginx

When Kyverno CLI attempts to validate such resources against policies (especially those using pattern matching on metadata.annotations), the validation incorrectly fails because:

  1. The pattern expects either a map with keys OR the field to be absent
  2. Nil map values fall into a gap between these two cases
  3. This particularly affects autogenerated rules for Deployments, StatefulSets, etc.

This issue was originally reported in #11658 where the restrict-apparmor-profiles policy was failing for Deployments with nil annotations.

Solution

Following the maintainer's recommendation (@realshuting) to fix this in the CLI parsing logic rather than modifying policy templates, this PR:

  1. Adds normalizeNilMaps() function that recursively walks through parsed resources and converts nil values to empty maps for known Kubernetes map fields:

    • annotations
    • labels
    • matchLabels
    • nodeSelector
    • data
    • stringData
  2. Integrates normalization into the YamlToUnstructured() function, ensuring all resources are normalized after YAML→JSON→Unstructured conversion

  3. Handles nested structures including templates in Deployments, StatefulSets, DaemonSets, Jobs, etc.

Testing

Added comprehensive test coverage in cmd/cli/kubectl-kyverno/resource/resource_test.go:

  • Pods with nil annotations
  • Pods with empty annotation maps
  • Deployments with nil template annotations
  • Deployments with nil labels
  • ConfigMaps with nil data
  • Nested structures (spec.template.metadata.annotations)
  • Unit tests for the normalizeNilMaps() function

Before this fix:

$ kyverno apply policy.yaml --resource deployment-with-nil-annotations.yaml
policy restrict-apparmor-profiles -> resource default/Deployment/my-app failed:
1 - autogen-app-armor validation error: ... rule autogen-app-armor failed at path /spec/template/metadata/annotations/

pass: 0, fail: 1, warn: 0, error: 0, skip: 0

After this fix:

$ kyverno apply policy.yaml --resource deployment-with-nil-annotations.yaml

Applying 3 policy rule(s) to 1 resource(s)...

pass: 1, fail: 0, warn: 0, error: 0, skip: 0

Related Issues

Fixes #11658

Checklist

  • I have read the contributing guidelines
  • I have read the PR documentation guide
  • This is a bug fix and I have added unit tests that prove my fix is effective
  • All tests pass locally (go test ./cmd/cli/kubectl-kyverno/resource/...)
  • Code is properly formatted (make fmt)
  • No linter errors
  • Build succeeds (go build ./cmd/cli/kubectl-kyverno/...)
  • Commit is signed off

Notes

  • This fix is scoped to the CLI only and does not affect the Kyverno admission controller
  • The normalization is conservative - it only converts nil to empty maps for well-known Kubernetes map fields
  • Non-nil values (including empty maps) are left unchanged
  • This approach aligns with how Kubernetes itself handles nil map values

Merge request reports

Loading