From 17ba925490432f8d7d396345d5ef0e1b1f5daf45 Mon Sep 17 00:00:00 2001 From: Sandesh More <34198712+sandeshlmore@users.noreply.github.com> Date: Thu, 13 Oct 2022 13:29:10 +0530 Subject: [PATCH] add filter for validation policies when ValidationFailureActionOverrides is used (#4809) Signed-off-by: Sandesh More Signed-off-by: Sandesh More --- pkg/policycache/cache.go | 43 ++++++++++++++ pkg/policycache/cache_test.go | 102 ++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/pkg/policycache/cache.go b/pkg/policycache/cache.go index 918c1fa50a..b1e4892e4b 100644 --- a/pkg/policycache/cache.go +++ b/pkg/policycache/cache.go @@ -2,6 +2,7 @@ package policycache import ( kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" + kyvernoutils "github.com/kyverno/kyverno/pkg/utils" ) // Cache get method use for to get policy names and mostly use to test cache testcases @@ -42,5 +43,47 @@ func (c *cache) GetPolicies(pkey PolicyType, kind, nspace string) []kyvernov1.Po result = append(result, c.store.get(pkey, kind, nspace)...) result = append(result, c.store.get(pkey, "*", nspace)...) } + + if pkey == ValidateAudit { // also get policies with ValidateEnforce + result = append(result, c.store.get(ValidateEnforce, kind, "")...) + result = append(result, c.store.get(ValidateEnforce, "*", "")...) + } + + if pkey == ValidateAudit || pkey == ValidateEnforce { + result = filterPolicies(pkey, result, nspace, kind) + } + return result } + +// Filter cluster policies using validationFailureAction override +func filterPolicies(pkey PolicyType, result []kyvernov1.PolicyInterface, nspace, kind string) []kyvernov1.PolicyInterface { + var policies []kyvernov1.PolicyInterface + for _, policy := range result { + keepPolicy := true + switch pkey { + case ValidateAudit: + keepPolicy = checkValidationFailureActionOverrides(kyvernov1.Audit, nspace, policy) + case ValidateEnforce: + keepPolicy = checkValidationFailureActionOverrides(kyvernov1.Enforce, nspace, policy) + } + if keepPolicy { // add policy to result + policies = append(policies, policy) + } + } + return policies +} + +func checkValidationFailureActionOverrides(requestedAction kyvernov1.ValidationFailureAction, ns string, policy kyvernov1.PolicyInterface) bool { + validationFailureAction := policy.GetSpec().ValidationFailureAction + validationFailureActionOverrides := policy.GetSpec().ValidationFailureActionOverrides + if validationFailureAction != requestedAction && (ns == "" || len(validationFailureActionOverrides) == 0) { + return false + } + for _, action := range validationFailureActionOverrides { + if action.Action != requestedAction && kyvernoutils.ContainsNamepace(action.Namespaces, ns) { + return false + } + } + return true +} diff --git a/pkg/policycache/cache_test.go b/pkg/policycache/cache_test.go index 4b062731b8..c57611aab2 100644 --- a/pkg/policycache/cache_test.go +++ b/pkg/policycache/cache_test.go @@ -1159,3 +1159,105 @@ func Test_Validate_Enforce_Policy(t *testing.T) { t.Errorf("removing: expected 0 validate audit policy, found %v", len(validateAudit)) } } + +func Test_Get_Policies(t *testing.T) { + cache := NewCache() + policy := newPolicy(t) + key, _ := kubecache.MetaNamespaceKeyFunc(policy) + cache.Set(key, policy) + + validateAudit := cache.GetPolicies(ValidateAudit, "Namespace", "") + if len(validateAudit) != 0 { + t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit)) + } + + validateAudit = cache.GetPolicies(ValidateAudit, "Pod", "test") + if len(validateAudit) != 0 { + t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit)) + } + + validateEnforce := cache.GetPolicies(ValidateEnforce, "Namespace", "") + if len(validateEnforce) != 1 { + t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) + } + + mutate := cache.GetPolicies(Mutate, "Pod", "") + if len(mutate) != 1 { + t.Errorf("expected 1 mutate policy, found %v", len(mutate)) + } + + generate := cache.GetPolicies(Generate, "Pod", "") + if len(generate) != 1 { + t.Errorf("expected 1 generate policy, found %v", len(generate)) + } + +} + +func Test_Get_Policies_Ns(t *testing.T) { + cache := NewCache() + policy := newNsPolicy(t) + key, _ := kubecache.MetaNamespaceKeyFunc(policy) + cache.Set(key, policy) + nspace := policy.GetNamespace() + + validateAudit := cache.GetPolicies(ValidateAudit, "Pod", nspace) + if len(validateAudit) != 0 { + t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit)) + } + + validateEnforce := cache.GetPolicies(ValidateEnforce, "Pod", nspace) + if len(validateEnforce) != 1 { + t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) + } + + mutate := cache.GetPolicies(Mutate, "Pod", nspace) + if len(mutate) != 1 { + t.Errorf("expected 1 mutate policy, found %v", len(mutate)) + } + + generate := cache.GetPolicies(Generate, "Pod", nspace) + if len(generate) != 1 { + t.Errorf("expected 1 generate policy, found %v", len(generate)) + } +} + +func Test_Get_Policies_Validate_Failure_Action_Overrides(t *testing.T) { + cache := NewCache() + policy1 := newValidateAuditPolicy(t) + policy2 := newValidateEnforcePolicy(t) + key1, _ := kubecache.MetaNamespaceKeyFunc(policy1) + cache.Set(key1, policy1) + key2, _ := kubecache.MetaNamespaceKeyFunc(policy2) + cache.Set(key2, policy2) + + validateAudit := cache.GetPolicies(ValidateAudit, "Pod", "") + if len(validateAudit) != 1 { + t.Errorf("expected 1 validate audit policy, found %v", len(validateAudit)) + } + + validateEnforce := cache.GetPolicies(ValidateEnforce, "Pod", "") + if len(validateEnforce) != 1 { + t.Errorf("expected 1 validate enforce policy, found %v", len(validateEnforce)) + } + + validateAudit = cache.GetPolicies(ValidateAudit, "Pod", "test") + if len(validateAudit) != 2 { + t.Errorf("expected 2 validate audit policy, found %v", len(validateAudit)) + } + + validateEnforce = cache.GetPolicies(ValidateEnforce, "Pod", "test") + if len(validateEnforce) != 0 { + t.Errorf("expected 0 validate enforce policy, found %v", len(validateEnforce)) + } + + validateAudit = cache.GetPolicies(ValidateAudit, "Pod", "default") + if len(validateAudit) != 0 { + t.Errorf("expected 0 validate audit policy, found %v", len(validateAudit)) + } + + validateEnforce = cache.GetPolicies(ValidateEnforce, "Pod", "default") + if len(validateEnforce) != 2 { + t.Errorf("expected 2 validate enforce policy, found %v", len(validateEnforce)) + } + +}