Repository: kyverno/kyverno
Pull request #1252 (2020-11-12 19:07:07)

1251 fix generate panic
## Related issue

Fixes: https://github.com/kyverno/kyverno/issues/1251

<!--
Please link the GitHub issue this pull request resolves in the format of `#1234`. If you discussed this change
with a maintainer, please mention her/him using the `@` syntax (e.g. `@JimBugwadia`).

If this change neither resolves an existing issue nor has sign-off from one of the maintainers, there is a
chance substantial changes will be requested or that the changes will be rejected.

You can discuss changes with maintainers in the [Kyvrno Slack Channel](https://kubernetes.slack.com/).
-->

**What type of PR is this?**
<!--

> Uncomment only one ` /kind <>` line, hit enter to put that in a new line, and remove leading whitespaces from that line:
>
> /kind api-change

/kind bug

> /kind cleanup
> /kind design
> /kind documentation
> /kind failing-test
> /kind feature
-->

## Proposed changes

fixed panic and added logs

## Checklist

<!--
Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of
them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.
-->

- [x ] I have read the [contributing guidelines](../blob/master/CONTRIBUTING.md).
- [ ] I have added tests that prove my fix is effective or that my feature
      works.
- [ ] I have added or changed [the documentation](documentation/).

## Further comments

<!--
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution
you did and what alternatives you considered, etc...
-->



Patch:
diff --git a/go.sum b/go.sum
index d64f1044f..d8d99822c 100644
--- a/go.sum
+++ b/go.sum
@@ -341,6 +341,7 @@ github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSN
 github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
 github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -1114,6 +1115,7 @@ k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3
 k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
 k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
 k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
+k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU=
 k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
 mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
 mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
@@ -1137,6 +1139,7 @@ sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1
 sigs.k8s.io/structured-merge-diff v1.0.1 h1:LOs1LZWMsz1xs77Phr/pkB4LFaavH7IVq/3+WTN9XTA=
 sigs.k8s.io/structured-merge-diff v1.0.1/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
 sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
+sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E=
 sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
diff --git a/pkg/engine/variables/vars.go b/pkg/engine/variables/vars.go
index 261cb510d..6255a4f19 100644
--- a/pkg/engine/variables/vars.go
+++ b/pkg/engine/variables/vars.go
@@ -76,7 +76,7 @@ type NotFoundVariableErr struct {
 }
 
 func (n NotFoundVariableErr) Error() string {
-	return fmt.Sprintf("could not find variable %v at path %v", n.variable, n.path)
+	return fmt.Sprintf("variable %v not found (path: %v)", n.variable, n.path)
 }
 
 // subValR resolves the variables if defined
diff --git a/pkg/generate/cleanup/controller.go b/pkg/generate/cleanup/controller.go
index 33775af23..1a7d113f5 100644
--- a/pkg/generate/cleanup/controller.go
+++ b/pkg/generate/cleanup/controller.go
@@ -260,9 +260,9 @@ func (c *Controller) syncGenerateRequest(key string) error {
 	logger := c.log.WithValues("key", key)
 	var err error
 	startTime := time.Now()
-	logger.Info("started syncing generate request", "startTime", startTime)
+	logger.V(3).Info("started syncing generate request", "startTime", startTime)
 	defer func() {
-		logger.V(4).Info("finished syncying generate request", "processingTIme", time.Since(startTime).String())
+		logger.V(4).Info("finished syncing generate request", "processingTIme", time.Since(startTime).String())
 	}()
 	_, grName, err := cache.SplitMetaNamespaceKey(key)
 	if errors.IsNotFound(err) {
diff --git a/pkg/generate/controller.go b/pkg/generate/controller.go
index 7353cfd18..4513d6f53 100644
--- a/pkg/generate/controller.go
+++ b/pkg/generate/controller.go
@@ -294,7 +294,7 @@ func (c *Controller) syncGenerateRequest(key string) error {
 	logger := c.log
 	var err error
 	startTime := time.Now()
-	logger.Info("started sync", "key", key, "startTime", startTime)
+	logger.V(3).Info("started sync", "key", key, "startTime", startTime)
 	defer func() {
 		logger.V(4).Info("finished sync", "key", key, "processingTime", time.Since(startTime).String())
 	}()
diff --git a/pkg/generate/generate.go b/pkg/generate/generate.go
index cfd7d1546..e41593b8b 100644
--- a/pkg/generate/generate.go
+++ b/pkg/generate/generate.go
@@ -30,7 +30,7 @@ func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
 	resource, err = getResource(c.client, gr.Spec.Resource)
 	if err != nil {
 		// Dont update status
-		logger.Error(err, "resource does not exist or is yet to be created, requeueing")
+		logger.V(3).Info("resource does not exist or is pending creation, re-queueing", "details", err.Error())
 		return err
 	}
 
@@ -58,7 +58,8 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
 			for _, e := range gr.Status.GeneratedResources {
 				resp, err := c.client.GetResource(e.APIVersion, e.Kind, e.Namespace, e.Name)
 				if err != nil {
-					logger.Error(err, "Generated resource failed to get", "Resource", e.Name)
+					logger.Error(err, "failed to find generated resource", "name", e.Name)
+					continue
 				}
 
 				labels := resp.GetLabels()
@@ -68,9 +69,11 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
 					}
 				}
 			}
+
 			return nil, nil
 		}
-		logger.Error(err, "error in getting policy")
+
+		logger.Error(err, "error in fetching policy")
 		return nil, err
 	}
 
@@ -117,8 +120,10 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
 		if !r.Success {
 			grList, err := c.kyvernoClient.KyvernoV1().GenerateRequests(config.KubePolicyNamespace).List(contextdefault.TODO(), metav1.ListOptions{})
 			if err != nil {
+				logger.Error(err, "failed to list generate requests")
 				continue
 			}
+
 			for _, v := range grList.Items {
 				if engineResponse.PolicyResponse.Policy == v.Spec.Policy && engineResponse.PolicyResponse.Resource.Name == v.Spec.Resource.Name && engineResponse.PolicyResponse.Resource.Kind == v.Spec.Resource.Kind && engineResponse.PolicyResponse.Resource.Namespace == v.Spec.Resource.Namespace {
 					err := c.kyvernoClient.KyvernoV1().GenerateRequests(config.KubePolicyNamespace).Delete(contextdefault.TODO(), v.GetName(), metav1.DeleteOptions{})
@@ -161,8 +166,8 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
 		if !rule.HasGenerate() {
 			continue
 		}
-		startTime := time.Now()
 
+		startTime := time.Now()
 		processExisting := false
 
 		if len(rule.MatchResources.Kinds) > 0 {
@@ -182,8 +187,9 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
 		}
 
 		genResource, err := applyRule(log, c.client, rule, resource, ctx, policy.Name, gr, processExisting)
-
 		if err != nil {
+			log.Error(err, "failed to apply generate rule", "policy", policy.Name,
+				"rule", rule.Name, "resource", resource.GetName())
 			return nil, err
 		}
 
diff --git a/pkg/generate/status.go b/pkg/generate/status.go
index 28c1a3c13..10b5b4e20 100644
--- a/pkg/generate/status.go
+++ b/pkg/generate/status.go
@@ -32,7 +32,7 @@ func (sc StatusControl) Failed(gr kyverno.GenerateRequest, message string, genRe
 		log.Log.Error(err, "failed to update generate request status", "name", gr.Name)
 		return err
 	}
-	log.Log.Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Failed))
+	log.Log.V(3).Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Failed))
 	return nil
 }
 
diff --git a/samples/AddDefaultNetworkPolicy.md b/samples/AddDefaultNetworkPolicy.md
index 00dd957c9..2f74d2a8d 100644
--- a/samples/AddDefaultNetworkPolicy.md
+++ b/samples/AddDefaultNetworkPolicy.md
@@ -22,11 +22,12 @@ spec:
         - Namespace
         name: "*"
     exclude:
-      namespaces:
-        - "kube-system"
-        - "default"
-        - "kube-public"
-        - "kyverno"
+      resources:
+        namespaces:
+          - "kube-system"
+          - "default"
+          - "kube-public"
+          - "kyverno"
     generate:
       kind: NetworkPolicy
       name: default-deny-ingress
diff --git a/samples/README.md b/samples/README.md
index 51969a442..e8ff61b2d 100644
--- a/samples/README.md
+++ b/samples/README.md
@@ -1,6 +1,6 @@
 # Sample Policies
 
-Sample policies are designed to be applied to your Kubernetes clusters with minimal changes. 
+Sample policies are designed to be applied to your Kubernetes clusters with minimal changes.
 
 The policies are mostly validation rules in `audit` mode i.e. your existing workloads will not be impacted, but will be audited for policy complaince.
 
@@ -9,45 +9,49 @@ The policies are mostly validation rules in `audit` mode i.e. your existing work
 These policies are highly recommended.
 
 1. [Disallow root user](DisallowRootUser.md)
-2. [Disallow privileged containers](DisallowPrivilegedContainers.md)
-3. [Disallow new capabilities](DisallowNewCapabilities.md)
-4. [Disallow kernel parameter changes](DisallowSysctls.md)
-5. [Disallow use of bind mounts (`hostPath` volumes)](DisallowBindMounts.md)
-6. [Disallow docker socket bind mount](DisallowDockerSockMount.md)
-7. [Disallow `hostNetwork` and `hostPort`](DisallowHostNetworkPort.md)
-8. [Disallow `hostPID` and `hostIPC`](DisallowHostPIDIPC.md)
-9. [Disallow use of default namespace](DisallowDefaultNamespace.md)
-10. [Disallow latest image tag](DisallowLatestTag.md)
-11. [Disallow Helm Tiller](DisallowHelmTiller.md)
-12. [Require read-only root filesystem](RequireReadOnlyRootFS.md)
-13. [Require pod resource requests and limits](RequirePodRequestsLimits.md)
-14. [Require pod `livenessProbe` and `readinessProbe`](RequirePodProbes.md)
-15. [Add default network policy](AddDefaultNetworkPolicy.md)
-16. [Add namespace quotas](AddNamespaceQuotas.md)
-17. [Add `safe-to-evict` for pods with `emptyDir` and `hostPath` volumes](AddSafeToEvict.md)
+1. [Disallow privileged containers](DisallowPrivilegedContainers.md)
+1. [Disallow new capabilities](DisallowNewCapabilities.md)
+1. [Disallow kernel parameter changes](DisallowSysctls.md)
+1. [Disallow use of bind mounts (`hostPath` volumes)](DisallowBindMounts.md)
+1. [Disallow docker socket bind mount](DisallowDockerSockMount.md)
+1. [Disallow `hostNetwork` and `hostPort`](DisallowHostNetworkPort.md)
+1. [Disallow `hostPID` and `hostIPC`](DisallowHostPIDIPC.md)
+1. [Disallow use of default namespace](DisallowDefaultNamespace.md)
+1. [Disallow latest image tag](DisallowLatestTag.md)
+1. [Disallow Helm Tiller](DisallowHelmTiller.md)
+1. [Require read-only root filesystem](RequireReadOnlyRootFS.md)
+1. [Require pod resource requests and limits](RequirePodRequestsLimits.md)
+1. [Require pod `livenessProbe` and `readinessProbe`](RequirePodProbes.md)
+1. [Add default network policy](AddDefaultNetworkPolicy.md)
+1. [Add namespace quotas](AddNamespaceQuotas.md)
+1. [Add `safe-to-evict` for pods with `emptyDir` and `hostPath` volumes](AddSafeToEvict.md)
 
 ## Additional Policies
 
-These policies provide additional best practices and are worthy of close consideration. These policies may require specific changes for your workloads and environments. 
+These policies provide additional best practices and are worthy of close consideration. These policies may require specific changes for your workloads and environments.
 
-17. [Restrict image registries](RestrictImageRegistries.md)
-18. [Restrict `NodePort` services](RestrictNodePort.md)
-19. [Restrict auto-mount of service account credentials](RestrictAutomountSAToken.md)
-20. [Restrict ingress classes](RestrictIngressClasses.md)
-21. [Restrict User Group](CheckUserGroup.md)
+1. [Restrict image registries](RestrictImageRegistries.md)
+1. [Restrict `NodePort` services](RestrictNodePort.md)
+1. [Restrict auto-mount of service account credentials](RestrictAutomountSAToken.md)
+1. [Restrict ingress classes](RestrictIngressClasses.md)
+1. [Restrict User Group](CheckUserGroup.md)
+1. [Require pods are labeled](RequireLabels.md)
+1. [Require pods have certain labels](RequireCertainLabels.md)
+1. [Require Deployments have multiple replicas](RequireDeploymentsHaveReplicas.md)
 
 ## Applying the sample policies
 
 To apply these policies to your cluster, install Kyverno and import the policies as follows:
 
-**Install Kyverno**
+### Install Kyverno**
 
 ````sh
-kubectl create -f https://github.com/kyverno/kyverno/raw/master/definitions/install.yaml
+kubectl create -f https://raw.githubusercontent.com/kyverno/kyverno/main/definitions/release/install.yaml
 ````
+
 <small>[(installation docs)](../documentation/installation.md)</small>
 
-**Apply Kyverno Policies**
+### Apply Kyverno Policies**
 
 To start applying policies to your cluster, first clone the repo:
 
@@ -56,15 +60,14 @@ git clone https://github.com/kyverno/kyverno.git
 cd kyverno
 ````
 
-Import best_practices from [here](best_pratices):
+Import best practices from [here](best_pratices):
 
 ````bash
 kubectl create -f samples/best_practices
 ````
 
-Import addition policies from [here](more):
+Import additional policies from [here](more):
 
 ````bash
 kubectl create -f samples/more/
 ````
-
diff --git a/samples/RequireCertainLabels.md b/samples/RequireCertainLabels.md
new file mode 100644
index 000000000..925c3262f
--- /dev/null
+++ b/samples/RequireCertainLabels.md
@@ -0,0 +1,31 @@
+# Require certain labels
+
+In many cases, you may require that at least a certain number of labels are assigned to each Pod from a select list of approved labels. This sample policy demonstrates the [`anyPattern`](https://kyverno.io/docs/writing-policies/validate/#anypattern---logical-or-across-multiple-validation-patterns) option in a policy by requiring any of the two possible labels defined within. A pod must either have the label `app.kubernetes.io/name` or `app.kubernetes.io/component` defined.
+
+## Policy YAML
+
+[require_certain_labels.yaml](best_practices/require_certain_labels.yaml)
+
+```yaml
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+  name: require-certain-labels
+spec:
+  validationFailureAction: audit
+  rules:
+  - name: validate-certain-labels
+    match:
+      resources:
+        kinds:
+        - Pod
+    validate:
+      message: "The label `app.kubernetes.io/name` or `app.kubernetes.io/component` is required."
+      anyPattern:
+      - metadata:
+          labels:
+            app.kubernetes.io/name: "?*"
+      - metadata:
+          labels:
+            app.kubernetes.io/component: "?*"
+```
diff --git a/samples/RequireDeploymentsHaveReplicas.md b/samples/RequireDeploymentsHaveReplicas.md
new file mode 100644
index 000000000..24ec30fd1
--- /dev/null
+++ b/samples/RequireDeploymentsHaveReplicas.md
@@ -0,0 +1,40 @@
+# Require deployments have multiple replicas
+
+Deployments with only a single replica produce availability concerns should that single replica fail. In most cases, you would want Deployment objects to have more than one replica to ensure continued availability if not scale.
+
+This sample policy requires that Deployments have more than one replica excluding a list of system namespaces.
+
+## More Information
+
+* [Kubernetes Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)
+
+## Policy YAML
+
+[require_deployments_have_multiple_replicas.yaml](more/require_deployments_have_multiple_replicas.yaml)
+
+```yaml
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+  name: deployment-has-multiple-replicas
+spec:
+  validationFailureAction: audit
+  rules:
+    - name: deployment-has-multiple-replicas
+      match:
+        resources:
+          kinds:
+            - Deployment
+      exclude:
+        resources:
+          namespaces:
+          - kyverno
+          - kube-system
+          - kube-node-lease
+          - kube-public
+      validate:
+        message: "Deployments must have more than one replica to ensure availability."
+        pattern:
+          spec:
+            replicas: ">1"
+```
diff --git a/samples/RequireLabels.md b/samples/RequireLabels.md
new file mode 100644
index 000000000..3f90f963d
--- /dev/null
+++ b/samples/RequireLabels.md
@@ -0,0 +1,34 @@
+# Require labels
+
+Labels are a fundamental and important way to assign descriptive metadata to Kubernetes resources, especially Pods. Labels are especially important as the number of applications grow and are composed in different ways.
+
+This sample policy requires that the label `app.kubernetes.io/name` be defined on all Pods. If you wish to require that all Pods have multiple labels defined (as opposed to [any labels from an approved list](RequireCertainLabels.md)), this policy can be altered by adding an additional rule block which checks for a second (or third, etc.) label name.
+
+## More Information
+
+* [Common labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/)
+
+## Policy YAML
+
+[require_labels.yaml](best_practices/require_labels.yaml)
+
+```yaml
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+  name: require-labels
+spec:
+  validationFailureAction: audit
+  rules:
+  - name: check-for-labels
+    match:
+      resources:
+        kinds:
+        - Pod
+    validate:
+      message: "The label `app.kubernetes.io/name` is required."
+      pattern:
+        metadata:
+          labels:
+            app.kubernetes.io/name: "?*"
+```
diff --git a/samples/best_practices/require_certain_labels.yaml b/samples/best_practices/require_certain_labels.yaml
new file mode 100644
index 000000000..4bab7a50c
--- /dev/null
+++ b/samples/best_practices/require_certain_labels.yaml
@@ -0,0 +1,21 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+  name: require-certain-labels
+spec:
+  validationFailureAction: audit
+  rules:
+  - name: validate-certain-labels
+    match:
+      resources:
+        kinds:
+        - Pod
+    validate:
+      message: "The label `app.kubernetes.io/name` or `app.kubernetes.io/component` is required."
+      anyPattern:
+      - metadata:
+          labels:
+            app.kubernetes.io/name: "?*"
+      - metadata:
+          labels:
+            app.kubernetes.io/component: "?*"
\ No newline at end of file
diff --git a/samples/best_practices/require_labels.yaml b/samples/best_practices/require_labels.yaml
new file mode 100644
index 000000000..e79b4756b
--- /dev/null
+++ b/samples/best_practices/require_labels.yaml
@@ -0,0 +1,18 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+  name: require-labels
+spec:
+  validationFailureAction: audit
+  rules:
+  - name: check-for-labels
+    match:
+      resources:
+        kinds:
+        - Pod
+    validate:
+      message: "The label `app.kubernetes.io/name` is required."
+      pattern:
+        metadata:
+          labels:
+            app.kubernetes.io/name: "?*"
\ No newline at end of file
diff --git a/samples/more/require_deployments_have_multiple_replicas.yaml b/samples/more/require_deployments_have_multiple_replicas.yaml
new file mode 100644
index 000000000..a0d411159
--- /dev/null
+++ b/samples/more/require_deployments_have_multiple_replicas.yaml
@@ -0,0 +1,24 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+  name: deployment-has-multiple-replicas
+spec:
+  validationFailureAction: audit
+  rules:
+    - name: deployment-has-multiple-replicas
+      match:
+        resources:
+          kinds:
+            - Deployment
+      exclude:
+        resources:
+          namespaces:
+          - kyverno
+          - kube-system
+          - kube-node-lease
+          - kube-public
+      validate:
+        message: "Deployments must have more than one replica to ensure availability."
+        pattern:
+          spec:
+            replicas: ">1"
\ No newline at end of file


Test patch:
diff --git a/pkg/engine/mutation_test.go b/pkg/engine/mutation_test.go
index 5c5d90b66..a579fd278 100644
--- a/pkg/engine/mutation_test.go
+++ b/pkg/engine/mutation_test.go
@@ -160,7 +160,7 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
 		Context:     ctx,
 		NewResource: *resourceUnstructured}
 	er := Mutate(policyContext)
-	expectedErrorStr := "could not find variable request.object.metadata.name1 at path /spec/name"
+	expectedErrorStr := "variable request.object.metadata.name1 not found (path: /spec/name)"
 	t.Log(er.PolicyResponse.Rules[0].Message)
 	assert.Equal(t, er.PolicyResponse.Rules[0].Message, expectedErrorStr)
 }
diff --git a/pkg/engine/validation_test.go b/pkg/engine/validation_test.go
index 946b35f36..f99d58aff 100644
--- a/pkg/engine/validation_test.go
+++ b/pkg/engine/validation_test.go
@@ -1330,7 +1330,7 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
 		NewResource: *resourceUnstructured}
 	er := Validate(policyContext)
 	assert.Assert(t, !er.PolicyResponse.Rules[0].Success)
-	assert.Equal(t, er.PolicyResponse.Rules[0].Message, "Validation error: ; Validation rule 'test-path-not-exist' failed. 'could not find variable request.object.metadata.name1 at path /spec/containers/0/name'")
+	assert.Equal(t, er.PolicyResponse.Rules[0].Message, "Validation error: ; Validation rule 'test-path-not-exist' failed. 'variable request.object.metadata.name1 not found (path: /spec/containers/0/name)'")
 }
 
 func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies(t *testing.T) {
@@ -1512,7 +1512,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
 		NewResource: *resourceUnstructured}
 	er := Validate(policyContext)
 	assert.Assert(t, !er.PolicyResponse.Rules[0].Success)
-	assert.Equal(t, er.PolicyResponse.Rules[0].Message, "Substitutions failed: [could not find variable request.object.metadata.name1 at path /spec/template/spec/containers/0/name could not find variable request.object.metadata.name2 at path /spec/template/spec/containers/0/name]")
+	assert.Equal(t, er.PolicyResponse.Rules[0].Message, "Substitutions failed: [variable request.object.metadata.name1 not found (path: /spec/template/spec/containers/0/name) variable request.object.metadata.name2 not found (path: /spec/template/spec/containers/0/name)]")
 }
 
 func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatternSatisfy(t *testing.T) {