News
What happened
Kyverno is a Kubernetes-native policy engine that validates, mutates, and generates resources before workloads reach your cluster, enforcing security and compliance rules as code, without requiring a separate policy language. Enterprise teams running Kyverno policies in... Kyverno is a Kubernetes-native policy engine that validates, mutates, and generates resources before workloads reach your cluster, enforcing security and compliance rules as code, without requiring a separate policy language. Enterprise teams running Kyverno policies in production face a specific, painful problem. Their policies use GlobalContextEntry references – at evaluation time, the engine looks up live Kubernetes resources to make decisions. In a real cluster, this works perfectly. In CI/CD, without a live API server, the CLI has nowhere to resolve those lookups. Tests panic. Rules are silently skipped. Policy reports show results that bear no relationship to what will actually happen in production. This was not a theoretical gap. It was the documented, open state of the Kyverno CLI at the start of 2026. And closing it was the problem I was handed as a Spring 2026 LFX Mentee. Week one: The Codebase wins I am a final-year Computer Engineering undergraduate. When I was selected under the Unified CLI project (#15264) , mentored by Shuting Zhao and Frank Jogeleit, I understood the problem clearly enough on paper. What I did not understand was what it would feel like to open policy_processor.go for the first time — thousands of lines of Go handling dynamic clients, REST mappers, CEL evaluation engines, and fake discovery clients — and realize that every single one of those systems was involved in the problem I needed to solve. My first instinct was to ask for help immediately. Instead, I spent the entire first week only reading CLI test fixtures. If I couldn’t understand the engine yet, I could at least understand what the engine was expected to produce. That worked. It also taught me
Kyverno is a Kubernetes-native policy engine that validates, mutates, and generates resources before workloads reach your cluster, enforcing security and compliance rules as code, without requiring a separate policy language. Enterprise teams running Kyverno policies in... Kyverno is a Kubernetes-native policy engine that validates, mutates, and generates resources before workloads reach your cluster, enforcing security and compliance rules as code, without requiring a separate policy language. Enterprise teams running Kyverno policies in production face a specific, painful problem. Their policies use GlobalContextEntry references – at evaluation time, the engine looks up live Kubernetes resources to make decisions. In a real cluster, this works perfectly. In CI/CD, without a live API server, the CLI has nowhere to resolve those lookups. Tests panic. Rules are silently skipped. Policy reports show results that bear no relationship to what will actually happen in production. This was not a theoretical gap. It was the documented, open state of the Kyverno CLI at the start of 2026. And closing it was the problem I was handed as a Spring 2026 LFX Mentee. Week one: The Codebase wins I am a final-year Computer Engineering undergraduate. When I was selected under the Unified CLI project (#15264) , mentored by Shuting Zhao and Frank Jogeleit, I understood the problem clearly enough on paper. What I did not understand was what it would feel like to open policy_processor.go for the first time — thousands of lines of Go handling dynamic clients, REST mappers, CEL evaluation engines, and fake discovery clients — and realize that every single one of those systems was involved in the problem I needed to solve. My first instinct was to ask for help immediately. Instead, I spent the entire first week only reading CLI test fixtures. If I couldn’t understand the engine yet, I could at least understand what the engine was expected to produce. That worked. It also taught me my most important lesson for the whole mentorship: when you ask a senior maintainer for help, don’t ask “how does this work?” Ask “I traced this to resolveResource() — is this where the offline RESTMapping fails for MutatingPolicy?” Make it possible for them to unblock you in sixty seconds. That discipline is what gets you taken seriously. Clearing the ground Before any new architecture could be built, the existing CLI had to stop crashing. Over the first four weeks, I worked through a series of bugs that ranged from hard panics to silent failures. The CLI was crashing with panic: coding error: you must register resource to list kind when wildcard mutateExisting rules triggered . List() calls against a fake dynamic client whose scheme was missing *List GVK registrations. Modern CEL policy types ( ValidatingPolicy, MutatingPolicy, GeneratingPolicy ) were having their test results silently swallowed because the engine was applying rule-name matching logic to policy types that don’t have named rules by design. And MutatingPolicy , GeneratingPolicy , and DeletingPolicy had all been added to the engine without the surrounding CLI plumbing ever being updated to match ValidatingPolicy's resource lookup behavior — which manifested as six distinct, interlocking bugs in a single PR. None of this was glamorous work. But it was necessary. You cannot build reliable offline infrastructure on top of an engine that panics unpredictably and silently drops results. The foundation had to be solid before the architecture could begin. The wrong approach (And why it mattered) When I finally turned to the core problem — making kubernetesResource-backed GlobalContextEntry objects work offline, my first instinct was completely wrong. I thought it was a data-passing problem. A user provides a YAML file mocking a Deployment. I unmarshal that YAML into a standard map[string]interface{} and pass it into the CEL engine’s global context. Simple. It blew up instantly. The moment any policy expression tried to access object.metadata.namespace or traverse the resource structure, the CEL engine threw no such overload. I spent hours fighting the compiler, trying different type coercions, considering whether I needed to write custom CEL macros just for the CLI path. I went deep into a rabbit hole of trying to force the engine to accept my data shape. That entire approach was wrong — and more importantly, it was dangerous. Modifying the core policy engine to accommodate CLI test files would have risked diverging offline behavior from production behavior. The point of offline testing is that it should be identical to what runs in the cluster. Any special-casing in the engine would have undermined that guarantee entirely. The disguise I stopped looking at the CLI and started looking at the Kubernetes informer cache. When Kyverno runs in a real cluster and resolves a kubernetesResource lookup, the cache does not return a single JSON object. It always returns a slice of unstructured objects — []interface{}, where each element is a map[string]interface{} mirroring unstructured.Unstructured.Object. That is the shape the CEL engine and JMESPath projections are built to expect. That is the shape they have always received in production. I was feeding the engine a single object, and it was failing because it expected a list it could iterate over. The breakthrough was realizing I should not touch the policy engine at all. Instead of forcing the engine to understand my test files, I needed to make my test files look exactly like what the engine had always seen. I built resolveResourcesMockData: a translation layer that lives entirely in the CLI. When a user declares mock resources in their kyverno-test.yaml , this function uses runtime.RawExtension to decode each manifest, forces it into an unstructured map, and wraps the result into an []interface{} slice. By the time the mock data reaches the CEL compilers or the JMESPath projectio
REMOTE ACCESS
Protect Your Admin Sessions
A zero-exposure architecture secures your server. A VPN secures you — encrypting your connection when managing infrastructure from untrusted networks, coffee shops, or travel. NordVPN is what we use for this layer.
Try NordVPN →This is an affiliate link. If you purchase, I earn a commission at no extra cost to you.
Changes at a glance
What's new
Kyverno is a Kubernetes-native policy engine that validates, mutates, and generates resources before workloads reach your cluster, enforcing security and compliance rules as code, without requiring a separate policy language. Enterprise teams running Kyverno policies in... Kyverno is a Kubernetes-native policy engine that validates, mutates, and generates resources before workloads reach your cluster, enforcing security and compliance rules as code, without requiring a separate policy language. Enterprise teams running Kyverno policies in production face a specific, painful problem. Their policies use GlobalContextEntry references – at evaluation time, the engine looks up live Kubernetes resources to make decisions. In a real cluster, this works perfectly. In CI/CD, without a live API server, the CLI has nowhere to resolve those lookups. Tests panic. Rules are silently skipped. Policy reports show results that bear no relationship to what will actually happen in production. This was not a theoretical gap. It was the documented, open state of the Kyverno CLI at the start of 2026. And closing it was the problem I was handed as a Spring 2026 LFX Mentee. Week one: The Codebase wins I am a final-year Computer Engineering undergraduate. When I was selected under the Unified CLI project (#15264) , mentored by Shuting Zhao and Frank Jogeleit, I understood the problem clearly enough on paper. What I did not understand was what it would feel like to open policy_processor.go for the first time — thousands of lines of Go handling dynamic clients, REST mappers, CEL evaluation engines, and fake discovery clients — and realize that every single one of those systems was involved in the problem I needed to solve. My first instinct was to ask for help immediately. Instead, I spent the entire first week only reading CLI test fixtures. If I couldn’t understand the engine yet, I could at least understand what the engine was expected to produce. That worked. It also taught me my most important lesson for the whole mentorship: when you ask a senior maintainer for help, don’t ask “how does this work?” Ask “I traced this to resolveResource() — is this where the offline RESTMapping fails for MutatingPolicy?” Make it possible for them to unblock you in sixty seconds. That discipline is what gets you taken seriously. Clearing the ground Before any new architecture could be built, the existing CLI had to stop crashing. Over the first four weeks, I worked through a series of bugs that ranged from hard panics to silent failures. The CLI was crashing with panic: coding error: you must register resource to list kind when wildcard mutateExisting rules triggered . List() calls against a fake dynamic client whose scheme was missing *List GVK registrations. Modern CEL policy types ( ValidatingPolicy, MutatingPolicy, GeneratingPolicy ) were having their test results silently swallowed because the engine was applying rule-name matching logic to policy types that don’t have named rules by design. And MutatingPolicy , GeneratingPolicy , and DeletingPolicy had all been added to the engine without the surrounding CLI plumbing ever being updated to match ValidatingPolicy's resource lookup behavior — which manifested as six distinct, interlocking bugs in a single PR. None of this was glamorous work. But it was necessary. You cannot build reliable offline infrastructure on top of an engine that panics unpredictably and silently drops results. The foundation had to be solid before the architecture could begin. The wrong approach (And why it mattered) When I finally turned to the core problem — making kubernetesResource-backed GlobalContextEntry objects work offline, my first instinct was completely wrong. I thought it was a data-passing problem. A user provides a YAML file mocking a Deployment. I unmarshal that YAML into a standard map[string]interface{} and pass it into the CEL engine’s global context. Simple. It blew up instantly. The moment any policy expression tried to access object.metadata.namespace or traverse the resource structure, the CEL engine threw no such overload. I spent hours fighting the compiler, trying different type coercions, considering whether I needed to write custom CEL macros just for the CLI path. I went deep into a rabbit hole of trying to force the engine to accept my data shape. That entire approach was wrong — and more importantly, it was dangerous. Modifying the core policy engine to accommodate CLI test files would have risked diverging offline behavior from production behavior. The point of offline testing is that it should be identical to what runs in the cluster. Any special-casing in the engine would have undermined that guarantee entirely. The disguise I stopped looking at the CLI and started looking at the Kubernetes informer cache. When Kyverno runs in a real cluster and resolves a kubernetesResource lookup, the cache does not return a single JSON object. It always returns a slice of unstructured objects — []interface{}, where each element is a map[string]interface{} mirroring unstructured.Unstructured.Object. That is the shape the CEL engine and JMESPath projections are built to expect. That is the shape they have always received in production. I was feeding the engine a single object, and it was failing because it expected a list it could iterate over. The breakthrough was realizing I should not touch the policy engine at all. Instead of forcing the engine to understand my test files, I needed to make my test files look exactly like what the engine had always seen. I built resolveResourcesMockData: a translation layer that lives entirely in the CLI. When a user declares mock resources in their kyverno-test.yaml , this function uses runtime.RawExtension to decode each manifest, forces it into an unstructured map, and wraps the result into an []interface{} slice. By the time the mock data reaches the CEL compilers or the JMESPath projectio
Breaking changes
No breaking changes were reported in the source material.
Analysis
In detail
Kyverno is a Kubernetes-native policy engine that validates, mutates, and generates resources before workloads reach your cluster, enforcing security and compliance rules as code, without requiring a separate policy language. Enterprise teams running Kyverno policies in... Kyverno is a Kubernetes-native policy engine that validates, mutates, and generates resources before workloads reach your cluster, enforcing security and compliance rules as code, without requiring a separate policy language. Enterprise teams running Kyverno policies in production face a specific, painful problem. Their policies use GlobalContextEntry references – at evaluation time, the engine looks up live Kubernetes resources to make decisions. In a real cluster, this works perfectly. In CI/CD, without a live API server, the CLI has nowhere to resolve those lookups. Tests panic. Rules are silently skipped. Policy reports show results that bear no relationship to what will actually happen in production. This was not a theoretical gap. It was the documented, open state of the Kyverno CLI at the start of 2026. And closing it was the problem I was handed as a Spring 2026 LFX Mentee. Week one: The Codebase wins I am a final-year Computer Engineering undergraduate. When I was selected under the Unified CLI project (#15264) , mentored by Shuting Zhao and Frank Jogeleit, I understood the problem clearly enough on paper. What I did not understand was what it would feel like to open policy_processor.go for the first time — thousands of lines of Go handling dynamic clients, REST mappers, CEL evaluation engines, and fake discovery clients — and realize that every single one of those systems was involved in the problem I needed to solve. My first instinct was to ask for help immediately. Instead, I spent the entire first week only reading CLI test fixtures. If I couldn’t understand the engine yet, I could at least understand what the engine was expected to produce. That worked. It also taught me my most important lesson for the whole mentorship: when you ask a senior maintainer for help, don’t ask “how does this work?” Ask “I traced this to resolveResource() — is this where the offline RESTMapping fails for MutatingPolicy?” Make it possible for them to unblock you in sixty seconds. That discipline is what gets you taken seriously. Clearing the ground Before any new architecture could be built, the existing CLI had to stop crashing. Over the first four weeks, I worked through a series of bugs that ranged from hard panics to silent failures. The CLI was crashing with panic: coding error: you must register resource to list kind when wildcard mutateExisting rules triggered . List() calls against a fake dynamic client whose scheme was missing *List GVK registrations. Modern CEL policy types ( ValidatingPolicy, MutatingPolicy, GeneratingPolicy ) were having their test results silently swallowed because the engine was applying rule-name matching logic to policy types that don’t have named rules by design. And MutatingPolicy , GeneratingPolicy , and DeletingPolicy had all been added to the engine without the surrounding CLI plumbing ever being updated to match ValidatingPolicy's resource lookup behavior — which manifested as six distinct, interlocking bugs in a single PR. None of this was glamorous work. But it was necessary. You cannot build reliable offline infrastructure on top of an engine that panics unpredictably and silently drops results. The foundation had to be solid before the architecture could begin. The wrong approach (And why it mattered) When I finally turned to the core problem — making kubernetesResource-backed GlobalContextEntry objects work offline, my first instinct was completely wrong. I thought it was a data-passing problem. A user provides a YAML file mocking a Deployment. I unmarshal that YAML into a standard map[string]interface{} and pass it into the CEL engine’s global context. Simple. It blew up instantly. The moment any policy expression tried to access object.metadata.namespace or traverse the resource structure, the CEL engine threw no such overload. I spent hours fighting the compiler, trying different type coercions, considering whether I needed to write custom CEL macros just for the CLI path. I went deep into a rabbit hole of trying to force the engine to accept my data shape. That entire approach was wrong — and more importantly, it was dangerous. Modifying the core policy engine to accommodate CLI test files would have risked diverging offline behavior from production behavior. The point of offline testing is that it should be identical to what runs in the cluster. Any special-casing in the engine would have undermined that guarantee entirely. The disguise I stopped looking at the CLI and started looking at the Kubernetes informer cache. When Kyverno runs in a real cluster and resolves a kubernetesResource lookup, the cache does not return a single JSON object. It always returns a slice of unstructured objects — []interface{}, where each element is a map[string]interface{} mirroring unstructured.Unstructured.Object. That is the shape the CEL engine and JMESPath projections are built to expect. That is the shape they have always received in production. I was feeding the engine a single object, and it was failing because it expected a list it could iterate over. The breakthrough was realizing I should not touch the policy engine at all. Instead of forcing the engine to understand my test files, I needed to make my test files look exactly like what the engine had always seen. I built resolveResourcesMockData: a translation layer that lives entirely in the CLI. When a user declares mock resources in their kyverno-test.yaml , this function uses runtime.RawExtension to decode each manifest, forces it into an unstructured map, and wraps the result into an []interface{} slice. By the time the mock data reaches the CEL compilers or the JMESPath projectio
Why it matters
If you run self-hosted infrastructure, homelab services, or automation stacks, this update is worth tracking before you change production.
Homelab impact
If you run related services in your homelab, review whether this update affects your current deployment. Check compatibility with your Docker Compose files, reverse proxy config, or network setup before you upgrade production stacks.
What to do next
Practical steps for operators running self-hosted stacks.
This brief covers what you need from CNCF Blog's reporting. Visit the original post for release notes, changelogs, and full technical documentation.
