diff --git a/pkg/engine/api/policycontext.go b/pkg/engine/api/policycontext.go index a075bec881..8afbfef3ea 100644 --- a/pkg/engine/api/policycontext.go +++ b/pkg/engine/api/policycontext.go @@ -27,4 +27,5 @@ type PolicyContext interface { SetElement(element unstructured.Unstructured) JSONContext() enginecontext.Interface + Copy() PolicyContext } diff --git a/pkg/engine/handlers/validation/validate_resource.go b/pkg/engine/handlers/validation/validate_resource.go index a423975c2b..ead88dd1d7 100644 --- a/pkg/engine/handlers/validation/validate_resource.go +++ b/pkg/engine/handlers/validation/validate_resource.go @@ -222,7 +222,7 @@ func (v *validator) validateElements(ctx context.Context, foreach kyvernov1.ForE } v.policyContext.JSONContext().Reset() - policyContext := v.policyContext + policyContext := v.policyContext.Copy() if err := engineutils.AddElementToContext(policyContext, element, index, v.nesting, elementScope); err != nil { v.log.Error(err, "failed to add element to context") return engineapi.RuleError(v.rule.Name, engineapi.Validation, "failed to process foreach", err), applyCount diff --git a/pkg/engine/policycontext/policy_context.go b/pkg/engine/policycontext/policy_context.go index cd2f8b9ec0..5d1ab58d0b 100644 --- a/pkg/engine/policycontext/policy_context.go +++ b/pkg/engine/policycontext/policy_context.go @@ -6,6 +6,7 @@ import ( kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1" "github.com/kyverno/kyverno/pkg/config" + engineapi "github.com/kyverno/kyverno/pkg/engine/api" enginectx "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/jmespath" admissionutils "github.com/kyverno/kyverno/pkg/utils/admission" @@ -125,6 +126,10 @@ func (c *PolicyContext) JSONContext() enginectx.Interface { return c.jsonContext } +func (c PolicyContext) Copy() engineapi.PolicyContext { + return &c +} + // Mutators func (c PolicyContext) WithPolicy(policy kyvernov1.PolicyInterface) *PolicyContext { diff --git a/test/cli/test/multiple-validate-rules/kyverno-test.yaml b/test/cli/test/multiple-validate-rules/kyverno-test.yaml new file mode 100644 index 0000000000..d3e1f6ee90 --- /dev/null +++ b/test/cli/test/multiple-validate-rules/kyverno-test.yaml @@ -0,0 +1,21 @@ +apiVersion: cli.kyverno.io/v1alpha1 +kind: Test +metadata: + name: kyverno-test.yaml +policies: +- policy.yaml +resources: +- resource.yaml +results: +- kind: Service + policy: restrict-service-ports + resources: + - service-example-port-22 + result: pass + rule: restrict-nodeport +- kind: Service + policy: restrict-service-ports + resources: + - service-example-port-22 + result: pass + rule: restrict-port-range diff --git a/test/cli/test/multiple-validate-rules/policy.yaml b/test/cli/test/multiple-validate-rules/policy.yaml new file mode 100644 index 0000000000..f8649cdf0b --- /dev/null +++ b/test/cli/test/multiple-validate-rules/policy.yaml @@ -0,0 +1,44 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-service-ports +spec: + validationFailureAction: Enforce + background: true + rules: + - name: restrict-port-range + match: + any: + - resources: + kinds: + - Service + preconditions: + all: + - key: "{{ request.object.spec.type }}" + operator: Equals + value: 'LoadBalancer' + validate: + message: >- + Only approved ports may be used for LoadBalancer services. + foreach: + - list: request.object.spec.ports[] + deny: + conditions: + all: + - key: "{{ element.port }}" + operator: AnyNotIn + value: + - 22 + - 80 + - 443 + - name: restrict-nodeport + match: + any: + - resources: + kinds: + - Service + validate: + message: "NodePort services are not allowed. This is {{ request.object.spec.type }}" + pattern: + spec: + =(type): "!NodePort" diff --git a/test/cli/test/multiple-validate-rules/resource.yaml b/test/cli/test/multiple-validate-rules/resource.yaml new file mode 100644 index 0000000000..7204732705 --- /dev/null +++ b/test/cli/test/multiple-validate-rules/resource.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: service-example-port-22 +spec: + selector: + app: example + ports: + - port: 22 + targetPort: 22 + type: LoadBalancer