Repository: kyverno/kyverno
Pull request #1789 (2021-04-10 14:57:29)

Feature/1515 - handle configmap and api variable cli 
## Related issue

closes https://github.com/kyverno/kyverno/issues/1515, https://github.com/kyverno/kyverno/issues/1525

## What type of PR is this

> /kind feature

## Proposed changes
Variables should be passed in a yaml file in the following format:
```
policies:
  - name: <policy name>
    rules:
      - name: <rule name>
        values:
          <variable>: <value>
```

## Checklist


- [X] I have read the [contributing guidelines](https://github.com/kyverno/kyverno/blob/main/CONTRIBUTING.md).
- [X] I have added tests that prove my fix is effective or that my feature works.
- [X] I have added or changed [the documentation](https://github.com/kyverno/website).
  - If not, I have raised an issue in [kyverno/website](https://github.com/kyverno/website) to track the doc update:
  https://github.com/kyverno/website/issues/134



Patch:
diff --git a/charts/kyverno/Chart.yaml b/charts/kyverno/Chart.yaml
index 44f7b512c..5cc326d9a 100644
--- a/charts/kyverno/Chart.yaml
+++ b/charts/kyverno/Chart.yaml
@@ -1,7 +1,7 @@
 apiVersion: v1
 name: kyverno
-version: v1.3.5-rc5
-appVersion: v1.3.5-rc5
+version: v1.3.5
+appVersion: v1.3.5
 icon: https://github.com/kyverno/kyverno/raw/main/img/logo.png
 description: Kubernetes Native Policy Management
 keywords:
diff --git a/charts/kyverno/README.md b/charts/kyverno/README.md
index 4d73304eb..e1e3a3990 100644
--- a/charts/kyverno/README.md
+++ b/charts/kyverno/README.md
@@ -103,6 +103,7 @@ The following table lists the configurable parameters of the kyverno chart and t
 | `tolerations`                      | list of node taints to tolerate                                                                                                                                                                                                                              | `[]`                                                                                                                                                                              |
 | `securityContext`                  | security context configuration                                                                                                                                                                                                                               | `{}`                                                                                                                                                                              |
 | `podSecurityStandard`              | set desired pod security level `privileged`, `default`, `restricted`, `custom`. Set to `restricted` for maximum security for your cluster. See: https://kyverno.io/policies/pod-security/                                                                    | `default`                                                                                                                                                                         |
+| `podSecuritySeverity`              | set desired pod security severity `low`, `medium`, `high`. Used severity level in PolicyReportResults for the selected pod security policies.                                                                    | `medium`                                                                                                                                                                         |
 | `podSecurityPolicies`              | Policies to include when `podSecurityStandard` is set to `custom`                                                                                                                                                                                            | `[]`                                                                                                                                                                              |
 | `validationFailureAction`          | set to get response in failed validation check. Supported values- `audit`, `enforce`. See: https://kyverno.io/docs/writing-policies/validate/                                                                                                                | `audit`                                                                                                                                                                           |
 
diff --git a/charts/kyverno/templates/clusterrole.yaml b/charts/kyverno/templates/clusterrole.yaml
index ae9b6eea6..3cec33ff0 100644
--- a/charts/kyverno/templates/clusterrole.yaml
+++ b/charts/kyverno/templates/clusterrole.yaml
@@ -194,4 +194,4 @@ rules:
   - reportchangerequests
   - clusterreportchangerequests
   verbs:
-  - "*"
\ No newline at end of file
+  - "*"
diff --git a/charts/kyverno/templates/policies/default/disallow-adding-capabilities.yaml b/charts/kyverno/templates/policies/default/disallow-adding-capabilities.yaml
index 802f1adf9..680a28f9c 100644
--- a/charts/kyverno/templates/policies/default/disallow-adding-capabilities.yaml
+++ b/charts/kyverno/templates/policies/default/disallow-adding-capabilities.yaml
@@ -1,4 +1,4 @@
-{{ $name := "disallow-add-capabilities" -}}
+{{- $name := "disallow-add-capabilities" }}
 {{- if eq (include "kyverno.podSecurityDefault" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Default)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       Capabilities permit privileged actions without giving full root access.
       Adding capabilities beyond the default set must not be allowed.
@@ -33,4 +36,4 @@ spec:
           - =(securityContext):
               =(capabilities):
                 X(add): null
-{{- end -}}
\ No newline at end of file
+{{- end -}}
diff --git a/charts/kyverno/templates/policies/default/disallow-host-namespaces.yaml b/charts/kyverno/templates/policies/default/disallow-host-namespaces.yaml
index b99076ffe..59301ddf8 100644
--- a/charts/kyverno/templates/policies/default/disallow-host-namespaces.yaml
+++ b/charts/kyverno/templates/policies/default/disallow-host-namespaces.yaml
@@ -1,4 +1,4 @@
-{{ $name := "disallow-host-namespaces" -}}
+{{- $name := "disallow-host-namespaces" }}
 {{- if eq (include "kyverno.podSecurityDefault" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Default)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >- 
       Host namespaces (Process ID namespace, Inter-Process Communication namespace, and
       network namespace) allow access to shared information and can be used to elevate
diff --git a/charts/kyverno/templates/policies/default/disallow-host-path.yaml b/charts/kyverno/templates/policies/default/disallow-host-path.yaml
index f0ae2f13a..ed1418f5b 100644
--- a/charts/kyverno/templates/policies/default/disallow-host-path.yaml
+++ b/charts/kyverno/templates/policies/default/disallow-host-path.yaml
@@ -1,4 +1,4 @@
-{{ $name := "disallow-host-path" -}}
+{{- $name := "disallow-host-path" }}
 {{- if eq (include "kyverno.podSecurityDefault" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Default)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       HostPath volumes let pods use host directories and volumes in containers.
       Using host resources can be used to access shared data or escalate privileges
diff --git a/charts/kyverno/templates/policies/default/disallow-host-ports.yaml b/charts/kyverno/templates/policies/default/disallow-host-ports.yaml
index ac71ce3cc..c167ba569 100644
--- a/charts/kyverno/templates/policies/default/disallow-host-ports.yaml
+++ b/charts/kyverno/templates/policies/default/disallow-host-ports.yaml
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Default)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       Access to host ports allows potential snooping of network traffic and should not be
       allowed, or at minimum restricted to a known list.
diff --git a/charts/kyverno/templates/policies/default/disallow-privileged-containers.yaml b/charts/kyverno/templates/policies/default/disallow-privileged-containers.yaml
index 80e7c7eb3..1dfcc8cdc 100644
--- a/charts/kyverno/templates/policies/default/disallow-privileged-containers.yaml
+++ b/charts/kyverno/templates/policies/default/disallow-privileged-containers.yaml
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Default)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       Privileged mode disables most security mechanisms and must not be allowed.
 spec:
diff --git a/charts/kyverno/templates/policies/default/disallow-proc-mount.yaml b/charts/kyverno/templates/policies/default/disallow-proc-mount.yaml
index 0a0589ea3..9ab8447bf 100644
--- a/charts/kyverno/templates/policies/default/disallow-proc-mount.yaml
+++ b/charts/kyverno/templates/policies/default/disallow-proc-mount.yaml
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Default)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       The default /proc masks are set up to reduce attack surface and should be required.
 spec:
diff --git a/charts/kyverno/templates/policies/default/disallow-selinux.yaml b/charts/kyverno/templates/policies/default/disallow-selinux.yaml
index ab9eab833..3ab24dde8 100644
--- a/charts/kyverno/templates/policies/default/disallow-selinux.yaml
+++ b/charts/kyverno/templates/policies/default/disallow-selinux.yaml
@@ -7,6 +7,9 @@ metadata:
   annotations:
     policies.kyverno.io/title: Disallow SELinux
     policies.kyverno.io/category: Pod Security Standards (Default)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       SELinux options can be used to escalate privileges and should not be allowed.
 spec:
diff --git a/charts/kyverno/templates/policies/default/restrict-apparmor-profiles.yaml b/charts/kyverno/templates/policies/default/restrict-apparmor-profiles.yaml
index 792adc36e..9449c3e1f 100644
--- a/charts/kyverno/templates/policies/default/restrict-apparmor-profiles.yaml
+++ b/charts/kyverno/templates/policies/default/restrict-apparmor-profiles.yaml
@@ -1,4 +1,4 @@
-{{ $name := "restrict-apparmor-profiles" -}}
+{{- $name := "restrict-apparmor-profiles" }}
 {{- if eq (include "kyverno.podSecurityDefault" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -7,6 +7,9 @@ metadata:
   annotations:
     policies.kyverno.io/title: Restrict AppArmor
     policies.kyverno.io/category: Pod Security Standards (Default)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       On supported hosts, the 'runtime/default' AppArmor profile is applied by default. 
       The default policy should prevent overriding or disabling the policy, or restrict 
diff --git a/charts/kyverno/templates/policies/default/restrict-sysctls.yaml b/charts/kyverno/templates/policies/default/restrict-sysctls.yaml
index ab3d2d7e9..e9aae2761 100644
--- a/charts/kyverno/templates/policies/default/restrict-sysctls.yaml
+++ b/charts/kyverno/templates/policies/default/restrict-sysctls.yaml
@@ -1,4 +1,4 @@
-{{ $name := "restrict-sysctls" -}}
+{{- $name := "restrict-sysctls" }}
 {{- if eq (include "kyverno.podSecurityDefault" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Default)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       Sysctls can disable security mechanisms or affect all containers on a
       host, and should be disallowed except for an allowed "safe" subset. A
diff --git a/charts/kyverno/templates/policies/restricted/deny-privilege-escalation.yaml b/charts/kyverno/templates/policies/restricted/deny-privilege-escalation.yaml
index 9177b2f1a..b2850b3f7 100644
--- a/charts/kyverno/templates/policies/restricted/deny-privilege-escalation.yaml
+++ b/charts/kyverno/templates/policies/restricted/deny-privilege-escalation.yaml
@@ -1,4 +1,4 @@
-{{ $name := "deny-privilege-escalation" -}}
+{{- $name := "deny-privilege-escalation" }}
 {{- if eq (include "kyverno.podSecurityRestricted" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Restricted)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       Privilege escalation, such as via set-user-ID or set-group-ID file mode, should not be allowed.
 spec:
diff --git a/charts/kyverno/templates/policies/restricted/require-non-root-groups.yaml b/charts/kyverno/templates/policies/restricted/require-non-root-groups.yaml
index 2fd0cc121..4b950c3a4 100644
--- a/charts/kyverno/templates/policies/restricted/require-non-root-groups.yaml
+++ b/charts/kyverno/templates/policies/restricted/require-non-root-groups.yaml
@@ -1,4 +1,4 @@
-{{ $name := "require-non-root-groups" -}}
+{{- $name := "require-non-root-groups" }}
 {{- if eq (include "kyverno.podSecurityRestricted" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Restricted)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       Containers should be forbidden from running with a root primary or supplementary GID.
 spec:
@@ -53,10 +56,10 @@ spec:
             - Pod
       validate:
         message: >-
-          Changing of file system groups is not allowed. The field	
-          spec.securityContext.fsGroup must not be defined.
+          Changing to root group ID is disallowed. The field
+          spec.securityContext.fsGroup must be empty or greater than zero.
         pattern:
           spec:
             =(securityContext):
-              X(fsGroup): "*"
+              =(fsGroup): ">0"
 {{- end -}}
\ No newline at end of file
diff --git a/charts/kyverno/templates/policies/restricted/require-run-as-nonroot.yaml b/charts/kyverno/templates/policies/restricted/require-run-as-nonroot.yaml
index 0d6eaba15..70e7dcb83 100644
--- a/charts/kyverno/templates/policies/restricted/require-run-as-nonroot.yaml
+++ b/charts/kyverno/templates/policies/restricted/require-run-as-nonroot.yaml
@@ -1,4 +1,4 @@
-{{ $name := "require-run-as-non-root" -}}
+{{- $name := "require-run-as-non-root" }}
 {{- if eq (include "kyverno.podSecurityRestricted" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Restricted)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: Containers must be required to run as non-root users.
 spec:
   background: true
diff --git a/charts/kyverno/templates/policies/restricted/restrict-seccomp.yaml b/charts/kyverno/templates/policies/restricted/restrict-seccomp.yaml
index 5b96246ab..1bc7ae63a 100644
--- a/charts/kyverno/templates/policies/restricted/restrict-seccomp.yaml
+++ b/charts/kyverno/templates/policies/restricted/restrict-seccomp.yaml
@@ -1,4 +1,4 @@
-{{ $name := "restrict-seccomp" -}}
+{{- $name := "restrict-seccomp" }}
 {{- if eq (include "kyverno.podSecurityRestricted" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -7,6 +7,9 @@ metadata:
   annotations:
     policies.kyverno.io/title: Restrict Seccomp
     policies.kyverno.io/category: Pod Security Standards (Restricted)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       The runtime default seccomp profile must be required, or only specific
       additional profiles should be allowed.
diff --git a/charts/kyverno/templates/policies/restricted/restrict-volume-types.yaml b/charts/kyverno/templates/policies/restricted/restrict-volume-types.yaml
index 8ef906a5b..bdd6b3529 100644
--- a/charts/kyverno/templates/policies/restricted/restrict-volume-types.yaml
+++ b/charts/kyverno/templates/policies/restricted/restrict-volume-types.yaml
@@ -1,4 +1,4 @@
-{{ $name := "restrict-volume-types" -}}
+{{- $name := "restrict-volume-types" }}
 {{- if eq (include "kyverno.podSecurityRestricted" (merge (dict "name" $name) .)) "true" }}
 apiVersion: kyverno.io/v1
 kind: ClusterPolicy
@@ -6,6 +6,9 @@ metadata:
   name: {{ $name }}
   annotations:
     policies.kyverno.io/category: Pod Security Standards (Restricted)
+    {{- if .Values.podSecuritySeverity }}
+    policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }}
+    {{- end }}
     policies.kyverno.io/description: >-
       In addition to restricting HostPath volumes, the restricted pod security profile
       limits usage of non-core volume types to those defined through PersistentVolumes.
diff --git a/charts/kyverno/values.yaml b/charts/kyverno/values.yaml
index fbeef11bc..6add45e1a 100644
--- a/charts/kyverno/values.yaml
+++ b/charts/kyverno/values.yaml
@@ -4,6 +4,8 @@ namespace:
 # Supported- default/restricted/privileged/custom
 # For more info- https://kyverno.io/policies/pod-security
 podSecurityStandard: default
+# Supported- low/medium/high
+podSecuritySeverity: medium
 # Policies to include when podSecurityStandard is custom
 podSecurityPolicies: []
 # Supported values- `audit`, `enforce`
diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go
index 80044f500..c54a1480b 100755
--- a/cmd/kyverno/main.go
+++ b/cmd/kyverno/main.go
@@ -138,13 +138,14 @@ func main() {
 	if err != nil {
 		setupLog.Error(err, "ConfigMap lookup disabled: failed to create resource cache")
 	}
-
+	debug := serverIP != ""
 	webhookCfg := webhookconfig.NewRegister(
 		clientConfig,
 		client,
 		rCache,
 		serverIP,
 		int32(webhookTimeout),
+		debug,
 		log.Log)
 
 	// Resource Mutating Webhook Watcher
@@ -334,7 +335,6 @@ func main() {
 	// -- annotations on resources with update details on mutation JSON patches
 	// -- generate policy violation resource
 	// -- generate events on policy and resource
-	debug := serverIP != ""
 	server, err := webhooks.NewWebhookServer(
 		pclient,
 		client,
diff --git a/definitions/install.yaml b/definitions/install.yaml
index f525a571b..5dd2dea71 100644
--- a/definitions/install.yaml
+++ b/definitions/install.yaml
@@ -2441,7 +2441,7 @@ spec:
               fieldPath: metadata.namespace
         - name: KYVERNO_SVC
           value: kyverno-svc
-        image: ghcr.io/kyverno/kyverno:v1.3.5-rc5
+        image: ghcr.io/kyverno/kyverno:v1.3.5
         imagePullPolicy: IfNotPresent
         livenessProbe:
           failureThreshold: 2
@@ -2483,7 +2483,7 @@ spec:
           readOnlyRootFilesystem: true
           runAsNonRoot: true
       initContainers:
-      - image: ghcr.io/kyverno/kyvernopre:v1.3.5-rc5
+      - image: ghcr.io/kyverno/kyvernopre:v1.3.5
         imagePullPolicy: IfNotPresent
         name: kyverno-pre
         securityContext:
diff --git a/definitions/kustomization.yaml b/definitions/kustomization.yaml
index a92916ccb..5be95fbdd 100755
--- a/definitions/kustomization.yaml
+++ b/definitions/kustomization.yaml
@@ -8,7 +8,7 @@ resources:
 images:
 - name: ghcr.io/kyverno/kyverno
   newName: ghcr.io/kyverno/kyverno
-  newTag: v1.3.5-rc5
+  newTag: v1.3.5
 - name: ghcr.io/kyverno/kyvernopre
   newName: ghcr.io/kyverno/kyvernopre
-  newTag: v1.3.5-rc5
+  newTag: v1.3.5
diff --git a/definitions/release/install.yaml b/definitions/release/install.yaml
index f525a571b..5dd2dea71 100755
--- a/definitions/release/install.yaml
+++ b/definitions/release/install.yaml
@@ -2441,7 +2441,7 @@ spec:
               fieldPath: metadata.namespace
         - name: KYVERNO_SVC
           value: kyverno-svc
-        image: ghcr.io/kyverno/kyverno:v1.3.5-rc5
+        image: ghcr.io/kyverno/kyverno:v1.3.5
         imagePullPolicy: IfNotPresent
         livenessProbe:
           failureThreshold: 2
@@ -2483,7 +2483,7 @@ spec:
           readOnlyRootFilesystem: true
           runAsNonRoot: true
       initContainers:
-      - image: ghcr.io/kyverno/kyvernopre:v1.3.5-rc5
+      - image: ghcr.io/kyverno/kyvernopre:v1.3.5
         imagePullPolicy: IfNotPresent
         name: kyverno-pre
         securityContext:
diff --git a/go.mod b/go.mod
index eea78ccce..bf382246e 100644
--- a/go.mod
+++ b/go.mod
@@ -13,11 +13,12 @@ require (
 	github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
 	github.com/go-git/go-billy/v5 v5.0.0
 	github.com/go-git/go-git/v5 v5.2.0
-	github.com/go-logr/logr v0.3.0
+	github.com/go-logr/logr v0.4.0
 	github.com/googleapis/gnostic v0.5.4
 	github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
 	github.com/julienschmidt/httprouter v1.3.0
 	github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23
+	github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
 	github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7
 	github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a
 	github.com/mattn/go-isatty v0.0.12 // indirect
@@ -25,23 +26,21 @@ require (
 	github.com/onsi/ginkgo v1.14.1
 	github.com/onsi/gomega v1.10.2
 	github.com/opencontainers/go-digest v1.0.0 // indirect
-	github.com/opencontainers/image-spec v1.0.1 // indirect
 	github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6
 	github.com/patrickmn/go-cache v2.1.0+incompatible
 	github.com/pkg/errors v0.9.1
-	github.com/sirupsen/logrus v1.6.0 // indirect
 	github.com/spf13/cobra v1.1.1
 	github.com/stretchr/testify v1.6.1
-	gopkg.in/yaml.v2 v2.3.0
+	gopkg.in/yaml.v2 v2.4.0
 	gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
 	gotest.tools v2.2.0+incompatible
-	k8s.io/api v0.20.2
-	k8s.io/apiextensions-apiserver v0.20.2
-	k8s.io/apimachinery v0.20.2
+	k8s.io/api v0.21.0
+	k8s.io/apiextensions-apiserver v0.21.0
+	k8s.io/apimachinery v0.21.0
 	k8s.io/cli-runtime v0.20.2
-	k8s.io/client-go v0.20.2
-	k8s.io/klog/v2 v2.4.0
-	k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd
+	k8s.io/client-go v0.21.0
+	k8s.io/klog/v2 v2.8.0
+	k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7
 	sigs.k8s.io/controller-runtime v0.8.1
 	sigs.k8s.io/kustomize/api v0.7.0
 	sigs.k8s.io/kustomize/kyaml v0.10.3
@@ -51,6 +50,7 @@ require (
 // Added for go1.13 migration https://github.com/golang/go/issues/32805
 replace (
 	github.com/gorilla/rpc v1.2.0+incompatible => github.com/gorilla/rpc v1.2.0
+	github.com/jmespath/go-jmespath => github.com/kyverno/go-jmespath v0.4.1-0.20210302163943-f30eab0a3ed6
 	k8s.io/code-generator => k8s.io/code-generator v0.0.0-20200306081859-6a048a382944
 	k8s.io/component-base => k8s.io/component-base v0.0.0-20190612130303-4062e14deebe
 )
diff --git a/go.sum b/go.sum
index faf5fd3ab..89faae839 100644
--- a/go.sum
+++ b/go.sum
@@ -33,6 +33,7 @@ github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW
 github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
 github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
+github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
 github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
 github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
 github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
@@ -53,6 +54,7 @@ github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITg
 github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
 github.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
 github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
@@ -92,6 +94,7 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
 github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/aws/aws-sdk-go v1.20.21/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
@@ -237,6 +240,8 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7
 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
 github.com/go-logr/logr v0.3.0 h1:q4c+kbcR0d5rSurhBR8dIgieOaYpXtsdTYfx22Cu6rs=
 github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
+github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
 github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU=
 github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
 github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
@@ -316,6 +321,8 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
 github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
 github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -476,8 +483,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
 github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -498,6 +505,7 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v
 github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
 github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
@@ -523,6 +531,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kurin/blazer v0.5.4-0.20190613185654-cf2f27cc0be3/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
+github.com/kyverno/go-jmespath v0.4.1-0.20210302163943-f30eab0a3ed6 h1:9rJUAc/XxL6wV4i+3X56wcRM8tDhoo0l7DIieuXPGfk=
+github.com/kyverno/go-jmespath v0.4.1-0.20210302163943-f30eab0a3ed6/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7 h1:k/1ku0yehLCPqERCHkIHMDqDg1R02AcCScRuHbamU3s=
 github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7/go.mod h1:YR/zYthNdWfO8+0IOyHDcIDBBBS2JMnYUIwSsnwmRqU=
 github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -592,8 +602,10 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb
 github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -652,8 +664,6 @@ github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
 github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6 h1:lNCW6THrCKBiJBpz8kbVGjC7MgdCGKwuvBgc7LoD6sw=
 github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@@ -734,6 +744,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/skyrings/skyring-common v0.0.0-20160929130248-d1c0bb1cbd5e/go.mod h1:d8hQseuYt4rJoOo21lFzYJdhMjmDqLY++ayArbgYjWI=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@@ -808,6 +819,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
 github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
 github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yujunz/go-getter v1.5.1-lite.0.20201201013212-6d9c071adddf/go.mod h1:bL0Pr07HEdsMZ1WBqZIxXj96r5LnFsY4LgPaPEGkw1k=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -859,6 +872,8 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
+golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -888,6 +903,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -926,8 +942,11 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
+golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -941,6 +960,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -993,6 +1013,13 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY=
 golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M=
+golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1008,6 +1035,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
 golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1061,6 +1090,8 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
 golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1173,6 +1204,8 @@ gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -1192,11 +1225,15 @@ k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
 k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
 k8s.io/api v0.20.2 h1:y/HR22XDZY3pniu9hIFDLpUCPq2w5eQ6aV/VFQ7uJMw=
 k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8=
+k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y=
+k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU=
 k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY=
 k8s.io/apiextensions-apiserver v0.16.4/go.mod h1:HYQwjujEkXmQNhap2C9YDdIVOSskGZ3et0Mvjcyjbto=
 k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk=
 k8s.io/apiextensions-apiserver v0.20.2 h1:rfrMWQ87lhd8EzQWRnbQ4gXrniL/yTRBgYH1x1+BLlo=
 k8s.io/apiextensions-apiserver v0.20.2/go.mod h1:F6TXp389Xntt+LUq3vw6HFOLttPa0V8821ogLGwb6Zs=
+k8s.io/apiextensions-apiserver v0.21.0 h1:Nd4uBuweg6ImzbxkC1W7xUNZcCV/8Vt10iTdTIVF3hw=
+k8s.io/apiextensions-apiserver v0.21.0/go.mod h1:gsQGNtGkc/YoDG9loKI0V+oLZM4ljRPjc/sql5tmvzc=
 k8s.io/apimachinery v0.0.0-20190612125636-6a5db36e93ad/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
 k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4=
 k8s.io/apimachinery v0.16.4/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ=
@@ -1204,10 +1241,13 @@ k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZ
 k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
 k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg=
 k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA=
+k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
 k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg=
 k8s.io/apiserver v0.16.4/go.mod h1:kbLJOak655g6W7C+muqu1F76u9wnEycfKMqbVaXIdAc=
 k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
 k8s.io/apiserver v0.20.2/go.mod h1:2nKd93WyMhZx4Hp3RfgH2K5PhwyTrprrkWYnI7id7jA=
+k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg=
 k8s.io/cli-runtime v0.20.2 h1:W0/FHdbApnl9oB7xdG643c/Zaf7TZT+43I+zKxwqvhU=
 k8s.io/cli-runtime v0.20.2/go.mod h1:FjH6uIZZZP3XmwrXWeeYCbgxcrD6YXxoAykBaWH0VdM=
 k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk=
@@ -1216,6 +1256,8 @@ k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
 k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
 k8s.io/client-go v0.20.2 h1:uuf+iIAbfnCSw8IGAv/Rg0giM+2bOzHLOsbbrwrdhNQ=
 k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE=
+k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag=
+k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA=
 k8s.io/code-generator v0.0.0-20200306081859-6a048a382944/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
 k8s.io/component-base v0.0.0-20190612130303-4062e14deebe/go.mod h1:MmIDXnint3qMN0cqXHKrSiJ2XQKo3J1BPIz7in7NvO0=
 k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
@@ -1232,12 +1274,16 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
 k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ=
 k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=
+k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
 k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
 k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
 k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
 k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
 k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c=
 k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
+k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0=
+k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
 k8s.io/metrics v0.16.4/go.mod h1:dckkfqvaASo+NrzEmp8ST8yCc9hGt7lx9ABAILyDHx8=
 k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
 k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
@@ -1252,6 +1298,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
 sigs.k8s.io/controller-runtime v0.8.1 h1:O0K2CJ2JavK8/Tf4LfcpAwRxOFBhv8DjyrbmE6Qw59s=
 sigs.k8s.io/controller-runtime v0.8.1/go.mod h1:U/l+DUopBc1ecfRZ5aviA9JDmGFQKvLf5YkZNx2e0sU=
 sigs.k8s.io/controller-tools v0.2.4/go.mod h1:m/ztfQNocGYBgTTCmFdnK94uVvgxeZeE3LtJvd/jIzA=
@@ -1268,6 +1315,8 @@ sigs.k8s.io/structured-merge-diff v1.0.1/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8AP
 sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
 sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8=
 sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/pkg/common/common.go b/pkg/common/common.go
index 3a73bdb73..b46f35a4d 100644
--- a/pkg/common/common.go
+++ b/pkg/common/common.go
@@ -2,6 +2,7 @@ package common
 
 import (
 	"encoding/json"
+	"fmt"
 	"strings"
 
 	"github.com/go-logr/logr"
@@ -77,3 +78,33 @@ func GetKindFromGVK(str string) (apiVersion string, kind string) {
 	}
 	return splitString[0] + "/" + splitString[1], splitString[2]
 }
+
+func VariableToJSON(key, value string) []byte {
+	var subString string
+	splitBySlash := strings.Split(key, "\"")
+	if len(splitBySlash) > 1 {
+		subString = splitBySlash[1]
+	}
+
+	startString := ""
+	endString := ""
+	lenOfVariableString := 0
+	addedSlashString := false
+	for _, k := range strings.Split(splitBySlash[0], ".") {
+		if k != "" {
+			startString += fmt.Sprintf(`{"%s":`, k)
+			endString += `}`
+			lenOfVariableString = lenOfVariableString + len(k) + 1
+			if lenOfVariableString >= len(splitBySlash[0]) && len(splitBySlash) > 1 && !addedSlashString {
+				startString += fmt.Sprintf(`{"%s":`, subString)
+				endString += `}`
+				addedSlashString = true
+			}
+		}
+	}
+
+	midString := fmt.Sprintf(`"%s"`, value)
+	finalString := startString + midString + endString
+	var jsonData = []byte(finalString)
+	return jsonData
+}
diff --git a/pkg/engine/context/evaluate.go b/pkg/engine/context/evaluate.go
index 05bfec755..fb8181974 100644
--- a/pkg/engine/context/evaluate.go
+++ b/pkg/engine/context/evaluate.go
@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"strings"
 
-	jmespath "github.com/jmespath/go-jmespath"
+	jmespath "github.com/kyverno/kyverno/pkg/engine/jmespath"
 )
 
 //Query the JSON context with JMESPATH search path
@@ -25,7 +25,7 @@ func (ctx *Context) Query(query string) (interface{}, error) {
 	}
 
 	// compile the query
-	queryPath, err := jmespath.Compile(query)
+	queryPath, err := jmespath.New(query)
 	if err != nil {
 		ctx.log.Error(err, "incorrect query", "query", query)
 		return emptyResult, fmt.Errorf("incorrect query %s: %v", query, err)
diff --git a/pkg/engine/forceMutate.go b/pkg/engine/forceMutate.go
index 718629824..ee4bb9029 100644
--- a/pkg/engine/forceMutate.go
+++ b/pkg/engine/forceMutate.go
@@ -3,6 +3,7 @@ package engine
 import (
 	"fmt"
 
+	"github.com/ghodss/yaml"
 	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"github.com/kyverno/kyverno/pkg/engine/context"
 	"github.com/kyverno/kyverno/pkg/engine/mutate"
@@ -86,6 +87,28 @@ func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resour
 				return unstructured.Unstructured{}, fmt.Errorf(resp.Message)
 			}
 		}
+
+		if rule.Mutation.PatchStrategicMerge != nil {
+			var resp response.RuleResponse
+			resp, resource = mutate.ProcessStrategicMergePatch(rule.Name, rule.Mutation.PatchStrategicMerge, resource, logger.WithValues("rule", rule.Name))
+			if !resp.Success {
+				return unstructured.Unstructured{}, fmt.Errorf(resp.Message)
+			}
+		}
+
+		if rule.Mutation.PatchesJSON6902 != "" {
+			var resp response.RuleResponse
+			jsonPatches, err := yaml.YAMLToJSON([]byte(rule.Mutation.PatchesJSON6902))
+			if err != nil {
+				return unstructured.Unstructured{}, err
+			}
+
+			resp, resource = mutate.ProcessPatchJSON6902(rule.Name, jsonPatches, resource, logger.WithValues("rule", rule.Name))
+			if !resp.Success {
+				return unstructured.Unstructured{}, fmt.Errorf(resp.Message)
+			}
+		}
+
 	}
 
 	return resource, nil
diff --git a/pkg/engine/generation.go b/pkg/engine/generation.go
index ee9fc72c0..8d29ce6fb 100644
--- a/pkg/engine/generation.go
+++ b/pkg/engine/generation.go
@@ -87,7 +87,7 @@ func filterRule(rule kyverno.Rule, policyContext *PolicyContext) *response.RuleR
 	policyContext.JSONContext.Checkpoint()
 	defer policyContext.JSONContext.Restore()
 
-	if err := LoadContext(logger, rule.Context, resCache, policyContext); err != nil {
+	if err := LoadContext(logger, rule.Context, resCache, policyContext, rule.Name); err != nil {
 		logger.V(4).Info("cannot add external data to the context", "reason", err.Error())
 		return nil
 	}
diff --git a/pkg/engine/jmespath/functions.go b/pkg/engine/jmespath/functions.go
new file mode 100644
index 000000000..4bfad9f5f
--- /dev/null
+++ b/pkg/engine/jmespath/functions.go
@@ -0,0 +1,381 @@
+package jmespath
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
+
+	gojmespath "github.com/jmespath/go-jmespath"
+)
+
+var (
+	JpObject      = gojmespath.JpObject
+	JpString      = gojmespath.JpString
+	JpNumber      = gojmespath.JpNumber
+	JpArray       = gojmespath.JpArray
+	JpArrayString = gojmespath.JpArrayString
+)
+
+type (
+	JpType  = gojmespath.JpType
+	ArgSpec = gojmespath.ArgSpec
+)
+
+// function names
+var (
+	compare                = "compare"
+	contains               = "contains"
+	equalFold              = "equal_fold"
+	replace                = "replace"
+	replaceAll             = "replace_all"
+	toUpper                = "to_upper"
+	toLower                = "to_lower"
+	trim                   = "trim"
+	split                  = "split"
+	equals                 = "equals"
+	regexReplaceAll        = "regex_replace_all"
+	regexReplaceAllLiteral = "regex_replace_all_literal"
+	regexMatch             = "regex_match"
+)
+
+const errorPrefix = "JMESPath function '%s': "
+const invalidArgumentTypeError = errorPrefix + "%d argument is expected of %s type"
+const genericError = errorPrefix + "%s"
+
+func getFunctions() []*gojmespath.FunctionEntry {
+	return []*gojmespath.FunctionEntry{
+		{
+			Name: compare,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString}},
+			},
+			Handler: jpfCompare,
+		},
+		{
+			Name: contains,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString}},
+			},
+			Handler: jpfContains,
+		},
+		{
+			Name: equalFold,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString}},
+			},
+			Handler: jpfEqualFold,
+		},
+		{
+			Name: replace,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpNumber}},
+			},
+			Handler: jpfReplace,
+		},
+		{
+			Name: replaceAll,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString}},
+			},
+			Handler: jpfReplaceAll,
+		},
+		{
+			Name: toUpper,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+			},
+			Handler: jpfToUpper,
+		},
+		{
+			Name: toLower,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+			},
+			Handler: jpfToLower,
+		},
+		{
+			Name: trim,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString}},
+			},
+			Handler: jpfTrim,
+		},
+		{
+			Name: split,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString}},
+			},
+			Handler: jpfSplit,
+		},
+		{
+			Name: regexReplaceAll,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString, JpNumber}},
+				{Types: []JpType{JpString, JpNumber}},
+			},
+			Handler: jpRegexReplaceAll,
+		},
+		{
+			Name: regexReplaceAllLiteral,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString, JpNumber}},
+				{Types: []JpType{JpString, JpNumber}},
+			},
+			Handler: jpRegexReplaceAllLiteral,
+		},
+		{
+			Name: regexMatch,
+			Arguments: []ArgSpec{
+				{Types: []JpType{JpString}},
+				{Types: []JpType{JpString, JpNumber}},
+			},
+			Handler: jpRegexMatch,
+		},
+	}
+
+}
+
+func jpfCompare(arguments []interface{}) (interface{}, error) {
+	var err error
+	a, err := validateArg(compare, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	b, err := validateArg(compare, arguments, 1, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.Compare(a.String(), b.String()), nil
+}
+
+func jpfContains(arguments []interface{}) (interface{}, error) {
+	var err error
+	str, err := validateArg(contains, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	substr, err := validateArg(contains, arguments, 1, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.Contains(str.String(), substr.String()), nil
+}
+
+func jpfEqualFold(arguments []interface{}) (interface{}, error) {
+	var err error
+	a, err := validateArg(equalFold, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	b, err := validateArg(equalFold, arguments, 1, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.EqualFold(a.String(), b.String()), nil
+}
+
+func jpfReplace(arguments []interface{}) (interface{}, error) {
+	var err error
+	str, err := validateArg(replace, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	old, err := validateArg(replace, arguments, 1, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	new, err := validateArg(replace, arguments, 2, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	n, err := validateArg(replace, arguments, 3, reflect.Float64)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.Replace(str.String(), old.String(), new.String(), int(n.Float())), nil
+}
+
+func jpfReplaceAll(arguments []interface{}) (interface{}, error) {
+	var err error
+	str, err := validateArg(replaceAll, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	old, err := validateArg(replaceAll, arguments, 1, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	new, err := validateArg(replaceAll, arguments, 2, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.ReplaceAll(str.String(), old.String(), new.String()), nil
+}
+
+func jpfToUpper(arguments []interface{}) (interface{}, error) {
+	var err error
+	str, err := validateArg(toUpper, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.ToUpper(str.String()), nil
+}
+
+func jpfToLower(arguments []interface{}) (interface{}, error) {
+	var err error
+	str, err := validateArg(toLower, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.ToLower(str.String()), nil
+}
+
+func jpfTrim(arguments []interface{}) (interface{}, error) {
+	var err error
+	str, err := validateArg(trim, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	cutset, err := validateArg(trim, arguments, 1, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.Trim(str.String(), cutset.String()), nil
+}
+
+func jpfSplit(arguments []interface{}) (interface{}, error) {
+	var err error
+	str, err := validateArg(split, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	sep, err := validateArg(split, arguments, 1, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.Split(str.String(), sep.String()), nil
+}
+
+func jpRegexReplaceAll(arguments []interface{}) (interface{}, error) {
+	var err error
+	regex, err := validateArg(regexReplaceAll, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	src, err := ifaceToString(arguments[1])
+	if err != nil {
+		return nil, fmt.Errorf(invalidArgumentTypeError, regexReplaceAll, 2, "String or Real")
+	}
+
+	repl, err := ifaceToString(arguments[2])
+	if err != nil {
+		return nil, fmt.Errorf(invalidArgumentTypeError, regexReplaceAll, 3, "String or Real")
+	}
+
+	reg, err := regexp.Compile(regex.String())
+	if err != nil {
+		return nil, fmt.Errorf(genericError, regexReplaceAll, err.Error())
+	}
+	return string(reg.ReplaceAll([]byte(src), []byte(repl))), nil
+}
+
+func jpRegexReplaceAllLiteral(arguments []interface{}) (interface{}, error) {
+	var err error
+	regex, err := validateArg(regexReplaceAllLiteral, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	src, err := ifaceToString(arguments[1])
+	if err != nil {
+		return nil, fmt.Errorf(invalidArgumentTypeError, regexReplaceAllLiteral, 2, "String or Real")
+	}
+
+	repl, err := ifaceToString(arguments[2])
+	if err != nil {
+		return nil, fmt.Errorf(invalidArgumentTypeError, regexReplaceAllLiteral, 3, "String or Real")
+	}
+
+	reg, err := regexp.Compile(regex.String())
+	if err != nil {
+		return nil, fmt.Errorf(genericError, regexReplaceAllLiteral, err.Error())
+	}
+	return string(reg.ReplaceAllLiteral([]byte(src), []byte(repl))), nil
+}
+
+func jpRegexMatch(arguments []interface{}) (interface{}, error) {
+	var err error
+	regex, err := validateArg(regexMatch, arguments, 0, reflect.String)
+	if err != nil {
+		return nil, err
+	}
+
+	src, err := ifaceToString(arguments[1])
+	if err != nil {
+		return nil, fmt.Errorf(invalidArgumentTypeError, regexMatch, 2, "String or Real")
+	}
+
+	return regexp.Match(regex.String(), []byte(src))
+}
+
+// InterfaceToString casts an interface to a string type
+func ifaceToString(iface interface{}) (string, error) {
+	switch iface.(type) {
+	case int:
+		return strconv.Itoa(iface.(int)), nil
+	case float64:
+		return strconv.FormatFloat(iface.(float64), 'f', -1, 32), nil
+	case float32:
+		return strconv.FormatFloat(iface.(float64), 'f', -1, 32), nil
+	case string:
+		return iface.(string), nil
+	case bool:
+		return strconv.FormatBool(iface.(bool)), nil
+	default:
+		return "", errors.New("error, undefined type cast")
+	}
+}
+
+func validateArg(f string, arguments []interface{}, index int, expectedType reflect.Kind) (reflect.Value, error) {
+	arg := reflect.ValueOf(arguments[index])
+	if arg.Type().Kind() != expectedType {
+		return reflect.Value{}, fmt.Errorf(invalidArgumentTypeError, equalFold, index+1, expectedType.String())
+	}
+
+	return arg, nil
+}
diff --git a/pkg/engine/jmespath/new.go b/pkg/engine/jmespath/new.go
new file mode 100644
index 000000000..5714de69d
--- /dev/null
+++ b/pkg/engine/jmespath/new.go
@@ -0,0 +1,18 @@
+package jmespath
+
+import (
+	gojmespath "github.com/jmespath/go-jmespath"
+)
+
+func New(query string) (*gojmespath.JMESPath, error) {
+	jp, err := gojmespath.Compile(query)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, function := range getFunctions() {
+		jp.Register(function)
+	}
+
+	return jp, nil
+}
diff --git a/pkg/engine/jsonContext.go b/pkg/engine/jsonContext.go
index 207086f14..5429cd88a 100644
--- a/pkg/engine/jsonContext.go
+++ b/pkg/engine/jsonContext.go
@@ -8,41 +8,56 @@ import (
 	"strings"
 
 	"github.com/go-logr/logr"
-	"github.com/jmespath/go-jmespath"
 	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
+	pkgcommon "github.com/kyverno/kyverno/pkg/common"
 	"github.com/kyverno/kyverno/pkg/engine/context"
+	jmespath "github.com/kyverno/kyverno/pkg/engine/jmespath"
 	"github.com/kyverno/kyverno/pkg/engine/variables"
+	"github.com/kyverno/kyverno/pkg/kyverno/store"
 	"github.com/kyverno/kyverno/pkg/resourcecache"
 	"k8s.io/client-go/dynamic/dynamiclister"
 )
 
 // LoadContext - Fetches and adds external data to the Context.
-func LoadContext(logger logr.Logger, contextEntries []kyverno.ContextEntry, resCache resourcecache.ResourceCache, ctx *PolicyContext) error {
+func LoadContext(logger logr.Logger, contextEntries []kyverno.ContextEntry, resCache resourcecache.ResourceCache, ctx *PolicyContext, ruleName string) error {
 	if len(contextEntries) == 0 {
 		return nil
 	}
 
-	// get GVR Cache for "configmaps"
-	// can get cache for other resources if the informers are enabled in resource cache
-	gvrC, ok := resCache.GetGVRCache("ConfigMap")
-	if !ok {
-		return errors.New("configmaps GVR Cache not found")
-	}
-
-	lister := gvrC.Lister()
+	policyName := ctx.Policy.Name
+	if store.GetMock() {
+		rule := store.GetPolicyRuleFromContext(policyName, ruleName)
+		variables := rule.Values
 
-	for _, entry := range contextEntries {
-		if entry.ConfigMap != nil {
-			if err := loadConfigMap(logger, entry, lister, ctx.JSONContext); err != nil {
+		for key, value := range variables {
+			jsonData := pkgcommon.VariableToJSON(key, value)
+			if err := ctx.JSONContext.AddJSON(jsonData); err != nil {
 				return err
 			}
-		} else if entry.APICall != nil {
-			if err := loadAPIData(logger, entry, ctx); err != nil {
-				return err
+		}
+
+	} else {
+		// get GVR Cache for "configmaps"
+		// can get cache for other resources if the informers are enabled in resource cache
+		gvrC, ok := resCache.GetGVRCache("ConfigMap")
+		if !ok {
+			return errors.New("configmaps GVR Cache not found")
+		}
+
+		lister := gvrC.Lister()
+
+		for _, entry := range contextEntries {
+			if entry.ConfigMap != nil {
+				if err := loadConfigMap(logger, entry, lister, ctx.JSONContext); err != nil {
+					return err
+				}
+			} else if entry.APICall != nil {
+				if err := loadAPIData(logger, entry, ctx); err != nil {
+					return err
+				}
 			}
 		}
 	}
-
 	return nil
 }
 
@@ -88,7 +103,7 @@ func loadAPIData(logger logr.Logger, entry kyverno.ContextEntry, ctx *PolicyCont
 }
 
 func applyJMESPath(jmesPath string, jsonData []byte) (interface{}, error) {
-	jp, err := jmespath.Compile(jmesPath)
+	jp, err := jmespath.New(jmesPath)
 	if err != nil {
 		return nil, fmt.Errorf("failed to compile JMESPath: %s, error: %v", jmesPath, err)
 	}
diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go
index 6b44cf130..1bdbdb531 100644
--- a/pkg/engine/mutation.go
+++ b/pkg/engine/mutation.go
@@ -72,7 +72,7 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
 		logger.V(3).Info("matched mutate rule")
 
 		policyContext.JSONContext.Restore()
-		if err := LoadContext(logger, rule.Context, resCache, policyContext); err != nil {
+		if err := LoadContext(logger, rule.Context, resCache, policyContext, rule.Name); err != nil {
 			logger.Error(err, "failed to load context")
 			continue
 		}
diff --git a/pkg/engine/validate/validate.go b/pkg/engine/validate/validate.go
index 4cc90db8b..fc7f31edb 100644
--- a/pkg/engine/validate/validate.go
+++ b/pkg/engine/validate/validate.go
@@ -59,8 +59,18 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
 	case string, float64, int, int64, bool, nil:
 		/*Analyze pattern */
 
-		if !ValidateValueWithPattern(log, resourceElement, patternElement) {
-			return path, fmt.Errorf("Validation rule failed at '%s' to validate value '%v' with pattern '%v'", path, resourceElement, patternElement)
+		switch resource := resourceElement.(type) {
+		case []interface{}:
+			for _, res := range resource {
+				if !ValidateValueWithPattern(log, res, patternElement) {
+					return path, fmt.Errorf("Validation rule failed at '%s' to validate value '%v' with pattern '%v'", path, resourceElement, patternElement)
+				}
+			}
+			return "", nil
+		default:
+			if !ValidateValueWithPattern(log, resourceElement, patternElement) {
+				return path, fmt.Errorf("Validation rule failed at '%s' to validate value '%v' with pattern '%v'", path, resourceElement, patternElement)
+			}
 		}
 
 	default:
@@ -117,7 +127,6 @@ func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}
 }
 
 func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, originPattern interface{}, path string, ac *common.AnchorKey) (string, error) {
-
 	if 0 == len(patternArray) {
 		return path, fmt.Errorf("Pattern Array empty")
 	}
@@ -130,6 +139,11 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
 		if err != nil {
 			return elemPath, err
 		}
+	case string, float64, int, int64, bool, nil:
+		elemPath, err := validateResourceElement(log, resourceArray, typedPatternElement, originPattern, path, ac)
+		if err != nil {
+			return elemPath, err
+		}
 	default:
 		// In all other cases - detect type and handle each array element with validateResourceElement
 		if len(resourceArray) >= len(patternArray) {
diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go
index 353d9e4e5..5fa35e4b0 100644
--- a/pkg/engine/validation.go
+++ b/pkg/engine/validation.go
@@ -97,7 +97,7 @@ func validateResource(log logr.Logger, ctx *PolicyContext) *response.EngineRespo
 		}
 
 		ctx.JSONContext.Restore()
-		if err := LoadContext(log, rule.Context, ctx.ResourceCache, ctx); err != nil {
+		if err := LoadContext(log, rule.Context, ctx.ResourceCache, ctx, rule.Name); err != nil {
 			log.Error(err, "failed to load context")
 			continue
 		}
diff --git a/pkg/engine/variables/vars.go b/pkg/engine/variables/vars.go
index 11943e740..2711ce984 100644
--- a/pkg/engine/variables/vars.go
+++ b/pkg/engine/variables/vars.go
@@ -185,6 +185,11 @@ func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface) jsonUt
 			for _, v := range vars {
 				variable := replaceBracesAndTrimSpaces(v)
 
+				if variable == "@" {
+					currentPath := getJMESPath(data.Path)
+					variable = strings.Replace(variable, "@", fmt.Sprintf("request.object%s", currentPath), -1)
+				}
+
 				operation, err := ctx.Query("request.operation")
 				if err == nil && operation == "DELETE" {
 					variable = strings.ReplaceAll(variable, "request.object", "request.oldObject")
@@ -228,6 +233,13 @@ func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface) jsonUt
 	})
 }
 
+// getJMESPath converts path to JMES format
+func getJMESPath(rawPath string) string {
+	path := strings.ReplaceAll(rawPath, "/", ".")
+	regex := regexp.MustCompile(`\.([\d])\.`)
+	return string(regex.ReplaceAll([]byte(path), []byte("[$1].")))
+}
+
 func substituteVarInPattern(pattern, variable string, value interface{}) (string, error) {
 	var stringToSubstitute string
 
diff --git a/pkg/generate/generate.go b/pkg/generate/generate.go
index bf80d13f4..44f5a57c0 100644
--- a/pkg/generate/generate.go
+++ b/pkg/generate/generate.go
@@ -221,7 +221,7 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext *engine.
 		}
 
 		// add configmap json data to context
-		if err := engine.LoadContext(log, rule.Context, resCache, policyContext); err != nil {
+		if err := engine.LoadContext(log, rule.Context, resCache, policyContext, rule.Name); err != nil {
 			log.Error(err, "cannot add configmaps to context")
 			return nil, err
 		}
@@ -377,7 +377,9 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
 	newResource.SetAPIVersion(genAPIVersion)
 	// manage labels
 	// - app.kubernetes.io/managed-by: kyverno
-	// - kyverno.io/generated-by: kind/namespace/name (trigger resource)
+	// "kyverno.io/generated-by-kind": kind (trigger resource)
+	// "kyverno.io/generated-by-namespace": namespace (trigger resource)
+	// "kyverno.io/generated-by-name": name (trigger resource)
 	manageLabels(newResource, resource)
 	// Add Synchronize label
 	label := newResource.GetLabels()
diff --git a/pkg/kyverno/apply/command.go b/pkg/kyverno/apply/command.go
index ecd8033a7..5f9358d5a 100644
--- a/pkg/kyverno/apply/command.go
+++ b/pkg/kyverno/apply/command.go
@@ -15,6 +15,7 @@ import (
 	"github.com/kyverno/kyverno/pkg/engine/response"
 	"github.com/kyverno/kyverno/pkg/kyverno/common"
 	sanitizederror "github.com/kyverno/kyverno/pkg/kyverno/sanitizedError"
+	"github.com/kyverno/kyverno/pkg/kyverno/store"
 	"github.com/kyverno/kyverno/pkg/openapi"
 	policy2 "github.com/kyverno/kyverno/pkg/policy"
 	"github.com/spf13/cobra"
@@ -148,6 +149,7 @@ func Command() *cobra.Command {
 func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, mutateLogPath string,
 	variablesString string, valuesFile string, namespace string, policyPaths []string, stdin bool) (validateEngineResponses []*response.EngineResponse, rc *resultCounts, resources []*unstructured.Unstructured, skippedPolicies []SkippedPolicy, err error) {
 
+	store.SetMock(true)
 	kubernetesConfig := genericclioptions.NewConfigFlags(true)
 	fs := memfs.New()
 
@@ -286,7 +288,7 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
 				thisPolicyResourceValues[k] = v
 			}
 
-			if len(common.PolicyHasVariables(*policy)) > 0 && len(thisPolicyResourceValues) == 0 {
+			if len(common.PolicyHasVariables(*policy)) > 0 && len(thisPolicyResourceValues) == 0 && len(store.GetContext().Policies) == 0 {
 				return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Sprintf("policy %s have variables. pass the values for the variables using set/values_file flag", policy.Name), err)
 			}
 
diff --git a/pkg/kyverno/common/common.go b/pkg/kyverno/common/common.go
index cd7b6f5fe..62f09775b 100644
--- a/pkg/kyverno/common/common.go
+++ b/pkg/kyverno/common/common.go
@@ -16,11 +16,13 @@ import (
 	"github.com/go-git/go-billy/v5"
 	"github.com/go-logr/logr"
 	v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
+	pkgcommon "github.com/kyverno/kyverno/pkg/common"
 	client "github.com/kyverno/kyverno/pkg/dclient"
 	"github.com/kyverno/kyverno/pkg/engine"
 	"github.com/kyverno/kyverno/pkg/engine/context"
 	"github.com/kyverno/kyverno/pkg/engine/response"
 	sanitizederror "github.com/kyverno/kyverno/pkg/kyverno/sanitizedError"
+	"github.com/kyverno/kyverno/pkg/kyverno/store"
 	"github.com/kyverno/kyverno/pkg/policymutation"
 	"github.com/kyverno/kyverno/pkg/utils"
 	ut "github.com/kyverno/kyverno/pkg/utils"
@@ -32,15 +34,15 @@ import (
 )
 
 // GetPolicies - Extracting the policies from multiple YAML
-
-type Resource struct {
-	Name   string            `json:"name"`
-	Values map[string]string `json:"values"`
-}
-
 type Policy struct {
 	Name      string     `json:"name"`
 	Resources []Resource `json:"resources"`
+	Rules     []Rule     `json:"rules"`
+}
+
+type Rule struct {
+	Name   string            `json:"name"`
+	Values map[string]string `json:"values"`
 }
 
 type Values struct {
@@ -48,6 +50,11 @@ type Values struct {
 	NamespaceSelectors []NamespaceSelector `json:"namespaceSelector"`
 }
 
+type Resource struct {
+	Name   string            `json:"name"`
+	Values map[string]string `json:"values"`
+}
+
 type NamespaceSelector struct {
 	Name   string            `json:"name"`
 	Labels map[string]string `json:"labels"`
@@ -305,9 +312,9 @@ func RemoveDuplicateVariables(matches [][]string) string {
 	return variableStr
 }
 
-// GetVariable - get the variables from console/file
 func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit bool, policyresoucePath string) (map[string]string, map[string]map[string]Resource, map[string]map[string]string, error) {
-	valuesMap := make(map[string]map[string]Resource)
+	valuesMapResource := make(map[string]map[string]Resource)
+	valuesMapRule := make(map[string]map[string]Rule)
 	namespaceSelectorMap := make(map[string]map[string]string)
 	variables := make(map[string]string)
 	var yamlFile []byte
@@ -331,25 +338,33 @@ func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit
 		}
 
 		if err != nil {
-			return variables, valuesMap, namespaceSelectorMap, sanitizederror.NewWithError("unable to read yaml", err)
+			return variables, valuesMapResource, namespaceSelectorMap, sanitizederror.NewWithError("unable to read yaml", err)
 		}
 
 		valuesBytes, err := yaml.ToJSON(yamlFile)
 		if err != nil {
-			return variables, valuesMap, namespaceSelectorMap, sanitizederror.NewWithError("failed to convert json", err)
+			return variables, valuesMapResource, namespaceSelectorMap, sanitizederror.NewWithError("failed to convert json", err)
 		}
 
 		values := &Values{}
 		if err := json.Unmarshal(valuesBytes, values); err != nil {
-			return variables, valuesMap, namespaceSelectorMap, sanitizederror.NewWithError("failed to decode yaml", err)
+			return variables, valuesMapResource, namespaceSelectorMap, sanitizederror.NewWithError("failed to decode yaml", err)
 		}
 
 		for _, p := range values.Policies {
-			pmap := make(map[string]Resource)
+			resourceMap := make(map[string]Resource)
 			for _, r := range p.Resources {
-				pmap[r.Name] = r
+				resourceMap[r.Name] = r
+			}
+			valuesMapResource[p.Name] = resourceMap
+
+			if p.Rules != nil {
+				ruleMap := make(map[string]Rule)
+				for _, r := range p.Rules {
+					ruleMap[r.Name] = r
+				}
+				valuesMapRule[p.Name] = ruleMap
 			}
-			valuesMap[p.Name] = pmap
 		}
 
 		for _, n := range values.NamespaceSelectors {
@@ -357,7 +372,26 @@ func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit
 		}
 	}
 
-	return variables, valuesMap, namespaceSelectorMap, nil
+	storePolices := make([]store.Policy, 0)
+	for policyName, ruleMap := range valuesMapRule {
+		storeRules := make([]store.Rule, 0)
+		for _, rule := range ruleMap {
+			storeRules = append(storeRules, store.Rule{
+				Name:   rule.Name,
+				Values: rule.Values,
+			})
+		}
+		storePolices = append(storePolices, store.Policy{
+			Name:  policyName,
+			Rules: storeRules,
+		})
+	}
+
+	store.SetContext(store.Context{
+		Policies: storePolices,
+	})
+
+	return variables, valuesMapResource, namespaceSelectorMap, nil
 }
 
 // MutatePolices - function to apply mutation on policies
@@ -409,32 +443,7 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
 
 	ctx := context.NewContext()
 	for key, value := range variables {
-		var subString string
-		splitBySlash := strings.Split(key, "\"")
-		if len(splitBySlash) > 1 {
-			subString = splitBySlash[1]
-		}
-
-		startString := ""
-		endString := ""
-		lenOfVariableString := 0
-		addedSlashString := false
-		for _, k := range strings.Split(splitBySlash[0], ".") {
-			if k != "" {
-				startString += fmt.Sprintf(`{"%s":`, k)
-				endString += `}`
-				lenOfVariableString = lenOfVariableString + len(k) + 1
-				if lenOfVariableString >= len(splitBySlash[0]) && len(splitBySlash) > 1 && addedSlashString == false {
-					startString += fmt.Sprintf(`{"%s":`, subString)
-					endString += `}`
-					addedSlashString = true
-				}
-			}
-		}
-
-		midString := fmt.Sprintf(`"%s"`, value)
-		finalString := startString + midString + endString
-		var jsonData = []byte(finalString)
+		jsonData := pkgcommon.VariableToJSON(key, value)
 		ctx.AddJSON(jsonData)
 	}
 
diff --git a/pkg/kyverno/crds/policy_crd.go b/pkg/kyverno/crds/policy_crd.go
new file mode 100644
index 000000000..9b7df79c4
--- /dev/null
+++ b/pkg/kyverno/crds/policy_crd.go
@@ -0,0 +1,709 @@
+package crds
+
+const PolicyCRD = `
+{
+	"group": "kyverno.io",
+	"names": {
+	  "kind": "Policy",
+	  "listKind": "PolicyList",
+	  "plural": "policies",
+	  "shortNames": [
+		"pol"
+	  ],
+	  "singular": "policy"
+	},
+	"scope": "Namespaced",
+	"versions": [
+	  {
+		"additionalPrinterColumns": [
+		  {
+			"jsonPath": ".spec.background",
+			"name": "Background",
+			"type": "string"
+		  },
+		  {
+			"jsonPath": ".spec.validationFailureAction",
+			"name": "Action",
+			"type": "string"
+		  }
+		],
+		"name": "v1",
+		"schema": {
+		  "openAPIV3Schema": {
+			"description": "Policy declares validation, mutation, and generation behaviors for matching resources. See: https://kyverno.io/docs/writing-policies/ for more information.",
+			"properties": {
+			  "apiVersion": {
+				"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
+				"type": "string"
+			  },
+			  "kind": {
+				"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
+				"type": "string"
+			  },
+			  "metadata": {
+				"type": "object"
+			  },
+			  "spec": {
+				"description": "Spec defines policy behaviors and contains one or rules.",
+				"properties": {
+				  "background": {
+					"description": "Background controls if rules are applied to existing resources during a background scan. Optional. Default value is \"true\". The value must be set to \"false\" if the policy rule uses variables that are only available in the admission review request (e.g. user name).",
+					"type": "boolean"
+				  },
+				  "rules": {
+					"description": "Rules is a list of Rule instances. A Policy contains multiple rules and each rule can validate, mutate, or generate resources.",
+					"items": {
+					  "schema": {
+						"description": "Rule defines a validation, mutation, or generation control for matching resources. Each rules contains a match declaration to select resources, and an optional exclude declaration to specify which resources to exclude.",
+						"properties": {
+						  "context": {
+							"description": "Context defines variables and data sources that can be used during rule execution.",
+							"items": {
+							  "schema": {
+								"description": "ContextEntry adds variables and data sources to a rule Context. Either a ConfigMap reference or a APILookup must be provided.",
+								"properties": {
+								  "apiCall": {
+									"description": "APICall defines an HTTP request to the Kubernetes API server. The JSON data retrieved is stored in the context.",
+									"properties": {
+									  "jmesPath": {
+										"description": "JMESPath is an optional JSON Match Expression that can be used to transform the JSON response returned from the API server. For example a JMESPath of \"items | length(@)\" applied to the API server response to the URLPath \"/apis/apps/v1/deployments\" will return the total count of deployments across all namespaces.",
+										"type": "string"
+									  },
+									  "urlPath": {
+										"description": "URLPath is the URL path to be used in the HTTP GET request to the Kubernetes API server (e.g. \"/api/v1/namespaces\" or  \"/apis/apps/v1/deployments\"). The format required is the same format used by the 'kubectl get --raw' command.",
+										"type": "string"
+									  }
+									},
+									"required": [
+									  "urlPath"
+									],
+									"type": "object"
+								  },
+								  "configMap": {
+									"description": "ConfigMap is the ConfigMap reference.",
+									"properties": {
+									  "name": {
+										"description": "Name is the ConfigMap name.",
+										"type": "string"
+									  },
+									  "namespace": {
+										"description": "Namespace is the ConfigMap namespace.",
+										"type": "string"
+									  }
+									},
+									"required": [
+									  "name"
+									],
+									"type": "object"
+								  },
+								  "name": {
+									"description": "Name is the variable name.",
+									"type": "string"
+								  }
+								},
+								"type": "object"
+							  }
+							},
+							"type": "array"
+						  },
+						  "exclude": {
+							"description": "ExcludeResources defines when this policy rule should not be applied. The exclude criteria can include resource information (e.g. kind, name, namespace, labels) and admission review request information like the name or role.",
+							"properties": {
+							  "clusterRoles": {
+								"description": "ClusterRoles is the list of cluster-wide role names for the user.",
+								"items": {
+								  "schema": {
+									"type": "string"
+								  }
+								},
+								"type": "array"
+							  },
+							  "resources": {
+								"description": "ResourceDescription contains information about the resource being created or modified.",
+								"properties": {
+								  "annotations": {
+									"additionalProperties": {
+									  "type": "string"
+									},
+									"description": "Annotations is a  map of annotations (key-value pairs of type string). Annotation keys and values support the wildcard characters \"*\" (matches zero or many characters) and \"?\" (matches at least one character).",
+									"type": "object"
+								  },
+								  "kinds": {
+									"description": "Kinds is a list of resource kinds.",
+									"items": {
+									  "schema": {
+										"type": "string"
+									  }
+									},
+									"type": "array"
+								  },
+								  "name": {
+									"description": "Name is the name of the resource. The name supports wildcard characters \"*\" (matches zero or many characters) and \"?\" (at least one character).",
+									"type": "string"
+								  },
+								  "namespaceSelector": {
+									"description": "NamespaceSelector is a label selector for the resource namespace. Label keys and values in 'matchLabels' support the wildcard characters '*' (matches zero or many characters) and '?' (matches one character).Wildcards allows writing label selectors like [\"storage.k8s.io/*\": \"*\"]. Note that using [\"*\" : \"*\"] matches any key and value but does not match an empty label set.",
+									"properties": {
+									  "matchExpressions": {
+										"description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.",
+										"items": {
+										  "schema": {
+											"description": "A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.",
+											"properties": {
+											  "key": {
+												"description": "key is the label key that the selector applies to.",
+												"type": "string"
+											  },
+											  "operator": {
+												"description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.",
+												"type": "string"
+											  },
+											  "values": {
+												"description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.",
+												"items": {
+												  "schema": {
+													"type": "string"
+												  }
+												},
+												"type": "array"
+											  }
+											},
+											"required": [
+											  "key",
+											  "operator"
+											],
+											"type": "object"
+										  }
+										},
+										"type": "array"
+									  },
+									  "matchLabels": {
+										"additionalProperties": {
+										  "type": "string"
+										},
+										"description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.",
+										"type": "object"
+									  }
+									},
+									"type": "object"
+								  },
+								  "namespaces": {
+									"description": "Namespaces is a list of namespaces names. Each name supports wildcard characters \"*\" (matches zero or many characters) and \"?\" (at least one character).",
+									"items": {
+									  "schema": {
+										"type": "string"
+									  }
+									},
+									"type": "array"
+								  },
+								  "selector": {
+									"description": "Selector is a label selector. Label keys and values in 'matchLabels' support the wildcard characters '*' (matches zero or many characters) and '?' (matches one character). Wildcards allows writing label selectors like [\"storage.k8s.io/*\": \"*\"]. Note that using [\"*\" : \"*\"] matches any key and value but does not match an empty label set.",
+									"properties": {
+									  "matchExpressions": {
+										"description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.",
+										"items": {
+										  "schema": {
+											"description": "A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.",
+											"properties": {
+											  "key": {
+												"description": "key is the label key that the selector applies to.",
+												"type": "string"
+											  },
+											  "operator": {
+												"description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.",
+												"type": "string"
+											  },
+											  "values": {
+												"description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.",
+												"items": {
+												  "schema": {
+													"type": "string"
+												  }
+												},
+												"type": "array"
+											  }
+											},
+											"required": [
+											  "key",
+											  "operator"
+											],
+											"type": "object"
+										  }
+										},
+										"type": "array"
+									  },
+									  "matchLabels": {
+										"additionalProperties": {
+										  "type": "string"
+										},
+										"description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.",
+										"type": "object"
+									  }
+									},
+									"type": "object"
+								  }
+								},
+								"type": "object"
+							  },
+							  "roles": {
+								"description": "Roles is the list of namespaced role names for the user.",
+								"items": {
+								  "schema": {
+									"type": "string"
+								  }
+								},
+								"type": "array"
+							  },
+							  "subjects": {
+								"description": "Subjects is the list of subject names like users, user groups, and service accounts.",
+								"items": {
+								  "schema": {
+									"description": "Subject contains a reference to the object or user identities a role binding applies to.  This can either hold a direct API object reference, or a value for non-objects such as user and group names.",
+									"properties": {
+									  "apiGroup": {
+										"description": "APIGroup holds the API group of the referenced subject. Defaults to \"\" for ServiceAccount subjects. Defaults to \"rbac.authorization.k8s.io\" for User and Group subjects.",
+										"type": "string"
+									  },
+									  "kind": {
+										"description": "Kind of object being referenced. Values defined by this API group are \"User\", \"Group\", and \"ServiceAccount\". If the Authorizer does not recognized the kind value, the Authorizer should report an error.",
+										"type": "string"
+									  },
+									  "name": {
+										"description": "Name of the object being referenced.",
+										"type": "string"
+									  },
+									  "namespace": {
+										"description": "Namespace of the referenced object.  If the object kind is non-namespace, such as \"User\" or \"Group\", and this value is not empty the Authorizer should report an error.",
+										"type": "string"
+									  }
+									},
+									"required": [
+									  "kind",
+									  "name"
+									],
+									"type": "object"
+								  }
+								},
+								"type": "array"
+							  }
+							},
+							"type": "object"
+						  },
+						  "generate": {
+							"description": "Generation is used to create new resources.",
+							"properties": {
+							  "apiVersion": {
+								"description": "APIVersion specifies resource apiVersion.",
+								"type": "string"
+							  },
+							  "clone": {
+								"description": "Clone specifies the source resource used to populate each generated resource. At most one of Data or Clone can be specified. If neither are provided, the generated resource will be created with default data only.",
+								"properties": {
+								  "name": {
+									"description": "Name specifies name of the resource.",
+									"type": "string"
+								  },
+								  "namespace": {
+									"description": "Namespace specifies source resource namespace.",
+									"type": "string"
+								  }
+								},
+								"type": "object"
+							  },
+							  "data": {
+								"description": "Data provides the resource declaration used to populate each generated resource. At most one of Data or Clone must be specified. If neither are provided, the generated resource will be created with default data only.",
+								"x-kubernetes-preserve-unknown-fields": true
+							  },
+							  "kind": {
+								"description": "Kind specifies resource kind.",
+								"type": "string"
+							  },
+							  "name": {
+								"description": "Name specifies the resource name.",
+								"type": "string"
+							  },
+							  "namespace": {
+								"description": "Namespace specifies resource namespace.",
+								"type": "string"
+							  },
+							  "synchronize": {
+								"description": "Synchronize controls if generated resources should be kept in-sync with their source resource. If Synchronize is set to \"true\" changes to generated resources will be overwritten with resource data from Data or the resource specified in the Clone declaration. Optional. Defaults to \"false\" if not specified.",
+								"type": "boolean"
+							  }
+							},
+							"type": "object"
+						  },
+						  "match": {
+							"description": "MatchResources defines when this policy rule should be applied. The match criteria can include resource information (e.g. kind, name, namespace, labels) and admission review request information like the user name or role. At least one kind is required.",
+							"properties": {
+							  "clusterRoles": {
+								"description": "ClusterRoles is the list of cluster-wide role names for the user.",
+								"items": {
+								  "schema": {
+									"type": "string"
+								  }
+								},
+								"type": "array"
+							  },
+							  "resources": {
+								"description": "ResourceDescription contains information about the resource being created or modified. Requires at least one tag to be specified when under MatchResources.",
+								"properties": {
+								  "annotations": {
+									"additionalProperties": {
+									  "type": "string"
+									},
+									"description": "Annotations is a  map of annotations (key-value pairs of type string). Annotation keys and values support the wildcard characters \"*\" (matches zero or many characters) and \"?\" (matches at least one character).",
+									"type": "object"
+								  },
+								  "kinds": {
+									"description": "Kinds is a list of resource kinds.",
+									"items": {
+									  "schema": {
+										"type": "string"
+									  }
+									},
+									"type": "array"
+								  },
+								  "name": {
+									"description": "Name is the name of the resource. The name supports wildcard characters \"*\" (matches zero or many characters) and \"?\" (at least one character).",
+									"type": "string"
+								  },
+								  "namespaceSelector": {
+									"description": "NamespaceSelector is a label selector for the resource namespace. Label keys and values in 'matchLabels' support the wildcard characters '*' (matches zero or many characters) and '?' (matches one character).Wildcards allows writing label selectors like [\"storage.k8s.io/*\": \"*\"]. Note that using [\"*\" : \"*\"] matches any key and value but does not match an empty label set.",
+									"properties": {
+									  "matchExpressions": {
+										"description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.",
+										"items": {
+										  "schema": {
+											"description": "A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.",
+											"properties": {
+											  "key": {
+												"description": "key is the label key that the selector applies to.",
+												"type": "string"
+											  },
+											  "operator": {
+												"description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.",
+												"type": "string"
+											  },
+											  "values": {
+												"description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.",
+												"items": {
+												  "schema": {
+													"type": "string"
+												  }
+												},
+												"type": "array"
+											  }
+											},
+											"required": [
+											  "key",
+											  "operator"
+											],
+											"type": "object"
+										  }
+										},
+										"type": "array"
+									  },
+									  "matchLabels": {
+										"additionalProperties": {
+										  "type": "string"
+										},
+										"description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.",
+										"type": "object"
+									  }
+									},
+									"type": "object"
+								  },
+								  "namespaces": {
+									"description": "Namespaces is a list of namespaces names. Each name supports wildcard characters \"*\" (matches zero or many characters) and \"?\" (at least one character).",
+									"items": {
+									  "schema": {
+										"type": "string"
+									  }
+									},
+									"type": "array"
+								  },
+								  "selector": {
+									"description": "Selector is a label selector. Label keys and values in 'matchLabels' support the wildcard characters '*' (matches zero or many characters) and '?' (matches one character). Wildcards allows writing label selectors like [\"storage.k8s.io/*\": \"*\"]. Note that using [\"*\" : \"*\"] matches any key and value but does not match an empty label set.",
+									"properties": {
+									  "matchExpressions": {
+										"description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.",
+										"items": {
+										  "schema": {
+											"description": "A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.",
+											"properties": {
+											  "key": {
+												"description": "key is the label key that the selector applies to.",
+												"type": "string"
+											  },
+											  "operator": {
+												"description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.",
+												"type": "string"
+											  },
+											  "values": {
+												"description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.",
+												"items": {
+												  "schema": {
+													"type": "string"
+												  }
+												},
+												"type": "array"
+											  }
+											},
+											"required": [
+											  "key",
+											  "operator"
+											],
+											"type": "object"
+										  }
+										},
+										"type": "array"
+									  },
+									  "matchLabels": {
+										"additionalProperties": {
+										  "type": "string"
+										},
+										"description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.",
+										"type": "object"
+									  }
+									},
+									"type": "object"
+								  }
+								},
+								"type": "object"
+							  },
+							  "roles": {
+								"description": "Roles is the list of namespaced role names for the user.",
+								"items": {
+								  "schema": {
+									"type": "string"
+								  }
+								},
+								"type": "array"
+							  },
+							  "subjects": {
+								"description": "Subjects is the list of subject names like users, user groups, and service accounts.",
+								"items": {
+								  "schema": {
+									"description": "Subject contains a reference to the object or user identities a role binding applies to.  This can either hold a direct API object reference, or a value for non-objects such as user and group names.",
+									"properties": {
+									  "apiGroup": {
+										"description": "APIGroup holds the API group of the referenced subject. Defaults to \"\" for ServiceAccount subjects. Defaults to \"rbac.authorization.k8s.io\" for User and Group subjects.",
+										"type": "string"
+									  },
+									  "kind": {
+										"description": "Kind of object being referenced. Values defined by this API group are \"User\", \"Group\", and \"ServiceAccount\". If the Authorizer does not recognized the kind value, the Authorizer should report an error.",
+										"type": "string"
+									  },
+									  "name": {
+										"description": "Name of the object being referenced.",
+										"type": "string"
+									  },
+									  "namespace": {
+										"description": "Namespace of the referenced object.  If the object kind is non-namespace, such as \"User\" or \"Group\", and this value is not empty the Authorizer should report an error.",
+										"type": "string"
+									  }
+									},
+									"required": [
+									  "kind",
+									  "name"
+									],
+									"type": "object"
+								  }
+								},
+								"type": "array"
+							  }
+							},
+							"type": "object"
+						  },
+						  "mutate": {
+							"description": "Mutation is used to modify matching resources.",
+							"properties": {
+							  "overlay": {
+								"description": "Overlay specifies an overlay pattern to modify resources. DEPRECATED. Use PatchStrategicMerge instead. Scheduled for removal in release 1.5+.",
+								"x-kubernetes-preserve-unknown-fields": true
+							  },
+							  "patchStrategicMerge": {
+								"description": "PatchStrategicMerge is a strategic merge patch used to modify resources. See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ and https://kubectl.docs.kubernetes.io/references/kustomize/patchesstrategicmerge/.",
+								"x-kubernetes-preserve-unknown-fields": true
+							  },
+							  "patches": {
+								"description": "Patches specifies a RFC 6902 JSON Patch to modify resources. DEPRECATED. Use PatchesJSON6902 instead. Scheduled for removal in release 1.5+.",
+								"items": {
+								  "schema": {
+									"description": "Patch is a RFC 6902 JSON Patch. See: https://tools.ietf.org/html/rfc6902",
+									"properties": {
+									  "op": {
+										"description": "Operation specifies operations supported by JSON Patch. i.e:- add, replace and delete.",
+										"type": "string"
+									  },
+									  "path": {
+										"description": "Path specifies path of the resource.",
+										"type": "string"
+									  },
+									  "value": {
+										"description": "Value specifies the value to be applied.",
+										"x-kubernetes-preserve-unknown-fields": true
+									  }
+									},
+									"type": "object"
+								  }
+								},
+								"nullable": true,
+								"type": "array",
+								"x-kubernetes-preserve-unknown-fields": true
+							  },
+							  "patchesJson6902": {
+								"description": "PatchesJSON6902 is a list of RFC 6902 JSON Patch declarations used to modify resources. See https://tools.ietf.org/html/rfc6902 and https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/.",
+								"type": "string"
+							  }
+							},
+							"type": "object"
+						  },
+						  "name": {
+							"description": "Name is a label to identify the rule, It must be unique within the policy.",
+							"maxLength": 63,
+							"type": "string"
+						  },
+						  "preconditions": {
+							"description": "AnyAllConditions enable variable-based conditional rule execution. This is useful for finer control of when an rule is applied. A condition can reference object data using JMESPath notation. This too can be made to happen in a logical-manner where in some situation all the conditions need to pass and in some other situation, atleast one condition is enough to pass. For the sake of backwards compatibility, it can be populated with []kyverno.Condition.",
+							"x-kubernetes-preserve-unknown-fields": true
+						  },
+						  "validate": {
+							"description": "Validation is used to validate matching resources.",
+							"properties": {
+							  "anyPattern": {
+								"description": "AnyPattern specifies list of validation patterns. At least one of the patterns must be satisfied for the validation rule to succeed.",
+								"x-kubernetes-preserve-unknown-fields": true
+							  },
+							  "deny": {
+								"description": "Deny defines conditions to fail the validation rule.",
+								"properties": {
+								  "conditions": {
+									"description": "specifies the set of conditions to deny in a logical manner For the sake of backwards compatibility, it can be populated with []kyverno.Condition.",
+									"x-kubernetes-preserve-unknown-fields": true
+								  }
+								},
+								"type": "object"
+							  },
+							  "message": {
+								"description": "Message specifies a custom message to be displayed on failure.",
+								"type": "string"
+							  },
+							  "pattern": {
+								"description": "Pattern specifies an overlay-style pattern used to check resources.",
+								"x-kubernetes-preserve-unknown-fields": true
+							  }
+							},
+							"type": "object"
+						  }
+						},
+						"type": "object"
+					  }
+					},
+					"type": "array"
+				  },
+				  "validationFailureAction": {
+					"description": "ValidationFailureAction controls if a validation policy rule failure should disallow the admission review request (enforce), or allow (audit) the admission review request and report an error in a policy report. Optional. The default value is \"audit\".",
+					"type": "string"
+				  }
+				},
+				"type": "object"
+			  },
+			  "status": {
+				"description": "Status contains policy runtime information.",
+				"properties": {
+				  "averageExecutionTime": {
+					"description": "AvgExecutionTime is the average time taken to process the policy rules on a resource.",
+					"type": "string"
+				  },
+				  "resourcesBlockedCount": {
+					"description": "ResourcesBlockedCount is the total count of admission review requests that were blocked by this policy.",
+					"type": "integer"
+				  },
+				  "resourcesGeneratedCount": {
+					"description": "ResourcesGeneratedCount is the total count of resources that were generated by this policy.",
+					"type": "integer"
+				  },
+				  "resourcesMutatedCount": {
+					"description": "ResourcesMutatedCount is the total count of resources that were mutated by this policy.",
+					"type": "integer"
+				  },
+				  "ruleStatus": {
+					"description": "Rules provides per rule statistics",
+					"items": {
+					  "schema": {
+						"description": "RuleStats provides statistics for an individual rule within a policy.",
+						"properties": {
+						  "appliedCount": {
+							"description": "AppliedCount is the total number of times this rule was applied.",
+							"type": "integer"
+						  },
+						  "averageExecutionTime": {
+							"description": "ExecutionTime is the average time taken to execute this rule.",
+							"type": "string"
+						  },
+						  "failedCount": {
+							"description": "FailedCount is the total count of policy error results for this rule.",
+							"type": "integer"
+						  },
+						  "resourcesBlockedCount": {
+							"description": "ResourcesBlockedCount is the total count of admission review requests that were blocked by this rule.",
+							"type": "integer"
+						  },
+						  "resourcesGeneratedCount": {
+							"description": "ResourcesGeneratedCount is the total count of resources that were generated by this rule.",
+							"type": "integer"
+						  },
+						  "resourcesMutatedCount": {
+							"description": "ResourcesMutatedCount is the total count of resources that were mutated by this rule.",
+							"type": "integer"
+						  },
+						  "ruleName": {
+							"description": "Name is the rule name.",
+							"type": "string"
+						  },
+						  "violationCount": {
+							"description": "ViolationCount is the total count of policy failure results for this rule.",
+							"type": "integer"
+						  }
+						},
+						"required": [
+						  "ruleName"
+						],
+						"type": "object"
+					  }
+					},
+					"type": "array"
+				  },
+				  "rulesAppliedCount": {
+					"description": "RulesAppliedCount is the total number of times this policy was applied.",
+					"type": "integer"
+				  },
+				  "rulesFailedCount": {
+					"description": "RulesFailedCount is the total count of policy execution errors for this policy.",
+					"type": "integer"
+				  },
+				  "violationCount": {
+					"description": "ViolationCount is the total count of policy failure results for this policy.",
+					"type": "integer"
+				  }
+				},
+				"type": "object"
+			  }
+			},
+			"required": [
+			  "spec"
+			],
+			"type": "object"
+		  }
+		},
+		"served": true,
+		"storage": true,
+		"subresources": {
+		  "status": {}
+		}
+	  }
+	]
+  }
+`
diff --git a/pkg/kyverno/store/store.go b/pkg/kyverno/store/store.go
new file mode 100644
index 000000000..878585f81
--- /dev/null
+++ b/pkg/kyverno/store/store.go
@@ -0,0 +1,56 @@
+package store
+
+var Mock bool
+var ContextVar Context
+
+func SetMock(mock bool) {
+	Mock = mock
+}
+
+func GetMock() bool {
+	return Mock
+}
+
+func SetContext(context Context) {
+	ContextVar = context
+}
+
+func GetContext() Context {
+	return ContextVar
+}
+
+func GetPolicyFromContext(policyName string) *Policy {
+	for _, policy := range ContextVar.Policies {
+		if policy.Name == policyName {
+			return &policy
+		}
+	}
+	return nil
+}
+
+func GetPolicyRuleFromContext(policyName string, ruleName string) *Rule {
+	for _, policy := range ContextVar.Policies {
+		if policy.Name == policyName {
+			for _, rule := range policy.Rules {
+				if rule.Name == ruleName {
+					return &rule
+				}
+			}
+		}
+	}
+	return nil
+}
+
+type Context struct {
+	Policies []Policy `json:"policies"`
+}
+
+type Policy struct {
+	Name  string `json:"name"`
+	Rules []Rule `json:"rules"`
+}
+
+type Rule struct {
+	Name   string            `json:"name"`
+	Values map[string]string `json:"values"`
+}
diff --git a/pkg/kyverno/validate/command.go b/pkg/kyverno/validate/command.go
index 9940f2bde..2736e8e4e 100644
--- a/pkg/kyverno/validate/command.go
+++ b/pkg/kyverno/validate/command.go
@@ -9,11 +9,16 @@ import (
 
 	v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"github.com/kyverno/kyverno/pkg/kyverno/common"
+	"github.com/kyverno/kyverno/pkg/kyverno/crds"
 	sanitizederror "github.com/kyverno/kyverno/pkg/kyverno/sanitizedError"
 	"github.com/kyverno/kyverno/pkg/openapi"
 	policy2 "github.com/kyverno/kyverno/pkg/policy"
 	"github.com/kyverno/kyverno/pkg/utils"
 	"github.com/spf13/cobra"
+	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
+	apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/util/validation/field"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 	"sigs.k8s.io/yaml"
 )
@@ -46,34 +51,14 @@ func Command() *cobra.Command {
 				return sanitizederror.NewWithError(fmt.Sprintf("policy file(s) required"), err)
 			}
 
-			var policies []*v1.ClusterPolicy
-			var errs []error
-			if policyPaths[0] == "-" {
-				if common.IsInputFromPipe() {
-					policyStr := ""
-					scanner := bufio.NewScanner(os.Stdin)
-					for scanner.Scan() {
-						policyStr = policyStr + scanner.Text() + "\n"
-					}
-
-					yamlBytes := []byte(policyStr)
-					policies, err = utils.GetPolicy(yamlBytes)
-					if err != nil {
-						return sanitizederror.NewWithError("failed to parse policy", err)
-					}
-				}
-			} else {
-				policies, errs = common.GetPolicies(policyPaths)
-				if len(errs) > 0 && len(policies) == 0 {
-					return sanitizederror.NewWithErrors("failed to read policies", errs)
-				}
+			policies, err := getPolicyFromGivenPath(policyPaths)
+			if err != nil {
+				return sanitizederror.NewWithError("failed to parse policy", err)
+			}
 
-				if len(errs) > 0 && log.Log.V(1).Enabled() {
-					fmt.Printf("ignoring errors: \n")
-					for _, e := range errs {
-						fmt.Printf("    %v \n", e.Error())
-					}
-				}
+			v1crd, err := getPolicyCRD()
+			if err != nil {
+				return sanitizederror.NewWithError("failed to decode crd: ", err)
 			}
 
 			openAPIController, err := openapi.NewOpenAPIController()
@@ -93,38 +78,9 @@ func Command() *cobra.Command {
 				}
 			}
 
-			invalidPolicyFound := false
-			for _, policy := range policies {
-				fmt.Println("----------------------------------------------------------------------")
-				err := policy2.Validate(policy, nil, true, openAPIController)
-				if err != nil {
-					fmt.Printf("Policy %s is invalid.\n", policy.Name)
-					fmt.Printf("Error: invalid policy.\nCause: %s\n\n", err)
-					invalidPolicyFound = true
-				} else {
-					fmt.Printf("Policy %s is valid.\n\n", policy.Name)
-					if outputType != "" {
-						logger := log.Log.WithName("validate")
-						p, err := common.MutatePolicy(policy, logger)
-						if err != nil {
-							if !sanitizederror.IsErrorSanitized(err) {
-								return sanitizederror.NewWithError("failed to mutate policy.", err)
-							}
-							return err
-						}
-						if outputType == "yaml" {
-							yamlPolicy, _ := yaml.Marshal(p)
-							fmt.Println(string(yamlPolicy))
-						} else {
-							jsonPolicy, _ := json.MarshalIndent(p, "", "  ")
-							fmt.Println(string(jsonPolicy))
-						}
-					}
-				}
-			}
-
-			if invalidPolicyFound == true {
-				os.Exit(1)
+			err = validatePolicies(policies, v1crd, openAPIController, outputType)
+			if err != nil {
+				return sanitizederror.NewWithError("failed to validate policies", err)
 			}
 			return nil
 		},
@@ -133,3 +89,115 @@ func Command() *cobra.Command {
 	cmd.Flags().StringArrayVarP(&crdPaths, "crd", "c", []string{}, "Path to CRD files")
 	return cmd
 }
+
+func getPolicyFromGivenPath(policyPaths []string) (policies []*v1.ClusterPolicy, err error) {
+	var errs []error
+	if policyPaths[0] == "-" {
+		if common.IsInputFromPipe() {
+			policyStr := ""
+			scanner := bufio.NewScanner(os.Stdin)
+			for scanner.Scan() {
+				policyStr = policyStr + scanner.Text() + "\n"
+			}
+
+			yamlBytes := []byte(policyStr)
+			policies, err = utils.GetPolicy(yamlBytes)
+			if err != nil {
+				return policies, sanitizederror.NewWithError("failed to parse policy", err)
+			}
+		}
+	} else {
+		policies, errs = common.GetPolicies(policyPaths)
+		if len(errs) > 0 && len(policies) == 0 {
+			return policies, sanitizederror.NewWithErrors("failed to parse policies", errs)
+		}
+
+		if len(errs) > 0 && log.Log.V(1).Enabled() {
+			fmt.Printf("ignoring errors: \n")
+			for _, e := range errs {
+				fmt.Printf("    %v \n", e.Error())
+			}
+		}
+	}
+	return policies, nil
+}
+
+func getPolicyCRD() (v1crd apiextensions.CustomResourceDefinitionSpec, err error) {
+	if err = json.Unmarshal([]byte(crds.PolicyCRD), &v1crd); err != nil {
+		return
+	}
+	return
+}
+
+func validatePolicyAccordingToPolicyCRD(policy *v1.ClusterPolicy, v1crd apiextensions.CustomResourceDefinitionSpec) (err error, errList field.ErrorList) {
+	policyBytes, err := json.Marshal(policy)
+	if err != nil {
+		return sanitizederror.NewWithError("failed to marshal policy", err), nil
+	}
+
+	u := &unstructured.Unstructured{}
+	err = u.UnmarshalJSON(policyBytes)
+	if err != nil {
+		return sanitizederror.NewWithError("failed to decode policy", err), nil
+	}
+
+	versions := v1crd.Versions
+	for _, version := range versions {
+		validator, _, err := apiservervalidation.NewSchemaValidator(&apiextensions.CustomResourceValidation{OpenAPIV3Schema: version.Schema.OpenAPIV3Schema})
+		if err != nil {
+			return sanitizederror.NewWithError("failed to create schema validator", err), nil
+		}
+
+		errList = apiservervalidation.ValidateCustomResource(nil, u.UnstructuredContent(), validator)
+	}
+	return
+}
+
+func validatePolicies(policies []*v1.ClusterPolicy, v1crd apiextensions.CustomResourceDefinitionSpec, openAPIController *openapi.Controller, outputType string) error {
+	invalidPolicyFound := false
+	for _, policy := range policies {
+		err, errorList := validatePolicyAccordingToPolicyCRD(policy, v1crd)
+		if err != nil {
+			return sanitizederror.NewWithError("failed to validate policy.", err)
+		}
+
+		if errorList == nil {
+			err = policy2.Validate(policy, nil, true, openAPIController)
+		}
+
+		fmt.Println("----------------------------------------------------------------------")
+		if errorList != nil || err != nil {
+			fmt.Printf("Policy %s is invalid.\n", policy.Name)
+			if errorList != nil {
+				fmt.Printf("Error: invalid policy.\nCause: %s\n\n", errorList)
+			} else {
+				fmt.Printf("Error: invalid policy.\nCause: %s\n\n", err)
+			}
+			invalidPolicyFound = true
+		} else {
+			fmt.Printf("Policy %s is valid.\n\n", policy.Name)
+			if outputType != "" {
+				logger := log.Log.WithName("validate")
+				p, err := common.MutatePolicy(policy, logger)
+				if err != nil {
+					if !sanitizederror.IsErrorSanitized(err) {
+						return sanitizederror.NewWithError("failed to mutate policy.", err)
+					}
+					return err
+				}
+				if outputType == "yaml" {
+					yamlPolicy, _ := yaml.Marshal(p)
+					fmt.Println(string(yamlPolicy))
+				} else {
+					jsonPolicy, _ := json.MarshalIndent(p, "", "  ")
+					fmt.Println(string(jsonPolicy))
+				}
+			}
+		}
+	}
+
+	if invalidPolicyFound {
+		os.Exit(1)
+	}
+	return nil
+}
diff --git a/pkg/policy/apply.go b/pkg/policy/apply.go
index 258b1c183..f39a4eb7c 100644
--- a/pkg/policy/apply.go
+++ b/pkg/policy/apply.go
@@ -50,6 +50,10 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
 		logger.Error(err, "failed to add namespace to ctx")
 	}
 
+	if err := ctx.AddImageInfo(&resource); err != nil {
+		logger.Error(err, "unable to add image info to variables context")
+	}
+
 	engineResponseMutation, err = mutation(policy, resource, logger, resCache, ctx, namespaceLabels)
 	if err != nil {
 		logger.Error(err, "failed to process mutation rule")
diff --git a/pkg/policy/background.go b/pkg/policy/background.go
index 0b3620224..af6084ee2 100644
--- a/pkg/policy/background.go
+++ b/pkg/policy/background.go
@@ -24,7 +24,7 @@ func ContainsVariablesOtherThanObject(policy kyverno.ClusterPolicy) error {
 			return fmt.Errorf("invalid variable used at path: spec/rules[%d]/exclude/%s", idx, path)
 		}
 
-		filterVars := []string{"request.object", "request.namespace"}
+		filterVars := []string{"request.object", "request.namespace", "images"}
 		ctx := context.NewContext(filterVars...)
 
 		for _, contextEntry := range rule.Context {
diff --git a/pkg/policy/validate_controller.go b/pkg/policy/validate_controller.go
index f23243871..e2ae1c12d 100644
--- a/pkg/policy/validate_controller.go
+++ b/pkg/policy/validate_controller.go
@@ -5,9 +5,7 @@ import (
 	"crypto/rand"
 	"fmt"
 	"math/big"
-	random "math/rand"
 	"reflect"
-	"strconv"
 	"strings"
 	"time"
 
@@ -20,6 +18,8 @@ import (
 	"github.com/kyverno/kyverno/pkg/config"
 	client "github.com/kyverno/kyverno/pkg/dclient"
 	"github.com/kyverno/kyverno/pkg/event"
+	"github.com/kyverno/kyverno/pkg/kyverno/common"
+	pm "github.com/kyverno/kyverno/pkg/policymutation"
 	"github.com/kyverno/kyverno/pkg/policyreport"
 	"github.com/kyverno/kyverno/pkg/resourcecache"
 	utils "github.com/kyverno/kyverno/pkg/utils"
@@ -197,10 +197,10 @@ func (pc *PolicyController) addPolicy(obj interface{}) {
 
 	logger.Info("policy created", "uid", p.UID, "kind", "ClusterPolicy", "name", p.Name)
 
-	if p.Spec.Background == nil || p.Spec.ValidationFailureAction == "" || checkAutoGenRules(p) {
-		p.ObjectMeta.SetAnnotations(map[string]string{"kyverno.io/mutate-policy": strconv.Itoa(random.Intn(100))})
+	if p.Spec.Background == nil || p.Spec.ValidationFailureAction == "" || checkAutoGenRules(p, logger) {
+		pol, _ := common.MutatePolicy(p, logger)
 		p.SetGroupVersionKind(schema.GroupVersionKind{Group: "kyverno.io", Version: "v1", Kind: "ClusterPolicy"})
-		_, err := pc.client.UpdateResource("kyverno.io/v1", "ClusterPolicy", "", p, false)
+		_, err := pc.client.UpdateResource("kyverno.io/v1", "ClusterPolicy", "", pol, false)
 		if err != nil {
 			logger.Error(err, "failed to add policy ")
 		}
@@ -219,10 +219,10 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) {
 	oldP := old.(*kyverno.ClusterPolicy)
 	curP := cur.(*kyverno.ClusterPolicy)
 
-	if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || checkAutoGenRules(curP) {
-		curP.ObjectMeta.SetAnnotations(map[string]string{"kyverno.io/mutate-policy": strconv.Itoa(random.Intn(100))})
+	if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || checkAutoGenRules(curP, logger) {
+		pol, _ := common.MutatePolicy(curP, logger)
 		curP.SetGroupVersionKind(schema.GroupVersionKind{Group: "kyverno.io", Version: "v1", Kind: "ClusterPolicy"})
-		_, err := pc.client.UpdateResource("kyverno.io/v1", "ClusterPolicy", "", curP, false)
+		_, err := pc.client.UpdateResource("kyverno.io/v1", "ClusterPolicy", "", pol, false)
 		if err != nil {
 			logger.Error(err, "failed to update policy ")
 		}
@@ -274,10 +274,10 @@ func (pc *PolicyController) addNsPolicy(obj interface{}) {
 	logger.Info("policy created", "uid", p.UID, "kind", "Policy", "name", p.Name, "namespaces", p.Namespace)
 
 	pol := ConvertPolicyToClusterPolicy(p)
-	if pol.Spec.Background == nil || pol.Spec.ValidationFailureAction == "" || checkAutoGenRules(pol) {
-		pol.ObjectMeta.SetAnnotations(map[string]string{"kyverno.io/mutate-policy": strconv.Itoa(random.Intn(100))})
+	if pol.Spec.Background == nil || pol.Spec.ValidationFailureAction == "" || checkAutoGenRules(pol, logger) {
+		nsPol, _ := common.MutatePolicy(pol, logger)
 		pol.SetGroupVersionKind(schema.GroupVersionKind{Group: "kyverno.io", Version: "v1", Kind: "Policy"})
-		_, err := pc.client.UpdateResource("kyverno.io/v1", "Policy", p.Namespace, pol, false)
+		_, err := pc.client.UpdateResource("kyverno.io/v1", "Policy", p.Namespace, nsPol, false)
 		if err != nil {
 			logger.Error(err, "failed to add namespace policy")
 		}
@@ -295,10 +295,10 @@ func (pc *PolicyController) updateNsPolicy(old, cur interface{}) {
 	curP := cur.(*kyverno.Policy)
 	ncurP := ConvertPolicyToClusterPolicy(curP)
 
-	if ncurP.Spec.Background == nil || ncurP.Spec.ValidationFailureAction == "" || checkAutoGenRules(ncurP) {
-		ncurP.ObjectMeta.SetAnnotations(map[string]string{"kyverno.io/mutate-policy": strconv.Itoa(random.Intn(100))})
+	if ncurP.Spec.Background == nil || ncurP.Spec.ValidationFailureAction == "" || checkAutoGenRules(ncurP, logger) {
+		nsPol, _ := common.MutatePolicy(ncurP, logger)
 		ncurP.SetGroupVersionKind(schema.GroupVersionKind{Group: "kyverno.io", Version: "v1", Kind: "Policy"})
-		_, err := pc.client.UpdateResource("kyverno.io/v1", "Policy", ncurP.GetNamespace(), ncurP, false)
+		_, err := pc.client.UpdateResource("kyverno.io/v1", "Policy", ncurP.GetNamespace(), nsPol, false)
 		if err != nil {
 			logger.Error(err, "failed to update namespace policy ")
 		}
@@ -520,11 +520,11 @@ func updateGR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList [
 	}
 }
 
-func checkAutoGenRules(policy *kyverno.ClusterPolicy) bool {
+func checkAutoGenRules(policy *kyverno.ClusterPolicy, log logr.Logger) bool {
 	var podRuleName []string
 	ruleCount := 1
-	for _, rule := range policy.Spec.Rules {
-		if utils.ContainsString(rule.MatchResources.ResourceDescription.Kinds, "Pod") {
+	if pm.GetControllers(policy, log) != "none" {
+		for _, rule := range policy.Spec.Rules {
 			podRuleName = append(podRuleName, rule.Name)
 		}
 	}
diff --git a/pkg/policymutation/policymutation.go b/pkg/policymutation/policymutation.go
index 118ae92c3..a3ada314f 100644
--- a/pkg/policymutation/policymutation.go
+++ b/pkg/policymutation/policymutation.go
@@ -246,6 +246,37 @@ func GeneratePodControllerRule(policy kyverno.ClusterPolicy, log logr.Logger) (p
 	return
 }
 
+// getControllers gets applicable pod controllers, it returns
+// - "none" if:
+//          - name or selector is defined
+//          - mixed kinds (Pod + pod controller) is defined
+//          - mutate.Patches/mutate.PatchesJSON6902/validate.deny/generate rule is defined
+// - otherwise it returns all pod controllers
+func GetControllers(policy *kyverno.ClusterPolicy, log logr.Logger) string {
+	for _, rule := range policy.Spec.Rules {
+		match := rule.MatchResources
+		exclude := rule.ExcludeResources
+
+		if match.ResourceDescription.Name != "" || match.ResourceDescription.Selector != nil ||
+			exclude.ResourceDescription.Name != "" || exclude.ResourceDescription.Selector != nil {
+			log.Info("skip generating rule on pod controllers: Name / Selector in resource description may not be applicable.", "rule", rule.Name)
+			return "none"
+		}
+
+		if (len(match.Kinds) > 1 && utils.ContainsString(match.Kinds, "Pod")) ||
+			(len(exclude.Kinds) > 1 && utils.ContainsString(exclude.Kinds, "Pod")) {
+			return "none"
+		}
+
+		if rule.Mutation.Patches != nil || rule.Mutation.PatchesJSON6902 != "" ||
+			rule.Validation.Deny != nil || rule.HasGenerate() {
+			return "none"
+		}
+	}
+
+	return engine.PodControllers
+}
+
 func createRuleMap(rules []kyverno.Rule) map[string]kyvernoRule {
 	var ruleMap = make(map[string]kyvernoRule)
 	for _, rule := range rules {
diff --git a/pkg/utils/util.go b/pkg/utils/util.go
index c4be1d4c4..51cf6456b 100644
--- a/pkg/utils/util.go
+++ b/pkg/utils/util.go
@@ -205,6 +205,26 @@ func SliceContains(slice []string, values ...string) bool {
 // and converts it into []kyverno.Condition or kyverno.AnyAllConditions according to its content.
 // it also helps in validating the condtions as it returns an error when the conditions are provided wrongfully by the user.
 func ApiextensionsJsonToKyvernoConditions(original apiextensions.JSON) (interface{}, error) {
+	path := "preconditions/validate.deny.conditions"
+
+	// checks for the existence any other field apart from 'any'/'all' under preconditions/validate.deny.conditions
+	unknownFieldChecker := func(jsonByteArr []byte, path string) error {
+		allowedKeys := map[string]bool{
+			"any": true,
+			"all": true,
+		}
+		var jsonDecoded map[string]interface{}
+		if err := json.Unmarshal(jsonByteArr, &jsonDecoded); err != nil {
+			return fmt.Errorf("error occurred while checking for unknown fields under %s: %+v", path, err)
+		}
+		for k := range jsonDecoded {
+			if !allowedKeys[k] {
+				return fmt.Errorf("unknown field '%s' found under %s", k, path)
+			}
+		}
+		return nil
+	}
+
 	// marshalling the abstract apiextensions.JSON back to JSON form
 	jsonByte, err := json.Marshal(original)
 
@@ -215,8 +235,12 @@ func ApiextensionsJsonToKyvernoConditions(original apiextensions.JSON) (interfac
 
 	var kyvernoAnyAllConditions kyverno.AnyAllConditions
 	if err = json.Unmarshal(jsonByte, &kyvernoAnyAllConditions); err == nil {
+		// checking if unknown fields exist or not
+		err = unknownFieldChecker(jsonByte, path)
+		if err != nil {
+			return nil, fmt.Errorf("error occurred while parsing %s: %+v", path, err)
+		}
 		return kyvernoAnyAllConditions, nil
 	}
-
-	return nil, fmt.Errorf("conditions filled wrongfully")
+	return nil, fmt.Errorf("error occurred while parsing %s: %+v", path, err)
 }
diff --git a/pkg/webhookconfig/registration.go b/pkg/webhookconfig/registration.go
index 208ac9a9e..b6c57234c 100644
--- a/pkg/webhookconfig/registration.go
+++ b/pkg/webhookconfig/registration.go
@@ -39,6 +39,7 @@ type Register struct {
 	serverIP       string // when running outside a cluster
 	timeoutSeconds int32
 	log            logr.Logger
+	debug          bool
 }
 
 // NewRegister creates new Register instance
@@ -48,6 +49,7 @@ func NewRegister(
 	resCache resourcecache.ResourceCache,
 	serverIP string,
 	webhookTimeout int32,
+	debug bool,
 	log logr.Logger) *Register {
 	return &Register{
 		clientConfig:   clientConfig,
@@ -56,6 +58,7 @@ func NewRegister(
 		serverIP:       serverIP,
 		timeoutSeconds: webhookTimeout,
 		log:            log.WithName("Register"),
+		debug:          debug,
 	}
 }
 
@@ -65,10 +68,11 @@ func (wrc *Register) Register() error {
 	if wrc.serverIP != "" {
 		logger.Info("Registering webhook", "url", fmt.Sprintf("https://%s", wrc.serverIP))
 	}
-	if err := wrc.checkEndpoint(); err != nil {
-		return err
+	if !wrc.debug {
+		if err := wrc.checkEndpoint(); err != nil {
+			return err
+		}
 	}
-
 	wrc.removeWebhookConfigurations()
 
 	caData := wrc.readCaData()
diff --git a/pkg/webhooks/generation.go b/pkg/webhooks/generation.go
index adadefeae..9c37a0fd8 100644
--- a/pkg/webhooks/generation.go
+++ b/pkg/webhooks/generation.go
@@ -2,6 +2,7 @@ package webhooks
 
 import (
 	contextdefault "context"
+	"encoding/json"
 	"fmt"
 	"reflect"
 	"sort"
@@ -14,10 +15,13 @@ import (
 	v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"github.com/kyverno/kyverno/pkg/common"
 	"github.com/kyverno/kyverno/pkg/config"
+	client "github.com/kyverno/kyverno/pkg/dclient"
 	"github.com/kyverno/kyverno/pkg/engine"
 	"github.com/kyverno/kyverno/pkg/engine/context"
+	enginectx "github.com/kyverno/kyverno/pkg/engine/context"
 	"github.com/kyverno/kyverno/pkg/engine/response"
 	enginutils "github.com/kyverno/kyverno/pkg/engine/utils"
+	"github.com/kyverno/kyverno/pkg/engine/variables"
 	"github.com/kyverno/kyverno/pkg/event"
 	gen "github.com/kyverno/kyverno/pkg/generate"
 	kyvernoutils "github.com/kyverno/kyverno/pkg/utils"
@@ -147,27 +151,32 @@ func (ws *WebhookServer) handleUpdateTargetResource(request *v1beta1.AdmissionRe
 		if policy.GetName() == policyName {
 			for _, rule := range policy.Spec.Rules {
 				if rule.Generation.Kind == targetSourceKind && rule.Generation.Name == targetSourceName {
-					data := rule.Generation.DeepCopy().Data
-					if data != nil {
-						if _, err := gen.ValidateResourceWithPattern(logger, newRes.Object, data); err != nil {
-							enqueueBool = true
-							break
+					updatedRule, err := getGeneratedByResource(newRes, resLabels, ws.client, rule, logger)
+					if err != nil {
+						logger.V(4).Info("skipping generate policy and resource pattern validaton", "error", err)
+					} else {
+						data := updatedRule.Generation.DeepCopy().Data
+						if data != nil {
+							if _, err := gen.ValidateResourceWithPattern(logger, newRes.Object, data); err != nil {
+								enqueueBool = true
+								break
+							}
 						}
-					}
 
-					cloneName := rule.Generation.Clone.Name
-					if cloneName != "" {
-						obj, err := ws.client.GetResource("", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name)
-						if err != nil {
-							logger.Error(err, fmt.Sprintf("source resource %s/%s/%s not found.", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name))
-							continue
-						}
+						cloneName := updatedRule.Generation.Clone.Name
+						if cloneName != "" {
+							obj, err := ws.client.GetResource("", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name)
+							if err != nil {
+								logger.Error(err, fmt.Sprintf("source resource %s/%s/%s not found.", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name))
+								continue
+							}
 
-						sourceObj, newResObj := stripNonPolicyFields(obj.Object, newRes.Object, logger)
+							sourceObj, newResObj := stripNonPolicyFields(obj.Object, newRes.Object, logger)
 
-						if _, err := gen.ValidateResourceWithPattern(logger, newResObj, sourceObj); err != nil {
-							enqueueBool = true
-							break
+							if _, err := gen.ValidateResourceWithPattern(logger, newResObj, sourceObj); err != nil {
+								enqueueBool = true
+								break
+							}
 						}
 					}
 				}
@@ -186,6 +195,38 @@ func (ws *WebhookServer) handleUpdateTargetResource(request *v1beta1.AdmissionRe
 	}
 }
 
+func getGeneratedByResource(newRes *unstructured.Unstructured, resLabels map[string]string, client *client.Client, rule v1.Rule, logger logr.Logger) (v1.Rule, error) {
+	var apiVersion, kind, name, namespace string
+	sourceRequest := &v1beta1.AdmissionRequest{}
+	kind = resLabels["kyverno.io/generated-by-kind"]
+	name = resLabels["kyverno.io/generated-by-name"]
+	if kind != "Namespace" {
+		namespace = resLabels["kyverno.io/generated-by-namespace"]
+	}
+	obj, err := client.GetResource(apiVersion, kind, namespace, name)
+	if err != nil {
+		logger.Error(err, "source resource not found.")
+		return rule, err
+	}
+	rawObj, err := json.Marshal(obj)
+	if err != nil {
+		logger.Error(err, "failed to marshal resource")
+		return rule, err
+	}
+	sourceRequest.Object.Raw = rawObj
+	sourceRequest.Operation = "CREATE"
+	ctx := enginectx.NewContext()
+	if err := ctx.AddRequest(sourceRequest); err != nil {
+		logger.Error(err, "failed to load incoming request in context")
+		return rule, err
+	}
+	if rule, err = variables.SubstituteAllInRule(logger, ctx, rule); err != nil {
+		logger.Error(err, "variable substitution failed for rule %s", rule.Name)
+		return rule, err
+	}
+	return rule, nil
+}
+
 //stripNonPolicyFields - remove feilds which get updated with each request by kyverno and are non policy fields
 func stripNonPolicyFields(obj, newRes map[string]interface{}, logger logr.Logger) (map[string]interface{}, map[string]interface{}) {
 
diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go
index a5993b31c..fa84b6c75 100644
--- a/pkg/webhooks/server.go
+++ b/pkg/webhooks/server.go
@@ -296,7 +296,6 @@ func writeResponse(rw http.ResponseWriter, admissionReview *v1beta1.AdmissionRev
 
 // ResourceMutation mutates resource
 func (ws *WebhookServer) ResourceMutation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
-
 	logger := ws.log.WithName("ResourceMutation").WithValues("uid", request.UID, "kind", request.Kind.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation)
 
 	if excludeKyvernoResources(request.Kind.Kind) {
diff --git a/pkg/webhooks/validation.go b/pkg/webhooks/validation.go
index c0f5799a9..b0eaf48bc 100644
--- a/pkg/webhooks/validation.go
+++ b/pkg/webhooks/validation.go
@@ -136,13 +136,14 @@ func HandleValidation(
 		return false, getEnforceFailureErrorMsg(engineResponses)
 	}
 
-	prInfos := policyreport.GeneratePRsFromEngineResponse(engineResponses, logger)
-	prGenerator.Add(prInfos...)
-
 	if request.Operation == v1beta1.Delete {
 		prGenerator.Add(buildDeletionPrInfo(oldR))
+		return true, ""
 	}
 
+	prInfos := policyreport.GeneratePRsFromEngineResponse(engineResponses, logger)
+	prGenerator.Add(prInfos...)
+
 	return true, ""
 }
 


Test patch:
diff --git a/pkg/engine/forceMutate_test.go b/pkg/engine/forceMutate_test.go
index a948d6129..38b0a640a 100644
--- a/pkg/engine/forceMutate_test.go
+++ b/pkg/engine/forceMutate_test.go
@@ -8,6 +8,7 @@ import (
 	"github.com/kyverno/kyverno/pkg/engine/context"
 	"github.com/kyverno/kyverno/pkg/engine/utils"
 	"gotest.tools/assert"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 )
 
 var rawPolicy = []byte(`
@@ -148,3 +149,194 @@ func Test_ForceMutateSubstituteVarsWithNilContext(t *testing.T) {
 
 	assert.DeepEqual(t, expectedResource, mutatedResource.UnstructuredContent())
 }
+
+func Test_ForceMutateSubstituteVarsWithPatchStrategicMerge(t *testing.T) {
+	rawPolicy := []byte(`
+	{
+		"apiVersion": "kyverno.io/v1",
+		"kind": "ClusterPolicy",
+		"metadata": {
+		  "name": "strategic-merge-patch"
+		},
+		"spec": {
+		  "rules": [
+			{
+			  "name": "set-image-pull-policy-add-command",
+			  "match": {
+				"resources": {
+				  "kinds": [
+					"Pod"
+				  ]
+				}
+			  },
+			  "mutate": {
+					"patchStrategicMerge": {
+					  "spec": {
+						"volumes": [
+						  {
+							"emptyDir": {
+							  "medium": "Memory"
+							},
+							"name": "cache-volume"
+						  }
+						]
+					  }
+					}
+			  }
+			}
+		  ]
+		}
+	  }
+`)
+
+	rawResource := []byte(`
+{
+	"apiVersion": "v1",
+	"kind": "Pod",
+	"metadata": {
+		"name": "check-root-user"
+	},
+	"spec": {
+		"volumes": [
+			{
+				"name": "cache-volume",
+				"emptyDir": { }
+			  },
+			  {
+				"name": "cache-volume2",
+				"emptyDir": {
+				  "medium": "Memory"
+				}
+			  }
+		]
+	}
+}
+`)
+
+	expectedRawResource := []byte(`
+	{"apiVersion":"v1","kind":"Pod","metadata":{"name":"check-root-user"},"spec":{"volumes":[{"emptyDir":{"medium":"Memory"},"name":"cache-volume"},{"emptyDir":{"medium":"Memory"},"name":"cache-volume2"}]}}
+	  `)
+
+	var expectedResource interface{}
+	assert.NilError(t, json.Unmarshal(expectedRawResource, &expectedResource))
+
+	var policy kyverno.ClusterPolicy
+	err := json.Unmarshal(rawPolicy, &policy)
+	assert.NilError(t, err)
+
+	resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
+	assert.NilError(t, err)
+	ctx := context.NewContext()
+	err = ctx.AddResource(rawResource)
+	assert.NilError(t, err)
+
+	mutatedResource, err := ForceMutate(ctx, policy, *resourceUnstructured)
+	assert.NilError(t, err)
+
+	assert.DeepEqual(t, expectedResource, mutatedResource.UnstructuredContent())
+}
+
+func Test_ForceMutateSubstituteVarsWithPatchesJson6902(t *testing.T) {
+	rawPolicy := []byte(`
+	{
+		"apiVersion": "kyverno.io/v1",
+		"kind": "ClusterPolicy",
+		"metadata": {
+		  "name": "insert-container"
+		},
+		"spec": {
+		  "rules": [
+			{
+			  "name": "insert-container",
+			  "match": {
+				"resources": {
+				  "kinds": [
+					"Pod"
+				  ]
+				}
+			  },
+			  "mutate": {
+				"patchesJson6902": "- op: add\n  path: \"/spec/template/spec/containers/0/command/0\"\n  value: ls"
+			  }
+			}
+		  ]
+		}
+	  }
+	`)
+
+	rawResource := []byte(`
+		{
+			"apiVersion": "apps/v1",
+			"kind": "Deployment",
+			"metadata": {
+				"name": "myDeploy"
+			},
+			"spec": {
+				"replica": 2,
+				"template": {
+				"metadata": {
+					"labels": {
+					"old-label": "old-value"
+					}
+				},
+				"spec": {
+					"containers": [
+					{
+						"command": ["ll", "rm"],
+						"image": "nginx",
+						"name": "nginx"
+					}
+					]
+				}
+				}
+			}
+		}
+	`)
+
+	rawExpected := []byte(`
+	{
+		"apiVersion": "apps/v1",
+		"kind": "Deployment",
+		"metadata": {
+		  "name": "myDeploy"
+		},
+		"spec": {
+		  "replica": 2,
+		  "template": {
+			"metadata": {
+			  "labels": {
+				"old-label": "old-value"
+			  }
+			},
+			"spec": {
+			  "containers": [
+				{
+					"command": ["ls", "ll", "rm"],
+				  "image": "nginx",
+				  "name": "nginx"
+				}
+			  ]
+			}
+		  }
+		}
+	  }
+	`)
+
+	var expectedResource unstructured.Unstructured
+	assert.NilError(t, json.Unmarshal(rawExpected, &expectedResource))
+
+	var policy kyverno.ClusterPolicy
+	err := json.Unmarshal(rawPolicy, &policy)
+	assert.NilError(t, err)
+
+	resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
+	assert.NilError(t, err)
+	ctx := context.NewContext()
+	err = ctx.AddResource(rawResource)
+	assert.NilError(t, err)
+
+	mutatedResource, err := ForceMutate(ctx, policy, *resourceUnstructured)
+	assert.NilError(t, err)
+
+	assert.DeepEqual(t, expectedResource.UnstructuredContent(), mutatedResource.UnstructuredContent())
+}
diff --git a/pkg/engine/jmespath/functions_test.go b/pkg/engine/jmespath/functions_test.go
new file mode 100644
index 000000000..b282c3171
--- /dev/null
+++ b/pkg/engine/jmespath/functions_test.go
@@ -0,0 +1,245 @@
+package jmespath
+
+import (
+	"encoding/json"
+	"testing"
+
+	"gotest.tools/assert"
+)
+
+func TestJMESPathFunctions_CompareEqualStrings(t *testing.T) {
+	jp, err := New("compare('a', 'a')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	equal, ok := result.(int)
+	assert.Assert(t, ok)
+	assert.Equal(t, equal, 0)
+}
+
+func TestJMESPathFunctions_CompareDifferentStrings(t *testing.T) {
+	jp, err := New("compare('a', 'b')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	equal, ok := result.(int)
+	assert.Assert(t, ok)
+	assert.Equal(t, equal, -1)
+}
+
+func TestJMESPathFunctions_Contains(t *testing.T) {
+	jp, err := New("contains('string', 'str')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	contains, ok := result.(bool)
+	assert.Assert(t, ok)
+	assert.Assert(t, contains)
+}
+
+func TestJMESPathFunctions_EqualFold(t *testing.T) {
+	jp, err := New("equal_fold('Go', 'go')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	equal, ok := result.(bool)
+	assert.Assert(t, ok)
+	assert.Assert(t, equal)
+}
+
+func TestJMESPathFunctions_Replace(t *testing.T) {
+	// Can't use integer literals due to
+	// https://github.com/jmespath/go-jmespath/issues/27
+	//
+	// TODO: fix this in https://github.com/kyverno/go-jmespath
+	//
+
+	jp, err := New("replace('Lorem ipsum dolor sit amet', 'ipsum', 'muspi', `-1`)")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	replaced, ok := result.(string)
+	assert.Assert(t, ok)
+	assert.Equal(t, replaced, "Lorem muspi dolor sit amet")
+}
+
+func TestJMESPathFunctions_ReplaceAll(t *testing.T) {
+	jp, err := New("replace_all('Lorem ipsum dolor sit amet', 'ipsum', 'muspi')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	replaced, ok := result.(string)
+	assert.Assert(t, ok)
+	assert.Equal(t, replaced, "Lorem muspi dolor sit amet")
+}
+
+func TestJMESPathFunctions_ToUpper(t *testing.T) {
+	jp, err := New("to_upper('abc')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	upper, ok := result.(string)
+	assert.Assert(t, ok)
+	assert.Equal(t, upper, "ABC")
+}
+
+func TestJMESPathFunctions_ToLower(t *testing.T) {
+	jp, err := New("to_lower('AbC')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	lower, ok := result.(string)
+	assert.Assert(t, ok)
+	assert.Equal(t, lower, "abc")
+}
+
+func TestJMESPathFunctions_Trim(t *testing.T) {
+	jp, err := New("trim('¡¡¡Hello, Gophers!!!', '!¡')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	trim, ok := result.(string)
+	assert.Assert(t, ok)
+	assert.Equal(t, trim, "Hello, Gophers")
+}
+
+func TestJMESPathFunctions_Split(t *testing.T) {
+	jp, err := New("split('Hello, Gophers', ', ')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	split, ok := result.([]string)
+	assert.Assert(t, ok)
+	assert.Equal(t, split[0], "Hello")
+	assert.Equal(t, split[1], "Gophers")
+}
+
+func TestJMESPathFunctions_HasPrefix(t *testing.T) {
+	jp, err := New("starts_with('Gophers', 'Go')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	split, ok := result.(bool)
+	assert.Assert(t, ok)
+	assert.Equal(t, split, true)
+}
+
+func TestJMESPathFunctions_HasSuffix(t *testing.T) {
+	jp, err := New("ends_with('Amigo', 'go')")
+	assert.NilError(t, err)
+
+	result, err := jp.Search("")
+	assert.NilError(t, err)
+
+	split, ok := result.(bool)
+	assert.Assert(t, ok)
+	assert.Equal(t, split, true)
+}
+
+func Test_regexMatch(t *testing.T) {
+	data := make(map[string]interface{})
+	data["foo"] = "hgf'b1a2r'b12g"
+
+	query, err := New("regex_match('12.*', foo)")
+	assert.NilError(t, err)
+
+	result, err := query.Search(data)
+	assert.NilError(t, err)
+	assert.Equal(t, true, result)
+}
+
+func Test_regexMatchWithNumber(t *testing.T) {
+	data := make(map[string]interface{})
+	data["foo"] = -12.0
+
+	query, err := New("regex_match('12.*', abs(foo))")
+	assert.NilError(t, err)
+
+	result, err := query.Search(data)
+	assert.NilError(t, err)
+	assert.Equal(t, true, result)
+}
+
+func Test_regexReplaceAll(t *testing.T) {
+	resourceRaw := []byte(`
+	{
+		"metadata": {
+			"name": "temp",
+			"namespace": "ns_first"
+		},
+		"spec": {
+			"namespace": "ns_first",
+			"name": "temp_other",
+			"field" : "Hello world, helworldlo"
+		}
+	}
+	`)
+	expected := "Glo world, Gworldlo"
+
+	var resource interface{}
+	err := json.Unmarshal(resourceRaw, &resource)
+	assert.NilError(t, err)
+	query, err := New(`regex_replace_all('([Hh]e|G)l', spec.field, '${2}G')`)
+	assert.NilError(t, err)
+
+	res, err := query.Search(resource)
+	assert.NilError(t, err)
+
+	result, ok := res.(string)
+	assert.Assert(t, ok)
+	assert.Equal(t, string(result), expected)
+}
+
+func Test_regexReplaceAllLiteral(t *testing.T) {
+	resourceRaw := []byte(`
+	{
+		"metadata": {
+			"name": "temp",
+			"namespace": "ns_first"
+		},
+		"spec": {
+			"namespace": "ns_first",
+			"name": "temp_other",
+			"field" : "Hello world, helworldlo"
+		}
+	}
+	`)
+	expected := "Glo world, Gworldlo"
+
+	var resource interface{}
+	err := json.Unmarshal(resourceRaw, &resource)
+	assert.NilError(t, err)
+
+	query, err := New(`regex_replace_all_literal('[Hh]el?', spec.field, 'G')`)
+	assert.NilError(t, err)
+
+	res, err := query.Search(resource)
+	assert.NilError(t, err)
+
+	result, ok := res.(string)
+	assert.Assert(t, ok)
+
+	assert.Equal(t, string(result), expected)
+}
diff --git a/pkg/engine/mutation_test.go b/pkg/engine/mutation_test.go
index 6d7f5bdb6..92a5d42e2 100644
--- a/pkg/engine/mutation_test.go
+++ b/pkg/engine/mutation_test.go
@@ -8,6 +8,7 @@ import (
 	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"github.com/kyverno/kyverno/pkg/engine/context"
 	"github.com/kyverno/kyverno/pkg/engine/utils"
+	"github.com/kyverno/kyverno/pkg/kyverno/store"
 	"gotest.tools/assert"
 )
 
@@ -164,3 +165,104 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
 	t.Log(er.PolicyResponse.Rules[0].Message)
 	assert.Equal(t, er.PolicyResponse.Rules[0].Message, expectedErrorStr)
 }
+
+func Test_variableSubstitutionCLI(t *testing.T) {
+	resourceRaw := []byte(`{
+		"apiVersion": "v1",
+		"kind": "Pod",
+		"metadata": {
+		  "name": "nginx-config-test"
+		},
+		"spec": {
+		  "containers": [
+			{
+			  "image": "nginx:latest",
+			  "name": "test-nginx"
+			}
+		  ]
+		}
+	}`)
+
+	policyraw := []byte(`{
+		"apiVersion": "kyverno.io/v1",
+		"kind": "ClusterPolicy",
+		"metadata": {
+		  "name": "cm-variable-example"
+		},
+		"spec": {
+		  "rules": [
+			{
+			  "name": "example-configmap-lookup",
+			  "context": [
+				{
+				  "name": "dictionary",
+				  "configMap": {
+					"name": "mycmap",
+					"namespace": "default"
+				  }
+				}
+			  ],
+			  "match": {
+				"resources": {
+				  "kinds": [
+					"Pod"
+				  ]
+				}
+			  },
+			  "mutate": {
+				"patchStrategicMerge": {
+				  "metadata": {
+					"labels": {
+					  "my-environment-name": "{{dictionary.data.env}}"
+					}
+				  }
+				}
+			  }
+			}
+		  ]
+		}
+	  }`)
+
+	configMapVariableContext := store.Context{
+		Policies: []store.Policy{
+			{
+				Name: "cm-variable-example",
+				Rules: []store.Rule{
+					{
+						Name: "example-configmap-lookup",
+						Values: map[string]string{
+							"dictionary.data.env": "dev1",
+						},
+					},
+				},
+			},
+		},
+	}
+
+	expectedPatch := []byte(`{"op":"add","path":"/metadata/labels","value":{"my-environment-name":"dev1"}}`)
+
+	store.SetContext(configMapVariableContext)
+	store.SetMock(true)
+	var policy kyverno.ClusterPolicy
+	err := json.Unmarshal(policyraw, &policy)
+	assert.NilError(t, err)
+	resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
+	assert.NilError(t, err)
+
+	ctx := context.NewContext()
+	err = ctx.AddResource(resourceRaw)
+	assert.NilError(t, err)
+
+	policyContext := &PolicyContext{
+		Policy:      policy,
+		JSONContext: ctx,
+		NewResource: *resourceUnstructured,
+	}
+
+	er := Mutate(policyContext)
+	t.Log(string(expectedPatch))
+	t.Log(string(er.PolicyResponse.Rules[0].Patches[0]))
+	if !reflect.DeepEqual(expectedPatch, er.PolicyResponse.Rules[0].Patches[0]) {
+		t.Error("patches dont match")
+	}
+}
diff --git a/pkg/engine/validation_test.go b/pkg/engine/validation_test.go
index 5fd4850ea..0af0d0648 100644
--- a/pkg/engine/validation_test.go
+++ b/pkg/engine/validation_test.go
@@ -7,6 +7,7 @@ import (
 	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"github.com/kyverno/kyverno/pkg/engine/context"
 	"github.com/kyverno/kyverno/pkg/engine/utils"
+	"github.com/kyverno/kyverno/pkg/kyverno/store"
 	utils2 "github.com/kyverno/kyverno/pkg/utils"
 	"gotest.tools/assert"
 	"k8s.io/api/admission/v1beta1"
@@ -713,6 +714,160 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
 	assert.Assert(t, er.IsSuccessful())
 }
 
+func TestValidate_inequality_List_Processing(t *testing.T) {
+	// anchor not present in resource
+	rawPolicy := []byte(`{
+		"apiVersion": "kyverno.io/v1",
+		"kind": "ClusterPolicy",
+		"metadata": {
+		   "name": "policy-secaas-k8s"
+		},
+		"spec": {
+		   "rules": [
+			  {
+				 "name": "pod rule 2",
+				 "match": {
+					"resources": {
+					   "kinds": [
+						  "Pod"
+					   ]
+					}
+				 },
+				 "validate": {
+					"message": "pod: validate run as non root user",
+					"pattern": {
+					   "spec": {
+						  "=(supplementalGroups)": ">0"
+					   }
+					}
+				 }
+			  }
+		   ]
+		}
+	 }	 `)
+
+	rawResource := []byte(`
+	{
+		"apiVersion": "v1",
+		"kind": "Pod",
+		"metadata": {
+		   "name": "myapp-pod",
+		   "labels": {
+			  "app": "v1"
+		   }
+		},
+		"spec": {
+		   "containers": [
+			  {
+				 "name": "nginx",
+				 "image": "nginx"
+			  }
+		   ],
+		   "supplementalGroups": [
+			  "2",
+			  "5",
+			  "10"
+		   ]
+		}
+	 }
+`)
+
+	var policy kyverno.ClusterPolicy
+	err := json.Unmarshal(rawPolicy, &policy)
+	assert.NilError(t, err)
+
+	resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
+	assert.NilError(t, err)
+	er := Validate(&PolicyContext{Policy: policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
+	msgs := []string{"validation rule 'pod rule 2' passed."}
+
+	for index, r := range er.PolicyResponse.Rules {
+		assert.Equal(t, r.Message, msgs[index])
+	}
+
+	assert.Assert(t, er.IsSuccessful())
+}
+
+func TestValidate_inequality_List_ProcessingBrackets(t *testing.T) {
+	// anchor not present in resource
+	rawPolicy := []byte(`{
+		"apiVersion": "kyverno.io/v1",
+		"kind": "ClusterPolicy",
+		"metadata": {
+		   "name": "policy-secaas-k8s"
+		},
+		"spec": {
+		   "rules": [
+			  {
+				 "name": "pod rule 2",
+				 "match": {
+					"resources": {
+					   "kinds": [
+						  "Pod"
+					   ]
+					}
+				 },
+				 "validate": {
+					"message": "pod: validate run as non root user",
+					"pattern": {
+					   "spec": {
+						"=(supplementalGroups)": [
+							">0 & <100001"
+						  ]
+					   }
+					}
+				 }
+			  }
+		   ]
+		}
+	 }	 `)
+
+	rawResource := []byte(`
+	{
+		"apiVersion": "v1",
+		"kind": "Pod",
+		"metadata": {
+		   "name": "myapp-pod",
+		   "labels": {
+			  "app": "v1"
+		   }
+		},
+		"spec": {
+		   "containers": [
+			  {
+				 "name": "nginx",
+				 "image": "nginx"
+			  }
+		   ],
+		   "supplementalGroups": [
+			  "2",
+			  "5",
+			  "10",
+			  "100",
+			  "10000",
+			  "1000",
+			  "543"
+		   ]
+		}
+	 }
+`)
+
+	var policy kyverno.ClusterPolicy
+	err := json.Unmarshal(rawPolicy, &policy)
+	assert.NilError(t, err)
+
+	resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
+	assert.NilError(t, err)
+	er := Validate(&PolicyContext{Policy: policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
+	msgs := []string{"validation rule 'pod rule 2' passed."}
+
+	for index, r := range er.PolicyResponse.Rules {
+		assert.Equal(t, r.Message, msgs[index])
+	}
+
+	assert.Assert(t, er.IsSuccessful())
+}
+
 func TestValidate_anchor_map_found_invalid(t *testing.T) {
 	// anchor not present in resource
 	rawPolicy := []byte(`{
@@ -1987,3 +2142,103 @@ func executeTest(t *testing.T, err error, test testCase) {
 		t.Errorf("Testcase has failed, policy: %v", policy.Name)
 	}
 }
+
+func TestValidate_context_variable_substitution_CLI(t *testing.T) {
+	rawPolicy := []byte(`{
+		"apiVersion": "kyverno.io/v1",
+		"kind": "ClusterPolicy",
+		"metadata": {
+		  "name": "restrict-pod-count"
+		},
+		"spec": {
+		  "validationFailureAction": "enforce",
+		  "background": false,
+		  "rules": [
+			{
+			  "name": "restrict-pod-count",
+			  "match": {
+				"resources": {
+				  "kinds": [
+					"Pod"
+				  ]
+				}
+			  },
+			  "context": [
+				{
+				  "name": "podcounts",
+				  "apiCall": {
+					"urlPath": "/api/v1/pods",
+					"jmesPath": "items[?spec.nodeName=='minikube'] | length(@)"
+				  }
+				}
+			  ],
+			  "validate": {
+				"message": "restrict pod counts to be no more than 10 on node minikube",
+				"deny": {
+				  "conditions": [
+					{
+					  "key": "{{ podcounts }}",
+					  "operator": "GreaterThanOrEquals",
+					  "value": 10
+					}
+				  ]
+				}
+			  }
+			}
+		  ]
+		}
+	  }
+	`)
+
+	rawResource := []byte(`
+	{
+		"apiVersion": "v1",
+		"kind": "Pod",
+		"metadata": {
+		  "name": "nginx-config-test"
+		},
+		"spec": {
+		  "containers": [
+			{
+			  "image": "nginx:latest",
+			  "name": "test-nginx"
+			}
+		  ]
+		}
+	  }
+	`)
+
+	configMapVariableContext := store.Context{
+		Policies: []store.Policy{
+			{
+				Name: "restrict-pod-count",
+				Rules: []store.Rule{
+					{
+						Name: "restrict-pod-count",
+						Values: map[string]string{
+							"podcounts": "12",
+						},
+					},
+				},
+			},
+		},
+	}
+
+	store.SetContext(configMapVariableContext)
+	store.SetMock(true)
+
+	var policy kyverno.ClusterPolicy
+	err := json.Unmarshal(rawPolicy, &policy)
+	assert.NilError(t, err)
+
+	resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
+	assert.NilError(t, err)
+	msgs := []string{
+		"restrict pod counts to be no more than 10 on node minikube",
+	}
+	er := Validate(&PolicyContext{Policy: policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
+	for index, r := range er.PolicyResponse.Rules {
+		assert.Equal(t, r.Message, msgs[index])
+	}
+	assert.Assert(t, !er.IsSuccessful())
+}
diff --git a/pkg/engine/variables/vars_test.go b/pkg/engine/variables/vars_test.go
index 6b17f98be..759cdb788 100644
--- a/pkg/engine/variables/vars_test.go
+++ b/pkg/engine/variables/vars_test.go
@@ -135,6 +135,149 @@ func Test_subVars_failed(t *testing.T) {
 	}
 }
 
+func Test_subVars_with_JMESPath_At(t *testing.T) {
+	patternMap := []byte(`
+	{
+		"kind": "{{@}}",
+		"data": {
+			"rules": [
+				{
+					"apiGroups": [
+						"{{request.object.metadata.name}}"
+					],
+					"resources": [
+						"namespaces"
+					],
+					"verbs": [
+						"*"
+					],
+					"resourceNames": [
+						"{{request.object.metadata.name}}"
+					]
+				}
+			]
+		}
+	}
+	`)
+
+	resourceRaw := []byte(`
+	{
+		"kind": "foo",
+		"name": "bar",
+		"metadata": {
+			"name": "temp",
+			"namespace": "n1"
+		},
+		"spec": {
+			"namespace": "n1",
+			"name": "temp1"
+		}
+	}
+		`)
+
+	expected := []byte(`{"data":{"rules":[{"apiGroups":["temp"],"resourceNames":["temp"],"resources":["namespaces"],"verbs":["*"]}]},"kind":"foo"}`)
+
+	var pattern, resource interface{}
+	var err error
+	err = json.Unmarshal(patternMap, &pattern)
+	assert.NilError(t, err)
+	err = json.Unmarshal(resourceRaw, &resource)
+	assert.NilError(t, err)
+	// context
+	ctx := context.NewContext()
+	err = ctx.AddResource(resourceRaw)
+	assert.NilError(t, err)
+
+	output, err := SubstituteAll(log.Log, ctx, pattern)
+	assert.NilError(t, err)
+	out, err := json.Marshal(output)
+	assert.NilError(t, err)
+	assert.Equal(t, string(out), string(expected))
+}
+
+func Test_subVars_withRegexMatch(t *testing.T) {
+	patternMap := []byte(`
+	{
+		"port": "{{ regex_match('(443)', '{{@}}') }}",
+		"name": "ns-owner-{{request.object.metadata.name}}"
+	}
+	`)
+
+	resourceRaw := []byte(`
+	{
+		"port": "443",
+		"metadata": {
+			"name": "temp",
+			"namespace": "n1"
+		},
+		"spec": {
+			"namespace": "n1",
+			"name": "temp1"
+		}
+	}
+		`)
+	expected := []byte(`{"name":"ns-owner-temp","port":true}`)
+
+	var pattern, resource interface{}
+	var err error
+	err = json.Unmarshal(patternMap, &pattern)
+	assert.NilError(t, err)
+	err = json.Unmarshal(resourceRaw, &resource)
+	assert.NilError(t, err)
+	// context
+	ctx := context.NewContext()
+	err = ctx.AddResource(resourceRaw)
+	assert.NilError(t, err)
+
+	output, err := SubstituteAll(log.Log, ctx, pattern)
+	assert.NilError(t, err)
+	out, err := json.Marshal(output)
+	assert.NilError(t, err)
+	fmt.Print(string(out))
+	assert.Equal(t, string(out), string(expected))
+}
+
+func Test_subVars_withRegexReplaceAll(t *testing.T) {
+	patternMap := []byte(`
+	{
+		"port": "{{ regex_replace_all_literal('.*', '{{@}}', '1313') }}",
+		"name": "ns-owner-{{request.object.metadata.name}}"
+	}
+	`)
+
+	resourceRaw := []byte(`
+	{
+		"port": "43123",
+		"metadata": {
+			"name": "temp",
+			"namespace": "n1"
+		},
+		"spec": {
+			"namespace": "n1",
+			"name": "temp1"
+		}
+	}
+		`)
+	expected := []byte(`{"name":"ns-owner-temp","port":"1313"}`)
+
+	var pattern, resource interface{}
+	var err error
+	err = json.Unmarshal(patternMap, &pattern)
+	assert.NilError(t, err)
+	err = json.Unmarshal(resourceRaw, &resource)
+	assert.NilError(t, err)
+	// context
+	ctx := context.NewContext()
+	err = ctx.AddResource(resourceRaw)
+	assert.NilError(t, err)
+
+	output, err := SubstituteAll(log.Log, ctx, pattern)
+	assert.NilError(t, err)
+	out, err := json.Marshal(output)
+	assert.NilError(t, err)
+	assert.Equal(t, string(out), string(expected))
+}
+
 func Test_ReplacingPathWhenDeleting(t *testing.T) {
 	patternRaw := []byte(`"{{request.object.metadata.annotations.target}}"`)
 
diff --git a/pkg/kyverno/validate/commmand_test.go b/pkg/kyverno/validate/commmand_test.go
new file mode 100644
index 000000000..0f2e9c468
--- /dev/null
+++ b/pkg/kyverno/validate/commmand_test.go
@@ -0,0 +1,112 @@
+package validate
+
+import (
+	"encoding/json"
+	"fmt"
+	"testing"
+
+	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
+	"gotest.tools/assert"
+)
+
+func Test_validateUsingPolicyCRD(t *testing.T) {
+	type TestCase struct {
+		rawPolicy   []byte
+		errorDetail string
+	}
+
+	testcases := []TestCase{
+		{
+			rawPolicy: []byte(`
+		{
+			"apiVersion": "kyverno.io/v1",
+			"kind": "ClusterPolicy",
+			"metadata": {
+			  "name": "add-requests"
+			},
+			"spec": {
+			  "rules": [
+				{
+				  "name": "Set memory and/or cpu requests for all pods in namespaces labeled 'myprivatelabel'",
+				  "match": {
+					"resources": {
+					  "kinds": [
+						"Pod"
+					  ]
+					}
+				  },
+				  "mutate": {
+					"overlay": {
+					  "spec": {
+						"containers": [
+						  {
+							"(name)": "*",
+							"resources": {
+							  "requests": {
+								"cpu": "1000m"
+							  }
+							}
+						  }
+						]
+					  }
+					}
+				  }
+				}
+			  ]
+			}
+		  }
+		`),
+			errorDetail: "spec.rules.name in body should be at most 63 chars long",
+		},
+		{
+			rawPolicy: []byte(`
+				{
+					"apiVersion": "kyverno.io/v1",
+					"kind": "ClusterPolicy",
+					"metadata": {
+					  "name": "min-replicas-clusterpolicy"
+					},
+					"spec": {
+					  "validationFailureAction": "audit",
+					  "rules": [
+						{
+						  "name": "check-min-replicas",
+						  "match": {
+							"resources": {
+							  "kinds": [
+								"Deployment"
+							  ]
+							}
+						  },
+						  "validate": {
+							"message": "should have at least 2 replicas",
+							"pattern": {
+							  "spec": {
+								"replicas": 2
+							  }
+							}
+						  }
+						}
+					  ]
+					}
+				  }
+		`),
+			errorDetail: "",
+		},
+	}
+
+	v1crd, err := getPolicyCRD()
+	assert.NilError(t, err)
+
+	var policy kyverno.ClusterPolicy
+	for _, tc := range testcases {
+		err = json.Unmarshal(tc.rawPolicy, &policy)
+		assert.NilError(t, err)
+
+		_, errorList := validatePolicyAccordingToPolicyCRD(&policy, v1crd)
+		fmt.Println("errorList:  ", errorList)
+		for _, e := range errorList {
+			assert.Assert(t, tc.errorDetail == e.Detail)
+		}
+	}
+}
diff --git a/pkg/policy/background_test.go b/pkg/policy/background_test.go
index a0d9e136a..32a1dda10 100644
--- a/pkg/policy/background_test.go
+++ b/pkg/policy/background_test.go
@@ -133,5 +133,5 @@ func Test_Validation_invalid_backgroundPolicy(t *testing.T) {
 	err := json.Unmarshal(rawPolicy, &policy)
 	assert.NilError(t, err)
 	err = ContainsVariablesOtherThanObject(policy)
-	assert.Assert(t, strings.Contains(err.Error(), "variable serviceAccountName cannot be used, allowed variables: [request.object request.namespace mycm]"))
+	assert.Assert(t, strings.Contains(err.Error(), "variable serviceAccountName cannot be used, allowed variables: [request.object request.namespace images mycm]"))
 }
diff --git a/pkg/policy/validate_test.go b/pkg/policy/validate_test.go
index c71cd4da6..7366e7d0b 100644
--- a/pkg/policy/validate_test.go
+++ b/pkg/policy/validate_test.go
@@ -2,10 +2,12 @@ package policy
 
 import (
 	"encoding/json"
+	"fmt"
 	"testing"
 
 	"github.com/kyverno/kyverno/pkg/openapi"
 	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
+	"sigs.k8s.io/controller-runtime/pkg/log"
 
 	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"gotest.tools/assert"
@@ -1237,3 +1239,56 @@ func Test_doesMatchExcludeConflict(t *testing.T) {
 		}
 	}
 }
+
+func Test_checkAutoGenRules(t *testing.T) {
+	testCases := []struct {
+		name           string
+		policy         []byte
+		expectedResult bool
+	}{
+		{
+			name:           "rule-with-match-name",
+			policy:         []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"test"},"spec":{"rules":[{"name":"test","match":{"resources":{"kinds":["Namespace"],"name":"*"}}}]}}`),
+			expectedResult: false,
+		},
+		{
+			name:           "rule-with-match-selector",
+			policy:         []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"test-getcontrollers"},"spec":{"background":false,"rules":[{"name":"test-getcontrollers","match":{"resources":{"kinds":["Pod"],"selector":{"matchLabels":{"foo":"bar"}}}}}]}}`),
+			expectedResult: false,
+		},
+		{
+			name:           "rule-with-exclude-name",
+			policy:         []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"test-getcontrollers"},"spec":{"background":false,"rules":[{"name":"test-getcontrollers","match":{"resources":{"kinds":["Pod"]}},"exclude":{"resources":{"name":"test"}}}]}}`),
+			expectedResult: false,
+		},
+		{
+			name:           "rule-with-exclude-selector",
+			policy:         []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"test-getcontrollers"},"spec":{"background":false,"rules":[{"name":"test-getcontrollers","match":{"resources":{"kinds":["Pod"]}},"exclude":{"resources":{"selector":{"matchLabels":{"foo":"bar"}}}}}]}}`),
+			expectedResult: false,
+		},
+		{
+			name:           "rule-with-deny",
+			policy:         []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"test"},"spec":{"rules":[{"name":"require-network-policy","match":{"resources":{"kinds":["Pod"]}},"validate":{"message":"testpolicy","deny":{"conditions":[{"key":"{{request.object.metadata.labels.foo}}","operator":"Equals","value":"bar"}]}}}]}}`),
+			expectedResult: false,
+		},
+		{
+			name:           "rule-with-match-kinds-pod-only",
+			policy:         []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"test"},"spec":{"rules":[{"name":"require-network-policy","match":{"resources":{"kinds":["Pod"]}},"validate":{"message":"testpolicy","pattern":{"metadata":{"labels":{"foo":"bar"}}}}}]}}`),
+			expectedResult: true,
+		},
+		{
+			name:           "rule-with-exclude-kinds-pod-only",
+			policy:         []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"test"},"spec":{"rules":[{"name":"require-network-policy","match":{"resources":{"kinds":["Pod"]}},"exclude":{"resources":{"kinds":["Pod"],"namespaces":["test"]}},"validate":{"message":"testpolicy","pattern":{"metadata":{"labels":{"foo":"bar"}}}}}]}}`),
+			expectedResult: true,
+		},
+	}
+
+	for _, test := range testCases {
+		var policy kyverno.ClusterPolicy
+		err := json.Unmarshal(test.policy, &policy)
+		assert.NilError(t, err)
+
+		res := checkAutoGenRules(&policy, log.Log)
+		assert.Equal(t, test.expectedResult, res, fmt.Sprintf("test %s failed", test.name))
+	}
+}
diff --git a/test/e2e/mutate/config.go b/test/e2e/mutate/config.go
index 26184bffb..0dc5e0995 100644
--- a/test/e2e/mutate/config.go
+++ b/test/e2e/mutate/config.go
@@ -15,4 +15,8 @@ var MutateTests = []struct {
 		TestName: "test-mutate-with-logic-in-context",
 		Data:     configMapMutationWithContextLogicYaml,
 	},
+	{
+		TestName: "test-mutate-with-context-label-selection",
+		Data:     configMapMutationWithContextLabelSelectionYaml,
+	},
 }
diff --git a/test/e2e/mutate/resources.go b/test/e2e/mutate/resources.go
index e49d66ae7..fe060d68a 100644
--- a/test/e2e/mutate/resources.go
+++ b/test/e2e/mutate/resources.go
@@ -57,6 +57,30 @@ spec:
             +(kyverno.key/copy-me): "{{ labelValue }}"
 `)
 
+var configMapMutationWithContextLabelSelectionYaml = []byte(`
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+  name: "mutate-policy"
+spec:
+  rules:
+  - name: "gen-role"
+    match:
+      resources:
+        kinds:
+          - ConfigMap
+    context:
+    - name: labelValue
+      apiCall:
+        urlPath: "/api/v1/namespaces/{{ request.object.metadata.namespace }}/configmaps"
+        jmesPath: "items[?metadata.name == '{{ request.object.metadata.labels.\"kyverno.key/copy-from\" }}'].metadata.labels.\"kyverno.key/copy-me\" | [0]"
+    mutate:
+      patchStrategicMerge:
+        metadata:
+          labels:
+            +(kyverno.key/copy-me): "{{ labelValue }}"
+`)
+
 // Source ConfigMap from which data is taken to copy
 var sourceConfigMapYaml = []byte(`
 apiVersion: v1
@@ -78,6 +102,8 @@ kind: ConfigMap
 metadata:
   name: target
   namespace: test-mutate
+  labels:
+    kyverno.key/copy-from: source
 data:
   data.yaml: |
     some: data