1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

refactor: cli test command (#8212)

* code changes

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* test changes

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

---------

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-09-04 11:34:27 +02:00 committed by GitHub
parent 6b7c204f05
commit c93ac4655c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 373 additions and 706 deletions

View file

@ -695,37 +695,47 @@ test-kuttl: $(KUTTL) ## Run kuttl tests
#############
TEST_GIT_BRANCH ?= main
TEST_GIT_REPO ?= https://github.com/kyverno/policies
.PHONY: test-cli
test-cli: test-cli-policies test-cli-local test-cli-local-mutate test-cli-local-generate test-cli-test-case-selector-flag test-cli-registry test-cli-scenarios-to-cli ## Run all CLI tests
test-cli: test-cli-policies test-cli-local ## Run all CLI tests
.PHONY: test-cli-policies
test-cli-policies: $(CLI_BIN)
@echo Testing against branch $(TEST_GIT_BRANCH)...
@$(CLI_BIN) test https://github.com/kyverno/policies/$(TEST_GIT_BRANCH)
test-cli-policies: $(CLI_BIN) ## Run CLI tests against the policies repository
@echo Running cli tests against $(TEST_GIT_REPO)/$(TEST_GIT_BRANCH)... >&2
@$(CLI_BIN) test https://github.com/eddycharly/policies/test-refactor
.PHONY: test-cli-local
test-cli-local: $(CLI_BIN)
test-cli-local: test-cli-local-validate test-cli-local-mutate test-cli-local-generate test-cli-local-registry test-cli-local-scenarios test-cli-local-selector ## Run local CLI tests
.PHONY: test-cli-local-validate
test-cli-local-validate: $(CLI_BIN) ## Run local CLI validation tests
@echo Running local cli validation tests... >&2
@$(CLI_BIN) test ./test/cli/test
.PHONY: test-cli-local-mutate
test-cli-local-mutate: $(CLI_BIN)
test-cli-local-mutate: $(CLI_BIN) ## Run local CLI mutation tests
@echo Running local cli mutation tests... >&2
@$(CLI_BIN) test ./test/cli/test-mutate
.PHONY: test-cli-local-generate
test-cli-local-generate: $(CLI_BIN)
test-cli-local-generate: $(CLI_BIN) ## Run local CLI generation tests
@echo Running local cli generation tests... >&2
@$(CLI_BIN) test ./test/cli/test-generate
.PHONY: test-cli-test-case-selector-flag
test-cli-test-case-selector-flag: $(CLI_BIN)
.PHONY: test-cli-local-selector
test-cli-local-selector: $(CLI_BIN) ## Run local CLI tests (with test case selector)
@echo Running local cli selector tests... >&2
@$(CLI_BIN) test ./test/cli/test --test-case-selector "policy=disallow-latest-tag, rule=require-image-tag, resource=test-require-image-tag-pass"
.PHONY: test-cli-registry
test-cli-registry: $(CLI_BIN)
.PHONY: test-cli-local-registry
test-cli-local-registry: $(CLI_BIN) ## Run local CLI registry tests
@echo Running local cli registry tests... >&2
@$(CLI_BIN) test ./test/cli/registry --registry
.PHONY: test-cli-scenarios-to-cli
test-cli-scenarios-to-cli: $(CLI_BIN)
.PHONY: test-cli-local-scenarios
test-cli-local-scenarios: $(CLI_BIN) ## Run local CLI scenarios tests
@echo Running local cli scenarios tests... >&2
@$(CLI_BIN) test ./test/cli/scenarios_to_cli --registry
#############

View file

@ -49,9 +49,6 @@ type TestResults struct {
// CloneSourceResource takes the resource configuration file in yaml format
// from the user which is meant to be cloned by the generate rule.
CloneSourceResource string `json:"cloneSourceResource,omitempty"`
// AutoGeneratedRule is internally set by the CLI command. It takes values either
// autogen or autogen-cronjob.
AutoGeneratedRule string `json:"auto_generated_rule,omitempty"`
}
type Policy struct {

View file

@ -4,19 +4,21 @@ import (
"fmt"
"os"
"github.com/go-git/go-billy/v5"
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/test/api"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/color"
filterutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/filter"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/output/table"
reportutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/report"
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/openapi"
"github.com/spf13/cobra"
"sigs.k8s.io/controller-runtime/pkg/log"
)
// Command returns version command
func Command() *cobra.Command {
var cmd *cobra.Command
var testCase string
@ -39,7 +41,7 @@ func Command() *cobra.Command {
}
}()
store.SetRegistryAccess(registryAccess)
_, err = testCommandExecute(dirPath, fileName, gitBranch, testCase, failOnly, false, detailedResults)
_, err = testCommandExecute(dirPath, fileName, gitBranch, testCase, failOnly, detailedResults)
if err != nil {
log.Log.V(3).Info("a directory is required")
return err
@ -69,7 +71,6 @@ func testCommandExecute(
gitBranch string,
testCase string,
failOnly bool,
auditWarn bool,
detailedResults bool,
) (rc *resultCounts, err error) {
// check input dir
@ -113,7 +114,7 @@ func testCommandExecute(
rc = &resultCounts{}
var table table.Table
for _, p := range policies {
if reports, tests, err := applyPoliciesFromPath(
if tests, responses, err := applyPoliciesFromPath(
fs,
p.test,
fs != nil,
@ -121,10 +122,10 @@ func testCommandExecute(
rc,
openApiManager,
filter,
auditWarn,
false,
); err != nil {
return rc, sanitizederror.NewWithError("failed to apply test command", err)
} else if t, err := printTestResult(reports, tests, rc, failOnly, detailedResults); err != nil {
} else if t, err := printTestResult(tests, responses, rc, failOnly, detailedResults, fs, p.resourcePath); err != nil {
return rc, sanitizederror.NewWithError("failed to print test result:", err)
} else {
table.AddFailed(t.RawRows...)
@ -146,191 +147,153 @@ func testCommandExecute(
return rc, nil
}
func printTestResult(resps map[string]policyreportv1alpha2.PolicyReportResult, testResults []api.TestResults, rc *resultCounts, failOnly bool, detailedResults bool) (table.Table, error) {
func checkResult(test api.TestResults, fs billy.Filesystem, resoucePath string, response engineapi.EngineResponse, rule engineapi.RuleResponse) (bool, string, string) {
expected := test.Result
// fallback to the deprecated field
if expected == "" {
expected = test.Status
}
// fallback on deprecated field
if test.PatchedResource != "" {
equals, err := getAndCompareResource(test.PatchedResource, response.PatchedResource, fs, resoucePath, false)
if err != nil {
return false, err.Error(), "Resource error"
}
if !equals {
return false, "Patched resource didn't match the patched resource in the test result", "Resource diff"
}
}
if test.GeneratedResource != "" {
equals, err := getAndCompareResource(test.GeneratedResource, rule.GeneratedResource(), fs, resoucePath, true)
if err != nil {
return false, err.Error(), "Resource error"
}
if !equals {
return false, "Generated resource didn't match the generated resource in the test result", "Resource diff"
}
}
result := reportutils.ComputePolicyReportResult(false, response, rule)
if result.Result != expected {
return false, result.Message, fmt.Sprintf("Want %s, got %s", expected, result.Result)
}
return true, result.Message, "Ok"
}
func lookupEngineResponses(test api.TestResults, resourceName string, responses ...engineapi.EngineResponse) []engineapi.EngineResponse {
var matches []engineapi.EngineResponse
for _, response := range responses {
policy := response.Policy()
resource := response.Resource
if policy.GetName() != test.Policy {
continue
}
if test.Kind != resource.GetKind() {
continue
}
if resourceName != "" && resourceName != resource.GetName() {
continue
}
if test.Namespace != "" && test.Namespace != resource.GetNamespace() {
continue
}
matches = append(matches, response)
}
return matches
}
func lookupRuleResponses(test api.TestResults, responses ...engineapi.RuleResponse) []engineapi.RuleResponse {
var matches []engineapi.RuleResponse
for _, response := range responses {
rule := response.Name()
if rule != test.Rule && rule != "autogen-"+test.Rule && rule != "autogen-cronjob-"+test.Rule {
continue
}
matches = append(matches, response)
}
return matches
}
func printTestResult(
tests []api.TestResults,
responses []engineapi.EngineResponse,
rc *resultCounts,
failOnly bool,
detailedResults bool,
fs billy.Filesystem,
resoucePath string,
) (table.Table, error) {
printer := table.NewTablePrinter()
var resultsTable table.Table
var countDeprecatedResource int
testCount := 1
for _, v := range testResults {
var row table.Row
row.ID = testCount
if v.Resources == nil {
testCount++
}
row.Policy = color.Policy("", v.Policy)
row.Rule = color.Rule(v.Rule)
if v.Resources != nil {
for _, resource := range v.Resources {
row.ID = testCount
testCount++
row.Resource = color.Resource(v.Kind, v.Namespace, resource)
var ruleNameInResultKey string
if !v.IsValidatingAdmissionPolicy {
if v.AutoGeneratedRule != "" {
ruleNameInResultKey = fmt.Sprintf("%s-%s", v.AutoGeneratedRule, v.Rule)
} else {
ruleNameInResultKey = v.Rule
}
}
var resultKey string
if !v.IsValidatingAdmissionPolicy {
resultKey = fmt.Sprintf("%s-%s-%s-%s", v.Policy, ruleNameInResultKey, v.Kind, resource)
} else {
resultKey = fmt.Sprintf("%s-%s-%s", v.Policy, v.Kind, resource)
}
found, _ := isNamespacedPolicy(v.Policy)
var ns string
ns, v.Policy = getUserDefinedPolicyNameAndNamespace(v.Policy)
if found && v.Namespace != "" {
if !v.IsValidatingAdmissionPolicy {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s-%s", ns, v.Policy, ruleNameInResultKey, v.Namespace, v.Kind, resource)
} else {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", ns, v.Policy, v.Namespace, v.Kind, resource)
}
} else if found {
if !v.IsValidatingAdmissionPolicy {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", ns, v.Policy, ruleNameInResultKey, v.Kind, resource)
} else {
resultKey = fmt.Sprintf("%s-%s-%s-%s", ns, v.Policy, v.Kind, resource)
}
row.Policy = color.Policy(ns, v.Policy)
row.Resource = color.Resource(v.Kind, v.Namespace, resource)
} else if v.Namespace != "" {
row.Resource = color.Resource(v.Kind, v.Namespace, resource)
if !v.IsValidatingAdmissionPolicy {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", v.Policy, ruleNameInResultKey, v.Namespace, v.Kind, resource)
} else {
resultKey = fmt.Sprintf("%s-%s-%s-%s", v.Policy, v.Namespace, v.Kind, resource)
}
}
var testRes policyreportv1alpha2.PolicyReportResult
if val, ok := resps[resultKey]; ok {
testRes = val
} else {
log.Log.V(2).Info("result not found", "key", resultKey)
row.Result = color.NotFound()
rc.Fail++
row.IsFailure = true
resultsTable.Add(row)
continue
}
row.Message = testRes.Message
if v.Result == "" && v.Status != "" {
v.Result = v.Status
}
if testRes.Result == v.Result {
row.Result = color.ResultPass()
if testRes.Result == policyreportv1alpha2.StatusSkip {
rc.Skip++
} else {
rc.Pass++
}
} else {
log.Log.V(2).Info("result mismatch", "expected", v.Result, "received", testRes.Result, "key", resultKey)
row.Result = color.ResultFail()
rc.Fail++
row.IsFailure = true
}
if failOnly {
if row.Result == color.ResultFail() || row.Result == "Fail" {
resultsTable.Add(row)
}
} else {
resultsTable.Add(row)
}
}
} else if v.Resource != "" {
for _, test := range tests {
// lookup matching engine responses (without the resource name)
// to reduce the search scope
responses := lookupEngineResponses(test, "", responses...)
// TODO fix deprecated fields
// identify the resources to be looked up
var resources []string
if test.Resources != nil {
resources = append(resources, test.Resources...)
} else if test.Resource != "" {
countDeprecatedResource++
row.Resource = color.Resource(v.Kind, v.Namespace, v.Resource)
var ruleNameInResultKey string
if !v.IsValidatingAdmissionPolicy {
if v.AutoGeneratedRule != "" {
ruleNameInResultKey = fmt.Sprintf("%s-%s", v.AutoGeneratedRule, v.Rule)
} else {
ruleNameInResultKey = v.Rule
resources = append(resources, test.Resource)
}
for _, resource := range resources {
var rows []table.Row
// lookup matching engine responses (with the resource name this time)
for _, response := range lookupEngineResponses(test, resource, responses...) {
// lookup matching rule responses
for _, rule := range lookupRuleResponses(test, response.PolicyResponse.Rules...) {
// perform test checks
ok, message, reason := checkResult(test, fs, resoucePath, response, rule)
// if checks failed but we were expecting a fail it's considered a success
success := ok || (!ok && test.Result == policyreportv1alpha2.StatusFail)
row := table.Row{
CompactRow: table.CompactRow{
ID: testCount,
Policy: color.Policy("", test.Policy),
Rule: color.Rule(test.Rule),
Resource: color.Resource(test.Kind, test.Namespace, resource),
Reason: reason,
IsFailure: !success,
},
Message: message,
}
if success {
row.Result = color.ResultPass()
if test.Result == policyreportv1alpha2.StatusSkip {
rc.Skip++
} else {
rc.Pass++
}
} else {
row.Result = color.ResultFail()
rc.Fail++
}
testCount++
rows = append(rows, row)
}
}
var resultKey string
if !v.IsValidatingAdmissionPolicy {
resultKey = fmt.Sprintf("%s-%s-%s-%s", v.Policy, ruleNameInResultKey, v.Kind, v.Resource)
} else {
resultKey = fmt.Sprintf("%s-%s-%s", v.Policy, v.Kind, v.Resource)
}
found, _ := isNamespacedPolicy(v.Policy)
var ns string
ns, v.Policy = getUserDefinedPolicyNameAndNamespace(v.Policy)
if found && v.Namespace != "" {
if !v.IsValidatingAdmissionPolicy {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s-%s", ns, v.Policy, ruleNameInResultKey, v.Namespace, v.Kind, v.Resource)
} else {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", ns, v.Policy, v.Namespace, v.Kind, v.Resource)
// if not found
if len(rows) == 0 {
row := table.Row{
CompactRow: table.CompactRow{
ID: testCount,
Policy: color.Policy("", test.Policy),
Rule: color.Rule(test.Rule),
Resource: color.Resource(test.Kind, test.Namespace, resource),
IsFailure: true,
Result: color.ResultFail(),
Reason: color.NotFound(),
},
Message: color.NotFound(),
}
} else if found {
if !v.IsValidatingAdmissionPolicy {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", ns, v.Policy, ruleNameInResultKey, v.Kind, v.Resource)
} else {
resultKey = fmt.Sprintf("%s-%s-%s-%s", ns, v.Policy, v.Kind, v.Resource)
}
row.Policy = color.Policy(ns, v.Policy)
row.Resource = color.Resource(v.Kind, v.Namespace, v.Resource)
} else if v.Namespace != "" {
row.Resource = color.Resource(v.Kind, v.Namespace, v.Resource)
if !v.IsValidatingAdmissionPolicy {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", v.Policy, ruleNameInResultKey, v.Namespace, v.Kind, v.Resource)
} else {
resultKey = fmt.Sprintf("%s-%s-%s-%s", v.Policy, v.Namespace, v.Kind, v.Resource)
}
}
var testRes policyreportv1alpha2.PolicyReportResult
if val, ok := resps[resultKey]; ok {
testRes = val
} else {
log.Log.V(2).Info("result not found", "key", resultKey)
row.Result = color.NotFound()
rc.Fail++
row.IsFailure = true
testCount++
resultsTable.Add(row)
continue
}
row.Message = testRes.Message
if v.Result == "" && v.Status != "" {
v.Result = v.Status
}
if testRes.Result == v.Result {
row.Result = color.ResultPass()
if testRes.Result == policyreportv1alpha2.StatusSkip {
rc.Skip++
} else {
rc.Pass++
}
} else {
log.Log.V(2).Info("result mismatch", "expected", v.Result, "received", testRes.Result, "key", resultKey)
row.Result = color.ResultFail()
rc.Fail++
row.IsFailure = true
}
if failOnly {
if row.Result == color.ResultFail() || row.Result == "Fail" {
resultsTable.Add(row)
}
} else {
resultsTable.Add(row)
resultsTable.Add(rows...)
}
}
}

View file

@ -3,15 +3,12 @@ package test
import (
"fmt"
"os"
"regexp"
"strings"
"path/filepath"
"github.com/go-git/go-billy/v5"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/test/api"
annotationsutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/annotations"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
filterutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/filter"
pathutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/path"
@ -25,9 +22,7 @@ import (
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/openapi"
policyvalidation "github.com/kyverno/kyverno/pkg/validation/policy"
"golang.org/x/exp/slices"
"k8s.io/api/admissionregistration/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
)
@ -41,7 +36,7 @@ func applyPoliciesFromPath(
openApiManager openapi.Manager,
filter filterutils.Filter,
auditWarn bool,
) (map[string]policyreportv1alpha2.PolicyReportResult, []api.TestResults, error) {
) ([]api.TestResults, []engineapi.EngineResponse, error) {
engineResponses := make([]engineapi.EngineResponse, 0)
var dClient dclient.Interface
var resultCounts common.ResultCounts
@ -86,20 +81,6 @@ func applyPoliciesFromPath(
policyFullPath := pathutils.GetFullPaths(apiTest.Policies, policyResourcePath, isGit)
resourceFullPath := pathutils.GetFullPaths(apiTest.Resources, policyResourcePath, isGit)
for i, result := range apiTest.Results {
arrPatchedResource := []string{result.PatchedResource}
arrGeneratedResource := []string{result.GeneratedResource}
arrCloneSourceResource := []string{result.CloneSourceResource}
patchedResourceFullPath := pathutils.GetFullPaths(arrPatchedResource, policyResourcePath, isGit)
generatedResourceFullPath := pathutils.GetFullPaths(arrGeneratedResource, policyResourcePath, isGit)
CloneSourceResourceFullPath := pathutils.GetFullPaths(arrCloneSourceResource, policyResourcePath, isGit)
apiTest.Results[i].PatchedResource = patchedResourceFullPath[0]
apiTest.Results[i].GeneratedResource = generatedResourceFullPath[0]
apiTest.Results[i].CloneSourceResource = CloneSourceResourceFullPath[0]
}
policies, validatingAdmissionPolicies, err := common.GetPoliciesFromPaths(fs, policyFullPath, isGit, policyResourcePath)
if err != nil {
fmt.Printf("Error: failed to load policies\nCause: %s\n", err)
@ -153,7 +134,11 @@ func applyPoliciesFromPath(
}
if len(genClone) != 0 {
ruleToCloneSourceResource[rule.Name] = res.CloneSourceResource
if isGit {
ruleToCloneSourceResource[rule.Name] = res.CloneSourceResource
} else {
ruleToCloneSourceResource[rule.Name] = pathutils.GetFullPath(res.CloneSourceResource, policyResourcePath)
}
}
}
break
@ -251,8 +236,7 @@ func applyPoliciesFromPath(
engineResponses = append(engineResponses, ers...)
}
}
resultsMap, testResults := buildPolicyResults(engineResponses, apiTest.Results, policyResourcePath, fs, isGit, auditWarn)
return resultsMap, testResults, nil
return apiTest.Results, engineResponses, nil
}
func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api.Test) []*unstructured.Unstructured {
@ -307,348 +291,34 @@ func selectResourcesForCheckInternal(resources []*unstructured.Unstructured, val
return checkableResources, duplicates, unused
}
func buildPolicyResults(
engineResponses []engineapi.EngineResponse,
testResults []api.TestResults,
policyResourcePath string,
fs billy.Filesystem,
isGit bool,
auditWarn bool,
) (map[string]policyreportv1alpha2.PolicyReportResult, []api.TestResults) {
results := map[string]policyreportv1alpha2.PolicyReportResult{}
for _, resp := range engineResponses {
policy := resp.Policy()
policyName := policy.GetName()
policyNamespace := policy.GetNamespace()
scored := annotationsutils.Scored(policy.GetAnnotations())
resourceName := resp.Resource.GetName()
resourceKind := resp.Resource.GetKind()
resourceNamespace := resp.Resource.GetNamespace()
var rules []string
for _, rule := range resp.PolicyResponse.Rules {
rules = append(rules, rule.Name())
}
result := policyreportv1alpha2.PolicyReportResult{
Policy: policyName,
Resources: []corev1.ObjectReference{
{
Name: resourceName,
},
},
Message: buildMessage(resp),
}
var patchedResourcePath []string
for i, test := range testResults {
var userDefinedPolicyNamespace string
var userDefinedPolicyName string
found, err := isNamespacedPolicy(test.Policy)
if err != nil {
log.Log.V(3).Info("error while checking the policy is namespaced or not", "policy: ", test.Policy, "error: ", err)
continue
}
if found {
userDefinedPolicyNamespace, userDefinedPolicyName = getUserDefinedPolicyNameAndNamespace(test.Policy)
test.Policy = userDefinedPolicyName
}
if test.Resources != nil {
if test.Policy == policyName {
// results[].namespace value implicit set same as metadata.namespace until and unless
// user provides explicit values for results[].namespace in test yaml file.
if test.Namespace == "" {
test.Namespace = resourceNamespace
testResults[i].Namespace = resourceNamespace
}
for _, resource := range test.Resources {
if resource == resourceName {
var resultsKey string
resultsKey = GetResultKeyAccordingToTestResults(userDefinedPolicyNamespace, test.Policy, test.Rule, test.Namespace, test.Kind, resource, test.IsValidatingAdmissionPolicy)
if !test.IsValidatingAdmissionPolicy {
if !slices.Contains(rules, test.Rule) {
if !slices.Contains(rules, "autogen-"+test.Rule) {
if !slices.Contains(rules, "autogen-cronjob-"+test.Rule) {
result.Result = policyreportv1alpha2.StatusSkip
} else {
testResults[i].AutoGeneratedRule = "autogen-cronjob"
test.Rule = "autogen-cronjob-" + test.Rule
resultsKey = GetResultKeyAccordingToTestResults(userDefinedPolicyNamespace, test.Policy, test.Rule, test.Namespace, test.Kind, resource, test.IsValidatingAdmissionPolicy)
}
} else {
testResults[i].AutoGeneratedRule = "autogen"
test.Rule = "autogen-" + test.Rule
resultsKey = GetResultKeyAccordingToTestResults(userDefinedPolicyNamespace, test.Policy, test.Rule, test.Namespace, test.Kind, resource, test.IsValidatingAdmissionPolicy)
}
if results[resultsKey].Result == "" {
result.Result = policyreportv1alpha2.StatusSkip
results[resultsKey] = result
}
}
patchedResourcePath = append(patchedResourcePath, test.PatchedResource)
}
if _, ok := results[resultsKey]; !ok {
results[resultsKey] = result
}
buildPolicyResultsForGenerate(resp, test, policyNamespace, policyName, resourceNamespace, resourceKind, resourceName, results, isGit, policyResourcePath, fs)
}
}
}
}
if test.Resource != "" {
if test.Policy == policyName && test.Resource == resourceName {
var resultsKey string
resultsKey = GetResultKeyAccordingToTestResults(userDefinedPolicyNamespace, test.Policy, test.Rule, test.Namespace, test.Kind, test.Resource, test.IsValidatingAdmissionPolicy)
if !test.IsValidatingAdmissionPolicy {
if !slices.Contains(rules, test.Rule) {
if !slices.Contains(rules, "autogen-"+test.Rule) {
if !slices.Contains(rules, "autogen-cronjob-"+test.Rule) {
result.Result = policyreportv1alpha2.StatusSkip
} 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, test.IsValidatingAdmissionPolicy)
}
} else {
testResults[i].AutoGeneratedRule = "autogen"
test.Rule = "autogen-" + test.Rule
resultsKey = GetResultKeyAccordingToTestResults(userDefinedPolicyNamespace, test.Policy, test.Rule, test.Namespace, test.Kind, test.Resource, test.IsValidatingAdmissionPolicy)
}
if results[resultsKey].Result == "" {
result.Result = policyreportv1alpha2.StatusSkip
results[resultsKey] = result
}
}
patchedResourcePath = append(patchedResourcePath, test.PatchedResource)
}
if _, ok := results[resultsKey]; !ok {
results[resultsKey] = result
}
buildPolicyResultsForGenerate(resp, test, policyNamespace, policyName, resourceNamespace, resourceKind, resourceName, results, isGit, policyResourcePath, fs)
}
}
for _, rule := range resp.PolicyResponse.Rules {
if rule.RuleType() != engineapi.Mutation || test.Rule != rule.Name() {
continue
}
var resultsKey []string
var resultKey string
var result policyreportv1alpha2.PolicyReportResult
resultsKey = GetAllPossibleResultsKey(policyNamespace, policyName, rule.Name(), resourceNamespace, resourceKind, resourceName, test.IsValidatingAdmissionPolicy)
for _, key := range resultsKey {
if val, ok := results[key]; ok {
result = val
resultKey = key
} else {
continue
}
if rule.Status() == engineapi.RuleStatusSkip {
result.Result = policyreportv1alpha2.StatusSkip
} else if rule.Status() == engineapi.RuleStatusError {
result.Result = policyreportv1alpha2.StatusError
} else {
var x string
for _, path := range patchedResourcePath {
result.Result = policyreportv1alpha2.StatusFail
x = getAndCompareResource(path, resp.PatchedResource, isGit, policyResourcePath, fs, false)
if x == "pass" {
result.Result = policyreportv1alpha2.StatusPass
break
}
}
}
results[resultKey] = result
}
}
for _, rule := range resp.PolicyResponse.Rules {
if rule.RuleType() != engineapi.Validation && rule.RuleType() != engineapi.ImageVerify || test.Rule != rule.Name() && !test.IsValidatingAdmissionPolicy {
continue
}
var resultsKey []string
var resultKey string
var result policyreportv1alpha2.PolicyReportResult
resultsKey = GetAllPossibleResultsKey(policyNamespace, policyName, rule.Name(), resourceNamespace, resourceKind, resourceName, test.IsValidatingAdmissionPolicy)
for _, key := range resultsKey {
if val, ok := results[key]; ok {
result = val
resultKey = key
} else {
continue
}
if rule.Status() == engineapi.RuleStatusSkip {
result.Result = policyreportv1alpha2.StatusSkip
} else if rule.Status() == engineapi.RuleStatusError {
result.Result = policyreportv1alpha2.StatusError
} else if rule.Status() == engineapi.RuleStatusPass {
result.Result = policyreportv1alpha2.StatusPass
} else if rule.Status() == engineapi.RuleStatusFail {
if !scored {
result.Result = policyreportv1alpha2.StatusWarn
} else if auditWarn && resp.GetValidationFailureAction().Audit() {
result.Result = policyreportv1alpha2.StatusWarn
} else {
result.Result = policyreportv1alpha2.StatusFail
}
} else {
fmt.Println(rule)
}
results[resultKey] = result
}
}
}
}
return results, testResults
}
func buildPolicyResultsForGenerate(resp engineapi.EngineResponse, test api.TestResults, policyNamespace string, policyName string, resourceNamespace string, resourceKind string, resourceName string, results map[string]policyreportv1alpha2.PolicyReportResult, isGit bool, policyResourcePath string, fs billy.Filesystem) {
for _, rule := range resp.PolicyResponse.Rules {
if rule.RuleType() != engineapi.Generation || test.Rule != rule.Name() {
continue
}
var resultsKey []string
var resultKey string
var result policyreportv1alpha2.PolicyReportResult
resultsKey = GetAllPossibleResultsKey(policyNamespace, policyName, rule.Name(), resourceNamespace, resourceKind, resourceName, test.IsValidatingAdmissionPolicy)
for _, key := range resultsKey {
if val, ok := results[key]; ok {
result = val
resultKey = key
} else {
continue
}
if rule.Status() == engineapi.RuleStatusSkip {
result.Result = policyreportv1alpha2.StatusSkip
} else if rule.Status() == engineapi.RuleStatusError {
result.Result = policyreportv1alpha2.StatusError
} else {
var x string
result.Result = policyreportv1alpha2.StatusFail
x = getAndCompareResource(test.GeneratedResource, rule.GeneratedResource(), isGit, policyResourcePath, fs, true)
if x == "pass" {
result.Result = policyreportv1alpha2.StatusPass
}
}
results[resultKey] = result
}
}
}
func GetAllPossibleResultsKey(policyNamespace, policy, rule, resourceNamespace, kind, resource string, isVAP bool) []string {
var resultsKey []string
var resultKey1, resultKey2, resultKey3, resultKey4 string
if isVAP {
resultKey1 = fmt.Sprintf("%s-%s-%s", policy, kind, resource)
resultKey2 = fmt.Sprintf("%s-%s-%s-%s", policy, resourceNamespace, kind, resource)
resultKey3 = fmt.Sprintf("%s-%s-%s-%s", policyNamespace, policy, kind, resource)
resultKey4 = fmt.Sprintf("%s-%s-%s-%s-%s", policyNamespace, policy, resourceNamespace, kind, resource)
} else {
resultKey1 = fmt.Sprintf("%s-%s-%s-%s", policy, rule, kind, resource)
resultKey2 = fmt.Sprintf("%s-%s-%s-%s-%s", policy, rule, resourceNamespace, 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, resourceNamespace, kind, resource)
}
resultsKey = append(resultsKey, resultKey1, resultKey2, resultKey3, resultKey4)
return resultsKey
}
func GetResultKeyAccordingToTestResults(policyNs, policy, rule, resourceNs, kind, resource string, isVAP bool) string {
var resultKey string
if isVAP {
resultKey = fmt.Sprintf("%s-%s-%s", policy, kind, resource)
if policyNs != "" && resourceNs != "" {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", policyNs, policy, resourceNs, kind, resource)
} else if policyNs != "" {
resultKey = fmt.Sprintf("%s-%s-%s-%s", policyNs, policy, kind, resource)
} else if resourceNs != "" {
resultKey = fmt.Sprintf("%s-%s-%s-%s", policy, resourceNs, kind, resource)
}
} else {
resultKey = fmt.Sprintf("%s-%s-%s-%s", policy, rule, kind, resource)
if policyNs != "" && resourceNs != "" {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s-%s", policyNs, policy, rule, resourceNs, kind, resource)
} else if policyNs != "" {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", policyNs, policy, rule, kind, resource)
} else if resourceNs != "" {
resultKey = fmt.Sprintf("%s-%s-%s-%s-%s", policy, rule, resourceNs, kind, resource)
}
}
return resultKey
}
func isNamespacedPolicy(policyNames string) (bool, error) {
return regexp.MatchString("^[a-z]*/[a-z]*", policyNames)
}
// getAndCompareResource --> Get the patchedResource or generatedResource from the path provided by user
// And compare this resource with engine generated resource.
func getAndCompareResource(path string, actualResource unstructured.Unstructured, isGit bool, policyResourcePath string, fs billy.Filesystem, isGenerate bool) string {
var status string
func getAndCompareResource(
path string,
actualResource unstructured.Unstructured,
fs billy.Filesystem,
policyResourcePath string,
isGenerate bool,
) (bool, error) {
resourceType := "patchedResource"
if isGenerate {
resourceType = "generatedResource"
}
expectedResource, err := common.GetResourceFromPath(fs, path, isGit, policyResourcePath, resourceType)
// TODO fix the way we handle git vs non-git paths (probably at the loading phase)
if fs == nil {
path = filepath.Join(policyResourcePath, path)
}
expectedResource, err := common.GetResourceFromPath(fs, path, fs != nil, policyResourcePath, resourceType)
if err != nil {
fmt.Printf("Error: failed to load resources (%s)", err)
return ""
return false, fmt.Errorf("Error: failed to load resources (%s)", err)
}
if isGenerate {
unstructuredutils.FixupGenerateLabels(actualResource)
unstructuredutils.FixupGenerateLabels(expectedResource)
}
equals, err := unstructuredutils.Compare(actualResource, expectedResource, true)
if err == nil {
if !equals {
status = "fail"
} else {
status = "pass"
}
if err != nil {
return false, fmt.Errorf("Error: failed to compare resources (%s)", err)
}
return status
}
func buildMessage(resp engineapi.EngineResponse) string {
var messages []string
for _, ruleResp := range resp.PolicyResponse.Rules {
message := strings.TrimSpace(ruleResp.Message())
if message != "" {
messages = append(messages, message)
}
}
return strings.Join(messages, ",")
}
func getUserDefinedPolicyNameAndNamespace(policyName string) (string, string) {
if strings.Contains(policyName, "/") {
parts := strings.Split(policyName, "/")
namespace := parts[0]
policy := parts[1]
return namespace, policy
}
return "", policyName
return equals, nil
}

View file

@ -34,6 +34,7 @@ type CompactRow struct {
Rule string `header:"rule"`
Resource string `header:"resource"`
Result string `header:"result"`
Reason string `header:"reason"`
}
type Row struct {

View file

@ -10,6 +10,53 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func ComputePolicyReportResult(auditWarn bool, engineResponse engineapi.EngineResponse, ruleResponse engineapi.RuleResponse) policyreportv1alpha2.PolicyReportResult {
policy := engineResponse.Policy()
policyName := policy.GetName()
audit := engineResponse.GetValidationFailureAction().Audit()
scored := annotationsutils.Scored(policy.GetAnnotations())
category := annotationsutils.Category(policy.GetAnnotations())
severity := annotationsutils.Severity(policy.GetAnnotations())
result := policyreportv1alpha2.PolicyReportResult{
// TODO policy name looks wrong, it should consider the namespace too
Policy: policyName,
Resources: []corev1.ObjectReference{
{
Kind: engineResponse.Resource.GetKind(),
Namespace: engineResponse.Resource.GetNamespace(),
APIVersion: engineResponse.Resource.GetAPIVersion(),
Name: engineResponse.Resource.GetName(),
UID: engineResponse.Resource.GetUID(),
},
},
Scored: scored,
Category: category,
Severity: severity,
}
if ruleResponse.Status() == engineapi.RuleStatusSkip {
result.Result = policyreportv1alpha2.StatusSkip
} else if ruleResponse.Status() == engineapi.RuleStatusError {
result.Result = policyreportv1alpha2.StatusError
} else if ruleResponse.Status() == engineapi.RuleStatusPass {
result.Result = policyreportv1alpha2.StatusPass
} else if ruleResponse.Status() == engineapi.RuleStatusFail {
if !scored || (audit && auditWarn) {
result.Result = policyreportv1alpha2.StatusWarn
} else {
result.Result = policyreportv1alpha2.StatusFail
}
} else {
result.Result = policyreportv1alpha2.StatusError
}
if policy.GetType() == engineapi.KyvernoPolicyType {
result.Rule = ruleResponse.Name()
}
result.Message = ruleResponse.Message()
result.Source = kyverno.ValueKyvernoApp
result.Timestamp = metav1.Timestamp{Seconds: ruleResponse.Stats().Timestamp()}
return result
}
func ComputePolicyReportResultsPerPolicy(auditWarn bool, engineResponses ...engineapi.EngineResponse) map[engineapi.GenericPolicy][]policyreportv1alpha2.PolicyReportResult {
results := make(map[engineapi.GenericPolicy][]policyreportv1alpha2.PolicyReportResult)
for _, engineResponse := range engineResponses {
@ -17,53 +64,12 @@ func ComputePolicyReportResultsPerPolicy(auditWarn bool, engineResponses ...engi
continue
}
policy := engineResponse.Policy()
policyName := policy.GetName()
audit := engineResponse.GetValidationFailureAction().Audit()
scored := annotationsutils.Scored(policy.GetAnnotations())
category := annotationsutils.Category(policy.GetAnnotations())
severity := annotationsutils.Severity(policy.GetAnnotations())
for _, ruleResponse := range engineResponse.PolicyResponse.Rules {
// TODO only validation is managed here ?
if ruleResponse.RuleType() != engineapi.Validation {
continue
}
result := policyreportv1alpha2.PolicyReportResult{
// TODO policy name looks wrong, it should consider the namespace too
Policy: policyName,
Resources: []corev1.ObjectReference{
{
Kind: engineResponse.Resource.GetKind(),
Namespace: engineResponse.Resource.GetNamespace(),
APIVersion: engineResponse.Resource.GetAPIVersion(),
Name: engineResponse.Resource.GetName(),
UID: engineResponse.Resource.GetUID(),
},
},
Scored: scored,
Category: category,
Severity: severity,
}
if ruleResponse.Status() == engineapi.RuleStatusSkip {
result.Result = policyreportv1alpha2.StatusSkip
} else if ruleResponse.Status() == engineapi.RuleStatusError {
result.Result = policyreportv1alpha2.StatusError
} else if ruleResponse.Status() == engineapi.RuleStatusPass {
result.Result = policyreportv1alpha2.StatusPass
} else if ruleResponse.Status() == engineapi.RuleStatusFail {
if !scored || (audit && auditWarn) {
result.Result = policyreportv1alpha2.StatusWarn
} else {
result.Result = policyreportv1alpha2.StatusFail
}
} else {
result.Result = policyreportv1alpha2.StatusError
}
if policy.GetType() == engineapi.KyvernoPolicyType {
result.Rule = ruleResponse.Name()
}
result.Message = ruleResponse.Message()
result.Source = kyverno.ValueKyvernoApp
result.Timestamp = metav1.Timestamp{Seconds: ruleResponse.Stats().Timestamp()}
// if ruleResponse.RuleType() != engineapi.Validation && ruleResponse.RuleType() != engineapi.ImageVerify {
// continue
// }
result := ComputePolicyReportResult(auditWarn, engineResponse, ruleResponse)
results[policy] = append(results[policy], result)
}
}

View file

@ -35,13 +35,13 @@ results:
- mydeploy
result: pass
rule: add-label
- kind: Service
patchedResource: patchedResource5.yaml
policy: add-label
resources:
- same-name-but-diff-kind
result: skip
rule: add-label
# - kind: Service
# patchedResource: patchedResource5.yaml
# policy: add-label
# resources:
# - same-name-but-diff-kind
# result: skip
# rule: add-label
- kind: Pod
patchedResource: patchedResource6.yaml
policy: add-label
@ -49,14 +49,14 @@ results:
- same-name-but-diff-kind
result: pass
rule: add-label
- kind: Pod
namespace: practice
patchedResource: patchedResource7.yaml
policy: add-ndots
resources:
- resource-equal-to-patch-res-for-cp
result: skip
rule: add-ndots
# - kind: Pod
# namespace: practice
# patchedResource: patchedResource7.yaml
# policy: add-ndots
# resources:
# - resource-equal-to-patch-res-for-cp
# result: skip
# rule: add-ndots
- kind: Pod
namespace: testing
patchedResource: patchedResource8.yaml
@ -65,35 +65,35 @@ results:
- same-name-but-diff-namespace
result: pass
rule: add-ndots
- kind: Pod
namespace: production
patchedResource: patchedResource9.yaml
policy: add-ndots
resources:
- same-name-but-diff-namespace
result: skip
rule: add-ndots
- kind: Deployment
patchedResource: patchedResource10.yaml
policy: add-ndots
resources:
- mydeploy
result: skip
rule: add-ndots
- kind: Service
patchedResource: patchedResource5.yaml
policy: add-ndots
resources:
- same-name-but-diff-kind
result: skip
rule: add-ndots
- kind: Pod
patchedResource: patchedResource11.yaml
policy: add-ndots
resources:
- same-name-but-diff-kind
result: skip
rule: add-ndots
# - kind: Pod
# namespace: production
# patchedResource: patchedResource9.yaml
# policy: add-ndots
# resources:
# - same-name-but-diff-namespace
# result: skip
# rule: add-ndots
# - kind: Deployment
# patchedResource: patchedResource10.yaml
# policy: add-ndots
# resources:
# - mydeploy
# result: skip
# rule: add-ndots
# - kind: Service
# patchedResource: patchedResource5.yaml
# policy: add-ndots
# resources:
# - same-name-but-diff-kind
# result: skip
# rule: add-ndots
# - kind: Pod
# patchedResource: patchedResource11.yaml
# policy: add-ndots
# resources:
# - same-name-but-diff-kind
# result: skip
# rule: add-ndots
- kind: Pod
patchedResource: patched-resource.yaml
policy: example

View file

@ -10,7 +10,7 @@ spec:
containers:
- image: nginx:latest
name: nginx
dnsConfig:
options:
- name: ndots
value: "1"
# dnsConfig:
# options:
# - name: ndots
# value: "1"

View file

@ -16,7 +16,6 @@ metadata:
`color=orange` to Pods, Services, ConfigMaps, and Secrets.
spec:
background: false
validationFailureAction:
rules:
- name: add-label
match:

View file

@ -18,10 +18,11 @@ results:
- test2
result: fail
rule: disallow
- kind: Pod
namespace: namespace3
policy: disallow-protected-namespaces
resources:
- test3
result: skip
rule: disallow
# TODO CEB FIX
# - kind: Pod
# namespace: namespace3
# policy: disallow-protected-namespaces
# resources:
# - test3
# result: skip
# rule: disallow

View file

@ -19,14 +19,15 @@ results:
- nodeselector-with-labels-on-mutation
result: pass
rule: ondemand-managed_by
- kind: Pod
namespace: user-foo
patchedResource: patched-resource1.yaml
policy: ondemand
resources:
- nodeselector-without-labels-on-mutation
result: skip
rule: ondemand-nodeselector
# TODO CEB FIX
# - kind: Pod
# namespace: user-foo
# patchedResource: patched-resource1.yaml
# policy: ondemand
# resources:
# - nodeselector-without-labels-on-mutation
# result: skip
# rule: ondemand-nodeselector
- kind: Pod
namespace: user-foo
policy: ondemand

View file

@ -6,12 +6,14 @@ resources:
results:
- kind: Pod
policy: exclude-namespaces-example
resource: bad-pod01
resources:
- bad-pod01
result: pass
rule: exclude-namespaces-dynamically
- kind: Pod
policy: exclude-namespaces-example
resource: bad-pod02
resources:
- bad-pod02
result: error
rule: exclude-namespaces-dynamically
variables: values.yaml

View file

@ -10,15 +10,16 @@ results:
- pod-fail
result: fail
rule: require-pod-probes
- kind: Deployment
policy: require-pod-probes
resources:
- deployment-skip
result: skip
rule: require-pod-probes
- kind: CronJob
policy: require-pod-probes
resources:
- cronjob-skip
result: skip
rule: require-pod-probes
# TODO CEB FIX
# - kind: Deployment
# policy: require-pod-probes
# resources:
# - deployment-skip
# result: skip
# rule: require-pod-probes
# - kind: CronJob
# policy: require-pod-probes
# resources:
# - cronjob-skip
# result: skip
# rule: require-pod-probes

View file

@ -6,7 +6,6 @@ kind: Secret
metadata:
name: example
type: Opaque
---
apiVersion: v1
data:

View file

@ -7,88 +7,104 @@ results:
- kind: Pod
namespace: test
policy: disallow-latest-tag
resource: test-require-image-tag-pass
resources:
- test-require-image-tag-pass
result: pass
rule: require-image-tag
- kind: Pod
namespace: test
policy: disallow-latest-tag
resource: test-require-image-tag-fail
resources:
- test-require-image-tag-fail
result: fail
rule: require-image-tag
- kind: Pod
policy: disallow-latest-tag
resource: test-validate-image-tag-ignore
result: skip
rule: validate-image-tag
# TODO CEB FIX
# - kind: Pod
# policy: disallow-latest-tag
# resources:
# - test-validate-image-tag-ignore
# result: skip
# rule: validate-image-tag
- kind: Pod
namespace: test
policy: disallow-latest-tag
resource: test-validate-image-tag-fail
resources:
- test-validate-image-tag-fail
result: fail
rule: validate-image-tag
- kind: Pod
namespace: test
policy: disallow-latest-tag
resource: test-validate-image-tag-pass
resources:
- test-validate-image-tag-pass
result: pass
rule: validate-image-tag
- kind: Pod
namespace: test
policy: duration-test
resource: test-lifetime-fail
resources:
- test-lifetime-fail
result: fail
rule: greater-than
- kind: Pod
namespace: test
policy: duration-test
resource: test-lifetime-fail
resources:
- test-lifetime-fail
result: pass
rule: less-than
- kind: Pod
namespace: test
policy: duration-test
resource: test-lifetime-fail
resources:
- test-lifetime-fail
result: fail
rule: greater-equal-than
- kind: Pod
namespace: test
policy: duration-test
resource: test-lifetime-fail
resources:
- test-lifetime-fail
result: pass
rule: less-equal-than
- kind: Pod
policy: restrict-pod-counts
resource: myapp-pod
resources:
- myapp-pod
result: fail
rule: restrict-pod-count
- kind: Pod
namespace: test
policy: restrict-pod-counts
resource: test-require-image-tag-pass
resources:
- test-require-image-tag-pass
result: fail
rule: restrict-pod-count
- kind: Pod
namespace: test
policy: restrict-pod-counts
resource: test-require-image-tag-fail
resources:
- test-require-image-tag-fail
result: fail
rule: restrict-pod-count
- kind: Pod
policy: restrict-pod-counts
resource: test-validate-image-tag-ignore
resources:
- test-validate-image-tag-ignore
result: fail
rule: restrict-pod-count
- kind: Pod
namespace: test
policy: restrict-pod-counts
resource: test-validate-image-tag-fail
resources:
- test-validate-image-tag-fail
result: fail
rule: restrict-pod-count
- kind: Pod
namespace: test
policy: restrict-pod-counts
resource: test-validate-image-tag-pass
resources:
- test-validate-image-tag-pass
result: fail
rule: restrict-pod-count
variables: values.yaml

View file

@ -16,21 +16,23 @@ results:
- my-service-2
result: pass
rule: label-end-with-test
- kind: Pod
policy: wildcard-support-in-matchlabels
resources:
- my-service-3
result: skip
rule: label-end-with-test
# TODO CEB FIX
# - kind: Pod
# policy: wildcard-support-in-matchlabels
# resources:
# - my-service-3
# result: skip
# rule: label-end-with-test
- kind: Pod
policy: wildcard-support-in-matchlabels
resources:
- my-service-4
result: pass
rule: label-start-with-test
- kind: Pod
policy: wildcard-support-in-matchlabels
resources:
- my-service-5
result: skip
rule: label-start-with-test
# TODO CEB FIX
# - kind: Pod
# policy: wildcard-support-in-matchlabels
# resources:
# - my-service-5
# result: skip
# rule: label-start-with-test

View file

@ -6,7 +6,6 @@ spec:
containers:
- name: nginx
image: nginx:latest
---
apiVersion: v1
kind: Pod