diff --git a/Makefile b/Makefile index a986d19a32..512e6092df 100644 --- a/Makefile +++ b/Makefile @@ -198,6 +198,7 @@ test-e2e-local: #Test TestCmd Policy test-cmd: cli $(PWD)/$(CLI_PATH)/kyverno test https://github.com/kyverno/policies/main + $(PWD)/$(CLI_PATH)/kyverno test ./test/cli/test-mutate $(PWD)/$(CLI_PATH)/kyverno test ./test/cli/test $(PWD)/$(CLI_PATH)/kyverno test ./test/cli/test-fail/missing-policy && exit 1 || exit 0 $(PWD)/$(CLI_PATH)/kyverno test ./test/cli/test-fail/missing-rule && exit 1 || exit 0 diff --git a/pkg/engine/generation.go b/pkg/engine/generation.go index 6750977404..dcd6257807 100644 --- a/pkg/engine/generation.go +++ b/pkg/engine/generation.go @@ -75,10 +75,10 @@ func filterRule(rule kyverno.Rule, policyContext *PolicyContext) *response.RuleR logger := log.Log.WithName("Generate").WithValues("policy", policy.Name, "kind", newResource.GetKind(), "namespace", newResource.GetNamespace(), "name", newResource.GetName()) - if err = MatchesResourceDescription(newResource, rule, admissionInfo, excludeGroupRole, namespaceLabels); err != nil { + if err = MatchesResourceDescription(newResource, rule, admissionInfo, excludeGroupRole, namespaceLabels, ""); err != nil { // if the oldResource matched, return "false" to delete GR for it - if err = MatchesResourceDescription(oldResource, rule, admissionInfo, excludeGroupRole, namespaceLabels); err == nil { + if err = MatchesResourceDescription(oldResource, rule, admissionInfo, excludeGroupRole, namespaceLabels, ""); err == nil { return &response.RuleResponse{ Name: rule.Name, Type: "Generation", diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index 75a5a74ef4..6cd0a221e4 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -65,7 +65,7 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) { excludeResource = policyContext.ExcludeGroupRole } - if err = MatchesResourceDescription(patchedResource, rule, policyContext.AdmissionInfo, excludeResource, policyContext.NamespaceLabels); err != nil { + if err = MatchesResourceDescription(patchedResource, rule, policyContext.AdmissionInfo, excludeResource, policyContext.NamespaceLabels, policyContext.Policy.Namespace); err != nil { logger.V(4).Info("rule not matched", "reason", err.Error()) continue } diff --git a/pkg/engine/utils.go b/pkg/engine/utils.go index 8b7929be18..7e82a50264 100644 --- a/pkg/engine/utils.go +++ b/pkg/engine/utils.go @@ -256,13 +256,16 @@ func matchSubjects(ruleSubjects []rbacv1.Subject, userInfo authenticationv1.User } //MatchesResourceDescription checks if the resource matches resource description of the rule or not -func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef kyverno.Rule, admissionInfoRef kyverno.RequestInfo, dynamicConfig []string, namespaceLabels map[string]string) error { +func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef kyverno.Rule, admissionInfoRef kyverno.RequestInfo, dynamicConfig []string, namespaceLabels map[string]string, policyNamespace string) error { rule := *ruleRef.DeepCopy() resource := *resourceRef.DeepCopy() admissionInfo := *admissionInfoRef.DeepCopy() var reasonsForFailure []error + if policyNamespace != "" && policyNamespace != resourceRef.GetNamespace() { + return errors.New(" The policy and resource namespace are different. Therefore, policy skip this resource.") + } if len(rule.MatchResources.Any) > 0 { // inlcude object if ANY of the criterias match // so if one matches then break from loop diff --git a/pkg/engine/utils_test.go b/pkg/engine/utils_test.go index 11340244cc..8de2ef5662 100644 --- a/pkg/engine/utils_test.go +++ b/pkg/engine/utils_test.go @@ -898,7 +898,7 @@ func TestMatchesResourceDescription(t *testing.T) { resource, _ := utils.ConvertToUnstructured(tc.Resource) for _, rule := range policy.Spec.Rules { - err := MatchesResourceDescription(*resource, rule, tc.AdmissionInfo, []string{}, nil) + err := MatchesResourceDescription(*resource, rule, tc.AdmissionInfo, []string{}, nil, "") if err != nil { if !tc.areErrorsExpected { t.Errorf("Testcase %d Unexpected error: %v", i+1, err) @@ -966,7 +966,7 @@ func TestResourceDescriptionMatch_MultipleKind(t *testing.T) { } rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}} - if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil { + if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil, ""); err != nil { t.Errorf("Testcase has failed due to the following:%v", err) } @@ -1027,7 +1027,7 @@ func TestResourceDescriptionMatch_Name(t *testing.T) { } rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}} - if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil { + if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil, ""); err != nil { t.Errorf("Testcase has failed due to the following:%v", err) } } @@ -1087,7 +1087,7 @@ func TestResourceDescriptionMatch_Name_Regex(t *testing.T) { } rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}} - if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil { + if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil, ""); err != nil { t.Errorf("Testcase has failed due to the following:%v", err) } } @@ -1155,7 +1155,7 @@ func TestResourceDescriptionMatch_Label_Expression_NotMatch(t *testing.T) { } rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}} - if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil { + if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil, ""); err != nil { t.Errorf("Testcase has failed due to the following:%v", err) } } @@ -1224,7 +1224,7 @@ func TestResourceDescriptionMatch_Label_Expression_Match(t *testing.T) { } rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}} - if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil { + if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil, ""); err != nil { t.Errorf("Testcase has failed due to the following:%v", err) } } @@ -1304,7 +1304,7 @@ func TestResourceDescriptionExclude_Label_Expression_Match(t *testing.T) { rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}, ExcludeResources: kyverno.ExcludeResources{ResourceDescription: resourceDescriptionExclude}} - if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err == nil { + if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil, ""); err == nil { t.Errorf("Testcase has failed due to the following:\n Function has returned no error, even though it was supposed to fail") } } diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go index 88d68633b3..fc4eb85ee4 100644 --- a/pkg/engine/validation.go +++ b/pkg/engine/validation.go @@ -198,13 +198,13 @@ func validateResourceWithRule(log logr.Logger, ctx *PolicyContext, rule kyverno. // matches checks if either the new or old resource satisfies the filter conditions defined in the rule func matches(logger logr.Logger, rule kyverno.Rule, ctx *PolicyContext) bool { - err := MatchesResourceDescription(ctx.NewResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole, ctx.NamespaceLabels) + err := MatchesResourceDescription(ctx.NewResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole, ctx.NamespaceLabels, "") if err == nil { return true } if !reflect.DeepEqual(ctx.OldResource, unstructured.Unstructured{}) { - err := MatchesResourceDescription(ctx.OldResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole, ctx.NamespaceLabels) + err := MatchesResourceDescription(ctx.OldResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole, ctx.NamespaceLabels, "") if err == nil { return true } diff --git a/pkg/kyverno/apply/apply_command.go b/pkg/kyverno/apply/apply_command.go index 4dfdfff698..c86f96f6fb 100644 --- a/pkg/kyverno/apply/apply_command.go +++ b/pkg/kyverno/apply/apply_command.go @@ -286,7 +286,7 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, return rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError(fmt.Sprintf("policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag", policy.Name, resource.GetName()), err) } - _, info, err := common.ApplyPolicyOnResource(policy, resource, mutateLogPath, mutateLogPathIsDir, thisPolicyResourceValues, policyReport, namespaceSelectorMap, stdin, rc) + _, info, err := common.ApplyPolicyOnResource(policy, resource, mutateLogPath, mutateLogPathIsDir, thisPolicyResourceValues, policyReport, namespaceSelectorMap, stdin, rc, true) if err != nil { return rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err) } diff --git a/pkg/kyverno/common/common.go b/pkg/kyverno/common/common.go index 10eb1ae4d0..bf5efb0842 100644 --- a/pkg/kyverno/common/common.go +++ b/pkg/kyverno/common/common.go @@ -524,7 +524,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, stdin bool, rc *ResultCounts) (*response.EngineResponse, policyreport.Info, error) { + mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, policyReport bool, namespaceSelectorMap map[string]map[string]string, stdin bool, rc *ResultCounts, printPatchResource bool) (*response.EngineResponse, policyreport.Info, error) { operationIsDelete := false @@ -533,7 +533,7 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst } namespaceLabels := make(map[string]string) - + var engineResponse *response.EngineResponse policyWithNamespaceSelector := false for _, p := range policy.Spec.Rules { if p.MatchResources.ResourceDescription.NamespaceSelector != nil || @@ -547,7 +547,7 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst resourceNamespace := resource.GetNamespace() namespaceLabels = namespaceSelectorMap[resource.GetNamespace()] if resourceNamespace != "default" && len(namespaceLabels) < 1 { - return &response.EngineResponse{}, policyreport.Info{}, sanitizederror.NewWithError(fmt.Sprintf("failed to get namesapce labels for resource %s. use --values-file flag to pass the namespace labels", resource.GetName()), nil) + return engineResponse, policyreport.Info{}, sanitizederror.NewWithError(fmt.Sprintf("failed to get namesapce labels for resource %s. use --values-file flag to pass the namespace labels", resource.GetName()), nil) } } @@ -575,10 +575,14 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst } mutateResponse := engine.Mutate(&engine.PolicyContext{Policy: *policy, NewResource: *resource, JSONContext: ctx, NamespaceLabels: namespaceLabels}) - err = processMutateEngineResponse(policy, mutateResponse, resPath, rc, mutateLogPath, stdin, mutateLogPathIsDir, resource.GetName()) + + if mutateResponse != nil { + engineResponse = mutateResponse + } + err = processMutateEngineResponse(policy, mutateResponse, resPath, rc, mutateLogPath, stdin, mutateLogPathIsDir, resource.GetName(), printPatchResource) if err != nil { if !sanitizederror.IsErrorSanitized(err) { - return &response.EngineResponse{}, policyreport.Info{}, sanitizederror.NewWithError("failed to print mutated result", err) + return engineResponse, policyreport.Info{}, sanitizederror.NewWithError("failed to print mutated result", err) } } @@ -604,6 +608,9 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst validateResponse = engine.Validate(policyCtx) info = ProcessValidateEngineResponse(policy, validateResponse, resPath, rc, policyReport) } + if validateResponse != nil { + engineResponse = validateResponse + } var policyHasGenerate bool for _, rule := range policy.Spec.Rules { @@ -624,10 +631,13 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst NamespaceLabels: namespaceLabels, } generateResponse := engine.Generate(policyContext) + if validateResponse != nil { + engineResponse = generateResponse + } processGenerateEngineResponse(policy, generateResponse, resPath, rc) } - return validateResponse, info, nil + return engineResponse, info, nil } // PrintMutatedOutput - function to print output in provided file or directory @@ -876,7 +886,7 @@ func SetInStoreContext(mutatedPolicies []*v1.ClusterPolicy, variables map[string return variables } -func processMutateEngineResponse(policy *v1.ClusterPolicy, mutateResponse *response.EngineResponse, resPath string, rc *ResultCounts, mutateLogPath string, stdin bool, mutateLogPathIsDir bool, resourceName string) error { +func processMutateEngineResponse(policy *v1.ClusterPolicy, mutateResponse *response.EngineResponse, resPath string, rc *ResultCounts, mutateLogPath string, stdin bool, mutateLogPathIsDir bool, resourceName string, printPatchResource bool) error { var policyHasMutate bool for _, rule := range policy.Spec.Rules { if rule.HasMutate() { @@ -922,11 +932,12 @@ func processMutateEngineResponse(policy *v1.ClusterPolicy, mutateResponse *respo if mutateLogPath == "" { mutatedResource := string(yamlEncodedResource) + string("\n---") if len(strings.TrimSpace(mutatedResource)) > 0 { - if !stdin { + if !stdin && printPatchResource { fmt.Printf("\nmutate policy %s applied to %s:", policy.Name, resPath) } - fmt.Printf("\n" + mutatedResource) - fmt.Printf("\n") + if printPatchResource { + fmt.Printf("\n" + mutatedResource) + } } } else { err := PrintMutatedOutput(mutateLogPath, mutateLogPathIsDir, string(yamlEncodedResource), resourceName+"-mutated") @@ -993,3 +1004,31 @@ func GetKindsFromPolicy(policy *v1.ClusterPolicy) map[string]struct{} { } return kindOnwhichPolicyIsApplied } + +//GetPatchedResourceFromPath - get patchedResource from given path +func GetPatchedResourceFromPath(fs billy.Filesystem, path string, isGit bool, policyResourcePath string) (unstructured.Unstructured, error) { + var patchedResourceBytes []byte + var patchedResource unstructured.Unstructured + var err error + if isGit { + if len(path) > 0 { + filep, err := fs.Open(filepath.Join(policyResourcePath, path)) + if err != nil { + fmt.Printf("Unable to open patchedResource file: %s. \nerror: %s", path, err) + } + patchedResourceBytes, err = ioutil.ReadAll(filep) + } + } else { + patchedResourceBytes, err = getFileBytes(path) + + } + if err != nil { + fmt.Printf("\n----------------------------------------------------------------------\nfailed to load patchedResource: %s. \nerror: %s\n----------------------------------------------------------------------\n", path, err) + return patchedResource, err + } + patchedResource, err = GetPatchedResource(patchedResourceBytes) + if err != nil { + return patchedResource, err + } + return patchedResource, nil +} diff --git a/pkg/kyverno/common/common_test.go b/pkg/kyverno/common/common_test.go index 4a8f02126d..d34b65839f 100644 --- a/pkg/kyverno/common/common_test.go +++ b/pkg/kyverno/common/common_test.go @@ -98,7 +98,7 @@ func Test_NamespaceSelector(t *testing.T) { for _, tc := range testcases { policyArray, _ := ut.GetPolicy(tc.policy) resourceArray, _ := GetResource(tc.resource) - ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, false, tc.namespaceSelectorMap, false, rc) + ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, false, tc.namespaceSelectorMap, false, rc, false) assert.Assert(t, int64(rc.Pass) == int64(tc.result.Pass)) assert.Assert(t, int64(rc.Fail) == int64(tc.result.Fail)) assert.Assert(t, int64(rc.Skip) == int64(tc.result.Skip)) diff --git a/pkg/kyverno/common/fetch.go b/pkg/kyverno/common/fetch.go index 2958b734fd..f067610e3d 100644 --- a/pkg/kyverno/common/fetch.go +++ b/pkg/kyverno/common/fetch.go @@ -275,6 +275,14 @@ func convertResourceToUnstructured(resourceYaml []byte) (*unstructured.Unstructu return resource, nil } +// GetPatchedResource converts raw bytes to unstructured object +func GetPatchedResource(patchResourceBytes []byte) (patchedResource unstructured.Unstructured, err error) { + getPatchedResource, err := GetResource(patchResourceBytes) + patchedResource = *getPatchedResource[0] + + return patchedResource, nil +} + // getKindsFromPolicy will return the kinds from policy match block func getKindsFromPolicy(rule v1.Rule) map[string]bool { var resourceTypesMap = make(map[string]bool) diff --git a/pkg/kyverno/test/test_command.go b/pkg/kyverno/test/test_command.go index 3518745e76..c6e900f94b 100644 --- a/pkg/kyverno/test/test_command.go +++ b/pkg/kyverno/test/test_command.go @@ -7,6 +7,7 @@ import ( "net/url" "os" "path/filepath" + "regexp" "sort" "strings" "time" @@ -14,11 +15,13 @@ import ( "github.com/fatih/color" "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/memfs" + "github.com/go-logr/logr" "github.com/kataras/tablewriter" report "github.com/kyverno/kyverno/pkg/api/policyreport/v1alpha2" client "github.com/kyverno/kyverno/pkg/dclient" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/engine/utils" + "github.com/kyverno/kyverno/pkg/generate" "github.com/kyverno/kyverno/pkg/kyverno/common" sanitizederror "github.com/kyverno/kyverno/pkg/kyverno/sanitizedError" "github.com/kyverno/kyverno/pkg/kyverno/store" @@ -30,17 +33,105 @@ import ( "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/yaml" log "sigs.k8s.io/controller-runtime/pkg/log" ) +var longHelp = ` +Test command provides a facility to test policies on resources. For that, user needs to provide the path of the folder containing test.yaml file. + + kyverno test /path/to/folderContaningTestYamls + or + kyverno test /path/to/githubRepository + +The test.yaml file is configuration file for test command. It consists of 4 parts:- + "policies" (required) --> element lists one or more path of policies + "resources" (required) --> element lists one or more path of resources. + "variables" (optional) --> element with one variables files + "results" (required) --> element lists one more expected result. +` +var exampleHelp = ` +For Validate Policy + test.yaml + +- name: test-1 + policies: + - + - + resources: + - + - + results: + - policy: + rule: + resource: + namespace: (OPTIONAL) + kind: + result: + +For more visit --> https://kyverno.io/docs/kyverno-cli/#test + + +For Mutate Policy +1) Policy (Namespaced-policy) + + test.yaml + +- name: test-1 + policies: + - + - + resources: + - + - + results: + - policy: / + rule: + resource: + namespace: (OPTIONAL) + patchedResource: + kind: + result: + + +2) ClusterPolicy(cluster-wide policy) + + test.yaml + +- name: test-1 + policies: + - + - + resources: + - + - + results: + - policy: + rule: + resource: + namespace: (OPTIONAL) + kind: + patchedResource: + result: + +NOTE:- +In the results section, policy(if ClusterPolicy) or /(if Policy), rule, resource, kind and result are mandatory fields for all type of policy. + +pass --> patched Resource generated from engine equals to patched Resource provided by the user. +fail --> patched Resource generated from engine is not equals to patched provided by the user. +skip --> rule is not applied. +` + // Command returns version command func Command() *cobra.Command { var cmd *cobra.Command var valuesFile, fileName string cmd = &cobra.Command{ - Use: "test", - Short: "run tests from directory", + Use: "test", + Short: "run tests from directory", + Long: longHelp, + Example: exampleHelp, RunE: func(cmd *cobra.Command, dirPath []string) (err error) { defer func() { if err != nil { @@ -76,6 +167,9 @@ type TestResults struct { Result report.PolicyResult `json:"result"` Status report.PolicyResult `json:"status"` Resource string `json:"resource"` + Kind string `json:"kind"` + Namespace string `json:"namespace"` + PatchedResource string `json:"patchedResource"` AutoGeneratedRule string `json:"auto_generated_rule"` } @@ -235,19 +329,21 @@ func getLocalDirTestFiles(fs billy.Filesystem, path, fileName, valuesFile string return errors } -func buildPolicyResults(resps []*response.EngineResponse, testResults []TestResults, infos []policyreport.Info) (map[string]report.PolicyReportResult, []TestResults) { +func buildPolicyResults(resps []*response.EngineResponse, testResults []TestResults, infos []policyreport.Info, policyResourcePath string, fs billy.Filesystem, isGit bool) (map[string]report.PolicyReportResult, []TestResults) { results := make(map[string]report.PolicyReportResult) now := metav1.Timestamp{Seconds: time.Now().Unix()} for _, resp := range resps { policyName := resp.PolicyResponse.Policy.Name resourceName := resp.PolicyResponse.Resource.Name + resourceKind := resp.PolicyResponse.Resource.Kind + resourceNamespace := resp.PolicyResponse.Resource.Namespace + policyNamespace := resp.PolicyResponse.Policy.Namespace var rules []string for _, rule := range resp.PolicyResponse.Rules { rules = append(rules, rule.Name) } - result := report.PolicyReportResult{ Policy: policyName, Resources: []*corev1.ObjectReference{ @@ -256,9 +352,19 @@ func buildPolicyResults(resps []*response.EngineResponse, testResults []TestResu }, }, } - + var patcheResourcePath []string for i, test := range testResults { + var userDefinedPolicyNamespace string + var userDefinedPolicyName string + found, _ := isNamespacedPolicy(test.Policy) + if found { + userDefinedPolicyNamespace, userDefinedPolicyName = getUserDefinedPolicyNameAndNamespace(test.Policy) + test.Policy = userDefinedPolicyName + } + if test.Policy == policyName && test.Resource == resourceName { + var resultsKey string + resultsKey = GetResultKeyAccordingToTestResults(userDefinedPolicyNamespace, test.Policy, test.Rule, test.Namespace, test.Kind, test.Resource) if !util.ContainsString(rules, test.Rule) { if !util.ContainsString(rules, "autogen-"+test.Rule) { if !util.ContainsString(rules, "autogen-cronjob-"+test.Rule) { @@ -266,18 +372,55 @@ func buildPolicyResults(resps []*response.EngineResponse, testResults []TestResu } else { testResults[i].AutoGeneratedRule = "autogen-cronjob" test.Rule = "autogen-cronjob-" + test.Rule + resultsKey = GetResultKeyAccordingToTestResults(userDefinedPolicyNamespace, test.Policy, test.Rule, test.Namespace, test.Kind, test.Resource) } } else { testResults[i].AutoGeneratedRule = "autogen" test.Rule = "autogen-" + test.Rule + resultsKey = GetResultKeyAccordingToTestResults(userDefinedPolicyNamespace, test.Policy, test.Rule, test.Namespace, test.Kind, test.Resource) + } + if results[resultsKey].Result == "" { + result.Result = report.StatusSkip + results[resultsKey] = result } } - resultsKey := fmt.Sprintf("%s-%s-%s", test.Policy, test.Rule, test.Resource) + patcheResourcePath = append(patcheResourcePath, test.PatchedResource) + if _, ok := results[resultsKey]; !ok { results[resultsKey] = result } } + + } + + for _, rule := range resp.PolicyResponse.Rules { + if rule.Type != utils.Mutation.String() { + continue + } + var resultsKey []string + var resultKey string + + var result report.PolicyReportResult + resultsKey = GetAllPossibleResultsKey(policyNamespace, policyName, rule.Name, resourceNamespace, resourceKind, resourceName) + for _, resultK := range resultsKey { + if val, ok := results[resultK]; ok { + result = val + resultKey = resultK + } else { + continue + } + var x string + for _, path := range patcheResourcePath { + result.Result = report.StatusFail + x = getAndComparePatchedResource(path, resp.PatchedResource, isGit, policyResourcePath, fs) + if x == "pass" { + result.Result = report.StatusPass + break + } + } + results[resultKey] = result + } } } @@ -289,18 +432,23 @@ func buildPolicyResults(resps []*response.EngineResponse, testResults []TestResu } var result report.PolicyReportResult - resultsKey := fmt.Sprintf("%s-%s-%s", info.PolicyName, rule.Name, infoResult.Resource.Name) - if val, ok := results[resultsKey]; ok { - result = val - } else { - continue + var resultsKey []string + var resultKey string + resultsKey = GetAllPossibleResultsKey("", info.PolicyName, rule.Name, infoResult.Resource.Namespace, infoResult.Resource.Kind, infoResult.Resource.Name) + for _, resultK := range resultsKey { + if val, ok := results[resultK]; ok { + result = val + resultKey = resultK + } else { + continue + } } result.Rule = rule.Name result.Result = report.PolicyResult(rule.Check) result.Source = policyreport.SourceValue result.Timestamp = now - results[resultsKey] = result + results[resultKey] = result } } } @@ -308,20 +456,89 @@ func buildPolicyResults(resps []*response.EngineResponse, testResults []TestResu return results, testResults } -func getPolicyResourceFullPath(path []string, policyResourcePath string, isGit bool) []string { +func GetAllPossibleResultsKey(policyNamespace, policy, rule, namespace, kind, resource string) []string { + var resultsKey []string + resultKey1 := fmt.Sprintf("%s-%s-%s-%s", policy, rule, kind, resource) + resultKey2 := fmt.Sprintf("%s-%s-%s-%s-%s", policy, rule, namespace, kind, resource) + resultKey3 := fmt.Sprintf("%s-%s-%s-%s-%s", policyNamespace, policy, rule, kind, resource) + resultKey4 := fmt.Sprintf("%s-%s-%s-%s-%s-%s", policyNamespace, policy, rule, namespace, kind, resource) + resultsKey = append(resultsKey, resultKey1, resultKey2, resultKey3, resultKey4) + return resultsKey +} + +func GetResultKeyAccordingToTestResults(policyNs, policy, rule, namespace, kind, resource string) string { + var resultKey string + resultKey = fmt.Sprintf("%s-%s-%s-%s", policy, rule, kind, resource) + + if namespace != "" || policyNs != "" { + if policyNs != "" { + resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", policyNs, policy, rule, kind, resource) + if namespace != "" { + resultKey = fmt.Sprintf("%s-%s-%s-%s-%s-%s", policyNs, policy, rule, namespace, kind, resource) + } + } else { + resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", policy, rule, namespace, kind, resource) + } + } + return resultKey +} + +func isNamespacedPolicy(policyNames string) (bool, error) { + return regexp.MatchString("^[a-z]*/[a-z]*", policyNames) +} + +func getUserDefinedPolicyNameAndNamespace(policyName string) (string, string) { + policy := policyName + policy_n_ns := strings.Split(policyName, "/") + namespace := policy_n_ns[0] + policy = policy_n_ns[1] + return namespace, policy +} + +// getAndComparePatchedResource --> Get the patchedResource from the path provided by user +// And compare this patchedResource with engine generated patcheResource. +func getAndComparePatchedResource(path string, enginePatchedResource unstructured.Unstructured, isGit bool, policyResourcePath string, fs billy.Filesystem) string { + var status string + patchedResources, err := common.GetPatchedResourceFromPath(fs, path, isGit, policyResourcePath) + if err != nil { + os.Exit(1) + } + var log logr.Logger + matched, err := generate.ValidateResourceWithPattern(log, enginePatchedResource.UnstructuredContent(), patchedResources.UnstructuredContent()) + + if err != nil { + status = "fail" + } + if matched == "" { + status = "pass" + } + return status +} + +func getPolicyResourceFullPaths(path []string, policyResourcePath string, isGit bool) []string { var pol []string if !isGit { for _, p := range path { - pol = append(pol, filepath.Join(policyResourcePath, p)) + pol = append(pol, getPolicyResourceFullPath(p, policyResourcePath, isGit)) } return pol } return path } +func getPolicyResourceFullPath(path string, policyResourcePath string, isGit bool) string { + var pol string + if !isGit { + pol = filepath.Join(policyResourcePath, path) + + return pol + } + return path +} + func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, valuesFile string, isGit bool, policyResourcePath string, rc *resultCounts) (err error) { openAPIController, err := openapi.NewOpenAPIController() - validateEngineResponses := make([]*response.EngineResponse, 0) + engineResponses := make([]*response.EngineResponse, 0) var dClient *client.Client values := &Test{} var variablesString string @@ -343,9 +560,15 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, valuesFile s return err } - fullPolicyPath := getPolicyResourceFullPath(values.Policies, policyResourcePath, isGit) - fullResourcePath := getPolicyResourceFullPath(values.Resources, policyResourcePath, isGit) + fullPolicyPath := getPolicyResourceFullPaths(values.Policies, policyResourcePath, isGit) + fullResourcePath := getPolicyResourceFullPaths(values.Resources, policyResourcePath, isGit) + for i, result := range values.Results { + var a []string + a = append(a, result.PatchedResource) + a = getPolicyResourceFullPaths(a, policyResourcePath, isGit) + values.Results[i].PatchedResource = a[0] + } policies, err := common.GetPoliciesFromPaths(fs, fullPolicyPath, isGit, policyResourcePath) if err != nil { fmt.Printf("Error: failed to load policies\nCause: %s\n", err) @@ -411,16 +634,15 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, valuesFile s return sanitizederror.NewWithError(fmt.Sprintf("policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag", policy.Name, resource.GetName()), err) } - validateErs, info, err := common.ApplyPolicyOnResource(policy, resource, "", false, thisPolicyResourceValues, true, namespaceSelectorMap, false, &resultCounts) + ers, info, err := common.ApplyPolicyOnResource(policy, resource, "", false, thisPolicyResourceValues, true, namespaceSelectorMap, false, &resultCounts, false) if err != nil { return sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err) } - validateEngineResponses = append(validateEngineResponses, validateErs) + engineResponses = append(engineResponses, ers) pvInfos = append(pvInfos, info) } } - resultsMap, testResults := buildPolicyResults(validateEngineResponses, values.Results, pvInfos) - + resultsMap, testResults := buildPolicyResults(engineResponses, values.Results, pvInfos, policyResourcePath, fs, isGit) resultErr := printTestResult(resultsMap, testResults, rc) if resultErr != nil { return sanitizederror.NewWithError("Unable to genrate result. Error:", resultErr) @@ -440,17 +662,34 @@ func printTestResult(resps map[string]report.PolicyReportResult, testResults []T res.ID = i + 1 res.Policy = boldFgCyan.Sprintf(v.Policy) res.Rule = boldFgCyan.Sprintf(v.Rule) - res.Resource = boldFgCyan.Sprintf(v.Resource) - + namespace := "default" + if v.Namespace != "" { + namespace = v.Namespace + } + res.Resource = boldFgCyan.Sprintf(namespace) + "/" + boldFgCyan.Sprintf(v.Kind) + "/" + boldFgCyan.Sprintf(v.Resource) var ruleNameInResultKey string if v.AutoGeneratedRule != "" { ruleNameInResultKey = fmt.Sprintf("%s-%s", v.AutoGeneratedRule, v.Rule) } else { ruleNameInResultKey = v.Rule } - - resultKey := fmt.Sprintf("%s-%s-%s", v.Policy, ruleNameInResultKey, v.Resource) - + resultKey := fmt.Sprintf("%s-%s-%s-%s", v.Policy, ruleNameInResultKey, v.Kind, v.Resource) + found, _ := isNamespacedPolicy(v.Policy) + if found || v.Namespace != "" { + if found { + var ns string + ns, v.Policy = getUserDefinedPolicyNameAndNamespace(v.Policy) + resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", ns, v.Policy, ruleNameInResultKey, v.Kind, v.Resource) + res.Policy = boldFgCyan.Sprintf(ns) + "/" + boldFgCyan.Sprintf(v.Policy) + res.Resource = boldFgCyan.Sprintf(namespace) + "/" + boldFgCyan.Sprintf(v.Kind) + "/" + boldFgCyan.Sprintf(v.Resource) + if v.Namespace != "" { + resultKey = fmt.Sprintf("%s-%s-%s-%s-%s-%s", ns, v.Policy, ruleNameInResultKey, v.Namespace, v.Kind, v.Resource) + } + } else { + res.Resource = boldFgCyan.Sprintf(namespace) + "/" + boldFgCyan.Sprintf(v.Kind) + "/" + boldFgCyan.Sprintf(v.Resource) + resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", v.Policy, ruleNameInResultKey, v.Namespace, v.Kind, v.Resource) + } + } var testRes report.PolicyReportResult if val, ok := resps[resultKey]; ok { testRes = val @@ -465,7 +704,7 @@ func printTestResult(resps map[string]report.PolicyReportResult, testResults []T } if testRes.Result == v.Result { if testRes.Result == report.StatusSkip { - res.Result = boldGreen.Sprintf("Pass") + res.Result = boldYellow.Sprintf("Skip") rc.Skip++ } else { res.Result = boldGreen.Sprintf("Pass") @@ -487,6 +726,7 @@ func printTestResult(resps map[string]report.PolicyReportResult, testResults []T } printer.HeaderBgColor = tablewriter.BgBlackColor printer.HeaderFgColor = tablewriter.FgGreenColor + fmt.Printf("\n") printer.Print(table) return nil } diff --git a/pkg/utils/loadpolicy.go b/pkg/utils/loadpolicy.go index 58f39934e8..6a621b7ad1 100644 --- a/pkg/utils/loadpolicy.go +++ b/pkg/utils/loadpolicy.go @@ -40,6 +40,12 @@ func GetPolicy(bytes []byte) (clusterPolicies []*v1.ClusterPolicy, err error) { return nil, fmt.Errorf(msg) } + if (policy.Namespace != "" || policy.Namespace == "") && policy.Kind == "Policy" { + if policy.Namespace == "" { + policy.Namespace = "default" + } + policy.Kind = "ClusterPolicy" + } clusterPolicies = append(clusterPolicies, policy) } diff --git a/test/cli/test-fail/missing-policy/test.yaml b/test/cli/test-fail/missing-policy/test.yaml index f177943769..3341796829 100644 --- a/test/cli/test-fail/missing-policy/test.yaml +++ b/test/cli/test-fail/missing-policy/test.yaml @@ -7,4 +7,5 @@ results: - policy: missing rule: validate-image-tag resource: test + kind: Pod result: pass diff --git a/test/cli/test-fail/missing-resource/test.yaml b/test/cli/test-fail/missing-resource/test.yaml index 5a3d42ede7..3b4eb9ce3f 100644 --- a/test/cli/test-fail/missing-resource/test.yaml +++ b/test/cli/test-fail/missing-resource/test.yaml @@ -7,4 +7,5 @@ results: - policy: disallow-latest-tag rule: validate-image-tag resource: missing + kind: Pod result: pass diff --git a/test/cli/test-fail/missing-rule/test.yaml b/test/cli/test-fail/missing-rule/test.yaml index 78b6f68665..c2bea69460 100644 --- a/test/cli/test-fail/missing-rule/test.yaml +++ b/test/cli/test-fail/missing-rule/test.yaml @@ -7,4 +7,5 @@ results: - policy: disallow-latest-tag rule: missing resource: test + kind: Pod status: pass diff --git a/test/cli/test-mutate/patchedResource1.yaml b/test/cli/test-mutate/patchedResource1.yaml new file mode 100644 index 0000000000..72e56c98eb --- /dev/null +++ b/test/cli/test-mutate/patchedResource1.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + labels: + foo: bar + color: orange + name: resource-equal-to-patch-res-for-cp + namespace: practice +spec: + containers: + - image: nginx:latest + name: nginx + dnsConfig: + options: + - name: ndots + value: "1" \ No newline at end of file diff --git a/test/cli/test-mutate/patchedResource10.yaml b/test/cli/test-mutate/patchedResource10.yaml new file mode 100644 index 0000000000..5c150b393f --- /dev/null +++ b/test/cli/test-mutate/patchedResource10.yaml @@ -0,0 +1,25 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mydeploy + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + dnsConfig: + options: + - name: ndots + value: "1" diff --git a/test/cli/test-mutate/patchedResource11.yaml b/test/cli/test-mutate/patchedResource11.yaml new file mode 100644 index 0000000000..9b6e986d6c --- /dev/null +++ b/test/cli/test-mutate/patchedResource11.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: same-name-but-diff-kind + labels: + foo: bar +spec: + containers: + - name: nginx + image: nginx:latest \ No newline at end of file diff --git a/test/cli/test-mutate/patchedResource2.yaml b/test/cli/test-mutate/patchedResource2.yaml new file mode 100644 index 0000000000..e9dda00052 --- /dev/null +++ b/test/cli/test-mutate/patchedResource2.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: same-name-but-diff-namespace + labels: + foo: bar + color: orange + namespace: testing +spec: + containers: + - name: nginx + image: nginx:latest \ No newline at end of file diff --git a/test/cli/test-mutate/patchedResource3.yaml b/test/cli/test-mutate/patchedResource3.yaml new file mode 100644 index 0000000000..195ab624ca --- /dev/null +++ b/test/cli/test-mutate/patchedResource3.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: same-name-but-diff-namespace + labels: + foo: bar + color: orange + namespace: production +spec: + containers: + - name: nginx + image: nginx:latest \ No newline at end of file diff --git a/test/cli/test-mutate/patchedResource4.yaml b/test/cli/test-mutate/patchedResource4.yaml new file mode 100644 index 0000000000..86f051a2b6 --- /dev/null +++ b/test/cli/test-mutate/patchedResource4.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: mydeploy +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + color: orange + spec: + containers: + - image: nginx:1.14.2 + name: nginx + ports: + - containerPort: 80 + diff --git a/test/cli/test-mutate/patchedResource5.yaml b/test/cli/test-mutate/patchedResource5.yaml new file mode 100644 index 0000000000..851afeef1a --- /dev/null +++ b/test/cli/test-mutate/patchedResource5.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: same-name-but-diff-kind +spec: + selector: + app: MyApp + ports: + - port: 80 + targetPort: 80 + nodePort: 30007 + type: NodePort \ No newline at end of file diff --git a/test/cli/test-mutate/patchedResource6.yaml b/test/cli/test-mutate/patchedResource6.yaml new file mode 100644 index 0000000000..29a7c205a4 --- /dev/null +++ b/test/cli/test-mutate/patchedResource6.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Pod +metadata: + name: same-name-but-diff-kind + labels: + foo: bar + color: orange +spec: + containers: + - name: nginx + image: nginx:latest \ No newline at end of file diff --git a/test/cli/test-mutate/patchedResource7.yaml b/test/cli/test-mutate/patchedResource7.yaml new file mode 100644 index 0000000000..6691ff130f --- /dev/null +++ b/test/cli/test-mutate/patchedResource7.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + labels: + foo: bar + color: orange + name: resource-equal-to-patch-res-for-cp + namespace: practice +spec: + containers: + - image: nginx:latest + name: nginx + dnsConfig: + options: + - name: ndots + value: "1" diff --git a/test/cli/test-mutate/patchedResource8.yaml b/test/cli/test-mutate/patchedResource8.yaml new file mode 100644 index 0000000000..4754a1f6b2 --- /dev/null +++ b/test/cli/test-mutate/patchedResource8.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + labels: + foo: bar + name: same-name-but-diff-namespace + namespace: testing +spec: + containers: + - image: nginx:latest + name: nginx + dnsConfig: + options: + - name: ndots + value: "1" \ No newline at end of file diff --git a/test/cli/test-mutate/patchedResource9.yaml b/test/cli/test-mutate/patchedResource9.yaml new file mode 100644 index 0000000000..7605238a09 --- /dev/null +++ b/test/cli/test-mutate/patchedResource9.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Pod +metadata: + name: same-name-but-diff-namespace + labels: + foo: bar + namespace: production +spec: + containers: + - name: nginx + image: nginx:latest \ No newline at end of file diff --git a/test/cli/test-mutate/policy.yaml b/test/cli/test-mutate/policy.yaml new file mode 100644 index 0000000000..1d9050b7e3 --- /dev/null +++ b/test/cli/test-mutate/policy.yaml @@ -0,0 +1,62 @@ +# Below there are both type of olicies: ClusterPolicy and Policy(Namespaced-Policy) + +#ClusterPolicy +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: add-label + annotations: + policies.kyverno.io/title: Add nodeSelector + policies.kyverno.io/category: Sample + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Labels are used as an important source of metadata describing objects in various ways + or triggering other functionality. Labels are also a very basic concept and should be + used throughout Kubernetes. This policy performs a simple mutation which adds a label + `color=orange` to Pods, Services, ConfigMaps, and Secrets. +spec: + background: false + validationFailureAction: + rules: + - name: add-label + match: + resources: + kinds: + - Pod + mutate: + patchStrategicMerge: + metadata: + labels: + color: orange + +--- + +# Policy ( In testing namespace ) +apiVersion: kyverno.io/v1 +kind: Policy +metadata: + name: add-ndots + namespace: testing + annotations: + policies.kyverno.io/title: Add ndots + policies.kyverno.io/category: Sample + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + The ndots value controls where DNS lookups are first performed in a cluster + and needs to be set to a lower value than the default of 5 in some cases. + This policy mutates all Pods to add the ndots option with a value of 1. +spec: + background: false + rules: + - name: add-ndots + match: + resources: + kinds: + - Pod + mutate: + patchStrategicMerge: + spec: + dnsConfig: + options: + - name: ndots + value: "1" \ No newline at end of file diff --git a/test/cli/test-mutate/resource.yaml b/test/cli/test-mutate/resource.yaml new file mode 100644 index 0000000000..b66186af9e --- /dev/null +++ b/test/cli/test-mutate/resource.yaml @@ -0,0 +1,100 @@ +# resource == patchedResource +apiVersion: v1 +kind: Pod +metadata: + labels: + foo: bar + color: orange + name: resource-equal-to-patch-res-for-cp + namespace: practice +spec: + containers: + - image: nginx:latest + name: nginx + +--- +# Resource with same name and diff. namespace +# Same namespace as namespaced-policy +apiVersion: v1 +kind: Pod +metadata: + name: same-name-but-diff-namespace + labels: + foo: bar + namespace: testing +spec: + containers: + - name: nginx + image: nginx:latest + +--- +# Resource with same name and diff. namespace +# Namespace differ from namespaced-policy +apiVersion: v1 +kind: Pod +metadata: + name: same-name-but-diff-namespace + labels: + foo: bar + namespace: production +spec: + containers: + - name: nginx + image: nginx:latest + +--- + +# Deployment in default namespace +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mydeploy + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + +--- + +# Resource (Service) with same name but different kind +apiVersion: v1 +kind: Service +metadata: + name: same-name-but-diff-kind +spec: + selector: + app: MyApp + ports: + - port: 80 + targetPort: 80 + nodePort: 30007 + type: NodePort + +--- + +# Resource (Pod) with same name but different kind +apiVersion: v1 +kind: Pod +metadata: + name: same-name-but-diff-kind + labels: + foo: bar +spec: + containers: + - name: nginx + image: nginx:latest + + diff --git a/test/cli/test-mutate/test.yaml b/test/cli/test-mutate/test.yaml new file mode 100644 index 0000000000..0b8925e206 --- /dev/null +++ b/test/cli/test-mutate/test.yaml @@ -0,0 +1,86 @@ +name: add-nodeselector +policies: + - policy.yaml +resources: + - resource.yaml +results: + - policy: add-label + rule: add-label + resource: resource-equal-to-patch-res-for-cp + patchedResource: patchedResource1.yaml + kind: Pod + namespace: practice + result: skip + - policy: add-label + rule: add-label + resource: same-name-but-diff-namespace + patchedResource: patchedResource2.yaml + kind: Pod + namespace: testing + result: pass + - policy: add-label + rule: add-label + resource: same-name-but-diff-namespace + patchedResource: patchedResource3.yaml + kind: Pod + namespace: production + result: pass + - policy: add-label + rule: add-label + resource: mydeploy + patchedResource: patchedResource4.yaml + kind: Deployment + result: pass + - policy: add-label + rule: add-label + resource: same-name-but-diff-kind + patchedResource: patchedResource5.yaml + kind: Service + result: skip + - policy: add-label + rule: add-label + resource: same-name-but-diff-kind + patchedResource: patchedResource6.yaml + kind: Pod + result: pass + + + - policy: testing/add-ndots + rule: add-ndots + resource: resource-equal-to-patch-res-for-cp + namespace: practice + patchedResource: patchedResource7.yaml + kind: Pod + result: skip + - policy: testing/add-ndots + rule: add-ndots + resource: same-name-but-diff-namespace + patchedResource: patchedResource8.yaml + namespace: testing + kind: Pod + result: pass + - policy: testing/add-ndots + rule: add-ndots + resource: same-name-but-diff-namespace + patchedResource: patchedResource9.yaml + kind: Pod + namespace: production + result: skip + - policy: testing/add-ndots + rule: add-ndots + resource: mydeploy + patchedResource: patchedResource10.yaml + kind: Deployment + result: skip + - policy: testing/add-ndots + rule: add-ndots + resource: same-name-but-diff-kind + patchedResource: patchedResource5.yaml + kind: Service + result: skip + - policy: testing/add-ndots + rule: add-ndots + resource: same-name-but-diff-kind + patchedResource: patchedResource11.yaml + kind: Pod + result: skip diff --git a/test/cli/test/autogen/test.yaml b/test/cli/test/autogen/test.yaml index d6bef7195f..bf19c8746f 100644 --- a/test/cli/test/autogen/test.yaml +++ b/test/cli/test/autogen/test.yaml @@ -7,46 +7,54 @@ results: - policy: require-common-labels rule: check-for-labels result: pass + kind: Pod resource: pod-with-labels # TEST: Pod Missing Labels Should Fail - policy: require-common-labels rule: check-for-labels result: fail + kind: Pod resource: pod-missing-labels # TEST: Deployment with Labels Should Pass - policy: require-common-labels rule: check-for-labels result: pass + kind: Deployment resource: deployment-with-labels # TEST: Deployment with Labels Should Fail - policy: require-common-labels rule: check-for-labels result: fail + kind: Deployment resource: deployment-missing-labels # TEST: StatefulSet with Labels Should Pass - policy: require-common-labels rule: check-for-labels result: pass + kind: StatefulSet resource: StatefulSet-with-labels # TEST: StatefulSet with Labels Should fail - policy: require-common-labels rule: check-for-labels result: fail + kind: StatefulSet resource: StatefulSet-without-labels # TEST: Cronjob with Labels Should pass - policy: require-common-labels rule: check-for-labels result: pass + kind: CronJob resource: cronjob-with-labels # TEST: Cronjob without Labels Should fail - policy: require-common-labels rule: check-for-labels result: fail + kind: CronJob resource: cronjob-without-labels diff --git a/test/cli/test/simple/test.yaml b/test/cli/test/simple/test.yaml index e5b6b01ec0..3abb5c2d47 100644 --- a/test/cli/test/simple/test.yaml +++ b/test/cli/test/simple/test.yaml @@ -7,20 +7,25 @@ results: - policy: disallow-latest-tag rule: require-image-tag resource: test-require-image-tag-pass + kind: Pod status: pass - policy: disallow-latest-tag rule: require-image-tag resource: test-require-image-tag-fail + kind: Pod status: fail - policy: disallow-latest-tag rule: validate-image-tag resource: test-validate-image-tag-ignore + kind: Pod status: skip - policy: disallow-latest-tag rule: validate-image-tag resource: test-validate-image-tag-fail + kind: Pod status: fail - policy: disallow-latest-tag rule: validate-image-tag resource: test-validate-image-tag-pass + kind: Pod status: pass diff --git a/test/cli/test/variables/test.yaml b/test/cli/test/variables/test.yaml index efb634a873..d29f364055 100644 --- a/test/cli/test/variables/test.yaml +++ b/test/cli/test/variables/test.yaml @@ -11,18 +11,22 @@ results: - policy: cm-variable-example rule: example-configmap-lookup resource: test-env-test + kind: Pod result: pass - policy: cm-variable-example rule: example-configmap-lookup resource: test-env-dev + kind: Pod result: fail - policy: cm-array-example rule: validate-role-annotation resource: test-web + kind: Pod result: fail - policy: cm-array-example rule: validate-role-annotation resource: test-app + kind: Pod result: pass - policy: cm-blk-scalar-example rule: validate-blk-role-annotation