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:
- The pattern expects either a map with keys OR the field to be absent
- Nil map values fall into a gap between these two cases
- 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:
-
Adds
normalizeNilMaps()function that recursively walks through parsed resources and converts nil values to empty maps for known Kubernetes map fields:annotationslabelsmatchLabelsnodeSelectordatastringData
-
Integrates normalization into the
YamlToUnstructured()function, ensuring all resources are normalized after YAML→JSON→Unstructured conversion -
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 thenormalizeNilMaps()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