Repository: kyverno/kyverno
Pull request #1736 (2021-03-26 15:04:37)

Skipping schema check for unknown kinds
Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>

## Related issue
closes https://github.com/kyverno/kyverno/issues/1677

## What type of PR is this
> /kind bug
> /kind feature

## Proposed changes
skipping schema check for unknown kinds

## Checklist

- [X] I have read the [contributing guidelines](https://github.com/kyverno/kyverno/blob/main/CONTRIBUTING.md).
- [] I have added tests that prove my fix is effective or that my feature works.
- [] 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:
  <!-- Uncomment to link to the issue -->
  <!-- https://github.com/kyverno/website/issues/1 -->



Patch:
diff --git a/charts/kyverno/Chart.yaml b/charts/kyverno/Chart.yaml
index 434396bc1..e5e64acea 100644
--- a/charts/kyverno/Chart.yaml
+++ b/charts/kyverno/Chart.yaml
@@ -1,7 +1,7 @@
 apiVersion: v1
 name: kyverno
-version: v1.3.4
-appVersion: v1.3.4
+version: v1.3.5-rc1
+appVersion: v1.3.5-rc1
 icon: https://github.com/kyverno/kyverno/raw/main/img/logo.png
 description: Kubernetes Native Policy Management
 keywords:
diff --git a/definitions/install.yaml b/definitions/install.yaml
index c1dc3bdc0..809671d16 100644
--- a/definitions/install.yaml
+++ b/definitions/install.yaml
@@ -2439,7 +2439,7 @@ spec:
               fieldPath: metadata.namespace
         - name: KYVERNO_SVC
           value: kyverno-svc
-        image: ghcr.io/kyverno/kyverno:v1.3.4
+        image: ghcr.io/kyverno/kyverno:v1.3.5-rc1
         imagePullPolicy: IfNotPresent
         livenessProbe:
           failureThreshold: 4
@@ -2481,7 +2481,7 @@ spec:
           readOnlyRootFilesystem: true
           runAsNonRoot: true
       initContainers:
-      - image: ghcr.io/kyverno/kyvernopre:v1.3.4
+      - image: ghcr.io/kyverno/kyvernopre:v1.3.5-rc1
         imagePullPolicy: IfNotPresent
         name: kyverno-pre
         securityContext:
diff --git a/definitions/kustomization.yaml b/definitions/kustomization.yaml
index b038b001a..7c6584621 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.4
+  newTag: v1.3.5-rc1
 - name: ghcr.io/kyverno/kyvernopre
   newName: ghcr.io/kyverno/kyvernopre
-  newTag: v1.3.4
+  newTag: v1.3.5-rc1
diff --git a/definitions/release/install.yaml b/definitions/release/install.yaml
index ca3b27db4..809671d16 100755
--- a/definitions/release/install.yaml
+++ b/definitions/release/install.yaml
@@ -2439,7 +2439,7 @@ spec:
               fieldPath: metadata.namespace
         - name: KYVERNO_SVC
           value: kyverno-svc
-        image: ghcr.io/kyverno/kyverno:v1.3.4
+        image: ghcr.io/kyverno/kyverno:v1.3.5-rc1
         imagePullPolicy: IfNotPresent
         livenessProbe:
           failureThreshold: 4
@@ -2480,9 +2480,8 @@ spec:
           privileged: false
           readOnlyRootFilesystem: true
           runAsNonRoot: true
-          runAsUser: 1000
       initContainers:
-      - image: ghcr.io/kyverno/kyvernopre:v1.3.4
+      - image: ghcr.io/kyverno/kyvernopre:v1.3.5-rc1
         imagePullPolicy: IfNotPresent
         name: kyverno-pre
         securityContext:
@@ -2493,7 +2492,6 @@ spec:
           privileged: false
           readOnlyRootFilesystem: true
           runAsNonRoot: true
-          runAsUser: 1000
       securityContext:
         runAsNonRoot: true
       serviceAccountName: kyverno-service-account
diff --git a/pkg/engine/anchor/common/common.go b/pkg/engine/anchor/common/common.go
index d83dd366f..087a9e052 100644
--- a/pkg/engine/anchor/common/common.go
+++ b/pkg/engine/anchor/common/common.go
@@ -1,5 +1,10 @@
 package common
 
+import (
+	"path"
+	"strings"
+)
+
 // IsAnchor is a function handler
 type IsAnchor func(str string) bool
 
@@ -72,6 +77,24 @@ func RemoveAnchor(key string) (string, string) {
 	return key, ""
 }
 
+// RemoveAnchorsFromPath removes all anchor from path string
+func RemoveAnchorsFromPath(str string) string {
+	components := strings.Split(str, "/")
+	if components[0] == "" {
+		components = components[1:]
+	}
+
+	for i, component := range components {
+		components[i], _ = RemoveAnchor(component)
+	}
+
+	newPath := path.Join(components...)
+	if path.IsAbs(str) {
+		newPath = "/" + newPath
+	}
+	return newPath
+}
+
 // AddAnchor adds an anchor with the supplied prefix.
 // The suffix is assumed to be ")".
 func AddAnchor(key, anchorPrefix string) string {
diff --git a/pkg/engine/common/utils.go b/pkg/engine/common/utils.go
new file mode 100644
index 000000000..aa84e694f
--- /dev/null
+++ b/pkg/engine/common/utils.go
@@ -0,0 +1,19 @@
+package common
+
+// CopyMap creates a full copy of the target map
+func CopyMap(m map[string]interface{}) map[string]interface{} {
+	mapCopy := make(map[string]interface{})
+	for k, v := range m {
+		mapCopy[k] = v
+	}
+
+	return mapCopy
+}
+
+// CopySlice creates a full copy of the target slice
+func CopySlice(s []interface{}) []interface{} {
+	sliceCopy := make([]interface{}, len(s))
+	copy(sliceCopy, s)
+
+	return sliceCopy
+}
diff --git a/pkg/engine/forceMutate.go b/pkg/engine/forceMutate.go
index 100245193..718629824 100644
--- a/pkg/engine/forceMutate.go
+++ b/pkg/engine/forceMutate.go
@@ -1,9 +1,7 @@
 package engine
 
 import (
-	"encoding/json"
 	"fmt"
-	"regexp"
 
 	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"github.com/kyverno/kyverno/pkg/engine/context"
@@ -53,6 +51,7 @@ func mutateResourceWithOverlay(resource unstructured.Unstructured, overlay inter
 }
 
 // ForceMutate does not check any conditions, it simply mutates the given resource
+// It is used to validate mutation logic, and for tests.
 func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured) (unstructured.Unstructured, error) {
 	var err error
 	logger := log.Log.WithName("EngineForceMutate").WithValues("policy", policy.Name, "kind", resource.GetKind(),
@@ -63,17 +62,15 @@ func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resour
 			continue
 		}
 
+		rule, err = variables.SubstituteAllForceMutate(log.Log, ctx, rule)
+		if err != nil {
+			return unstructured.Unstructured{}, err
+		}
+
 		mutation := rule.Mutation.DeepCopy()
 
 		if mutation.Overlay != nil {
 			overlay := mutation.Overlay
-			if ctx != nil {
-				if overlay, err = variables.SubstituteVars(log.Log, ctx, overlay); err != nil {
-					return unstructured.Unstructured{}, err
-				}
-			} else {
-				overlay = replaceSubstituteVariables(overlay)
-			}
 
 			resource, err = mutateResourceWithOverlay(resource, overlay)
 			if err != nil {
@@ -93,27 +90,3 @@ func ForceMutate(ctx context.EvalInterface, policy kyverno.ClusterPolicy, resour
 
 	return resource, nil
 }
-
-func replaceSubstituteVariables(overlay interface{}) interface{} {
-	overlayRaw, err := json.Marshal(overlay)
-	if err != nil {
-		return overlay
-	}
-
-	regex := regexp.MustCompile(`\{\{([^{}]*)\}\}`)
-	for {
-		if len(regex.FindAllStringSubmatch(string(overlayRaw), -1)) > 0 {
-			overlayRaw = regex.ReplaceAll(overlayRaw, []byte(`placeholderValue`))
-		} else {
-			break
-		}
-	}
-
-	var output interface{}
-	err = json.Unmarshal(overlayRaw, &output)
-	if err != nil {
-		return overlay
-	}
-
-	return output
-}
diff --git a/pkg/engine/json-utils/traverse.go b/pkg/engine/json-utils/traverse.go
new file mode 100644
index 000000000..381928a53
--- /dev/null
+++ b/pkg/engine/json-utils/traverse.go
@@ -0,0 +1,94 @@
+package json_utils
+
+import (
+	"strconv"
+
+	"github.com/kyverno/kyverno/pkg/engine/common"
+)
+
+// ActionData represents data available for action on current element
+type ActionData struct {
+	Document interface{}
+	Element  interface{}
+	Path     string
+}
+
+// Action encapsulates the logic that must be performed for each
+// JSON element
+type Action func(data *ActionData) (interface{}, error)
+
+// OnlyForLeafs is an action modifier - apply action only for leafs
+func OnlyForLeafs(action Action) Action {
+	return func(data *ActionData) (interface{}, error) {
+		switch data.Element.(type) {
+		case map[string]interface{}, []interface{}: // skip arrays and maps
+			return data.Element, nil
+
+		default: // leaf detected
+			return action(data)
+		}
+	}
+}
+
+// Traversal is a type that encapsulates JSON traversal algorithm
+// It traverses entire JSON structure applying some logic to its elements
+type Traversal struct {
+	document interface{}
+	action   Action
+}
+
+// NewTraversal creates JSON Traversal object
+func NewTraversal(document interface{}, action Action) *Traversal {
+	return &Traversal{
+		document,
+		action,
+	}
+}
+
+// TraverseJSON performs a traverse of JSON document and applying
+// action for each JSON element
+func (t *Traversal) TraverseJSON() (interface{}, error) {
+	return t.traverseJSON(t.document, "")
+}
+
+func (t *Traversal) traverseJSON(element interface{}, path string) (interface{}, error) {
+	// perform an action
+	element, err := t.action(&ActionData{t.document, element, path})
+	if err != nil {
+		return element, err
+	}
+
+	// traverse further
+	switch typed := element.(type) {
+	case map[string]interface{}:
+		return t.traverseObject(common.CopyMap(typed), path)
+
+	case []interface{}:
+		return t.traverseList(common.CopySlice(typed), path)
+
+	default:
+		return element, nil
+	}
+}
+
+func (t *Traversal) traverseObject(object map[string]interface{}, path string) (map[string]interface{}, error) {
+	for key, element := range object {
+		value, err := t.traverseJSON(element, path+"/"+key)
+		if err != nil {
+			return nil, err
+		}
+		object[key] = value
+	}
+	return object, nil
+}
+
+func (t *Traversal) traverseList(list []interface{}, path string) ([]interface{}, error) {
+	for idx, element := range list {
+		value, err := t.traverseJSON(element, path+"/"+strconv.Itoa(idx))
+		if err != nil {
+			return nil, err
+		}
+		list[idx] = value
+	}
+	return list, nil
+}
diff --git a/pkg/engine/jsonContext.go b/pkg/engine/jsonContext.go
index 081cf6c3c..adf6c21a7 100644
--- a/pkg/engine/jsonContext.go
+++ b/pkg/engine/jsonContext.go
@@ -62,7 +62,7 @@ func loadAPIData(logger logr.Logger, entry kyverno.ContextEntry, ctx *PolicyCont
 		return nil
 	}
 
-	path, err := variables.SubstituteVars(logger, ctx.JSONContext, entry.APICall.JMESPath)
+	path, err := variables.SubstituteAll(logger, ctx.JSONContext, entry.APICall.JMESPath)
 	if err != nil {
 		return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.APICall.JMESPath, err)
 	}
@@ -108,7 +108,7 @@ func fetchAPIData(log logr.Logger, entry kyverno.ContextEntry, ctx *PolicyContex
 		return nil, fmt.Errorf("missing APICall in context entry %s %v", entry.Name, entry.APICall)
 	}
 
-	path, err := variables.SubstituteVars(log, ctx.JSONContext, entry.APICall.URLPath)
+	path, err := variables.SubstituteAll(log, ctx.JSONContext, entry.APICall.URLPath)
 	if err != nil {
 		return nil, fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.APICall.URLPath, err)
 	}
@@ -175,12 +175,12 @@ func loadConfigMap(logger logr.Logger, entry kyverno.ContextEntry, lister dynami
 func fetchConfigMap(logger logr.Logger, entry kyverno.ContextEntry, lister dynamiclister.Lister, jsonContext *context.Context) ([]byte, error) {
 	contextData := make(map[string]interface{})
 
-	name, err := variables.SubstituteVars(logger, jsonContext, entry.ConfigMap.Name)
+	name, err := variables.SubstituteAll(logger, jsonContext, entry.ConfigMap.Name)
 	if err != nil {
 		return nil, fmt.Errorf("failed to substitute variables in context %s configMap.name %s: %v", entry.Name, entry.ConfigMap.Name, err)
 	}
 
-	namespace, err := variables.SubstituteVars(logger, jsonContext, entry.ConfigMap.Namespace)
+	namespace, err := variables.SubstituteAll(logger, jsonContext, entry.ConfigMap.Namespace)
 	if err != nil {
 		return nil, fmt.Errorf("failed to substitute variables in context %s configMap.namespace %s: %v", entry.Name, entry.ConfigMap.Namespace, err)
 	}
diff --git a/pkg/engine/mutate/mutation.go b/pkg/engine/mutate/mutation.go
index 4b32c5b89..4c54e4fd5 100644
--- a/pkg/engine/mutate/mutation.go
+++ b/pkg/engine/mutate/mutation.go
@@ -62,7 +62,7 @@ func (h patchStrategicMergeHandler) Handle() (response.RuleResponse, unstructure
 
 	// substitute the variables
 	var err error
-	if PatchStrategicMerge, err = variables.SubstituteVars(log, h.evalCtx, PatchStrategicMerge); err != nil {
+	if PatchStrategicMerge, err = variables.SubstituteAll(log, h.evalCtx, PatchStrategicMerge); err != nil {
 		// variable subsitution failed
 		ruleResponse.Name = h.ruleName
 		ruleResponse.Success = false
@@ -131,7 +131,7 @@ func (h overlayHandler) Handle() (response.RuleResponse, unstructured.Unstructur
 
 	// substitute the variables
 	var err error
-	if overlay, err = variables.SubstituteVars(h.logger, h.evalCtx, overlay); err != nil {
+	if overlay, err = variables.SubstituteAll(h.logger, h.evalCtx, overlay); err != nil {
 		// variable substitution failed
 		ruleResponse.Success = false
 		ruleResponse.Message = err.Error()
diff --git a/pkg/engine/validate/validate.go b/pkg/engine/validate/validate.go
index 58bc3cc33..4cc90db8b 100644
--- a/pkg/engine/validate/validate.go
+++ b/pkg/engine/validate/validate.go
@@ -3,10 +3,7 @@ package validate
 import (
 	"errors"
 	"fmt"
-	"path"
-	"reflect"
 	"strconv"
-	"strings"
 
 	"github.com/go-logr/logr"
 	"github.com/kyverno/kyverno/pkg/engine/anchor"
@@ -39,7 +36,6 @@ func ValidateResourceWithPattern(log logr.Logger, resource, pattern interface{})
 // and calls corresponding handler
 // Pattern tree and resource tree can have different structure. In this case validation fails
 func validateResourceElement(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string, ac *common.AnchorKey) (string, error) {
-	var err error
 	switch typedPatternElement := patternElement.(type) {
 	// map
 	case map[string]interface{}:
@@ -62,14 +58,6 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
 	// elementary values
 	case string, float64, int, int64, bool, nil:
 		/*Analyze pattern */
-		if checkedPattern := reflect.ValueOf(patternElement); checkedPattern.Kind() == reflect.String {
-			if isStringIsReference(checkedPattern.String()) { //check for $ anchor
-				patternElement, err = actualizePattern(log, originPattern, checkedPattern.String(), path)
-				if err != nil {
-					return path, err
-				}
-			}
-		}
 
 		if !ValidateValueWithPattern(log, resourceElement, patternElement) {
 			return path, fmt.Errorf("Validation rule failed at '%s' to validate value '%v' with pattern '%v'", path, resourceElement, patternElement)
@@ -162,73 +150,6 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
 	return "", nil
 }
 
-func actualizePattern(log logr.Logger, origPattern interface{}, referencePattern, absolutePath string) (interface{}, error) {
-	var foundValue interface{}
-
-	referencePattern = strings.Trim(referencePattern, "$()")
-
-	operatorVariable := operator.GetOperatorFromStringPattern(referencePattern)
-	referencePattern = referencePattern[len(operatorVariable):]
-
-	if len(referencePattern) == 0 {
-		return nil, errors.New("Expected path. Found empty reference")
-	}
-	// Check for variables
-	// substitute it from Context
-	// remove absolute path
-	// {{ }}
-	// value :=
-	actualPath := formAbsolutePath(referencePattern, absolutePath)
-
-	valFromReference, err := getValueFromReference(log, origPattern, actualPath)
-	if err != nil {
-		return err, nil
-	}
-	//TODO validate this
-	if operatorVariable == operator.Equal { //if operator does not exist return raw value
-		return valFromReference, nil
-	}
-
-	foundValue, err = valFromReferenceToString(valFromReference, string(operatorVariable))
-	if err != nil {
-		return "", err
-	}
-	return string(operatorVariable) + foundValue.(string), nil
-}
-
-//Parse value to string
-func valFromReferenceToString(value interface{}, operator string) (string, error) {
-
-	switch typed := value.(type) {
-	case string:
-		return typed, nil
-	case int, int64:
-		return fmt.Sprintf("%d", value), nil
-	case float64:
-		return fmt.Sprintf("%f", value), nil
-	default:
-		return "", fmt.Errorf("Incorrect expression. Operator %s does not match with value: %v", operator, value)
-	}
-}
-
-// returns absolute path
-func formAbsolutePath(referencePath, absolutePath string) string {
-	if path.IsAbs(referencePath) {
-		return referencePath
-	}
-
-	return path.Join(absolutePath, referencePath)
-}
-
-//Prepares original pattern, path to value, and call traverse function
-func getValueFromReference(log logr.Logger, origPattern interface{}, reference string) (interface{}, error) {
-	originalPatternMap := origPattern.(map[string]interface{})
-	reference = reference[1:]
-	statements := strings.Split(reference, "/")
-
-	return getValueFromPattern(log, originalPatternMap, statements, 0)
-}
-
 func getValueFromPattern(log logr.Logger, patternMap map[string]interface{}, keys []string, currentKeyIndex int) (interface{}, error) {
 
 	for key, pattern := range patternMap {
diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go
index 1f2de9e9e..88ae9936f 100644
--- a/pkg/engine/validation.go
+++ b/pkg/engine/validation.go
@@ -61,7 +61,7 @@ func buildResponse(logger logr.Logger, ctx *PolicyContext, resp *response.Engine
 	}
 
 	for i := range resp.PolicyResponse.Rules {
-		messageInterface, err := variables.SubstituteVars(logger, ctx.JSONContext, resp.PolicyResponse.Rules[i].Message)
+		messageInterface, err := variables.SubstituteAll(logger, ctx.JSONContext, resp.PolicyResponse.Rules[i].Message)
 		if err != nil {
 			logger.V(4).Info("failed to substitute variables", "error", err.Error())
 			continue
@@ -119,7 +119,6 @@ func validateResource(log logr.Logger, ctx *PolicyContext) *response.EngineRespo
 			continue
 		}
 		// evaluate pre-conditions
-		// - handle variable substitutions
 		if !variables.EvaluateConditions(log, ctx.JSONContext, preconditionsCopy) {
 			log.V(4).Info("resource fails the preconditions")
 			continue
@@ -226,15 +225,16 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
 		logger.V(4).Info("finished processing rule", "processingTime", resp.RuleStats.ProcessingTime.String())
 	}()
 
+	var err error
+	if rule, err = variables.SubstituteAllInRule(logger, ctx, rule); err != nil {
+		resp.Success = false
+		resp.Message = fmt.Sprintf("variable substitution failed for rule %s: %s", rule.Name, err.Error())
+		return resp
+	}
+
 	validationRule := rule.Validation.DeepCopy()
 	if validationRule.Pattern != nil {
 		pattern := validationRule.Pattern
-		var err error
-		if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil {
-			resp.Success = false
-			resp.Message = fmt.Sprintf("variable substitution failed for rule %s: %s", rule.Name, err.Error())
-			return resp
-		}
 
 		if path, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern); err != nil {
 			logger.V(3).Info("validation failed", "path", path, "error", err.Error())
@@ -250,7 +250,6 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
 	}
 
 	if validationRule.AnyPattern != nil {
-		var failedSubstitutionsErrors []error
 		var failedAnyPatternsErrors []error
 		var err error
 
@@ -262,11 +261,6 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
 		}
 
 		for idx, pattern := range anyPatterns {
-			if pattern, err = variables.SubstituteVars(logger, ctx, pattern); err != nil {
-				failedSubstitutionsErrors = append(failedSubstitutionsErrors, err)
-				continue
-			}
-
 			path, err := validate.ValidateResourceWithPattern(logger, resource.Object, pattern)
 			if err == nil {
 				resp.Success = true
@@ -279,13 +273,6 @@ func validatePatterns(log logr.Logger, ctx context.EvalInterface, resource unstr
 			failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr)
 		}
 
-		// Substitution failures
-		if len(failedSubstitutionsErrors) > 0 {
-			resp.Success = false
-			resp.Message = fmt.Sprintf("failed to substitute variables: %v", failedSubstitutionsErrors)
-			return resp
-		}
-
 		// Any Pattern validation errors
 		if len(failedAnyPatternsErrors) > 0 {
 			var errorStr []string
diff --git a/pkg/engine/variables/evaluate.go b/pkg/engine/variables/evaluate.go
index 351dc357b..c4782d89b 100644
--- a/pkg/engine/variables/evaluate.go
+++ b/pkg/engine/variables/evaluate.go
@@ -10,7 +10,7 @@ import (
 //Evaluate evaluates the condition
 func Evaluate(log logr.Logger, ctx context.EvalInterface, condition kyverno.Condition) bool {
 	// get handler for the operator
-	handle := operator.CreateOperatorHandler(log, ctx, condition.Operator, SubstituteVars)
+	handle := operator.CreateOperatorHandler(log, ctx, condition.Operator, SubstituteAll)
 	if handle == nil {
 		return false
 	}
diff --git a/pkg/engine/variables/vars.go b/pkg/engine/variables/vars.go
index f32fdfa71..126590e8d 100644
--- a/pkg/engine/variables/vars.go
+++ b/pkg/engine/variables/vars.go
@@ -1,86 +1,87 @@
 package variables
 
 import (
+	"encoding/json"
+	"errors"
 	"fmt"
+	"path"
 	"regexp"
-	"strconv"
 	"strings"
 
 	"github.com/go-logr/logr"
+	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
+	"github.com/kyverno/kyverno/pkg/engine/anchor/common"
 	"github.com/kyverno/kyverno/pkg/engine/context"
+	jsonUtils "github.com/kyverno/kyverno/pkg/engine/json-utils"
+	"github.com/kyverno/kyverno/pkg/engine/operator"
 )
 
 var regexVariables = regexp.MustCompile(`\{\{[^{}]*\}\}`)
+var regexReferences = regexp.MustCompile(`\$\(.[^\ ]*\)`)
 
-//IsVariable returns true if the element contains a 'valid' variable {{}}
-func IsVariable(element string) bool {
-	groups := regexVariables.FindAllStringSubmatch(element, -1)
+// IsVariable returns true if the element contains a 'valid' variable {{}}
+func IsVariable(value string) bool {
+	groups := regexVariables.FindAllStringSubmatch(value, -1)
 	return len(groups) != 0
 }
 
-//ReplaceAllVars replaces all variables with the value defined in the replacement function
+// IsReference returns true if the element contains a 'valid' reference $()
+func IsReference(value string) bool {
+	groups := regexReferences.FindAllStringSubmatch(value, -1)
+	return len(groups) != 0
+}
+
+// ReplaceAllVars replaces all variables with the value defined in the replacement function
+// This is used to avoid validation errors
 func ReplaceAllVars(src string, repl func(string) string) string {
 	return regexVariables.ReplaceAllStringFunc(src, repl)
 }
 
-//SubstituteVars replaces the variables with the values defined in the context
-// - if any variable is invalid or has nil value, it is considered as a failed variable substitution
-func SubstituteVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}) (interface{}, error) {
-	pattern, err := subVars(log, ctx, pattern, "")
+func SubstituteAll(log logr.Logger, ctx context.EvalInterface, document interface{}) (_ interface{}, err error) {
+	document, err = substituteReferences(log, document)
 	if err != nil {
-		return pattern, err
+		return kyverno.Rule{}, err
 	}
-	return pattern, nil
-}
 
-func subVars(log logr.Logger, ctx context.EvalInterface, pattern interface{}, path string) (interface{}, error) {
-	switch typedPattern := pattern.(type) {
-	case map[string]interface{}:
-		mapCopy := make(map[string]interface{})
-		for k, v := range typedPattern {
-			mapCopy[k] = v
-		}
-		return subMap(log, ctx, mapCopy, path)
+	return substituteVars(log, ctx, document)
+}
 
-	case []interface{}:
-		sliceCopy := make([]interface{}, len(typedPattern))
-		copy(sliceCopy, typedPattern)
-		return subArray(log, ctx, sliceCopy, path)
+func SubstituteAllForceMutate(log logr.Logger, ctx context.EvalInterface, typedRule kyverno.Rule) (_ kyverno.Rule, err error) {
+	var rule interface{}
 
-	case string:
-		return subValR(log, ctx, typedPattern, path)
+	rule, err = RuleToUntyped(typedRule)
+	if err != nil {
+		return kyverno.Rule{}, err
+	}
 
-	default:
-		return pattern, nil
+	rule, err = substituteReferences(log, rule)
+	if err != nil {
+		return kyverno.Rule{}, err
 	}
-}
 
-func subMap(log logr.Logger, ctx context.EvalInterface, patternMap map[string]interface{}, path string) (map[string]interface{}, error) {
-	for key, patternElement := range patternMap {
-		curPath := path + "/" + key
-		value, err := subVars(log, ctx, patternElement, curPath)
+	if ctx == nil {
+		rule = replaceSubstituteVariables(rule)
+	} else {
+		rule, err = substituteVars(log, ctx, rule)
 		if err != nil {
-			return nil, err
+			return kyverno.Rule{}, err
 		}
-		patternMap[key] = value
-
 	}
-	return patternMap, nil
+
+	return UntypedToRule(rule)
 }
 
-func subArray(log logr.Logger, ctx context.EvalInterface, patternList []interface{}, path string) ([]interface{}, error) {
-	for idx, patternElement := range patternList {
-		curPath := path + "/" + strconv.Itoa(idx)
-		value, err := subVars(log, ctx, patternElement, curPath)
-		if err != nil {
-			return nil, err
-		}
-		patternList[idx] = value
-	}
-	return patternList, nil
+//SubstituteVars replaces the variables with the values defined in the context
+// - if any variable is invalid or has nil value, it is considered as a failed variable substitution
+func substituteVars(log logr.Logger, ctx context.EvalInterface, rule interface{}) (interface{}, error) {
+	return jsonUtils.NewTraversal(rule, substituteVariablesIfAny(log, ctx)).TraverseJSON()
 }
 
-// NotFoundVariableErr ...
+func substituteReferences(log logr.Logger, rule interface{}) (interface{}, error) {
+	return jsonUtils.NewTraversal(rule, substituteReferencesIfAny(log)).TraverseJSON()
+}
+
+// NotFoundVariableErr is returned when it is impossible to resolve the variable
 type NotFoundVariableErr struct {
 	variable string
 	path     string
@@ -90,59 +91,281 @@ func (n NotFoundVariableErr) Error() string {
 	return fmt.Sprintf("variable %s not resolved at path %s", n.variable, n.path)
 }
 
-// subValR resolves the variables if defined
-func subValR(log logr.Logger, ctx context.EvalInterface, valuePattern string, path string) (interface{}, error) {
-	originalPattern := valuePattern
-	vars := regexVariables.FindAllString(valuePattern, -1)
-	for len(vars) > 0 {
-		for _, v := range vars {
-			variable := strings.ReplaceAll(v, "{{", "")
-			variable = strings.ReplaceAll(variable, "}}", "")
-			variable = strings.TrimSpace(variable)
-
-			var substitutedVar interface{}
-			if operation, err := ctx.Query("request.operation"); err != nil {
-				return nil, fmt.Errorf("failed to resolve %v at path %s", variable, path)
-			} else {
-				if operation == "DELETE" {
-					variable = strings.ReplaceAll(variable, "request.object", "request.oldObject")
-				}
-			}
+// NotResolvedReferenceErr is returned when it is impossible to resolve the variable
+type NotResolvedReferenceErr struct {
+	reference string
+	path      string
+}
+
+func (n NotResolvedReferenceErr) Error() string {
+	return fmt.Sprintf("reference %s not resolved at path %s", n.reference, n.path)
+}
 
-			substitutedVar, err := ctx.Query(variable)
+func substituteReferencesIfAny(log logr.Logger) jsonUtils.Action {
+	return jsonUtils.OnlyForLeafs(func(data *jsonUtils.ActionData) (interface{}, error) {
+		value, ok := data.Element.(string)
+		if !ok {
+			return data.Element, nil
+		}
+
+		for _, v := range regexReferences.FindAllString(value, -1) {
+			resolvedReference, err := resolveReference(log, data.Document, v, data.Path)
 			if err != nil {
 				switch err.(type) {
 				case context.InvalidVariableErr:
 					return nil, err
 				default:
-					return nil, fmt.Errorf("failed to resolve %v at path %s", variable, path)
+					return nil, fmt.Errorf("failed to resolve %v at path %s", v, data.Path)
 				}
 			}
 
-			log.V(3).Info("variable substituted", "variable", v, "value", substitutedVar, "path", path)
+			if resolvedReference == nil {
+				return data.Element, fmt.Errorf("failed to resolve %v at path %s", v, data.Path)
+			}
+
+			log.V(3).Info("reference resolved", "reference", v, "value", resolvedReference, "path", data.Path)
 
-			if val, ok := substitutedVar.(string); ok {
-				valuePattern = strings.Replace(valuePattern, v, val, -1)
+			if val, ok := resolvedReference.(string); ok {
+				value = strings.Replace(value, v, val, -1)
 				continue
 			}
 
-			if substitutedVar != nil {
-				if originalPattern == v {
-					return substitutedVar, nil
+			return data.Element, NotResolvedReferenceErr{
+				reference: v,
+				path:      data.Path,
+			}
+		}
+
+		return value, nil
+	})
+}
+
+func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface) jsonUtils.Action {
+	return jsonUtils.OnlyForLeafs(func(data *jsonUtils.ActionData) (interface{}, error) {
+		value, ok := data.Element.(string)
+		if !ok {
+			return data.Element, nil
+		}
+
+		originalPattern := value
+		vars := regexVariables.FindAllString(value, -1)
+		for len(vars) > 0 {
+			for _, v := range vars {
+				variable := strings.ReplaceAll(v, "{{", "")
+				variable = strings.ReplaceAll(variable, "}}", "")
+				variable = strings.TrimSpace(variable)
+
+				operation, err := ctx.Query("request.operation")
+				if err != nil {
+					return nil, fmt.Errorf("failed to check request.operation")
+				}
+
+				if operation == "DELETE" {
+					variable = strings.ReplaceAll(variable, "request.object", "request.oldObject")
+				}
+
+				substitutedVar, err := ctx.Query(variable)
+				if err != nil {
+					switch err.(type) {
+					case context.InvalidVariableErr:
+						return nil, err
+					default:
+						return nil, fmt.Errorf("failed to resolve %v at path %s", variable, data.Path)
+					}
+				}
+
+				log.V(3).Info("variable substituted", "variable", v, "value", substitutedVar, "path", data.Path)
+
+				if val, ok := substitutedVar.(string); ok {
+					value = strings.Replace(value, v, val, -1)
+					continue
 				}
 
-				return nil, fmt.Errorf("failed to resolve %v at path %s", variable, path)
+				if substitutedVar != nil {
+					if originalPattern == v {
+						return substitutedVar, nil
+					}
+
+					return nil, fmt.Errorf("failed to resolve %v at path %s", variable, data.Path)
+				}
+
+				return nil, NotFoundVariableErr{
+					variable: variable,
+					path:     data.Path,
+				}
 			}
 
-			return nil, NotFoundVariableErr{
-				variable: variable,
-				path:     path,
+			// check for nested variables in strings
+			vars = regexVariables.FindAllString(value, -1)
+		}
+
+		return value, nil
+	})
+}
+
+func resolveReference(log logr.Logger, fullDocument interface{}, reference, absolutePath string) (interface{}, error) {
+	var foundValue interface{}
+
+	path := strings.Trim(reference, "$()")
+
+	operation := operator.GetOperatorFromStringPattern(path)
+	path = path[len(operation):]
+
+	if len(path) == 0 {
+		return nil, errors.New("Expected path. Found empty reference")
+	}
+
+	path = formAbsolutePath(path, absolutePath)
+
+	valFromReference, err := getValueFromReference(fullDocument, path)
+	if err != nil {
+		return err, nil
+	}
+
+	if operation == operator.Equal { //if operator does not exist return raw value
+		return valFromReference, nil
+	}
+
+	foundValue, err = valFromReferenceToString(valFromReference, string(operation))
+	if err != nil {
+		return "", err
+	}
+
+	return string(operation) + foundValue.(string), nil
+}
+
+//Parse value to string
+func valFromReferenceToString(value interface{}, operator string) (string, error) {
+
+	switch typed := value.(type) {
+	case string:
+		return typed, nil
+	case int, int64:
+		return fmt.Sprintf("%d", value), nil
+	case float64:
+		return fmt.Sprintf("%f", value), nil
+	default:
+		return "", fmt.Errorf("Incorrect expression. Operator %s does not match with value: %v", operator, value)
+	}
+}
+
+func FindAndShiftReferences(log logr.Logger, value, shift, pivot string) string {
+	for _, reference := range regexReferences.FindAllString(value, -1) {
+
+		index := strings.Index(reference, pivot)
+		if index == -1 {
+			log.Error(fmt.Errorf(`Failed to shit reference. Pivot value "%s" was not found`, pivot), "pivot search failed")
+		}
+
+		// try to get rule index from the reference
+		if pivot == "anyPattern" {
+			ruleIndex := strings.Split(reference[index+len(pivot)+1:], "/")[0]
+			pivot = pivot + "/" + ruleIndex
+		}
+
+		shiftedReference := strings.Replace(reference, pivot, pivot+"/"+shift, 1)
+		value = strings.Replace(value, reference, shiftedReference, -1)
+	}
+
+	return value
+}
+
+func formAbsolutePath(referencePath, absolutePath string) string {
+	if path.IsAbs(referencePath) {
+		return referencePath
+	}
+
+	return path.Join(absolutePath, referencePath)
+}
+
+func getValueFromReference(fullDocument interface{}, path string) (interface{}, error) {
+	var element interface{}
+
+	if _, err := jsonUtils.NewTraversal(fullDocument, jsonUtils.OnlyForLeafs(
+		func(data *jsonUtils.ActionData) (interface{}, error) {
+			if common.RemoveAnchorsFromPath(data.Path) == path {
+				element = data.Element
 			}
+
+			return data.Element, nil
+		})).TraverseJSON(); err != nil {
+		return nil, err
+	}
+
+	return element, nil
+}
+
+func SubstituteAllInRule(log logr.Logger, ctx context.EvalInterface, typedRule kyverno.Rule) (_ kyverno.Rule, err error) {
+	var rule interface{}
+
+	rule, err = RuleToUntyped(typedRule)
+	if err != nil {
+		return typedRule, err
+	}
+
+	rule, err = substituteReferences(log, rule)
+	if err != nil {
+		return typedRule, err
+	}
+
+	rule, err = substituteVars(log, ctx, rule)
+	if err != nil {
+		return typedRule, err
+	}
+
+	return UntypedToRule(rule)
+}
+
+func RuleToUntyped(rule kyverno.Rule) (interface{}, error) {
+	jsonRule, err := json.Marshal(rule)
+	if err != nil {
+		return nil, err
+	}
+
+	var untyped interface{}
+	err = json.Unmarshal(jsonRule, &untyped)
+	if err != nil {
+		return nil, err
+	}
+
+	return untyped, nil
+}
+
+func UntypedToRule(untyped interface{}) (kyverno.Rule, error) {
+	jsonRule, err := json.Marshal(untyped)
+	if err != nil {
+		return kyverno.Rule{}, err
+	}
+
+	var rule kyverno.Rule
+	err = json.Unmarshal(jsonRule, &rule)
+	if err != nil {
+		return kyverno.Rule{}, err
+	}
+
+	return rule, nil
+}
+
+func replaceSubstituteVariables(document interface{}) interface{} {
+	rawDocument, err := json.Marshal(document)
+	if err != nil {
+		return document
+	}
+
+	regex := regexp.MustCompile(`\{\{([^{}]*)\}\}`)
+	for {
+		if len(regex.FindAllStringSubmatch(string(rawDocument), -1)) > 0 {
+			rawDocument = regex.ReplaceAll(rawDocument, []byte(`placeholderValue`))
+		} else {
+			break
 		}
+	}
 
-		// check for nested variables in strings
-		vars = regexVariables.FindAllString(valuePattern, -1)
+	var output interface{}
+	err = json.Unmarshal(rawDocument, &output)
+	if err != nil {
+		return document
 	}
 
-	return valuePattern, nil
+	return output
 }
diff --git a/pkg/generate/generate.go b/pkg/generate/generate.go
index c54f36c9a..9c9cb7a42 100644
--- a/pkg/generate/generate.go
+++ b/pkg/generate/generate.go
@@ -320,7 +320,7 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
 	// format : {{<variable_name}}
 	// - if there is variables that are not defined the context -> results in error and rule is not applied
 	// - valid variables are replaced with the values
-	object, err := variables.SubstituteVars(log, ctx, genUnst.Object)
+	object, err := variables.SubstituteAll(log, ctx, genUnst.Object)
 	if err != nil {
 		return noGenResource, err
 	}
diff --git a/pkg/kyverno/apply/command.go b/pkg/kyverno/apply/command.go
index 772423bb2..ecd8033a7 100644
--- a/pkg/kyverno/apply/command.go
+++ b/pkg/kyverno/apply/command.go
@@ -107,7 +107,7 @@ More info: https://kyverno.io/docs/kyverno-cli/
 func Command() *cobra.Command {
 	var cmd *cobra.Command
 	var resourcePaths []string
-	var cluster, policyReport bool
+	var cluster, policyReport, stdin bool
 	var mutateLogPath, variablesString, valuesFile, namespace string
 
 	cmd = &cobra.Command{
@@ -124,12 +124,12 @@ func Command() *cobra.Command {
 				}
 			}()
 
-			validateEngineResponses, rc, resources, skippedPolicies, err := applyCommandHelper(resourcePaths, cluster, policyReport, mutateLogPath, variablesString, valuesFile, namespace, policyPaths)
+			validateEngineResponses, rc, resources, skippedPolicies, err := applyCommandHelper(resourcePaths, cluster, policyReport, mutateLogPath, variablesString, valuesFile, namespace, policyPaths, stdin)
 			if err != nil {
 				return err
 			}
 
-			printReportOrViolation(policyReport, validateEngineResponses, rc, resourcePaths, len(resources), skippedPolicies)
+			printReportOrViolation(policyReport, validateEngineResponses, rc, resourcePaths, len(resources), skippedPolicies, stdin)
 			return nil
 		},
 	}
@@ -141,11 +141,12 @@ func Command() *cobra.Command {
 	cmd.Flags().StringVarP(&valuesFile, "values-file", "f", "", "File containing values for policy variables")
 	cmd.Flags().BoolVarP(&policyReport, "policy-report", "", false, "Generates policy report when passed (default policyviolation r")
 	cmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Optional Policy parameter passed with cluster flag")
+	cmd.Flags().BoolVarP(&stdin, "stdin", "i", false, "Optional mutate policy parameter to pipe directly through to kubectl")
 	return cmd
 }
 
 func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, mutateLogPath string,
-	variablesString string, valuesFile string, namespace string, policyPaths []string) (validateEngineResponses []*response.EngineResponse, rc *resultCounts, resources []*unstructured.Unstructured, skippedPolicies []SkippedPolicy, err error) {
+	variablesString string, valuesFile string, namespace string, policyPaths []string, stdin bool) (validateEngineResponses []*response.EngineResponse, rc *resultCounts, resources []*unstructured.Unstructured, skippedPolicies []SkippedPolicy, err error) {
 
 	kubernetesConfig := genericclioptions.NewConfigFlags(true)
 	fs := memfs.New()
@@ -241,7 +242,9 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
 	}
 
 	if len(mutatedPolicies) > 0 && len(resources) > 0 {
-		fmt.Printf("\napplying %s to %s... \n", msgPolicies, msgResources)
+		if !stdin {
+			fmt.Printf("\napplying %s to %s... \n", msgPolicies, msgResources)
+		}
 	}
 
 	rc = &resultCounts{}
@@ -287,7 +290,7 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
 				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)
 			}
 
-			ers, validateErs, responseError, rcErs, err := common.ApplyPolicyOnResource(policy, resource, mutateLogPath, mutateLogPathIsDir, thisPolicyResourceValues, policyReport, namespaceSelectorMap)
+			ers, validateErs, responseError, rcErs, err := common.ApplyPolicyOnResource(policy, resource, mutateLogPath, mutateLogPathIsDir, thisPolicyResourceValues, policyReport, namespaceSelectorMap, stdin)
 			if err != nil {
 				return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
 			}
@@ -330,7 +333,7 @@ func checkMutateLogPath(mutateLogPath string) (mutateLogPathIsDir bool, err erro
 }
 
 // printReportOrViolation - printing policy report/violations
-func printReportOrViolation(policyReport bool, validateEngineResponses []*response.EngineResponse, rc *resultCounts, resourcePaths []string, resourcesLen int, skippedPolicies []SkippedPolicy) {
+func printReportOrViolation(policyReport bool, validateEngineResponses []*response.EngineResponse, rc *resultCounts, resourcePaths []string, resourcesLen int, skippedPolicies []SkippedPolicy, stdin bool) {
 	if policyReport {
 		os.Setenv("POLICY-TYPE", pkgCommon.PolicyReport)
 		resps := buildPolicyReports(validateEngineResponses, skippedPolicies)
@@ -347,9 +350,10 @@ func printReportOrViolation(policyReport bool, validateEngineResponses []*respon
 		if rcCount < len(resourcePaths) {
 			rc.skip += len(resourcePaths) - rcCount
 		}
-
-		fmt.Printf("\npass: %d, fail: %d, warn: %d, error: %d, skip: %d \n",
-			rc.pass, rc.fail, rc.warn, rc.error, rc.skip)
+		if !stdin {
+			fmt.Printf("\npass: %d, fail: %d, warn: %d, error: %d, skip: %d \n",
+				rc.pass, rc.fail, rc.warn, rc.error, rc.skip)
+		}
 
 		if rc.fail > 0 || rc.error > 0 {
 			os.Exit(1)
diff --git a/pkg/kyverno/common/common.go b/pkg/kyverno/common/common.go
index c36ebd0c4..cd7b6f5fe 100644
--- a/pkg/kyverno/common/common.go
+++ b/pkg/kyverno/common/common.go
@@ -380,7 +380,7 @@ func MutatePolices(policies []*v1.ClusterPolicy) ([]*v1.ClusterPolicy, error) {
 
 // ApplyPolicyOnResource - function to apply policy on resource
 func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured,
-	mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, policyReport bool, namespaceSelectorMap map[string]map[string]string) ([]*response.EngineResponse, *response.EngineResponse, bool, bool, error) {
+	mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, policyReport bool, namespaceSelectorMap map[string]map[string]string, stdin bool) ([]*response.EngineResponse, *response.EngineResponse, bool, bool, error) {
 
 	responseError := false
 	rcError := false
@@ -455,9 +455,11 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
 			}
 
 			if mutateLogPath == "" {
-				mutatedResource := string(yamlEncodedResource)
+				mutatedResource := string(yamlEncodedResource) + string("\n---")
 				if len(strings.TrimSpace(mutatedResource)) > 0 {
-					fmt.Printf("\nmutate policy %s applied to %s:", policy.Name, resPath)
+					if !stdin {
+						fmt.Printf("\nmutate policy %s applied to %s:", policy.Name, resPath)
+					}
 					fmt.Printf("\n" + mutatedResource)
 					fmt.Printf("\n")
 				}
diff --git a/pkg/kyverno/common/fetch.go b/pkg/kyverno/common/fetch.go
index 8f386132e..5e650bbfb 100644
--- a/pkg/kyverno/common/fetch.go
+++ b/pkg/kyverno/common/fetch.go
@@ -232,9 +232,12 @@ func getFileBytes(path string) ([]byte, error) {
 
 func convertResourceToUnstructured(resourceYaml []byte) (*unstructured.Unstructured, error) {
 	decode := scheme.Codecs.UniversalDeserializer().Decode
-	_, metaData, err := decode(resourceYaml, nil, nil)
-	if err != nil {
-		return nil, err
+	_, metaData, decodeErr := decode(resourceYaml, nil, nil)
+
+	if decodeErr != nil {
+		if !strings.Contains(decodeErr.Error(), "no kind") {
+			return nil, decodeErr
+		}
 	}
 
 	resourceJSON, err := yaml.YAMLToJSON(resourceYaml)
@@ -247,7 +250,9 @@ func convertResourceToUnstructured(resourceYaml []byte) (*unstructured.Unstructu
 		return nil, err
 	}
 
-	resource.SetGroupVersionKind(*metaData)
+	if decodeErr == nil {
+		resource.SetGroupVersionKind(*metaData)
+	}
 
 	if resource.GetNamespace() == "" {
 		resource.SetNamespace("default")
diff --git a/pkg/policy/background.go b/pkg/policy/background.go
index 33115ca5d..ee46f4fea 100644
--- a/pkg/policy/background.go
+++ b/pkg/policy/background.go
@@ -1,8 +1,8 @@
 package policy
 
 import (
+	"encoding/json"
 	"fmt"
-	"reflect"
 
 	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"github.com/kyverno/kyverno/pkg/engine/context"
@@ -27,29 +27,17 @@ func ContainsVariablesOtherThanObject(policy kyverno.ClusterPolicy) error {
 		filterVars := []string{"request.object", "request.namespace"}
 		ctx := context.NewContext(filterVars...)
 
-		for contextIdx, contextEntry := range rule.Context {
+		if rule, err = variables.SubstituteAllInRule(log.Log, ctx, rule); !checkNotFoundErr(err) {
+			return fmt.Errorf("variable substitution failed for rule %s: %s", rule.Name, err.Error())
+		}
+
+		for _, contextEntry := range rule.Context {
 			if contextEntry.APICall != nil {
 				ctx.AddBuiltInVars(contextEntry.Name)
-
-				if _, err := variables.SubstituteVars(log.Log, ctx, contextEntry.APICall.URLPath); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable used at spec/rules[%d]/context[%d]/apiCall/urlPath: %s", idx, contextIdx, err.Error())
-				}
-
-				if _, err := variables.SubstituteVars(log.Log, ctx, contextEntry.APICall.JMESPath); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable used at spec/rules[%d]/context[%d]/apiCall/jmesPath: %s", idx, contextIdx, err.Error())
-				}
 			}
 
 			if contextEntry.ConfigMap != nil {
 				ctx.AddBuiltInVars(contextEntry.Name)
-
-				if _, err = variables.SubstituteVars(log.Log, ctx, contextEntry.ConfigMap.Name); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable used at spec/rules[%d]/context[%d]/configMap/name: %s", idx, contextIdx, err.Error())
-				}
-
-				if _, err = variables.SubstituteVars(log.Log, ctx, contextEntry.ConfigMap.Namespace); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable used at spec/rules[%d]/context[%d]/configMap/namespace: %s", idx, contextIdx, err.Error())
-				}
 			}
 		}
 
@@ -59,64 +47,11 @@ func ContainsVariablesOtherThanObject(policy kyverno.ClusterPolicy) error {
 			}
 		}
 
-		if rule.Mutation.Overlay != nil {
-			if rule.Mutation.Overlay, err = variables.SubstituteVars(log.Log, ctx, rule.Mutation.Overlay); !checkNotFoundErr(err) {
-				return fmt.Errorf("invalid variable used at spec/rules[%d]/mutate/overlay: %s", idx, err.Error())
-			}
-		}
-
-		if rule.Mutation.PatchStrategicMerge != nil {
-			if rule.Mutation.Overlay, err = variables.SubstituteVars(log.Log, ctx, rule.Mutation.PatchStrategicMerge); !checkNotFoundErr(err) {
-				return fmt.Errorf("invalid variable used at spec/rules[%d]/mutate/patchStrategicMerge: %s", idx, err.Error())
-			}
-		}
-
-		if rule.Validation.Pattern != nil {
-			if rule.Validation.Pattern, err = variables.SubstituteVars(log.Log, ctx, rule.Validation.Pattern); !checkNotFoundErr(err) {
-				return fmt.Errorf("invalid variable used at spec/rules[%d]/validate/pattern: %s", idx, err.Error())
-			}
-		}
-
-		anyPattern, err := rule.Validation.DeserializeAnyPattern()
-		if err != nil {
-			return fmt.Errorf("failed to deserialize anyPattern, expect array: %s", err.Error())
-		}
-
-		for idx2, pattern := range anyPattern {
-			if anyPattern[idx2], err = variables.SubstituteVars(log.Log, ctx, pattern); !checkNotFoundErr(err) {
-				return fmt.Errorf("invalid variable used at spec/rules[%d]/validate/anyPattern[%d]: %s", idx, idx2, err.Error())
-			}
-		}
-
-		if _, err = variables.SubstituteVars(log.Log, ctx, rule.Validation.Message); !checkNotFoundErr(err) {
-			return fmt.Errorf("invalid variable used at spec/rules[%d]/validate/message: %s", idx, err.Error())
-		}
-
 		if rule.Validation.Deny != nil {
 			if err = validateDenyConditions(idx, ctx, rule.Validation.Deny.AnyAllConditions); err != nil {
 				return err
 			}
 		}
-
-		if _, err = variables.SubstituteVars(log.Log, ctx, rule.Generation.Name); !checkNotFoundErr(err) {
-			return fmt.Errorf("invalid variable used at spec/rules[%d]/generate/name: %v", idx, err)
-		}
-
-		if _, err = variables.SubstituteVars(log.Log, ctx, rule.Generation.Namespace); !checkNotFoundErr(err) {
-			return fmt.Errorf("invalid variable used at spec/rules[%d]/generate/name: %v", idx, err)
-		}
-
-		if _, err = variables.SubstituteVars(log.Log, ctx, rule.Generation.Data); !checkNotFoundErr(err) {
-			return fmt.Errorf("invalid variable used at spec/rules[%d]/generate/data: %v", idx, err)
-		}
-
-		if _, err = variables.SubstituteVars(log.Log, ctx, rule.Generation.Clone.Name); !checkNotFoundErr(err) {
-			return fmt.Errorf("invalid variable used at spec/rules[%d]/generate/clone/name: %v", idx, err)
-		}
-
-		if _, err = variables.SubstituteVars(log.Log, ctx, rule.Generation.Clone.Namespace); !checkNotFoundErr(err) {
-			return fmt.Errorf("invalid variable used at spec/rules[%d]/generate/clone/namespace: %v", idx, err)
-		}
 	}
 
 	return nil
@@ -124,96 +59,31 @@ func ContainsVariablesOtherThanObject(policy kyverno.ClusterPolicy) error {
 
 func validatePreConditions(idx int, ctx context.EvalInterface, anyAllConditions apiextensions.JSON) error {
 	var err error
-	// conditions are currently in the form of []interface{}
-	kyvernoAnyAllConditions, err := utils.ApiextensionsJsonToKyvernoConditions(anyAllConditions)
+
+	anyAllConditions, err = substituteVarsInJSON(ctx, anyAllConditions)
 	if err != nil {
 		return err
 	}
-	switch typedPreConditions := kyvernoAnyAllConditions.(type) {
-	case kyverno.AnyAllConditions:
-		if !reflect.DeepEqual(typedPreConditions, kyverno.AnyAllConditions{}) && typedPreConditions.AnyConditions != nil {
-			for condIdx, condition := range typedPreConditions.AnyConditions {
-				if condition.Key, err = variables.SubstituteVars(log.Log, ctx, condition.Key); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable %s used at spec/rules[%d]/any/condition[%d]/key", condition.Key, idx, condIdx)
-				}
-
-				if condition.Value, err = variables.SubstituteVars(log.Log, ctx, condition.Value); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid %s variable used at spec/rules[%d]/any/condition[%d]/value", condition.Value, idx, condIdx)
-				}
-			}
-		}
-		if !reflect.DeepEqual(typedPreConditions, kyverno.AnyAllConditions{}) && typedPreConditions.AllConditions != nil {
-			for condIdx, condition := range typedPreConditions.AllConditions {
-				if condition.Key, err = variables.SubstituteVars(log.Log, ctx, condition.Key); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable %s used at spec/rules[%d]/all/condition[%d]/key", condition.Key, idx, condIdx)
-				}
-
-				if condition.Value, err = variables.SubstituteVars(log.Log, ctx, condition.Value); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid %s variable used at spec/rules[%d]/all/condition[%d]/value", condition.Value, idx, condIdx)
-				}
-			}
-		}
-	case []kyverno.Condition: //backwards compatibility
-		for condIdx, condition := range typedPreConditions {
-			if condition.Key, err = variables.SubstituteVars(log.Log, ctx, condition.Key); !checkNotFoundErr(err) {
-				return fmt.Errorf("invalid variable %s used at spec/rules[%d]/condition[%d]/key", condition.Key, idx, condIdx)
-			}
 
-			if condition.Value, err = variables.SubstituteVars(log.Log, ctx, condition.Value); !checkNotFoundErr(err) {
-				return fmt.Errorf("invalid %s variable used at spec/rules[%d]/condition[%d]/value", condition.Value, idx, condIdx)
-			}
-		}
+	_, err = utils.ApiextensionsJsonToKyvernoConditions(anyAllConditions)
+	if err != nil {
+		return err
 	}
 
 	return nil
 }
 
 func validateDenyConditions(idx int, ctx context.EvalInterface, denyConditions apiextensions.JSON) error {
-	// conditions are currently in the form of []interface{}
-	kyvernoDenyConditions, err := utils.ApiextensionsJsonToKyvernoConditions(denyConditions)
+	var err error
+
+	denyConditions, err = substituteVarsInJSON(ctx, denyConditions)
 	if err != nil {
 		return err
 	}
-	switch typedDenyConditions := kyvernoDenyConditions.(type) {
-	case kyverno.AnyAllConditions:
-		// validating validate.deny.any.conditions
-		if !reflect.DeepEqual(typedDenyConditions, kyverno.AnyAllConditions{}) && typedDenyConditions.AnyConditions != nil {
-			for i := range typedDenyConditions.AnyConditions {
-				if _, err := variables.SubstituteVars(log.Log, ctx, typedDenyConditions.AnyConditions[i].Key); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable %s used at spec/rules[%d]/validate/deny/any/conditions[%d]/key: %v",
-						typedDenyConditions.AnyConditions[i].Key, idx, i, err)
-				}
-				if _, err := variables.SubstituteVars(log.Log, ctx, typedDenyConditions.AnyConditions[i].Value); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable %s used at spec/rules[%d]/validate/deny/any/conditions[%d]/value: %v",
-						typedDenyConditions.AnyConditions[i].Value, idx, i, err)
-				}
-			}
-		}
-		// validating validate.deny.all.conditions
-		if !reflect.DeepEqual(typedDenyConditions, kyverno.AnyAllConditions{}) && typedDenyConditions.AllConditions != nil {
-			for i := range typedDenyConditions.AllConditions {
-				if _, err := variables.SubstituteVars(log.Log, ctx, typedDenyConditions.AllConditions[i].Key); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable %s used at spec/rules[%d]/validate/deny/all/conditions[%d]/key: %v",
-						typedDenyConditions.AllConditions[i].Key, idx, i, err)
-				}
-				if _, err := variables.SubstituteVars(log.Log, ctx, typedDenyConditions.AllConditions[i].Value); !checkNotFoundErr(err) {
-					return fmt.Errorf("invalid variable %s used at spec/rules[%d]/validate/deny/all/conditions[%d]/value: %v",
-						typedDenyConditions.AllConditions[i].Value, idx, i, err)
-				}
-			}
-		}
-	case []kyverno.Condition: // backwards compatibility
-		// validating validate.deny.conditions
-		for i := range typedDenyConditions {
-			if _, err := variables.SubstituteVars(log.Log, ctx, typedDenyConditions[i].Key); !checkNotFoundErr(err) {
-				return fmt.Errorf("invalid variable %s used at spec/rules[%d]/validate/deny/conditions[%d]/key: %v",
-					typedDenyConditions[i].Key, idx, i, err)
-			}
-			if _, err := variables.SubstituteVars(log.Log, ctx, typedDenyConditions[i].Value); !checkNotFoundErr(err) {
-				return fmt.Errorf("invalid variable %s used at spec/rules[%d]/validate/deny/conditions[%d]/value: %v",
-					typedDenyConditions[i].Value, idx, i, err)
-			}
-		}
+
+	_, err = utils.ApiextensionsJsonToKyvernoConditions(denyConditions)
+	if err != nil {
+		return err
 	}
 
 	return nil
@@ -247,3 +117,33 @@ func userInfoDefined(ui kyverno.UserInfo) string {
 	}
 	return ""
 }
+
+func substituteVarsInJSON(ctx context.EvalInterface, document apiextensions.JSON) (apiextensions.JSON, error) {
+	jsonByte, err := json.Marshal(document)
+	if err != nil {
+		return nil, err
+	}
+
+	var jsonInterface interface{}
+	err = json.Unmarshal(jsonByte, &jsonInterface)
+	if err != nil {
+		return nil, err
+	}
+
+	jsonInterface, err = variables.SubstituteAll(log.Log, ctx, jsonInterface)
+	if err != nil {
+		return nil, err
+	}
+
+	jsonByte, err = json.Marshal(jsonInterface)
+	if err != nil {
+		return nil, err
+	}
+
+	err = json.Unmarshal(jsonByte, &document)
+	if err != nil {
+		return nil, err
+	}
+
+	return document, nil
+}
diff --git a/pkg/policymutation/cronjob.go b/pkg/policymutation/cronjob.go
index da3f79d8b..7647a5d76 100644
--- a/pkg/policymutation/cronjob.go
+++ b/pkg/policymutation/cronjob.go
@@ -8,6 +8,7 @@ import (
 	"github.com/go-logr/logr"
 	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"github.com/kyverno/kyverno/pkg/engine"
+	"github.com/kyverno/kyverno/pkg/engine/variables"
 )
 
 func generateCronJobRule(rule kyverno.Rule, controllers string, log logr.Logger) kyvernoRule {
@@ -65,7 +66,7 @@ func generateCronJobRule(rule kyverno.Rule, controllers string, log logr.Logger)
 
 	if (jobRule.Validation != nil) && (jobRule.Validation.Pattern != nil) {
 		newValidate := &kyverno.Validation{
-			Message: rule.Validation.Message,
+			Message: variables.FindAndShiftReferences(log, rule.Validation.Message, "spec/jobTemplate/spec/template", "pattern"),
 			Pattern: map[string]interface{}{
 				"spec": map[string]interface{}{
 					"jobTemplate": jobRule.Validation.Pattern,
@@ -94,7 +95,7 @@ func generateCronJobRule(rule kyverno.Rule, controllers string, log logr.Logger)
 		}
 
 		cronJobRule.Validation = &kyverno.Validation{
-			Message:    rule.Validation.Message,
+			Message:    variables.FindAndShiftReferences(log, rule.Validation.Message, "spec/jobTemplate/spec/template", "anyPattern"),
 			AnyPattern: patterns,
 		}
 		return *cronJobRule
diff --git a/pkg/policymutation/policymutation.go b/pkg/policymutation/policymutation.go
index fa0d5420e..118ae92c3 100644
--- a/pkg/policymutation/policymutation.go
+++ b/pkg/policymutation/policymutation.go
@@ -13,6 +13,7 @@ import (
 	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
 	"github.com/kyverno/kyverno/pkg/common"
 	"github.com/kyverno/kyverno/pkg/engine"
+	"github.com/kyverno/kyverno/pkg/engine/variables"
 	"github.com/kyverno/kyverno/pkg/utils"
 	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
 )
@@ -272,6 +273,18 @@ func createRuleMap(rules []kyverno.Rule) map[string]kyvernoRule {
 	}
 	return ruleMap
 }
+func updateGenRuleByte(pbyte []byte, kind string, genRule kyvernoRule) (obj []byte) {
+	if err := json.Unmarshal(pbyte, &genRule); err != nil {
+		return obj
+	}
+	if kind == "Pod" {
+		return []byte(strings.Replace(string(pbyte), "request.object.spec", "request.object.spec.template.spec", -1))
+	}
+	if kind == "Cronjob" {
+		return []byte(strings.Replace(string(pbyte), "request.object.spec", "request.object.spec.jobTemplate.spec.template.spec", -1))
+	}
+	return obj
+}
 
 // generateRulePatches generates rule for podControllers based on scenario A and C
 func generateRulePatches(policy kyverno.ClusterPolicy, controllers string, log logr.Logger) (rulePatches [][]byte, errs []error) {
@@ -327,6 +340,7 @@ func generateRulePatches(policy kyverno.ClusterPolicy, controllers string, log l
 		genRule := generateRuleForControllers(rule, stripCronJob(controllers), log)
 		if !reflect.DeepEqual(genRule, kyvernoRule{}) {
 			pbytes := convertToPatches(genRule, patchPostion)
+			pbytes = updateGenRuleByte(pbytes, "Pod", genRule)
 			if pbytes != nil {
 				rulePatches = append(rulePatches, pbytes)
 			}
@@ -338,6 +352,7 @@ func generateRulePatches(policy kyverno.ClusterPolicy, controllers string, log l
 		genRule = generateCronJobRule(rule, controllers, log)
 		if !reflect.DeepEqual(genRule, kyvernoRule{}) {
 			pbytes := convertToPatches(genRule, patchPostion)
+			pbytes = updateGenRuleByte(pbytes, "Cronjob", genRule)
 			if pbytes != nil {
 				rulePatches = append(rulePatches, pbytes)
 			}
@@ -480,7 +495,7 @@ func generateRuleForControllers(rule kyverno.Rule, controllers string, log logr.
 
 	if rule.Validation.Pattern != nil {
 		newValidate := &kyverno.Validation{
-			Message: rule.Validation.Message,
+			Message: variables.FindAndShiftReferences(log, rule.Validation.Message, "spec/template", "pattern"),
 			Pattern: map[string]interface{}{
 				"spec": map[string]interface{}{
 					"template": rule.Validation.Pattern,
@@ -509,7 +524,7 @@ func generateRuleForControllers(rule kyverno.Rule, controllers string, log logr.
 		}
 
 		controllerRule.Validation = &kyverno.Validation{
-			Message:    rule.Validation.Message,
+			Message:    variables.FindAndShiftReferences(log, rule.Validation.Message, "spec/template", "anyPattern"),
 			AnyPattern: patterns,
 		}
 		return *controllerRule


Test patch:
diff --git a/pkg/engine/anchor/common/common_test.go b/pkg/engine/anchor/common/common_test.go
index 24bfc7c95..96b2e7d78 100644
--- a/pkg/engine/anchor/common/common_test.go
+++ b/pkg/engine/anchor/common/common_test.go
@@ -56,3 +56,13 @@ func TestIsExistenceAnchor_OnlyHat(t *testing.T) {
 func TestIsExistenceAnchor_ConditionAnchor(t *testing.T) {
 	assert.Assert(t, !IsExistenceAnchor("(abc)"))
 }
+
+func TestRemoveAnchorsFromPath_WorksWithAbsolutePath(t *testing.T) {
+	newPath := RemoveAnchorsFromPath("/path/(to)/X(anchors)")
+	assert.Equal(t, newPath, "/path/to/anchors")
+}
+
+func TestRemoveAnchorsFromPath_WorksWithRelativePath(t *testing.T) {
+	newPath := RemoveAnchorsFromPath("path/(to)/X(anchors)")
+	assert.Equal(t, newPath, "path/to/anchors")
+}
diff --git a/pkg/engine/common/utils_test.go b/pkg/engine/common/utils_test.go
new file mode 100644
index 000000000..152cfe41d
--- /dev/null
+++ b/pkg/engine/common/utils_test.go
@@ -0,0 +1,37 @@
+package common
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+)
+
+func Test_OriginalMapMustNotBeChanged(t *testing.T) {
+	// no variables
+	originalMap := map[string]interface{}{
+		"rsc": 3711,
+		"r":   2138,
+		"gri": 1908,
+		"adg": 912,
+	}
+
+	mapCopy := CopyMap(originalMap)
+	mapCopy["r"] = 1
+
+	assert.Equal(t, originalMap["r"], 2138)
+}
+
+func Test_OriginalSliceMustNotBeChanged(t *testing.T) {
+	// no variables
+	originalSlice := []interface{}{
+		3711,
+		2138,
+		1908,
+		912,
+	}
+
+	sliceCopy := CopySlice(originalSlice)
+	sliceCopy[0] = 1
+
+	assert.Equal(t, originalSlice[0], 3711)
+}
diff --git a/pkg/engine/forceMutate_test.go b/pkg/engine/forceMutate_test.go
new file mode 100644
index 000000000..a948d6129
--- /dev/null
+++ b/pkg/engine/forceMutate_test.go
@@ -0,0 +1,150 @@
+package engine
+
+import (
+	"encoding/json"
+	"testing"
+
+	kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
+	"github.com/kyverno/kyverno/pkg/engine/context"
+	"github.com/kyverno/kyverno/pkg/engine/utils"
+	"gotest.tools/assert"
+)
+
+var rawPolicy = []byte(`
+{
+	"apiVersion": "kyverno.io/v1",
+	"kind": "ClusterPolicy",
+	"metadata": {
+		"name": "add-label"
+	},
+	"spec": {
+		"rules": [
+			{
+				"name": "add-name-label",
+				"match": {
+					"resources": {
+						"kinds": [
+							"Pod"
+						]
+					}
+				},
+				"mutate": {
+					"overlay": {
+						"metadata": {
+							"labels": {
+								"appname": "{{request.object.metadata.name}}"
+							}
+						}
+					}
+				}
+			}
+		]
+	}
+}
+`)
+
+var rawResource = []byte(`
+{
+	"apiVersion": "v1",
+	"kind": "Pod",
+	"metadata": {
+		"name": "check-root-user"
+	},
+	"spec": {
+		"containers": [
+			{
+				"name": "check-root-user",
+				"image": "nginxinc/nginx-unprivileged",
+				"securityContext": {
+					"runAsNonRoot": true
+				}
+			}
+		]
+	}
+}
+`)
+
+func Test_ForceMutateSubstituteVars(t *testing.T) {
+	expectedRawResource := []byte(`
+	{
+		"apiVersion": "v1",
+		"kind": "Pod",
+		"metadata": {
+			"name": "check-root-user",
+			"labels": {
+				"appname": "check-root-user"
+			}
+		},
+		"spec": {
+			"containers": [
+				{
+					"name": "check-root-user",
+					"image": "nginxinc/nginx-unprivileged",
+					"securityContext": {
+						"runAsNonRoot": true
+					}
+				}
+			]
+		}
+	}
+	`)
+
+	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_ForceMutateSubstituteVarsWithNilContext(t *testing.T) {
+	expectedRawResource := []byte(`
+	{
+		"apiVersion": "v1",
+		"kind": "Pod",
+		"metadata": {
+			"name": "check-root-user",
+			"labels": {
+				"appname": "placeholderValue"
+			}
+		},
+		"spec": {
+			"containers": [
+				{
+					"name": "check-root-user",
+					"image": "nginxinc/nginx-unprivileged",
+					"securityContext": {
+						"runAsNonRoot": true
+					}
+				}
+			]
+		}
+	}
+	`)
+
+	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)
+
+	mutatedResource, err := ForceMutate(nil, policy, *resourceUnstructured)
+	assert.NilError(t, err)
+
+	assert.DeepEqual(t, expectedResource, mutatedResource.UnstructuredContent())
+}
diff --git a/pkg/engine/json-utils/traverse_test.go b/pkg/engine/json-utils/traverse_test.go
new file mode 100644
index 000000000..54a8a29e2
--- /dev/null
+++ b/pkg/engine/json-utils/traverse_test.go
@@ -0,0 +1,73 @@
+package json_utils
+
+import (
+	"encoding/json"
+	"testing"
+
+	"gotest.tools/assert"
+)
+
+var document = []byte(`
+{
+	"kind": "{{request.object.metadata.name1}}",
+	"name": "ns-owner-{{request.object.metadata.name}}",
+	"data": {
+		"rules": [
+			{
+				"apiGroups": [
+					"{{request.object.metadata.name}}"
+				],
+				"resources": [
+					"namespaces"
+				],
+				"verbs": [
+					"*"
+				]
+			}
+		]
+	}
+}
+`)
+
+func Test_TraverseLeafsCheckIfTheyHit(t *testing.T) {
+	hitMap := map[string]int{
+		"{{request.object.metadata.name1}}":         0,
+		"ns-owner-{{request.object.metadata.name}}": 0,
+		"{{request.object.metadata.name}}":          0,
+		"namespaces":                                0,
+		"*":                                         0,
+	}
+
+	var originalJSON interface{}
+	err := json.Unmarshal(document, &originalJSON)
+	assert.NilError(t, err)
+
+	traversal := NewTraversal(originalJSON, OnlyForLeafs(func(data *ActionData) (interface{}, error) {
+		hitMap[data.Element.(string)]++
+		return data.Element, nil
+	}))
+
+	_, err = traversal.TraverseJSON()
+
+	for _, v := range hitMap {
+		assert.Equal(t, v, 1)
+	}
+}
+
+func Test_PathMustBeCorrectEveryTime(t *testing.T) {
+	expectedValue := "ns-owner-{{request.object.metadata.name}}"
+	expectedPath := "/name"
+
+	var originalJSON interface{}
+	err := json.Unmarshal(document, &originalJSON)
+	assert.NilError(t, err)
+
+	traversal := NewTraversal(originalJSON, OnlyForLeafs(func(data *ActionData) (interface{}, error) {
+		if data.Element.(string) == expectedValue {
+			assert.Equal(t, expectedPath, data.Path)
+		}
+		return data.Element, nil
+	}))
+
+	_, err = traversal.TraverseJSON()
+}
diff --git a/pkg/engine/validate/validate_test.go b/pkg/engine/validate/validate_test.go
index e037d7bd2..0167e490d 100644
--- a/pkg/engine/validate/validate_test.go
+++ b/pkg/engine/validate/validate_test.go
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/kyverno/kyverno/pkg/engine/common"
+	"github.com/kyverno/kyverno/pkg/engine/variables"
 	"gotest.tools/assert"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 )
@@ -788,6 +789,9 @@ func TestValidateMap_CorrectRelativePathInConfig(t *testing.T) {
 	assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
 	assert.Assert(t, json.Unmarshal(rawMap, &resource))
 
+	pattern, err := variables.SubstituteAll(log.Log, nil, pattern)
+	assert.NilError(t, err)
+
 	path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
 	assert.Equal(t, path, "")
 	assert.NilError(t, err)
@@ -1004,6 +1008,9 @@ func TestValidateMap_RelativePathWithParentheses(t *testing.T) {
 	assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
 	assert.Assert(t, json.Unmarshal(rawMap, &resource))
 
+	pattern, err := variables.SubstituteAll(log.Log, nil, pattern)
+	assert.NilError(t, err)
+
 	path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
 	assert.Equal(t, path, "")
 	assert.NilError(t, err)
@@ -1112,6 +1119,9 @@ func TestValidateMap_AbosolutePathExists(t *testing.T) {
 	assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
 	assert.Assert(t, json.Unmarshal(rawMap, &resource))
 
+	pattern, err := variables.SubstituteAll(log.Log, nil, pattern)
+	assert.NilError(t, err)
+
 	path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
 	assert.Equal(t, path, "")
 	assert.Assert(t, err == nil)
@@ -1195,6 +1205,9 @@ func TestValidateMap_AbsolutePathToMetadata_fail(t *testing.T) {
 	assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
 	assert.Assert(t, json.Unmarshal(rawMap, &resource))
 
+	pattern, err := variables.SubstituteAll(log.Log, nil, pattern)
+	assert.NilError(t, err)
+
 	path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
 	assert.Equal(t, path, "/spec/containers/0/image/")
 	assert.Assert(t, err != nil)
@@ -1254,75 +1267,6 @@ func TestValidateMap_AbosolutePathDoesNotExists(t *testing.T) {
 	assert.Assert(t, err != nil)
 }
 
-func TestActualizePattern_GivenRelativePathThatExists(t *testing.T) {
-	absolutePath := "/spec/containers/0/resources/requests/memory"
-	referencePath := "$(<=./../../limits/memory)"
-
-	rawPattern := []byte(`{
-		"spec":{
-			"containers":[
-				{
-					"name":"*",
-					"resources":{
-						"requests":{
-							"memory":"$(<=./../../limits/memory)"
-						},
-						"limits":{
-							"memory":"2048Mi"
-						}
-					}
-				}
-			]
-		}
-	}`)
-
-	var pattern interface{}
-
-	assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
-
-	pattern, err := actualizePattern(log.Log, pattern, referencePath, absolutePath)
-
-	assert.Assert(t, err == nil)
-}
-
-func TestFormAbsolutePath_RelativePathExists(t *testing.T) {
-	absolutePath := "/spec/containers/0/resources/requests/memory"
-	referencePath := "./../../limits/memory"
-	expectedString := "/spec/containers/0/resources/limits/memory"
-
-	result := formAbsolutePath(referencePath, absolutePath)
-
-	assert.Assert(t, result == expectedString)
-}
-
-func TestFormAbsolutePath_RelativePathWithBackToTopInTheBegining(t *testing.T) {
-	absolutePath := "/spec/containers/0/resources/requests/memory"
-	referencePath := "../../limits/memory"
-	expectedString := "/spec/containers/0/resources/limits/memory"
-
-	result := formAbsolutePath(referencePath, absolutePath)
-
-	assert.Assert(t, result == expectedString)
-}
-
-func TestFormAbsolutePath_AbsolutePathExists(t *testing.T) {
-	absolutePath := "/spec/containers/0/resources/requests/memory"
-	referencePath := "/spec/containers/0/resources/limits/memory"
-
-	result := formAbsolutePath(referencePath, absolutePath)
-
-	assert.Assert(t, result == referencePath)
-}
-
-func TestFormAbsolutePath_EmptyPath(t *testing.T) {
-	absolutePath := "/spec/containers/0/resources/requests/memory"
-	referencePath := ""
-
-	result := formAbsolutePath(referencePath, absolutePath)
-
-	assert.Assert(t, result == absolutePath)
-}
-
 func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) {
 	rawPattern := []byte(`[
 		{
diff --git a/pkg/engine/validation_test.go b/pkg/engine/validation_test.go
index 93afb8bf8..88545fc6c 100644
--- a/pkg/engine/validation_test.go
+++ b/pkg/engine/validation_test.go
@@ -1321,10 +1321,10 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
 	er := Validate(policyContext)
 	assert.Assert(t, !er.PolicyResponse.Rules[0].Success)
 	assert.Equal(t, er.PolicyResponse.Rules[0].Message,
-		"variable substitution failed for rule test-path-not-exist: variable request.object.metadata.name1 not resolved at path /spec/containers/0/name")
+		"variable substitution failed for rule test-path-not-exist: variable request.object.metadata.name1 not resolved at path /validate/pattern/spec/containers/0/name")
 }
 
-func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies(t *testing.T) {
+func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfiesButSubstitutionFails(t *testing.T) {
 	resourceRaw := []byte(`{
 		"apiVersion": "v1",
 		"kind": "Deployment",
@@ -1411,8 +1411,8 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies(t *t
 		JSONContext: ctx,
 		NewResource: *resourceUnstructured}
 	er := Validate(policyContext)
-	assert.Assert(t, er.PolicyResponse.Rules[0].Success)
-	assert.Equal(t, er.PolicyResponse.Rules[0].Message, "validation rule 'test-path-not-exist' anyPattern[1] passed.")
+	assert.Assert(t, !er.PolicyResponse.Rules[0].Success)
+	assert.Equal(t, er.PolicyResponse.Rules[0].Message, "variable substitution failed for rule test-path-not-exist: variable request.object.metadata.name1 not resolved at path /validate/anyPattern/0/spec/template/spec/containers/0/name")
 }
 
 func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *testing.T) {
@@ -1503,7 +1503,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
 		NewResource: *resourceUnstructured}
 	er := Validate(policyContext)
 	assert.Assert(t, !er.PolicyResponse.Rules[0].Success)
-	assert.Equal(t, er.PolicyResponse.Rules[0].Message, "failed to substitute variables: [variable request.object.metadata.name1 not resolved at path /spec/template/spec/containers/0/name variable request.object.metadata.name2 not resolved at path /spec/template/spec/containers/0/name]")
+	assert.Equal(t, er.PolicyResponse.Rules[0].Message, "variable substitution failed for rule test-path-not-exist: variable request.object.metadata.name1 not resolved at path /validate/anyPattern/0/spec/template/spec/containers/0/name")
 }
 
 func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatternSatisfy(t *testing.T) {
diff --git a/pkg/engine/variables/variables_test.go b/pkg/engine/variables/variables_test.go
index 8b300b90f..a42a8ea06 100644
--- a/pkg/engine/variables/variables_test.go
+++ b/pkg/engine/variables/variables_test.go
@@ -85,7 +85,7 @@ func Test_variablesub1(t *testing.T) {
 		t.Error(err)
 	}
 
-	if patternCopy, err = SubstituteVars(log.Log, ctx, patternCopy); err != nil {
+	if patternCopy, err = SubstituteAll(log.Log, ctx, patternCopy); err != nil {
 		t.Error(err)
 	}
 	resultRaw, err := json.Marshal(patternCopy)
@@ -175,7 +175,7 @@ func Test_variablesub_multiple(t *testing.T) {
 		t.Error(err)
 	}
 
-	if patternCopy, err = SubstituteVars(log.Log, ctx, patternCopy); err != nil {
+	if patternCopy, err = SubstituteAll(log.Log, ctx, patternCopy); err != nil {
 		t.Error(err)
 	}
 	resultRaw, err := json.Marshal(patternCopy)
@@ -262,7 +262,7 @@ func Test_variablesubstitution(t *testing.T) {
 		t.Error(err)
 	}
 
-	if patternCopy, err = SubstituteVars(log.Log, ctx, patternCopy); err != nil {
+	if patternCopy, err = SubstituteAll(log.Log, ctx, patternCopy); err != nil {
 		t.Error(err)
 	}
 	resultRaw, err := json.Marshal(patternCopy)
@@ -323,7 +323,7 @@ func Test_variableSubstitutionValue(t *testing.T) {
 		t.Error(err)
 	}
 
-	if patternCopy, err = SubstituteVars(log.Log, ctx, patternCopy); err != nil {
+	if patternCopy, err = SubstituteAll(log.Log, ctx, patternCopy); err != nil {
 		t.Error(err)
 	}
 	resultRaw, err := json.Marshal(patternCopy)
@@ -381,7 +381,7 @@ func Test_variableSubstitutionValueOperatorNotEqual(t *testing.T) {
 		t.Error(err)
 	}
 
-	if patternCopy, err = SubstituteVars(log.Log, ctx, patternCopy); err != nil {
+	if patternCopy, err = SubstituteAll(log.Log, ctx, patternCopy); err != nil {
 		t.Error(err)
 	}
 	resultRaw, err := json.Marshal(patternCopy)
@@ -440,7 +440,7 @@ func Test_variableSubstitutionValueFail(t *testing.T) {
 		t.Error(err)
 	}
 
-	if patternCopy, err = SubstituteVars(log.Log, ctx, patternCopy); err == nil {
+	if patternCopy, err = SubstituteAll(log.Log, ctx, patternCopy); err == nil {
 		t.Log("expected to fails")
 		t.Fail()
 	}
@@ -498,7 +498,7 @@ func Test_variableSubstitutionObject(t *testing.T) {
 		t.Error(err)
 	}
 
-	if patternCopy, err = SubstituteVars(log.Log, ctx, patternCopy); err != nil {
+	if patternCopy, err = SubstituteAll(log.Log, ctx, patternCopy); err != nil {
 		t.Error(err)
 	}
 	resultRaw, err := json.Marshal(patternCopy)
@@ -562,7 +562,7 @@ func Test_variableSubstitutionObjectOperatorNotEqualFail(t *testing.T) {
 		t.Error(err)
 	}
 
-	if patternCopy, err = SubstituteVars(log.Log, ctx, patternCopy); err == nil {
+	if patternCopy, err = SubstituteAll(log.Log, ctx, patternCopy); err == nil {
 		t.Error(err)
 	}
 
@@ -621,7 +621,7 @@ func Test_variableSubstitutionMultipleObject(t *testing.T) {
 		t.Error(err)
 	}
 
-	if patternCopy, err = SubstituteVars(log.Log, ctx, patternCopy); err != nil {
+	if patternCopy, err = SubstituteAll(log.Log, ctx, patternCopy); err != nil {
 		t.Error(err)
 	}
 	resultRaw, err := json.Marshal(patternCopy)
diff --git a/pkg/engine/variables/vars_test.go b/pkg/engine/variables/vars_test.go
index 70ad52b02..efb5e1a26 100644
--- a/pkg/engine/variables/vars_test.go
+++ b/pkg/engine/variables/vars_test.go
@@ -3,9 +3,11 @@ package variables
 import (
 	"encoding/json"
 	"fmt"
+	"strings"
 	"testing"
 
 	"github.com/kyverno/kyverno/pkg/engine/context"
+	ju "github.com/kyverno/kyverno/pkg/engine/json-utils"
 	"gotest.tools/assert"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 )
@@ -66,7 +68,7 @@ func Test_subVars_success(t *testing.T) {
 		t.Error(err)
 	}
 
-	if _, err := SubstituteVars(log.Log, ctx, pattern); err != nil {
+	if _, err := SubstituteAll(log.Log, ctx, pattern); err != nil {
 		t.Error(err)
 	}
 }
@@ -127,7 +129,7 @@ func Test_subVars_failed(t *testing.T) {
 		t.Error(err)
 	}
 
-	if _, err := SubstituteVars(log.Log, ctx, pattern); err == nil {
+	if _, err := SubstituteAll(log.Log, ctx, pattern); err == nil {
 		t.Error("error is expected")
 	}
 }
@@ -170,7 +172,7 @@ func Test_ReplacingPathWhenDeleting(t *testing.T) {
 	err = ctx.AddJSON(resourceRaw)
 	assert.NilError(t, err)
 
-	pattern, err = SubstituteVars(log.Log, ctx, pattern)
+	pattern, err = SubstituteAll(log.Log, ctx, pattern)
 	assert.NilError(t, err)
 
 	assert.Equal(t, fmt.Sprintf("%v", pattern), "bar")
@@ -206,7 +208,7 @@ func Test_ReplacingNestedVariableWhenDeleting(t *testing.T) {
 	err = ctx.AddJSON(resourceRaw)
 	assert.NilError(t, err)
 
-	pattern, err = SubstituteVars(log.Log, ctx, pattern)
+	pattern, err = SubstituteAll(log.Log, ctx, pattern)
 	assert.NilError(t, err)
 
 	assert.Equal(t, fmt.Sprintf("%v", pattern), "nested_target")
@@ -235,7 +237,13 @@ func Test_SubstituteSuccess(t *testing.T) {
 	var pattern interface{}
 	patternRaw := []byte(`"{{request.object.metadata.annotations.test}}"`)
 	assert.Assert(t, json.Unmarshal(patternRaw, &pattern))
-	results, err := subValR(log.Log, ctx, string(patternRaw), "/")
+
+	action := substituteVariablesIfAny(log.Log, ctx)
+	results, err := action(&ju.ActionData{
+		Document: nil,
+		Element:  string(patternRaw),
+		Path:     "/"})
+
 	if err != nil {
 		t.Errorf("substitution failed: %v", err.Error())
 		return
@@ -253,14 +261,26 @@ func Test_SubstituteRecursiveErrors(t *testing.T) {
 	var pattern interface{}
 	patternRaw := []byte(`"{{request.object.metadata.{{request.object.metadata.annotations.test2}}}}"`)
 	assert.Assert(t, json.Unmarshal(patternRaw, &pattern))
-	results, err := subValR(log.Log, ctx, string(patternRaw), "/")
+
+	action := substituteVariablesIfAny(log.Log, ctx)
+	results, err := action(&ju.ActionData{
+		Document: nil,
+		Element:  string(patternRaw),
+		Path:     "/"})
+
 	if err == nil {
 		t.Errorf("expected error but received: %v", results)
 	}
 
 	patternRaw = []byte(`"{{request.object.metadata2.{{request.object.metadata.annotations.test}}}}"`)
 	assert.Assert(t, json.Unmarshal(patternRaw, &pattern))
-	results, err = subValR(log.Log, ctx, string(patternRaw), "/")
+
+	action = substituteVariablesIfAny(log.Log, ctx)
+	results, err = action(&ju.ActionData{
+		Document: nil,
+		Element:  string(patternRaw),
+		Path:     "/"})
+
 	if err == nil {
 		t.Errorf("expected error but received: %v", results)
 	}
@@ -273,7 +293,13 @@ func Test_SubstituteRecursive(t *testing.T) {
 	var pattern interface{}
 	patternRaw := []byte(`"{{request.object.metadata.{{request.object.metadata.annotations.test}}}}"`)
 	assert.Assert(t, json.Unmarshal(patternRaw, &pattern))
-	results, err := subValR(log.Log, ctx, string(patternRaw), "/")
+
+	action := substituteVariablesIfAny(log.Log, ctx)
+	results, err := action(&ju.ActionData{
+		Document: nil,
+		Element:  string(patternRaw),
+		Path:     "/"})
+
 	if err != nil {
 		t.Errorf("substitution failed: %v", err.Error())
 		return
@@ -304,6 +330,144 @@ func Test_policyContextValidation(t *testing.T) {
 
 	ctx := context.NewContext("request.object")
 
-	_, err = SubstituteVars(log.Log, ctx, contextMap)
+	_, err = SubstituteAll(log.Log, ctx, contextMap)
 	assert.Assert(t, err != nil, err)
 }
+
+func Test_ReferenceSubstitution(t *testing.T) {
+	jsonRaw := []byte(`
+	{
+		"metadata": {
+			"name": "temp",
+			"namespace": "n1",
+			"annotations": {
+			  "test": "$(../../../../spec/namespace)"
+            }
+		},
+		"(spec)": {
+			"namespace": "n1",
+			"name": "temp1"
+		}
+	}`)
+
+	expectedJSON := []byte(`
+	{
+		"metadata": {
+			"name": "temp",
+			"namespace": "n1",
+			"annotations": {
+			  "test": "n1"
+            }
+		},
+		"(spec)": {
+			"namespace": "n1",
+			"name": "temp1"
+		}
+	}`)
+
+	var document interface{}
+	err := json.Unmarshal(jsonRaw, &document)
+	assert.NilError(t, err)
+
+	var expectedDocument interface{}
+	err = json.Unmarshal(expectedJSON, &expectedDocument)
+	assert.NilError(t, err)
+
+	ctx := context.NewContext()
+	err = ctx.AddResource(jsonRaw)
+	assert.NilError(t, err)
+
+	actualDocument, err := SubstituteAll(log.Log, ctx, document)
+	assert.NilError(t, err)
+
+	assert.DeepEqual(t, expectedDocument, actualDocument)
+}
+
+func TestFormAbsolutePath_RelativePathExists(t *testing.T) {
+	absolutePath := "/spec/containers/0/resources/requests/memory"
+	referencePath := "./../../limits/memory"
+	expectedString := "/spec/containers/0/resources/limits/memory"
+
+	result := formAbsolutePath(referencePath, absolutePath)
+
+	assert.Assert(t, result == expectedString)
+}
+
+func TestFormAbsolutePath_RelativePathWithBackToTopInTheBegining(t *testing.T) {
+	absolutePath := "/spec/containers/0/resources/requests/memory"
+	referencePath := "../../limits/memory"
+	expectedString := "/spec/containers/0/resources/limits/memory"
+
+	result := formAbsolutePath(referencePath, absolutePath)
+
+	assert.Assert(t, result == expectedString)
+}
+
+func TestFormAbsolutePath_AbsolutePathExists(t *testing.T) {
+	absolutePath := "/spec/containers/0/resources/requests/memory"
+	referencePath := "/spec/containers/0/resources/limits/memory"
+
+	result := formAbsolutePath(referencePath, absolutePath)
+
+	assert.Assert(t, result == referencePath)
+}
+
+func TestFormAbsolutePath_EmptyPath(t *testing.T) {
+	absolutePath := "/spec/containers/0/resources/requests/memory"
+	referencePath := ""
+
+	result := formAbsolutePath(referencePath, absolutePath)
+
+	assert.Assert(t, result == absolutePath)
+}
+
+func TestActualizePattern_GivenRelativePathThatExists(t *testing.T) {
+	absolutePath := "/spec/containers/0/resources/requests/memory"
+	referencePath := "$(<=./../../limits/memory)"
+
+	rawPattern := []byte(`{
+		"spec":{
+			"containers":[
+				{
+					"name":"*",
+					"resources":{
+						"requests":{
+							"memory":"$(<=./../../limits/memory)"
+						},
+						"limits":{
+							"memory":"2048Mi"
+						}
+					}
+				}
+			]
+		}
+	}`)
+
+	resolvedReference := "<=2048Mi"
+
+	var pattern interface{}
+	assert.NilError(t, json.Unmarshal(rawPattern, &pattern))
+
+	// pattern, err := actualizePattern(log.Log, pattern, referencePath, absolutePath)
+
+	pattern, err := resolveReference(log.Log, pattern, referencePath, absolutePath)
+
+	assert.NilError(t, err)
+	assert.DeepEqual(t, resolvedReference, pattern)
+}
+
+func TestFindAndShiftReferences_PositiveCase(t *testing.T) {
+	message := "Message with $(./../../pattern/spec/containers/0/image) reference inside. Or maybe even two $(./../../pattern/spec/containers/0/image), but they are same."
+	expectedMessage := strings.Replace(message, "$(./../../pattern/spec/containers/0/image)", "$(./../../pattern/spec/jobTemplate/spec/containers/0/image)", -1)
+	actualMessage := FindAndShiftReferences(log.Log, message, "spec/jobTemplate", "pattern")
+
+	assert.Equal(t, expectedMessage, actualMessage)
+}
+
+func TestFindAndShiftReferences_AnyPatternPositiveCase(t *testing.T) {
+	message := "Message with $(./../../anyPattern/0/spec/containers/0/image)."
+	expectedMessage := strings.Replace(message, "$(./../../anyPattern/0/spec/containers/0/image)", "$(./../../anyPattern/0/spec/jobTemplate/spec/containers/0/image)", -1)
+	actualMessage := FindAndShiftReferences(log.Log, message, "spec/jobTemplate", "anyPattern")
+
+	assert.Equal(t, expectedMessage, actualMessage)
+}
diff --git a/pkg/kyverno/apply/command_test.go b/pkg/kyverno/apply/command_test.go
index cfbc4f153..3b59a181d 100644
--- a/pkg/kyverno/apply/command_test.go
+++ b/pkg/kyverno/apply/command_test.go
@@ -56,7 +56,7 @@ func Test_Apply(t *testing.T) {
 	}
 
 	for _, tc := range testcases {
-		validateEngineResponses, _, _, skippedPolicies, _ := applyCommandHelper(tc.ResourcePaths, false, true, "", "", "", "", tc.PolicyPaths)
+		validateEngineResponses, _, _, skippedPolicies, _ := applyCommandHelper(tc.ResourcePaths, false, true, "", "", "", "", tc.PolicyPaths, false)
 		resps := buildPolicyReports(validateEngineResponses, skippedPolicies)
 		for i, resp := range resps {
 			compareSummary(tc.expectedPolicyReports[i].Summary, resp.UnstructuredContent()["summary"].(map[string]interface{}))
diff --git a/pkg/kyverno/common/common_test.go b/pkg/kyverno/common/common_test.go
index 3f58b4ea9..07587a9fd 100644
--- a/pkg/kyverno/common/common_test.go
+++ b/pkg/kyverno/common/common_test.go
@@ -85,7 +85,7 @@ func Test_NamespaceSelector(t *testing.T) {
 	for _, tc := range testcases {
 		policyArray, _ := ut.GetPolicy(tc.policy)
 		resourceArray, _ := GetResource(tc.resource)
-		_, validateErs, _, _, _ := ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, false, tc.namespaceSelectorMap)
+		_, validateErs, _, _, _ := ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, false, tc.namespaceSelectorMap, false)
 		assert.Assert(t, tc.sucess == validateErs.IsSuccessful())
 	}
 }
diff --git a/pkg/kyverno/test/command.go b/pkg/kyverno/test/command.go
index fa589a991..fa519d9e8 100644
--- a/pkg/kyverno/test/command.go
+++ b/pkg/kyverno/test/command.go
@@ -341,7 +341,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, valuesFile s
 				return sanitizederror.NewWithError(fmt.Sprintf("policy %s have variables. pass the values for the variables using set/values_file flag", policy.Name), err)
 			}
 
-			ers, validateErs, _, _, err := common.ApplyPolicyOnResource(policy, resource, "", false, thisPolicyResourceValues, true, namespaceSelectorMap)
+			ers, validateErs, _, _, err := common.ApplyPolicyOnResource(policy, resource, "", false, thisPolicyResourceValues, true, namespaceSelectorMap, false)
 			if err != nil {
 				return sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
 			}