Documentskyverno
ValidatingPolicy Engine
ValidatingPolicy Engine
Type
Topic
Status
Published
Created
Jul 7, 2026
Updated
Jul 7, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

ValidatingPolicy Engine (vpolengine)#

Kyverno maintains two separate validation pipelines: the legacy engine for Policy/ClusterPolicy resources, and a distinct CEL-based engine (vpolengine) for ValidatingPolicy and NamespacedValidatingPolicy resources. They diverge in their type systems, response structures, and how enforcement intent is expressed. Understanding this split is essential when adding features, wiring admission handlers, or processing policy evaluation results.


Location#

The vpolengine lives under pkg/cel/policies/vpol/engine/:

FilePurpose
engine.goengineImpl, the concrete Handle() implementation
policy.goInternal Policy struct (actions + compiled policy)
provider.goStatic (NewProvider) and Kubernetes-dynamic (NewKubeProvider) providers
reconciler.goController-runtime reconciler that watches ValidatingPolicy / NamespacedValidatingPolicy

The shared generic building blocks (Engine[T], EngineRequest, EngineResponse) are in pkg/cel/engine/.


Generic Engine Interface#

The engine is built on a Go generic interface defined in pkg/cel/engine/engine.go. For ValidatingPolicies the concrete alias instantiates the generic over policiesv1beta1.ValidatingPolicyLike . The predicate parameter (func(T) bool) lets callers filter which policies are evaluated at call time.


EngineResponse — vpolengine vs. legacy#

These two response types are not interchangeable:

vpolengine (pkg/cel/engine/response.go)Legacy engine (pkg/engine/api/engineresponse.go)
Typeengine.EngineResponseapi.EngineResponse
Top-level resource*unstructured.Unstructured (pointer)unstructured.Unstructured (value) + PatchedResource
Policy results[]ValidatingPolicyResponsePolicyResponse (single policy, flat rule list)
Enforcement fieldActions sets.Set[admissionregistrationv1.ValidationAction] per policyResolved via GetValidationFailureAction()kyvernov1.ValidationFailureAction
Mutation supportNoYes (GetPatches(), PatchedResource)

The legacy api.EngineResponse exposes GetValidationFailureAction() which walks kyvernov1.Spec.ValidationFailureAction and override lists . For VAP-based resources (including ValidatingAdmissionPolicy), this method explicitly returns an empty string .


ValidationAction vs. ValidationFailureAction#

vpolengineLegacy engine
Typeadmissionregistrationv1.ValidationAction (Kubernetes stdlib)kyvernov1.ValidationFailureAction (Kyverno-defined string)
ValuesDeny, Warn, Audit (set-based, multiple can coexist)Enforce / Audit (single value, case-insensitive variants)
Storagesets.Set[ValidationAction] on the internal Policy structField on kyvernov1.Spec + per-rule overrides

ValidationAction values are sourced from spec.ValidationActions() on the ValidatingPolicySpec . The legacy ValidationFailureAction is declared in api/kyverno/v1/spec_types.go, with Enforce and Audit as the canonical casing and deprecated lowercase aliases.


Internal Policy Struct#

Each compiled policy carried by the vpolengine is represented as a Policy struct with three fields: Actions (sets.Set[admissionregistrationv1.ValidationAction]), Policy (the API object), and CompiledPolicy (CEL-compiled rules). Actions is pre-computed at reconcile time so the Handle() hot-path does not re-read the spec on every request. The same action set is echoed into ValidatingPolicyResponse.Actions so consumers can apply enforcement decisions without re-fetching the policy.


Provider and Reconciliation#

Two provider modes are available :

  • NewProvider — static list, compiles all policies upfront (used in CLI / background scan pipelines).
  • NewKubeProvider — spins up two controller-runtime controllers, one for ValidatingPolicy and one for NamespacedValidatingPolicy, with optional PolicyException watch .

The reconciler skips policies whose status.generated == true (auto-generated policies are managed separately) and compiles autogen variants using autogen.Autogen() .


Evaluation Flow#

When Handle() is called :

  1. Fetches all compiled policies from the Provider.
  2. For JSON payload requests, evaluates directly without admission attributes.
  3. For admission requests, builds admission.Attributes from the AdmissionRequest, resolves the namespace object, then calls handlePolicy per policy.
  4. handlePolicy runs match constraints, calls CompiledPolicy.Evaluate(), and maps the EvaluationResult to engineapi.RulePass, RuleSkip, RuleFail, or RuleError.
  5. On a fail with a known validation index, the zero-based index of the failing CEL expression is stored in the cel.validationIndex annotation .

Exceptions are resolved during compilation (reconcile time), not at evaluation time. When exceptions are present the highest-priority exception (by label LabelPolicyExceptionPriority) determines whether the rule is skipped or passed .

ValidatingPolicy Engine | Dosu