Kyverno CLI
The Kyverno Command Line Interface (CLI) is designed to validate and test policy behavior to resources prior to adding them to a cluster.
The CLI can be used in CI/CD pipelines to assist with the resource authoring process to ensure they conform to standards prior to them being deployed. It can be used as a kubectl plugin or as a standalone CLI.
The CLI, although composed of the same Kyverno codebase, is a purpose-built binary available via multiple installation methods but is distinct from the Kyverno container image which runs as a Pod in a target Kubernetes cluster.
This page covers the main Kyverno CLI commands, for other commands please refer to the Reference documentation
Install via Homebrew
Section titled “Install via Homebrew”The Kyverno CLI can also be installed with Homebrew as a formula.
brew install kyvernoInstall via Krew
Section titled “Install via Krew”You can use Krew to install the Kyverno CLI:
# Install Kyverno CLI using kubectl krew plugin managerkubectl krew install kyverno
# test the Kyverno CLIkubectl kyverno versionInstall via AUR (archlinux)
Section titled “Install via AUR (archlinux)”You can install the Kyverno CLI via your favorite AUR helper (e.g. yay)
yay -S kyverno-gitInstall in GitHub Actions
Section titled “Install in GitHub Actions”The Kyverno CLI can be installed in GitHub Actions using kyverno-cli-installer from the GitHub Marketplace. Please refer to kyverno-cli-installer for more information.
Manual Binary Installation
Section titled “Manual Binary Installation”The Kyverno CLI may also be installed by manually downloading the compiled binary available on the releases page. An example of installing the Kyverno CLI v1.12.0 on a Linux x86_64 system is shown below.
curl -LO https://github.com/kyverno/kyverno/releases/download/v1.12.0/kyverno-cli_v1.12.0_linux_x86_64.tar.gztar -xvf kyverno-cli_v1.12.0_linux_x86_64.tar.gzsudo cp kyverno /usr/local/bin/Building the CLI from source
Section titled “Building the CLI from source”You can also build the CLI binary from the Git repository (requires Go).
git clone https://github.com/kyverno/kyvernocd kyvernomake build-clisudo mv ./cmd/cli/kubectl-kyverno/kubectl-kyverno /usr/local/bin/Apply Command
Section titled “Apply Command”The apply command evaluates supported CEL-based Kyverno policies and Kubernetes-native admission policies against resource manifests, or against resources in a cluster when --cluster is specified. It can also show mutations and generate policy reports for supported policy types.
Apply a policy to local resources:
kyverno apply /path/to/policy.yaml --resource /path/to/resources.yamlEvaluate policies against resources in the current Kubernetes context:
kyverno apply /path/to/policy.yaml --clusterThe CLI supports Kubernetes ValidatingAdmissionPolicy and MutatingAdmissionPolicy, as well as Kyverno CEL policies such as ValidatingPolicy. The following examples show how to apply these policy types locally and against a cluster.
Applying Kubernetes Native Policies
Section titled “Applying Kubernetes Native Policies”The kyverno apply command can be used to apply native Kubernetes policies and their corresponding bindings to resources, allowing you to test them locally without a cluster.
Applying ValidatingAdmissionPolicy
Section titled “Applying ValidatingAdmissionPolicy”With the apply command, Kubernetes ValidatingAdmissionPolicies can be applied to resources as follows:
Policy manifest (check-deployment-replicas.yaml):
apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicymetadata: name: check-deployments-replicasspec: failurePolicy: Fail matchConstraints: resourceRules: - apiGroups: ['apps'] apiVersions: ['v1'] operations: ['CREATE', 'UPDATE'] resources: ['deployments'] validations: - expression: 'object.spec.replicas <= 3' message: 'Replicas must be less than or equal 3'Resource manifest (deployment.yaml):
apiVersion: apps/v1kind: Deploymentmetadata: name: nginx-passspec: replicas: 2 selector: matchLabels: app: nginx-pass template: metadata: labels: app: nginx-pass spec: containers: - name: nginx-server image: nginxApply the ValidatingAdmissionPolicy to the resource:
kyverno apply /path/to/check-deployment-replicas.yaml --resource /path/to/deployment.yamlThe following output will be generated:
Applying 1 policy rule(s) to 1 resource(s)...
pass: 1, fail: 0, warn: 0, error: 0, skip: 0The below example applies a ValidatingAdmissionPolicyBinding along with the policy to all resources in the cluster.
Policy manifest (check-deployment-replicas.yaml):
apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicymetadata: name: 'check-deployment-replicas'spec: matchConstraints: resourceRules: - apiGroups: - apps apiVersions: - v1 operations: - CREATE - UPDATE resources: - deployments validations: - expression: object.spec.replicas <= 5---apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicyBindingmetadata: name: 'check-deployment-replicas-binding'spec: policyName: 'check-deployment-replicas' validationActions: [Deny] matchResources: namespaceSelector: matchLabels: environment: stagingThe above policy verifies that the number of deployment replicas is not greater than 5 and is limited to a namespace labeled environment: staging.
Create a Namespace with the label environment: staging:
kubectl create ns stagingkubectl label ns staging environment=stagingCreate two Deployments, one of them in the staging namespace, which violates the policy.
kubectl create deployment nginx-1 --image=nginx --replicas=6 -n stagingkubectl create deployment nginx-2 --image=nginx --replicas=6Get all Deployments from the cluster:
kubectl get deployments -A
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGEdefault nginx-2 6/6 6 6 7m26skube-system coredns 2/2 2 2 13mlocal-path-storage local-path-provisioner 1/1 1 1 13mstaging nginx-1 6/6 6 6 7m44sApply the ValidatingAdmissionPolicy with its binding to all resources in the cluster:
kyverno apply /path/to/check-deployment-replicas.yaml --cluster --policy-reportThe following output will be generated:
Applying 1 policy rule(s) to 4 resource(s)...----------------------------------------------------------------------POLICY REPORT:----------------------------------------------------------------------apiVersion: wgpolicyk8s.io/v1alpha2kind: ClusterPolicyReportmetadata: creationTimestamp: null name: mergedresults:- message: 'failed expression: object.spec.replicas <= 5' policy: check-deployment-replicas resources: - apiVersion: apps/v1 kind: Deployment name: nginx-1 namespace: staging uid: a95d1594-44a7-4c8a-9225-04ac34cb9494 result: fail scored: true source: kyverno timestamp: nanos: 0 seconds: 1707394871summary: error: 0 fail: 1 pass: 0 skip: 0 warn: 0As expected, the policy is only applied to nginx-1 as it matches both the policy definition and its binding.
MutatingAdmissionPolicy
Section titled “MutatingAdmissionPolicy”Similarly, you can test a MutatingAdmissionPolicy to preview the changes it would make to a resource. The CLI will output the final, mutated resource.
Example 1: Basic Mutation
Section titled “Example 1: Basic Mutation”For instance, you can test a MutatingAdmissionPolicy that adds a label to a ConfigMap.
Policy manifest (add-label-to-configmap.yaml):
apiVersion: admissionregistration.k8s.io/v1alpha1kind: MutatingAdmissionPolicymetadata: name: 'add-label-to-configmap'spec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE'] resources: ['configmaps'] failurePolicy: Fail reinvocationPolicy: Never mutations: - patchType: 'ApplyConfiguration' applyConfiguration: expression: > object.metadata.?labels["lfx-mentorship"].hasValue() ? Object{} : Object{ metadata: Object.metadata{ labels: {"lfx-mentorship": "kyverno"}}}Resource manifest (configmap.yaml):
apiVersion: v1kind: ConfigMapmetadata: name: game-demo labels: app: gamedata: player_initial_lives: '3'Now, apply the MutatingAdmissionPolicy to the ConfigMap resource:
kyverno apply /path/to/add-label-to-configmap.yaml --resource /path/to/configmap.yamlThe output will show the mutated ConfigMap with the added label:
Applying 1 policy rule(s) to 1 resource(s)...
policy add-label-to-configmap applied to default/ConfigMap/game-demo:apiVersion: v1data: player_initial_lives: "3"kind: ConfigMapmetadata: labels: app: game lfx-mentorship: kyverno name: game-demo namespace: default---
Mutation has been applied successfully.pass: 1, fail: 0, warn: 0, error: 0, skip: 0The output displays the ConfigMap with the new lfx-mentorship: kyverno label, confirming the mutation was applied correctly.
Example 2: Mutation with a Binding and Namespace Selector
Section titled “Example 2: Mutation with a Binding and Namespace Selector”You can also test policies that include a MutatingAdmissionPolicyBinding to control where the policy is applied. This example makes use of a namespace selector to apply the policy only to ConfigMaps in a specific namespace.
To do this, you must provide a values.yaml file to simulate the labels of the Namespaces your resources belong to.
Policy manifest (add-label-to-configmap.yaml):
This file defines a policy to add a label and a binding that restricts it to Namespaces labeled environment: staging or environment: production.
apiVersion: admissionregistration.k8s.io/v1alpha1kind: MutatingAdmissionPolicymetadata: name: 'add-label-to-configmap'spec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE'] resources: ['configmaps'] failurePolicy: Fail reinvocationPolicy: Never mutations: - patchType: 'ApplyConfiguration' applyConfiguration: expression: > object.metadata.?labels["lfx-mentorship"].hasValue() ? Object{} : Object{ metadata: Object.metadata{ labels: {"lfx-mentorship": "kyverno"}}}---apiVersion: admissionregistration.k8s.io/v1alpha1kind: MutatingAdmissionPolicyBindingmetadata: name: 'add-label-to-configmap-binding'spec: policyName: 'add-label-to-configmap' matchResources: namespaceSelector: matchExpressions: - key: environment operator: In values: - staging - productionResource manifest (configmaps.yaml):
This file contains three ConfigMap resources in different Namespaces. Only the ones in staging and production should be mutated.
apiVersion: v1kind: ConfigMapmetadata: name: matched-cm-1 namespace: staging labels: color: reddata: player_initial_lives: '3'---apiVersion: v1kind: ConfigMapmetadata: name: matched-cm-2 namespace: production labels: color: reddata: player_initial_lives: '3'---apiVersion: v1kind: ConfigMapmetadata: name: unmatched-cm namespace: testing labels: color: bluedata: player_initial_lives: '3'Values file (values.yaml):
This file provides the necessary context. It tells the Kyverno CLI what labels are associated with the staging, production, and testing Namespaces so it can correctly evaluate the namespaceSelector in the binding.
apiVersion: cli.kyverno.io/v1alpha1kind: Valuemetadata: name: valuesnamespaceSelector: - labels: environment: staging name: staging - labels: environment: production name: production - labels: environment: testing name: testingNow, apply the MutatingAdmissionPolicy and its binding to the ConfigMaps:
kyverno apply /path/to/add-label-to-configmap.yaml --resource /path/to/configmaps.yaml -f /path/to/values.yamlThe output will show the mutated ConfigMaps in the staging and production Namespaces, while the one in the testing Namespace remains unchanged:
Applying 1 policy rule(s) to 3 resource(s)...
policy add-label-to-configmap applied to staging/ConfigMap/matched-cm-1:apiVersion: v1data: player_initial_lives: "3"kind: ConfigMapmetadata: labels: color: red lfx-mentorship: kyverno name: matched-cm-1 namespace: staging---
Mutation has been applied successfully.policy add-label-to-configmap applied to production/ConfigMap/matched-cm-2:apiVersion: v1data: player_initial_lives: "3"kind: ConfigMapmetadata: labels: color: red lfx-mentorship: kyverno name: matched-cm-2 namespace: production---
Mutation has been applied successfully.pass: 2, fail: 0, warn: 0, error: 0, skip: 0Applying ValidatingPolicies
Section titled “Applying ValidatingPolicies”In this example, we will apply a ValidatingPolicy against two Deployment manifests: one that complies with the policy and one that violates it.
First, we define a ValidatingPolicy that ensures any Deployment has no more than two replicas.
Policy manifest (check-deployment-replicas.yaml):
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: check-deployment-replicasspec: matchConstraints: resourceRules: - apiGroups: ['apps'] apiVersions: ['v1'] operations: ['CREATE', 'UPDATE'] resources: ['deployments'] validations: - expression: 'object.spec.replicas <= 2' message: 'Deployment replicas must be less than or equal to 2'Next, we have two Deployment manifests. The good-deployment is compliant with 2 replicas, while the bad-deployment is non-compliant with 3 replicas.
Resource manifest (deployments.yaml):
apiVersion: apps/v1kind: Deploymentmetadata: name: good-deployment labels: app: nginxspec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest---apiVersion: apps/v1kind: Deploymentmetadata: name: bad-deployment labels: app: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latestNow, we use the kyverno apply command to test the policy against both resources.
kyverno apply /path/to/check-deployment-replicas.yaml --resource /path/to/deployments.yaml --policy-reportThe following output will be generated:
apiVersion: openreports.io/v1alpha1kind: ClusterReportmetadata: creationTimestamp: null name: mergedresults:- message: Deployment replicas must be less than or equal 2 policy: check-deployment-replicas properties: process: background scan resources: - apiVersion: apps/v1 kind: Deployment name: bad-deployment namespace: default result: fail scored: true source: KyvernoValidatingPolicy timestamp: nanos: 0 seconds: 1752755472- message: success policy: check-deployment-replicas properties: process: background scan resources: - apiVersion: apps/v1 kind: Deployment name: good-deployment namespace: default result: pass scored: true source: KyvernoValidatingPolicy timestamp: nanos: 0 seconds: 1752755472source: ""summary: error: 0 fail: 1 pass: 1 skip: 0 warn: 0In addition to testing local YAML files, you can use the kyverno apply command to validate policies against resources that are already running in a Kubernetes cluster. Instead of specifying resource files with the --resource flag, you can use the --cluster flag.
For example, to test the check-deployment-replicas policy against all Deployment resources in your currently active cluster, you would run:
kyverno apply /path/to/check-deployment-replicas.yaml --cluster --policy-reportMany advanced policies need to look up the state of other resources in the cluster using Kyverno’s custom CEL functions like resource.Get(). When testing such policies locally with the kyverno apply command, the CLI cannot connect to the cluster to retrieve the required resources so you have to provide these resources as input via the --context-path flag.
This flag allows you to specify the resources that the policy will reference. The CLI will then use these resources to evaluate the policy.
This example demonstrates how to test a policy that validates an incoming Pod by checking its name against a value stored in a ConfigMap.
First, we define a ValidatingPolicy that uses resource.Get() to fetch a ConfigMap named policy-cm. The policy then validates that the incoming Pod’s name matches the name key in the ConfigMap’s data.
Policy manifest (check-pod-name-from-configmap.yaml):
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: check-pod-name-from-configmapspec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE', 'UPDATE'] resources: ['pods'] variables: # This variable uses a Kyverno CEL function to get a ConfigMap from the cluster. - name: cm expression: >- resource.Get("v1", "configmaps", object.metadata.namespace, "policy-cm") validations: # This rule validates that the Pod's name matches the 'name' key in the ConfigMap's data. - expression: >- object.metadata.name == variables.cm.data.nameNext, we define two Pod manifests: good-pod, which should pass the validation, and bad-pod, which should fail.
Resource manifest (pods.yaml):
apiVersion: v1kind: Podmetadata: name: good-podspec: containers: - name: nginx image: nginx---apiVersion: v1kind: Podmetadata: name: bad-podspec: containers: - name: nginx image: nginxBecause the CLI cannot connect to a cluster to fetch the policy-cm ConfigMap, we must provide it in a context file. This file contains a mock ConfigMap that resource.Get() will use during local evaluation.
Context file (context.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Contextmetadata: name: contextspec: # The resources defined here will be available to functions like resource.Get() resources: - apiVersion: v1 kind: ConfigMap metadata: namespace: default name: policy-cm data: # According to this, the valid pod name is 'good-pod'. name: good-podNow, we can run the kyverno apply command, providing the policy, the resources, and the context file. We also use the -p (or --policy-report) flag to generate a ClusterReport detailing the results.
kyverno apply /path/to/policy.yaml --resource /path/to/pods.yaml --context-file /path/to/context.yaml -pThe following output will be generated:
apiVersion: openreports.io/v1alpha1kind: ClusterReportmetadata: creationTimestamp: null name: mergedresults: - message: success policy: check-pod-name-from-configmap properties: process: background scan resources: - apiVersion: v1 kind: Pod name: good-pod namespace: default result: pass scored: true source: KyvernoValidatingPolicy timestamp: nanos: 0 seconds: 1752756617 - policy: check-pod-name-from-configmap properties: process: background scan resources: - apiVersion: v1 kind: Pod name: bad-pod namespace: default result: fail scored: true source: KyvernoValidatingPolicy timestamp: nanos: 0 seconds: 1752756617source: ''summary: error: 0 fail: 1 pass: 1 skip: 0 warn: 0-
The
good-podresource resulted in apassbecause its name matches the value in the ConfigMap provided by the context file. -
The
bad-podresource resulted in afailbecause its name does not match, and the report includes the validation error message from the policy.
When using the --cluster flag, the CLI connects to your active Kubernetes cluster, so a local context file is not needed. The resource.Get() function will fetch the live ConfigMap directly from the cluster so you have to ensure the ConfigMap and the Pod resources exist in your cluster before running the command.
kyverno apply /path/to/check-pod-name-from-configmap.yaml --cluster --policy-reportIn case of applying a CEL ValidatingPolicy with a policies.kyverno.io PolicyException, use the --exception flag to specify the exception manifest. The CLI will then apply the policy and its exception together.
In this example, we will test a CEL policy that disallows hostPath volumes, then use a policies.kyverno.io PolicyException to exempt a specific Pod.
Policy manifest (disallow-host-path.yaml):
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: disallow-host-pathspec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE', 'UPDATE'] resources: ['pods'] validations: - expression: '!has(object.spec.volumes) || object.spec.volumes.all(volume, !has(volume.hostPath))' message: 'HostPath volumes are forbidden. The field spec.volumes[*].hostPath must be unset.'Next, we define a Pod that clearly violates this policy by mounting a hostPath volume. Without an exception, this Pod would be blocked.
Resource manifest (pod-with-hostpath.yaml):
apiVersion: v1kind: Podmetadata: name: pod-with-hostpathspec: containers: - name: nginx image: nginx volumes: - name: udev hostPath: path: /etc/udevNow, create a CEL PolicyException to exempt the specific Pod from the policy. The exception matches the Pod by name and references the disallow-host-path policy.
Policy Exception manifest (exception.yaml):
apiVersion: policies.kyverno.io/v1kind: PolicyExceptionmetadata: name: exempt-hostpath-podspec: policyRefs: - name: disallow-host-path kind: ValidatingPolicy matchConditions: - name: 'skip-pod-by-name' expression: "object.metadata.name == 'pod-with-hostpath'"Now, we use the kyverno apply command, providing the policy, the resource, and the exception using the --exception flag. We will also use -p to generate a detailed report.
kyverno apply policy.yaml --resource resource.yaml --exception exception.yaml -pThe following output will be generated:
apiVersion: openreports.io/v1alpha1kind: ClusterReportmetadata: creationTimestamp: null name: mergedresults: - message: 'rule is skipped due to policy exception: exempt-hostpath-pod' policy: disallow-host-path properties: exceptions: exempt-hostpath-pod process: background scan resources: - apiVersion: v1 kind: Pod name: pod-with-hostpath namespace: default result: skip rule: exception scored: true source: KyvernoValidatingPolicy timestamp: nanos: 0 seconds: 1752759828source: ''summary: error: 0 fail: 0 pass: 0 skip: 1 warn: 0The output confirms that the CEL PolicyException worked as intended:
-
result: skip: The policy rule was not enforced on the resource. -
properties.exceptions: exempt-hostpath-pod: The report explicitly names the CEL PolicyException responsible for the skip. -
summary.skip: 1: The final count reflects that one rule was skipped.
Test Command
Section titled “Test Command”The test command evaluates policy behavior against resource manifests and compares the results with expectations declared in a kyverno-test.yaml file. It scans a local directory or Git repository for test manifests and runs each test with its colocated policy and resource files.
Kyverno CLI tests support CEL-based Kyverno policies, including ValidatingPolicy, and Kubernetes-native admission policies including ValidatingAdmissionPolicy and MutatingAdmissionPolicy. Use --detailed-results for comprehensive output, or pass -h for the command’s flags and usage.
Test File Structure
Section titled “Test File Structure”A test manifest identifies the policies and resources to evaluate, optional test context or CEL policy exceptions, and expected outcomes. For example:
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: kyverno-testpolicies: - policy.yamlresources: - resources.yamlcontext: context.yaml # optional mock resources for CEL resource lookupsvariables: values.yaml # optional CEL test values, such as mock namespace objectsexceptions: # optional PolicyException manifests for CEL ValidatingPolicies - exception.yamlapiCallResponses: # optional offline HTTP mocks for CEL http.Get()/http.Post() - url: https://example.com/api method: GET response: statusCode: 200 body: allowed: trueglobalContextEntries: # optional mock data for CEL globalContext.Get() - name: config data: allowed: trueresults: - isValidatingPolicy: true # set for a Kyverno CEL ValidatingPolicy policy: check-policy kind: Pod resources: - default/example result: pass - isValidatingAdmissionPolicy: true # set for a Kubernetes ValidatingAdmissionPolicy policy: check-native-policy kind: Pod resources: - default/example result: passFor native ValidatingAdmissionPolicy tests, set isValidatingAdmissionPolicy: true on the corresponding result. For Kyverno CEL ValidatingPolicy tests, set isValidatingPolicy: true. See the examples below for complete test manifests.
Test Against Local Files
Section titled “Test Against Local Files”Test a set of local files in the working directory.
kyverno test .Test a set of local files by specifying the directory.
kyverno test /path/to/folderContainingTestYamlsTest Against Git Repositories
Section titled “Test Against Git Repositories”Test an entire Git repository by specifying its URL. If a branch is not specified, main is used by default.
kyverno test https://github.com/owner/repositoryTest a specific directory of the repository by specifying the directory within repo URL and the branch with the --git-branch or -b flag. Even if testing against main, when using a directory in the URL of the repo requires passing the --git-branch or -b flag.
kyverno test https://github.com/owner/repository/path/to/tests -b branch-nameUse the -f flag to set a custom file name which includes test cases. By default, test will search for a file called kyverno-test.yaml.
Testing Policies with Image Registry Access
Section titled “Testing Policies with Image Registry Access”For CEL policies which require image registry access to set context variables, those variables may be sourced from a values file or from a live registry by passing the --registry flag.
Test Subset of Resources
Section titled “Test Subset of Resources”In some cases, you may wish to test only a subset of policy and resource combinations from a test manifest. Use the --test-case-selector flag to specify the exact tests you wish to execute.
kyverno test . --test-case-selector "policy=check-deployment-replicas, resource=nginx-demo"Kubernetes Native Policies
Section titled “Kubernetes Native Policies”The kyverno test command can be used to test native Kubernetes policies.
ValidatingAdmissionPolicy
Section titled “ValidatingAdmissionPolicy”To test a ValidatingAdmissionPolicy, the test manifest must include the isValidatingAdmissionPolicy: true field in each result entry.
Below is an example of testing a ValidatingAdmissionPolicy against two resources, one of which violates the policy.
Policy manifest (disallow-host-path.yaml):
apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicymetadata: name: disallow-host-pathspec: failurePolicy: Fail matchConstraints: resourceRules: - apiGroups: ['apps'] apiVersions: ['v1'] operations: ['CREATE', 'UPDATE'] resources: ['deployments'] validations: - expression: '!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))' message: 'HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset.'Resource manifest (deployments.yaml):
apiVersion: apps/v1kind: Deploymentmetadata: name: deployment-passspec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx-server image: nginx volumeMounts: - name: temp mountPath: /scratch volumes: - name: temp emptyDir: {}---apiVersion: apps/v1kind: Deploymentmetadata: name: deployment-failspec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx-server image: nginx volumeMounts: - name: udev mountPath: /data volumes: - name: udev hostPath: path: /etc/udevTest manifest (kyverno-test.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: disallow-host-path-testpolicies: - disallow-host-path.yamlresources: - deployments.yamlresults: - policy: disallow-host-path resources: - deployment-pass isValidatingAdmissionPolicy: true kind: Deployment result: pass - policy: disallow-host-path resources: - deployment-fail isValidatingAdmissionPolicy: true kind: Deployment result: fail$ kyverno test .
Loading test ( kyverno-test.yaml ) ... Loading values/variables ... Loading policies ... Loading resources ... Applying 1 policy to 2 resources ... Checking results ...
│────│────────────────────│──────│────────────────────────────│────────│────────││ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON ││────│────────────────────│──────│────────────────────────────│────────│────────││ 1 │ disallow-host-path │ │ Deployment/deployment-pass │ Pass │ Ok ││ 2 │ disallow-host-path │ │ Deployment/deployment-fail │ Pass │ Ok ││────│────────────────────│──────│────────────────────────────│────────│────────│
Test Summary: 2 tests passed and 0 tests failedIn the below example, a ValidatingAdmissionPolicy and its corresponding ValidatingAdmissionPolicyBinding are tested against six resources. Two of these resources do not match the binding, two match the binding but violate the policy, and the remaining two match the binding and do not violate the policy.
Policy manifest (check-deployment-replicas.yaml):
apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicymetadata: name: 'check-deployment-replicas'spec: matchConstraints: resourceRules: - apiGroups: - apps apiVersions: - v1 operations: - CREATE - UPDATE resources: - deployments validations: - expression: object.spec.replicas <= 2---apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicyBindingmetadata: name: 'check-deployment-replicas-binding'spec: policyName: 'check-deployment-replicas' validationActions: [Deny] matchResources: namespaceSelector: matchExpressions: - key: environment operator: In values: - staging - productionResource manifest (resource.yaml):
apiVersion: apps/v1kind: Deploymentmetadata: name: testing-deployment-1 namespace: testing labels: app: busyboxspec: replicas: 4 selector: matchLabels: app: busybox template: metadata: labels: app: busybox spec: containers: - name: busybox image: busybox:latest---apiVersion: apps/v1kind: Deploymentmetadata: name: testing-deployment-2 namespace: testing labels: app: busyboxspec: replicas: 2 selector: matchLabels: app: busybox template: metadata: labels: app: busybox spec: containers: - name: busybox image: busybox:latest---apiVersion: apps/v1kind: Deploymentmetadata: name: staging-deployment-1 namespace: staging labels: app: nginxspec: replicas: 4 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest---apiVersion: apps/v1kind: Deploymentmetadata: name: staging-deployment-2 namespace: staging labels: app: nginxspec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest---apiVersion: apps/v1kind: Deploymentmetadata: name: production-deployment-1 namespace: production labels: app: nginxspec: replicas: 4 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest---apiVersion: apps/v1kind: Deploymentmetadata: name: production-deployment-2 namespace: production labels: app: nginxspec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latestThe above resource manifest contains the following:
-
Two Deployments named
testing-deployment-1andtesting-deployment-2in thetestingnamespace. The first Deployment has four replicas, while the second Deployment has two. -
Two Deployments named
staging-deployment-1andstaging-deployment-2in thestagingnamespace. The first Deployment has four replicas, while the second Deployment has two. -
Two Deployments named
production-deployment-1andproduction-deployment-2in theproductionnamespace. The first Deployment has four replicas, while the second Deployment has two.
Variables manifest (values.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Valuesmetadata: name: valuesnamespaceSelector: - name: staging labels: environment: staging - name: production labels: environment: production - name: testing labels: environment: testingTest manifest (kyverno-test.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: kyverno-test.yamlpolicies: - policy.yamlresources: - resource.yamlvariables: values.yamlresults: - kind: Deployment policy: check-deployment-replicas isValidatingAdmissionPolicy: true resources: - testing-deployment-1 - testing-deployment-2 result: skip - kind: Deployment policy: check-deployment-replicas isValidatingAdmissionPolicy: true resources: - staging-deployment-1 - production-deployment-1 result: fail - kind: Deployment policy: check-deployment-replicas isValidatingAdmissionPolicy: true resources: - staging-deployment-2 - production-deployment-2 result: pass$ kyverno test .
Loading test ( kyverno-test.yaml ) ... Loading values/variables ... Loading policies ... Loading resources ... Loading exceptions ... Applying 1 policy to 6 resources ... Checking results ...
│────│───────────────────────────│──────│────────────────────────────────────│────────│──────────││ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON ││────│───────────────────────────│──────│────────────────────────────────────│────────│──────────││ 1 │ check-deployment-replicas │ │ Deployment/testing-deployment-1 │ Pass │ Excluded ││ 2 │ check-deployment-replicas │ │ Deployment/testing-deployment-2 │ Pass │ Excluded ││ 3 │ check-deployment-replicas │ │ Deployment/staging-deployment-1 │ Pass │ Ok ││ 4 │ check-deployment-replicas │ │ Deployment/production-deployment-1 │ Pass │ Ok ││ 5 │ check-deployment-replicas │ │ Deployment/staging-deployment-2 │ Pass │ Ok ││ 6 │ check-deployment-replicas │ │ Deployment/production-deployment-2 │ Pass │ Ok ││────│───────────────────────────│──────│────────────────────────────────────│────────│──────────│
Test Summary: 6 tests passed and 0 tests failedMutatingAdmissionPolicy
Section titled “MutatingAdmissionPolicy”To test a MutatingAdmissionPolicy, the test manifest must include the isMutatingAdmissionPolicy field set to true in the test results array. In addition, the patchedResources field must be included to specify the resource that is expected to be patched by the policy.
Example 1: Simple Mutation
Section titled “Example 1: Simple Mutation”This example tests a policy that adds a label to a ConfigMap.
Policy manifest (policy.yaml):
apiVersion: admissionregistration.k8s.io/v1alpha1kind: MutatingAdmissionPolicymetadata: name: 'add-label-to-configmap'spec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE'] resources: ['configmaps'] failurePolicy: Fail reinvocationPolicy: Never mutations: - patchType: 'ApplyConfiguration' applyConfiguration: expression: > object.metadata.?labels["lfx-mentorship"].hasValue() ? Object{} : Object{ metadata: Object.metadata{ labels: {"lfx-mentorship": "kyverno"}}}Resource manifest (resource.yaml):
apiVersion: v1kind: ConfigMapmetadata: name: game-demo labels: app: gamedata: player_initial_lives: '3'Patched resource manifest (patched-resource.yaml):
This file defines what the ConfigMap should look like after the policy is applied.
apiVersion: v1kind: ConfigMapmetadata: name: game-demo labels: app: game lfx-mentorship: kyvernodata: player_initial_lives: '3'Test manifest (kyverno-test.yaml):
apiVersion: kyverno.io/v1kind: Testmetadata: name: testpolicies: - policy.yamlresources: - resource.yamlresults: - isMutatingAdmissionPolicy: true kind: ConfigMap patchedResources: patched-resource.yaml policy: add-label-to-configmap resources: - game-demo result: pass$ kyverno test .
Loading test ( kyverno-test.yaml ) ... Loading values/variables ... Loading policies ... Loading resources ... Loading exceptions ... Applying 1 policy to 1 resource with 0 exceptions ... Checking results ...
│────│────────────────────────│──────│────────────────────────────────│────────│────────││ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON ││────│────────────────────────│──────│────────────────────────────────│────────│────────││ 1 │ add-label-to-configmap │ │ v1/ConfigMap/default/game-demo │ Pass │ Ok ││────│────────────────────────│──────│────────────────────────────────│────────│────────│
Test Summary: 1 tests passed and 0 tests failedExample 2: Mutation with a Binding and Namespace Selector
Section titled “Example 2: Mutation with a Binding and Namespace Selector”This example tests a policy that adds a label to ConfigMaps in specific namespaces.
Policy manifest (policy.yaml):
apiVersion: admissionregistration.k8s.io/v1alpha1kind: MutatingAdmissionPolicymetadata: name: 'add-label-to-configmap'spec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE'] resources: ['configmaps'] failurePolicy: Fail reinvocationPolicy: Never mutations: - patchType: 'ApplyConfiguration' applyConfiguration: expression: > object.metadata.?labels["lfx-mentorship"].hasValue() ? Object{} : Object{ metadata: Object.metadata{ labels: {"lfx-mentorship": "kyverno"}}}---apiVersion: admissionregistration.k8s.io/v1alpha1kind: MutatingAdmissionPolicyBindingmetadata: name: 'add-label-to-configmap-binding'spec: policyName: 'add-label-to-configmap' matchResources: namespaceSelector: matchExpressions: - key: environment operator: In values: - staging - productionResource manifest (resource.yaml):
apiVersion: v1kind: ConfigMapmetadata: name: matched-cm-1 namespace: staging labels: color: reddata: player_initial_lives: '3'---apiVersion: v1kind: ConfigMapmetadata: name: matched-cm-2 namespace: production labels: color: reddata: player_initial_lives: '3'---apiVersion: v1kind: ConfigMapmetadata: name: unmatched-cm namespace: testing labels: color: bluedata: player_initial_lives: '3'Patched resource manifest (patched-resource.yaml):
apiVersion: v1kind: ConfigMapmetadata: name: matched-cm-1 namespace: staging labels: color: red lfx-mentorship: kyvernodata: player_initial_lives: '3'---apiVersion: v1kind: ConfigMapmetadata: name: matched-cm-2 namespace: production labels: color: red lfx-mentorship: kyvernodata: player_initial_lives: '3'Variables manifest (values.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Valuemetadata: name: valuesnamespaceSelector: - labels: environment: staging name: staging - labels: environment: production name: production - labels: environment: testing name: testingTest manifest (kyverno-test.yaml):
apiVersion: kyverno.io/v1kind: Testmetadata: name: testpolicies: - policy.yamlresources: - resource.yamlresults: - isMutatingAdmissionPolicy: true kind: ConfigMap patchedResources: patched-resource.yaml policy: add-label-to-configmap resources: - matched-cm-1 - matched-cm-2 result: passvariables: values.yaml$ kyverno test .
Loading test ( kyverno-test.yaml ) ... Loading values/variables ... Loading policies ... Loading resources ... Loading exceptions ... Applying 1 policy to 3 resources with 0 exceptions ... Checking results ...
│────│────────────────────────│──────│──────────────────────────────────────│────────│────────││ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON ││────│────────────────────────│──────│──────────────────────────────────────│────────│────────││ 1 │ add-label-to-configmap │ │ v1/ConfigMap/staging/matched-cm-1 │ Pass │ Ok ││ 2 │ add-label-to-configmap │ │ v1/ConfigMap/production/matched-cm-2 │ Pass │ Ok ││────│────────────────────────│──────│──────────────────────────────────────│────────│────────│
Test Summary: 2 tests passed and 0 tests failedTesting ValidatingPolicies
Section titled “Testing ValidatingPolicies”To test a ValidatingPolicy, the test manifest must include the isValidatingPolicy field set to true in the results[] array.
Below is an example of testing a ValidatingPolicy against two resources, one of which violates the policy.
Policy manifest (check-deployment-replicas.yaml):
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: check-deployment-replicasspec: matchConstraints: resourceRules: - apiGroups: ['apps'] apiVersions: ['v1'] operations: ['CREATE', 'UPDATE'] resources: ['deployments'] validations: - expression: 'object.spec.replicas <= 2' message: 'Deployment replicas must be less than or equal to 2'Resource manifest (deployments.yaml):
apiVersion: apps/v1kind: Deploymentmetadata: name: good-deployment labels: app: nginxspec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest---apiVersion: apps/v1kind: Deploymentmetadata: name: bad-deployment labels: app: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latestTest manifest (kyverno-test.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: kyverno-testpolicies: - policy.yamlresources: - deployments.yamlresults: - isValidatingPolicy: true kind: Deployment policy: check-deployment-replicas resources: - bad-deployment result: fail - isValidatingPolicy: true kind: Deployment policy: check-deployment-replicas resources: - good-deployment result: pass$ kyverno test .
Loading test ( kyverno-test.yaml ) ... Loading values/variables ... Loading policies ... Loading resources ... Loading exceptions ... Applying 1 policy to 2 resources with 0 exceptions ... Checking results ...
│────│───────────────────────────│──────│────────────────────────────────────────────│────────│────────││ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON ││────│───────────────────────────│──────│────────────────────────────────────────────│────────│────────││ 1 │ check-deployment-replicas │ │ apps/v1/Deployment/default/bad-deployment │ Pass │ Ok ││ 2 │ check-deployment-replicas │ │ apps/v1/Deployment/default/good-deployment │ Pass │ Ok ││────│───────────────────────────│──────│────────────────────────────────────────────│────────│────────│
Test Summary: 2 tests passed and 0 tests failedSome policies need to make decisions based on the properties of the namespace where a resource is being created, such as its labels or name. The namespaceObject variable in CEL provides access to the full namespace object for this purpose.
When running kyverno test, the command operates in an offline mode and does not have access to a live cluster’s namespaces. To test policies that use namespaceObject, you must provide mock namespace definitions. This is done by creating a “values file” and referencing it in your kyverno-test.yaml.
Let’s start with a policy that disallows creating certain Deployments in the default namespace. It uses namespaceObject.metadata.name to check the name of the Namespace.
Policy manifest (disallow-default-deployment.yaml):
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: check-deployment-namespacespec: matchConstraints: resourceRules: - apiGroups: ['apps'] apiVersions: ['v1'] operations: ['CREATE', 'UPDATE'] resources: ['deployments'] # This policy only applies to Deployments with the label `app: nginx` objectSelector: matchLabels: app: nginx validations: # The validation logic checks the name of the Namespace object. - expression: "namespaceObject.metadata.name != 'default'" message: "Using 'default' namespace is not allowed for this application."We define several Deployments to cover all test cases:
- A Deployment in the
defaultnamespace (should fail). - A Deployment in a different namespace,
staging(should pass). - Two Deployments that do not have the
app: nginxlabel (should be skipped).
Resource manifest (deployments.yaml):
# This deployment should FAIL because it's in the 'default' namespace.apiVersion: apps/v1kind: Deploymentmetadata: name: bad-deployment namespace: default labels: app: nginxspec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest---# This deployment should PASS because it's in the 'staging' namespace.apiVersion: apps/v1kind: Deploymentmetadata: name: good-deployment namespace: staging labels: app: nginxspec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest---# This deployment should be SKIPPED because it lacks the 'app: nginx' label.apiVersion: apps/v1kind: Deploymentmetadata: name: skipped-deployment-1 namespace: defaultspec: replicas: 1 selector: matchLabels: app: busybox template: metadata: labels: app: busybox spec: containers: - name: busybox image: busybox:latest---# This deployment should also be SKIPPED for the same reason.apiVersion: apps/v1kind: Deploymentmetadata: name: skipped-deployment-2 namespace: stagingspec: replicas: 1 selector: matchLabels: app: busybox template: metadata: labels: app: busybox spec: containers: - name: busybox image: busybox:latestThis is the crucial step. We create a values file (e.g., values.yaml) to provide the mock Namespace objects. The kyverno test command will use these objects to populate the namespaceObject variable during the test run.
Values manifest (values.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Valuemetadata: name: valuesnamespaces: - apiVersion: v1 kind: namespace metadata: labels: environment: staging name: staging - apiVersion: v1 kind: namespace metadata: labels: environment: default name: defaultFinally, we create the test manifest that ties everything together.
Test manifest (kyverno-test.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: kyverno-test.yamlpolicies: - policy.yamlresources: - resources.yamlresults: - isValidatingPolicy: true kind: Deployment policy: check-deployment-namespace resources: - bad-deployment result: fail - isValidatingPolicy: true kind: Deployment policy: check-deployment-namespace resources: - good-deployment result: pass - isValidatingPolicy: true kind: Deployment policy: check-deployment-namespace resources: - skipped-deployment-1 - skipped-deployment-2 result: skipvariables: values.yaml$ kyverno test .
Loading test ( kyverno-test.yaml ) ... Loading values/variables ... Loading policies ... Loading resources ... Loading exceptions ... Applying 1 policy to 4 resources with 0 exceptions ... Checking results ...
│────│────────────────────────────│──────│────────────────────────────────────────────│────────│──────────││ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON ││────│────────────────────────────│──────│────────────────────────────────────────────│────────│──────────││ 1 │ check-deployment-namespace │ │ apps/v1/Deployment/default/bad-deployment │ Pass │ Ok ││ 2 │ check-deployment-namespace │ │ apps/v1/Deployment/staging/good-deployment │ Pass │ Ok ││ 3 │ check-deployment-namespace │ │ apps/Deployment/v1 │ Pass │ Excluded ││ 4 │ check-deployment-namespace │ │ apps/Deployment/v1 │ Pass │ Excluded ││────│────────────────────────────│──────│────────────────────────────────────────────│────────│──────────│
Test Summary: 4 tests passed and 0 tests failedPolicies often need to validate resources based on external data, such as a value stored in a ConfigMap. Kyverno’s custom CEL function resource.Get() allows policies to fetch these external resources from the cluster.
When using kyverno test for offline testing, you must provide this external resource as “context” so that the resource.Get() function can resolve successfully. This can be done by referencing a context file directly from your kyverno-test.yaml.
In this example, we will test a policy that validates a Pod’s name against a value stored in a ConfigMap.
First, let’s define a policy named check-pod-name-from-configmap. This policy uses resource.Get() to fetch a ConfigMap named policy-cm and then checks if the incoming Pod’s name matches the name key in the ConfigMap’s data.
Policy manifest (check-pod-name-from-configmap.yaml):
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: check-pod-name-from-configmapspec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: ['CREATE', 'UPDATE'] resources: ['pods'] variables: # Get the ConfigMap 'policy-cm' from the Pod's namespace. - name: cm expression: >- resource.Get("v1", "configmaps", object.metadata.namespace, "policy-cm") validations: # The Pod is valid only if its name matches the value from the ConfigMap. - expression: >- object.metadata.name == variables.cm.data.nameNext, we create a context file that contains the mock ConfigMap policy-cm. The kyverno test command will load this file and make its contents available to the resource.Get() function during the test.
Context manifest (context.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Contextmetadata: name: test-contextspec: resources: - apiVersion: v1 kind: ConfigMap metadata: namespace: default name: policy-cm data: # The 'name' key specifies that the only valid pod name is 'good-pod'. name: good-podWe define two Pod manifests: good-pod, whose name matches the value in our context, and bad-pod, whose name does not.
Resource manifest (pods.yaml):
# This Pod should PASS validation.apiVersion: v1kind: Podmetadata: name: good-podspec: containers: - name: nginx image: nginx---# This Pod should FAIL validation.apiVersion: v1kind: Podmetadata: name: bad-podspec: containers: - name: nginx image: nginxFinally, we create the kyverno-test.yaml file. The key here is the context: context.yaml field, which links our mock ConfigMap to the test.
Test manifest (kyverno-test.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: kyverno-test.yamlpolicies: - policy.yamlresources: - pod1.yaml - pod2.yamlresults: - isValidatingPolicy: true kind: Pod policy: disallow-host-path resources: - bad-pod result: fail - isValidatingPolicy: true kind: Pod policy: disallow-host-path resources: - good-pod result: passcontext: context.yaml$ kyverno test .
Loading test ( kyverno-test.yaml ) ... Loading values/variables ... Loading policies ... Loading resources ... Loading exceptions ... Applying 1 policy to 2 resources with 0 exceptions ... Checking results ...
│────│────────────────────│──────│─────────────────────────│────────│────────││ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON ││────│────────────────────│──────│─────────────────────────│────────│────────││ 1 │ disallow-host-path │ │ v1/Pod/default/bad-pod │ Pass │ Ok ││ 2 │ disallow-host-path │ │ v1/Pod/default/good-pod │ Pass │ Ok ││────│────────────────────│──────│─────────────────────────│────────│────────│
Test Summary: 2 tests passed and 0 tests failedTesting Policies with Offline HTTP Mocks and Global Context
Section titled “Testing Policies with Offline HTTP Mocks and Global Context”CEL policies that call an external HTTP service via http.Get() or http.Post(), or look up a GlobalContextEntry, can be tested offline with kyverno test. Starting in Kyverno CLI v1.14, kyverno-test.yaml accepts two optional fields — apiCallResponses and globalContextEntries — so expected external data can be declared inline for local development and CI/CD pipelines.
Schema overview
Section titled “Schema overview”apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: my-testpolicies: - policy.yamlresources: - resources.yaml# Inline mock responses for CEL http.Get() / http.Post() calls.apiCallResponses: - url: https://external-service.example.com/api/check # URL to match (required) method: GET # HTTP method (optional; matches any method if omitted) response: statusCode: 200 # Must be a valid HTTP status code (100–599) body: # Arbitrary JSON object allowed: true# Inline mock data for GlobalContextEntry references.# Each entry requires exactly ONE of: data, resources, or resourceFiles (mutually exclusive).globalContextEntries: - name: gctxentry-deployments # Must match the GlobalContextEntry name used in the policy # Option 1: arbitrary JSON root value data: deployments: - name: existing-deployment-1 - name: existing-deployment-2 # Option 2: inline Kubernetes resource manifests (mimics kubernetesResource cache shape) # resources: # - apiVersion: apps/v1 # kind: Deployment # metadata: # name: existing-deployment-1 # namespace: default # Option 3: YAML file paths relative to the test directory # resourceFiles: # - gce-deployments.yamlresults: - kind: Pod isValidatingPolicy: true policy: my-policy resources: - default/my-pod result: passMocking CEL http.Get() calls
Section titled “Mocking CEL http.Get() calls”The following example tests a ValidatingPolicy that calls an external configuration endpoint using Kyverno’s CEL http.Get() library function.
Policy manifest (policy.yaml):
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: check-external-configspec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: [CREATE, UPDATE] resources: [pods] variables: - name: config expression: http.Get("https://example.com/config") validations: - expression: variables.config.allowed == true message: 'External config check failed'Test manifest (kyverno-test.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: cel-http-get-mock-testpolicies: - policy.yamlresources: - resources.yamlapiCallResponses: - method: GET url: https://example.com/config response: statusCode: 200 body: allowed: trueresults: - isValidatingPolicy: true kind: Pod policy: check-external-config resources: - default/test-pod result: passRun the test:
kyverno test .Expected output:
Loading test ( kyverno-test.yaml ) ... Applying 1 policy to 1 resource with 0 exceptions ... Checking results ...
│────│───────────────────────│──────│─────────────────────────────│────────│────────││ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON ││────│───────────────────────│──────│─────────────────────────────│────────│────────││ 1 │ check-external-config │ │ v1/Pod/default/test-pod │ Pass │ Ok ││────│───────────────────────│──────│─────────────────────────────│────────│────────│
Test Summary: 1 tests passed and 0 tests failedMocking CEL http.Post() calls
Section titled “Mocking CEL http.Post() calls”The following example tests a ValidatingPolicy that calls an external authorization service using Kyverno’s CEL http.Post() library function. Both a pass scenario (the service allows the request) and a deny scenario (the service rejects the request) are shown.
Policy manifest (policy.yaml):
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: check-pod-admissionspec: matchConstraints: resourceRules: - apiGroups: [''] apiVersions: ['v1'] operations: [CREATE, UPDATE] resources: [pods] validations: - expression: >- http.Post("https://authz.example.com/validate", {"namespace": object.metadata.namespace, "name": object.metadata.name}).body.allowed == true message: 'External authorization service rejected this pod'Test manifest — pass scenario (kyverno-test.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: cel-http-post-mockpolicies: - policy.yamlresources: - resources.yamlapiCallResponses: - method: POST url: https://authz.example.com/validate response: statusCode: 200 body: allowed: trueresults: - isValidatingPolicy: true kind: Pod policy: check-pod-admission resources: - default/test-pod result: passTest manifest — deny scenario (kyverno-test.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: cel-http-post-mock-denypolicies: - policy.yamlresources: - resources.yamlapiCallResponses: - method: POST url: https://authz.example.com/validate response: statusCode: 200 body: allowed: falseresults: - isValidatingPolicy: true kind: Pod policy: check-pod-admission resources: - default/test-pod result: failRun the test:
kyverno test .Expected output (pass scenario):
Loading test ( kyverno-test.yaml ) ... Applying 1 policy to 1 resource with 0 exceptions ... Checking results ...
│────│───────────────────────│──────│─────────────────────────────│────────│────────││ ID │ POLICY │ RULE │ RESOURCE │ RESULT │ REASON ││────│───────────────────────│──────│─────────────────────────────│────────│────────││ 1 │ check-pod-admission │ │ v1/Pod/default/test-pod │ Pass │ Ok ││────│───────────────────────│──────│─────────────────────────────│────────│────────│
Test Summary: 1 tests passed and 0 tests failedMocking GlobalContextEntry data for CEL policies
Section titled “Mocking GlobalContextEntry data for CEL policies”The globalContextEntries field supplies offline data for CEL policies that call globalContext.Get(). Declare either arbitrary JSON with data, Kubernetes manifests with resources, or fixture file paths with resourceFiles for each entry. These sources are mutually exclusive.
For example, a ValidatingPolicy can read a mocked collection of Deployments:
Policy manifest (policy.yaml):
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: check-deployment-countspec: matchConstraints: resourceRules: - apiGroups: [apps] apiVersions: [v1] operations: [CREATE, UPDATE] resources: [deployments] variables: - name: deploymentData expression: globalContext.Get("gctxentry-deployments", "") validations: - expression: >- variables.deploymentData != null && size(variables.deploymentData.deployments) >= 2 message: 'At least two deployments must be present in global context'Test manifest (kyverno-test.yaml):
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: mock-global-contextpolicies: - policy.yamlresources: - resources.yamlglobalContextEntries: - name: gctxentry-deployments data: deployments: - name: existing-deployment-1 - name: existing-deployment-2results: - isValidatingPolicy: true kind: Deployment policy: check-deployment-count resources: - test-ns/test-deployment result: passFor larger fixtures, replace data with resourceFiles and list YAML manifests relative to the test directory, or use resources to define them inline. The policy’s CEL expression must read the shape of the data supplied by the selected source.