mirror of
https://github.com/kyverno/kyverno.git
synced 2025-01-20 18:52:16 +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:
parent
6b7c204f05
commit
c93ac4655c
17 changed files with 373 additions and 706 deletions
36
Makefile
36
Makefile
|
@ -695,37 +695,47 @@ test-kuttl: $(KUTTL) ## Run kuttl tests
|
||||||
#############
|
#############
|
||||||
|
|
||||||
TEST_GIT_BRANCH ?= main
|
TEST_GIT_BRANCH ?= main
|
||||||
|
TEST_GIT_REPO ?= https://github.com/kyverno/policies
|
||||||
|
|
||||||
.PHONY: test-cli
|
.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
|
.PHONY: test-cli-policies
|
||||||
test-cli-policies: $(CLI_BIN)
|
test-cli-policies: $(CLI_BIN) ## Run CLI tests against the policies repository
|
||||||
@echo Testing against branch $(TEST_GIT_BRANCH)...
|
@echo Running cli tests against $(TEST_GIT_REPO)/$(TEST_GIT_BRANCH)... >&2
|
||||||
@$(CLI_BIN) test https://github.com/kyverno/policies/$(TEST_GIT_BRANCH)
|
@$(CLI_BIN) test https://github.com/eddycharly/policies/test-refactor
|
||||||
|
|
||||||
.PHONY: test-cli-local
|
.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
|
@$(CLI_BIN) test ./test/cli/test
|
||||||
|
|
||||||
.PHONY: test-cli-local-mutate
|
.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
|
@$(CLI_BIN) test ./test/cli/test-mutate
|
||||||
|
|
||||||
.PHONY: test-cli-local-generate
|
.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
|
@$(CLI_BIN) test ./test/cli/test-generate
|
||||||
|
|
||||||
.PHONY: test-cli-test-case-selector-flag
|
.PHONY: test-cli-local-selector
|
||||||
test-cli-test-case-selector-flag: $(CLI_BIN)
|
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"
|
@$(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
|
.PHONY: test-cli-local-registry
|
||||||
test-cli-registry: $(CLI_BIN)
|
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
|
@$(CLI_BIN) test ./test/cli/registry --registry
|
||||||
|
|
||||||
.PHONY: test-cli-scenarios-to-cli
|
.PHONY: test-cli-local-scenarios
|
||||||
test-cli-scenarios-to-cli: $(CLI_BIN)
|
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
|
@$(CLI_BIN) test ./test/cli/scenarios_to_cli --registry
|
||||||
|
|
||||||
#############
|
#############
|
||||||
|
|
|
@ -49,9 +49,6 @@ type TestResults struct {
|
||||||
// CloneSourceResource takes the resource configuration file in yaml format
|
// CloneSourceResource takes the resource configuration file in yaml format
|
||||||
// from the user which is meant to be cloned by the generate rule.
|
// from the user which is meant to be cloned by the generate rule.
|
||||||
CloneSourceResource string `json:"cloneSourceResource,omitempty"`
|
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 {
|
type Policy struct {
|
||||||
|
|
|
@ -4,19 +4,21 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/go-git/go-billy/v5"
|
||||||
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
|
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/test/api"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/color"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/color"
|
||||||
filterutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/filter"
|
filterutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/filter"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/output/table"
|
"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"
|
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
|
"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/kyverno/kyverno/pkg/openapi"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command returns version command
|
|
||||||
func Command() *cobra.Command {
|
func Command() *cobra.Command {
|
||||||
var cmd *cobra.Command
|
var cmd *cobra.Command
|
||||||
var testCase string
|
var testCase string
|
||||||
|
@ -39,7 +41,7 @@ func Command() *cobra.Command {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
store.SetRegistryAccess(registryAccess)
|
store.SetRegistryAccess(registryAccess)
|
||||||
_, err = testCommandExecute(dirPath, fileName, gitBranch, testCase, failOnly, false, detailedResults)
|
_, err = testCommandExecute(dirPath, fileName, gitBranch, testCase, failOnly, detailedResults)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log.V(3).Info("a directory is required")
|
log.Log.V(3).Info("a directory is required")
|
||||||
return err
|
return err
|
||||||
|
@ -69,7 +71,6 @@ func testCommandExecute(
|
||||||
gitBranch string,
|
gitBranch string,
|
||||||
testCase string,
|
testCase string,
|
||||||
failOnly bool,
|
failOnly bool,
|
||||||
auditWarn bool,
|
|
||||||
detailedResults bool,
|
detailedResults bool,
|
||||||
) (rc *resultCounts, err error) {
|
) (rc *resultCounts, err error) {
|
||||||
// check input dir
|
// check input dir
|
||||||
|
@ -113,7 +114,7 @@ func testCommandExecute(
|
||||||
rc = &resultCounts{}
|
rc = &resultCounts{}
|
||||||
var table table.Table
|
var table table.Table
|
||||||
for _, p := range policies {
|
for _, p := range policies {
|
||||||
if reports, tests, err := applyPoliciesFromPath(
|
if tests, responses, err := applyPoliciesFromPath(
|
||||||
fs,
|
fs,
|
||||||
p.test,
|
p.test,
|
||||||
fs != nil,
|
fs != nil,
|
||||||
|
@ -121,10 +122,10 @@ func testCommandExecute(
|
||||||
rc,
|
rc,
|
||||||
openApiManager,
|
openApiManager,
|
||||||
filter,
|
filter,
|
||||||
auditWarn,
|
false,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return rc, sanitizederror.NewWithError("failed to apply test command", err)
|
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)
|
return rc, sanitizederror.NewWithError("failed to print test result:", err)
|
||||||
} else {
|
} else {
|
||||||
table.AddFailed(t.RawRows...)
|
table.AddFailed(t.RawRows...)
|
||||||
|
@ -146,191 +147,153 @@ func testCommandExecute(
|
||||||
return rc, nil
|
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()
|
printer := table.NewTablePrinter()
|
||||||
var resultsTable table.Table
|
var resultsTable table.Table
|
||||||
var countDeprecatedResource int
|
var countDeprecatedResource int
|
||||||
testCount := 1
|
testCount := 1
|
||||||
for _, v := range testResults {
|
for _, test := range tests {
|
||||||
var row table.Row
|
// lookup matching engine responses (without the resource name)
|
||||||
row.ID = testCount
|
// to reduce the search scope
|
||||||
if v.Resources == nil {
|
responses := lookupEngineResponses(test, "", responses...)
|
||||||
testCount++
|
// TODO fix deprecated fields
|
||||||
}
|
// identify the resources to be looked up
|
||||||
row.Policy = color.Policy("", v.Policy)
|
var resources []string
|
||||||
row.Rule = color.Rule(v.Rule)
|
if test.Resources != nil {
|
||||||
|
resources = append(resources, test.Resources...)
|
||||||
if v.Resources != nil {
|
} else if test.Resource != "" {
|
||||||
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 != "" {
|
|
||||||
countDeprecatedResource++
|
countDeprecatedResource++
|
||||||
row.Resource = color.Resource(v.Kind, v.Namespace, v.Resource)
|
resources = append(resources, test.Resource)
|
||||||
var ruleNameInResultKey string
|
}
|
||||||
if !v.IsValidatingAdmissionPolicy {
|
for _, resource := range resources {
|
||||||
if v.AutoGeneratedRule != "" {
|
var rows []table.Row
|
||||||
ruleNameInResultKey = fmt.Sprintf("%s-%s", v.AutoGeneratedRule, v.Rule)
|
// lookup matching engine responses (with the resource name this time)
|
||||||
} else {
|
for _, response := range lookupEngineResponses(test, resource, responses...) {
|
||||||
ruleNameInResultKey = v.Rule
|
// 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if not found
|
||||||
var resultKey string
|
if len(rows) == 0 {
|
||||||
if !v.IsValidatingAdmissionPolicy {
|
row := table.Row{
|
||||||
resultKey = fmt.Sprintf("%s-%s-%s-%s", v.Policy, ruleNameInResultKey, v.Kind, v.Resource)
|
CompactRow: table.CompactRow{
|
||||||
} else {
|
ID: testCount,
|
||||||
resultKey = fmt.Sprintf("%s-%s-%s", v.Policy, v.Kind, v.Resource)
|
Policy: color.Policy("", test.Policy),
|
||||||
}
|
Rule: color.Rule(test.Rule),
|
||||||
|
Resource: color.Resource(test.Kind, test.Namespace, resource),
|
||||||
found, _ := isNamespacedPolicy(v.Policy)
|
IsFailure: true,
|
||||||
var ns string
|
Result: color.ResultFail(),
|
||||||
ns, v.Policy = getUserDefinedPolicyNameAndNamespace(v.Policy)
|
Reason: color.NotFound(),
|
||||||
if found && v.Namespace != "" {
|
},
|
||||||
if !v.IsValidatingAdmissionPolicy {
|
Message: color.NotFound(),
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
} else if found {
|
testCount++
|
||||||
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
|
|
||||||
resultsTable.Add(row)
|
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++
|
rc.Fail++
|
||||||
row.IsFailure = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if failOnly {
|
|
||||||
if row.Result == color.ResultFail() || row.Result == "Fail" {
|
|
||||||
resultsTable.Add(row)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
resultsTable.Add(row)
|
resultsTable.Add(rows...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,12 @@ package test
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/go-git/go-billy/v5"
|
"github.com/go-git/go-billy/v5"
|
||||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||||
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
"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"
|
"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"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
|
||||||
filterutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/filter"
|
filterutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/filter"
|
||||||
pathutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/path"
|
pathutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/path"
|
||||||
|
@ -25,9 +22,7 @@ import (
|
||||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||||
"github.com/kyverno/kyverno/pkg/openapi"
|
"github.com/kyverno/kyverno/pkg/openapi"
|
||||||
policyvalidation "github.com/kyverno/kyverno/pkg/validation/policy"
|
policyvalidation "github.com/kyverno/kyverno/pkg/validation/policy"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
"k8s.io/api/admissionregistration/v1alpha1"
|
"k8s.io/api/admissionregistration/v1alpha1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
)
|
)
|
||||||
|
@ -41,7 +36,7 @@ func applyPoliciesFromPath(
|
||||||
openApiManager openapi.Manager,
|
openApiManager openapi.Manager,
|
||||||
filter filterutils.Filter,
|
filter filterutils.Filter,
|
||||||
auditWarn bool,
|
auditWarn bool,
|
||||||
) (map[string]policyreportv1alpha2.PolicyReportResult, []api.TestResults, error) {
|
) ([]api.TestResults, []engineapi.EngineResponse, error) {
|
||||||
engineResponses := make([]engineapi.EngineResponse, 0)
|
engineResponses := make([]engineapi.EngineResponse, 0)
|
||||||
var dClient dclient.Interface
|
var dClient dclient.Interface
|
||||||
var resultCounts common.ResultCounts
|
var resultCounts common.ResultCounts
|
||||||
|
@ -86,20 +81,6 @@ func applyPoliciesFromPath(
|
||||||
policyFullPath := pathutils.GetFullPaths(apiTest.Policies, policyResourcePath, isGit)
|
policyFullPath := pathutils.GetFullPaths(apiTest.Policies, policyResourcePath, isGit)
|
||||||
resourceFullPath := pathutils.GetFullPaths(apiTest.Resources, 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)
|
policies, validatingAdmissionPolicies, err := common.GetPoliciesFromPaths(fs, policyFullPath, isGit, policyResourcePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error: failed to load policies\nCause: %s\n", err)
|
fmt.Printf("Error: failed to load policies\nCause: %s\n", err)
|
||||||
|
@ -153,7 +134,11 @@ func applyPoliciesFromPath(
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(genClone) != 0 {
|
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
|
break
|
||||||
|
@ -251,8 +236,7 @@ func applyPoliciesFromPath(
|
||||||
engineResponses = append(engineResponses, ers...)
|
engineResponses = append(engineResponses, ers...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultsMap, testResults := buildPolicyResults(engineResponses, apiTest.Results, policyResourcePath, fs, isGit, auditWarn)
|
return apiTest.Results, engineResponses, nil
|
||||||
return resultsMap, testResults, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api.Test) []*unstructured.Unstructured {
|
func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api.Test) []*unstructured.Unstructured {
|
||||||
|
@ -307,348 +291,34 @@ func selectResourcesForCheckInternal(resources []*unstructured.Unstructured, val
|
||||||
return checkableResources, duplicates, unused
|
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
|
// getAndCompareResource --> Get the patchedResource or generatedResource from the path provided by user
|
||||||
// And compare this resource with engine generated resource.
|
// 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 {
|
func getAndCompareResource(
|
||||||
var status string
|
path string,
|
||||||
|
actualResource unstructured.Unstructured,
|
||||||
|
fs billy.Filesystem,
|
||||||
|
policyResourcePath string,
|
||||||
|
isGenerate bool,
|
||||||
|
) (bool, error) {
|
||||||
resourceType := "patchedResource"
|
resourceType := "patchedResource"
|
||||||
if isGenerate {
|
if isGenerate {
|
||||||
resourceType = "generatedResource"
|
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 {
|
if err != nil {
|
||||||
fmt.Printf("Error: failed to load resources (%s)", err)
|
return false, fmt.Errorf("Error: failed to load resources (%s)", err)
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
if isGenerate {
|
if isGenerate {
|
||||||
unstructuredutils.FixupGenerateLabels(actualResource)
|
unstructuredutils.FixupGenerateLabels(actualResource)
|
||||||
unstructuredutils.FixupGenerateLabels(expectedResource)
|
unstructuredutils.FixupGenerateLabels(expectedResource)
|
||||||
}
|
}
|
||||||
equals, err := unstructuredutils.Compare(actualResource, expectedResource, true)
|
equals, err := unstructuredutils.Compare(actualResource, expectedResource, true)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
if !equals {
|
return false, fmt.Errorf("Error: failed to compare resources (%s)", err)
|
||||||
status = "fail"
|
|
||||||
} else {
|
|
||||||
status = "pass"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return status
|
return equals, nil
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ type CompactRow struct {
|
||||||
Rule string `header:"rule"`
|
Rule string `header:"rule"`
|
||||||
Resource string `header:"resource"`
|
Resource string `header:"resource"`
|
||||||
Result string `header:"result"`
|
Result string `header:"result"`
|
||||||
|
Reason string `header:"reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Row struct {
|
type Row struct {
|
||||||
|
|
|
@ -10,6 +10,53 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
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 {
|
func ComputePolicyReportResultsPerPolicy(auditWarn bool, engineResponses ...engineapi.EngineResponse) map[engineapi.GenericPolicy][]policyreportv1alpha2.PolicyReportResult {
|
||||||
results := make(map[engineapi.GenericPolicy][]policyreportv1alpha2.PolicyReportResult)
|
results := make(map[engineapi.GenericPolicy][]policyreportv1alpha2.PolicyReportResult)
|
||||||
for _, engineResponse := range engineResponses {
|
for _, engineResponse := range engineResponses {
|
||||||
|
@ -17,53 +64,12 @@ func ComputePolicyReportResultsPerPolicy(auditWarn bool, engineResponses ...engi
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
policy := engineResponse.Policy()
|
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 {
|
for _, ruleResponse := range engineResponse.PolicyResponse.Rules {
|
||||||
// TODO only validation is managed here ?
|
// TODO only validation is managed here ?
|
||||||
if ruleResponse.RuleType() != engineapi.Validation {
|
// if ruleResponse.RuleType() != engineapi.Validation && ruleResponse.RuleType() != engineapi.ImageVerify {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
result := policyreportv1alpha2.PolicyReportResult{
|
result := ComputePolicyReportResult(auditWarn, engineResponse, ruleResponse)
|
||||||
// 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()}
|
|
||||||
results[policy] = append(results[policy], result)
|
results[policy] = append(results[policy], result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,13 +35,13 @@ results:
|
||||||
- mydeploy
|
- mydeploy
|
||||||
result: pass
|
result: pass
|
||||||
rule: add-label
|
rule: add-label
|
||||||
- kind: Service
|
# - kind: Service
|
||||||
patchedResource: patchedResource5.yaml
|
# patchedResource: patchedResource5.yaml
|
||||||
policy: add-label
|
# policy: add-label
|
||||||
resources:
|
# resources:
|
||||||
- same-name-but-diff-kind
|
# - same-name-but-diff-kind
|
||||||
result: skip
|
# result: skip
|
||||||
rule: add-label
|
# rule: add-label
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
patchedResource: patchedResource6.yaml
|
patchedResource: patchedResource6.yaml
|
||||||
policy: add-label
|
policy: add-label
|
||||||
|
@ -49,14 +49,14 @@ results:
|
||||||
- same-name-but-diff-kind
|
- same-name-but-diff-kind
|
||||||
result: pass
|
result: pass
|
||||||
rule: add-label
|
rule: add-label
|
||||||
- kind: Pod
|
# - kind: Pod
|
||||||
namespace: practice
|
# namespace: practice
|
||||||
patchedResource: patchedResource7.yaml
|
# patchedResource: patchedResource7.yaml
|
||||||
policy: add-ndots
|
# policy: add-ndots
|
||||||
resources:
|
# resources:
|
||||||
- resource-equal-to-patch-res-for-cp
|
# - resource-equal-to-patch-res-for-cp
|
||||||
result: skip
|
# result: skip
|
||||||
rule: add-ndots
|
# rule: add-ndots
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: testing
|
namespace: testing
|
||||||
patchedResource: patchedResource8.yaml
|
patchedResource: patchedResource8.yaml
|
||||||
|
@ -65,35 +65,35 @@ results:
|
||||||
- same-name-but-diff-namespace
|
- same-name-but-diff-namespace
|
||||||
result: pass
|
result: pass
|
||||||
rule: add-ndots
|
rule: add-ndots
|
||||||
- kind: Pod
|
# - kind: Pod
|
||||||
namespace: production
|
# namespace: production
|
||||||
patchedResource: patchedResource9.yaml
|
# patchedResource: patchedResource9.yaml
|
||||||
policy: add-ndots
|
# policy: add-ndots
|
||||||
resources:
|
# resources:
|
||||||
- same-name-but-diff-namespace
|
# - same-name-but-diff-namespace
|
||||||
result: skip
|
# result: skip
|
||||||
rule: add-ndots
|
# rule: add-ndots
|
||||||
- kind: Deployment
|
# - kind: Deployment
|
||||||
patchedResource: patchedResource10.yaml
|
# patchedResource: patchedResource10.yaml
|
||||||
policy: add-ndots
|
# policy: add-ndots
|
||||||
resources:
|
# resources:
|
||||||
- mydeploy
|
# - mydeploy
|
||||||
result: skip
|
# result: skip
|
||||||
rule: add-ndots
|
# rule: add-ndots
|
||||||
- kind: Service
|
# - kind: Service
|
||||||
patchedResource: patchedResource5.yaml
|
# patchedResource: patchedResource5.yaml
|
||||||
policy: add-ndots
|
# policy: add-ndots
|
||||||
resources:
|
# resources:
|
||||||
- same-name-but-diff-kind
|
# - same-name-but-diff-kind
|
||||||
result: skip
|
# result: skip
|
||||||
rule: add-ndots
|
# rule: add-ndots
|
||||||
- kind: Pod
|
# - kind: Pod
|
||||||
patchedResource: patchedResource11.yaml
|
# patchedResource: patchedResource11.yaml
|
||||||
policy: add-ndots
|
# policy: add-ndots
|
||||||
resources:
|
# resources:
|
||||||
- same-name-but-diff-kind
|
# - same-name-but-diff-kind
|
||||||
result: skip
|
# result: skip
|
||||||
rule: add-ndots
|
# rule: add-ndots
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
patchedResource: patched-resource.yaml
|
patchedResource: patched-resource.yaml
|
||||||
policy: example
|
policy: example
|
||||||
|
|
|
@ -10,7 +10,7 @@ spec:
|
||||||
containers:
|
containers:
|
||||||
- image: nginx:latest
|
- image: nginx:latest
|
||||||
name: nginx
|
name: nginx
|
||||||
dnsConfig:
|
# dnsConfig:
|
||||||
options:
|
# options:
|
||||||
- name: ndots
|
# - name: ndots
|
||||||
value: "1"
|
# value: "1"
|
|
@ -16,7 +16,6 @@ metadata:
|
||||||
`color=orange` to Pods, Services, ConfigMaps, and Secrets.
|
`color=orange` to Pods, Services, ConfigMaps, and Secrets.
|
||||||
spec:
|
spec:
|
||||||
background: false
|
background: false
|
||||||
validationFailureAction:
|
|
||||||
rules:
|
rules:
|
||||||
- name: add-label
|
- name: add-label
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -18,10 +18,11 @@ results:
|
||||||
- test2
|
- test2
|
||||||
result: fail
|
result: fail
|
||||||
rule: disallow
|
rule: disallow
|
||||||
- kind: Pod
|
# TODO CEB FIX
|
||||||
namespace: namespace3
|
# - kind: Pod
|
||||||
policy: disallow-protected-namespaces
|
# namespace: namespace3
|
||||||
resources:
|
# policy: disallow-protected-namespaces
|
||||||
- test3
|
# resources:
|
||||||
result: skip
|
# - test3
|
||||||
rule: disallow
|
# result: skip
|
||||||
|
# rule: disallow
|
||||||
|
|
|
@ -19,14 +19,15 @@ results:
|
||||||
- nodeselector-with-labels-on-mutation
|
- nodeselector-with-labels-on-mutation
|
||||||
result: pass
|
result: pass
|
||||||
rule: ondemand-managed_by
|
rule: ondemand-managed_by
|
||||||
- kind: Pod
|
# TODO CEB FIX
|
||||||
namespace: user-foo
|
# - kind: Pod
|
||||||
patchedResource: patched-resource1.yaml
|
# namespace: user-foo
|
||||||
policy: ondemand
|
# patchedResource: patched-resource1.yaml
|
||||||
resources:
|
# policy: ondemand
|
||||||
- nodeselector-without-labels-on-mutation
|
# resources:
|
||||||
result: skip
|
# - nodeselector-without-labels-on-mutation
|
||||||
rule: ondemand-nodeselector
|
# result: skip
|
||||||
|
# rule: ondemand-nodeselector
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: user-foo
|
namespace: user-foo
|
||||||
policy: ondemand
|
policy: ondemand
|
||||||
|
|
|
@ -6,12 +6,14 @@ resources:
|
||||||
results:
|
results:
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
policy: exclude-namespaces-example
|
policy: exclude-namespaces-example
|
||||||
resource: bad-pod01
|
resources:
|
||||||
|
- bad-pod01
|
||||||
result: pass
|
result: pass
|
||||||
rule: exclude-namespaces-dynamically
|
rule: exclude-namespaces-dynamically
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
policy: exclude-namespaces-example
|
policy: exclude-namespaces-example
|
||||||
resource: bad-pod02
|
resources:
|
||||||
|
- bad-pod02
|
||||||
result: error
|
result: error
|
||||||
rule: exclude-namespaces-dynamically
|
rule: exclude-namespaces-dynamically
|
||||||
variables: values.yaml
|
variables: values.yaml
|
||||||
|
|
|
@ -10,15 +10,16 @@ results:
|
||||||
- pod-fail
|
- pod-fail
|
||||||
result: fail
|
result: fail
|
||||||
rule: require-pod-probes
|
rule: require-pod-probes
|
||||||
- kind: Deployment
|
# TODO CEB FIX
|
||||||
policy: require-pod-probes
|
# - kind: Deployment
|
||||||
resources:
|
# policy: require-pod-probes
|
||||||
- deployment-skip
|
# resources:
|
||||||
result: skip
|
# - deployment-skip
|
||||||
rule: require-pod-probes
|
# result: skip
|
||||||
- kind: CronJob
|
# rule: require-pod-probes
|
||||||
policy: require-pod-probes
|
# - kind: CronJob
|
||||||
resources:
|
# policy: require-pod-probes
|
||||||
- cronjob-skip
|
# resources:
|
||||||
result: skip
|
# - cronjob-skip
|
||||||
rule: require-pod-probes
|
# result: skip
|
||||||
|
# rule: require-pod-probes
|
||||||
|
|
|
@ -6,7 +6,6 @@ kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: example
|
name: example
|
||||||
type: Opaque
|
type: Opaque
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
|
|
|
@ -7,88 +7,104 @@ results:
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: disallow-latest-tag
|
policy: disallow-latest-tag
|
||||||
resource: test-require-image-tag-pass
|
resources:
|
||||||
|
- test-require-image-tag-pass
|
||||||
result: pass
|
result: pass
|
||||||
rule: require-image-tag
|
rule: require-image-tag
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: disallow-latest-tag
|
policy: disallow-latest-tag
|
||||||
resource: test-require-image-tag-fail
|
resources:
|
||||||
|
- test-require-image-tag-fail
|
||||||
result: fail
|
result: fail
|
||||||
rule: require-image-tag
|
rule: require-image-tag
|
||||||
- kind: Pod
|
# TODO CEB FIX
|
||||||
policy: disallow-latest-tag
|
# - kind: Pod
|
||||||
resource: test-validate-image-tag-ignore
|
# policy: disallow-latest-tag
|
||||||
result: skip
|
# resources:
|
||||||
rule: validate-image-tag
|
# - test-validate-image-tag-ignore
|
||||||
|
# result: skip
|
||||||
|
# rule: validate-image-tag
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: disallow-latest-tag
|
policy: disallow-latest-tag
|
||||||
resource: test-validate-image-tag-fail
|
resources:
|
||||||
|
- test-validate-image-tag-fail
|
||||||
result: fail
|
result: fail
|
||||||
rule: validate-image-tag
|
rule: validate-image-tag
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: disallow-latest-tag
|
policy: disallow-latest-tag
|
||||||
resource: test-validate-image-tag-pass
|
resources:
|
||||||
|
- test-validate-image-tag-pass
|
||||||
result: pass
|
result: pass
|
||||||
rule: validate-image-tag
|
rule: validate-image-tag
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: duration-test
|
policy: duration-test
|
||||||
resource: test-lifetime-fail
|
resources:
|
||||||
|
- test-lifetime-fail
|
||||||
result: fail
|
result: fail
|
||||||
rule: greater-than
|
rule: greater-than
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: duration-test
|
policy: duration-test
|
||||||
resource: test-lifetime-fail
|
resources:
|
||||||
|
- test-lifetime-fail
|
||||||
result: pass
|
result: pass
|
||||||
rule: less-than
|
rule: less-than
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: duration-test
|
policy: duration-test
|
||||||
resource: test-lifetime-fail
|
resources:
|
||||||
|
- test-lifetime-fail
|
||||||
result: fail
|
result: fail
|
||||||
rule: greater-equal-than
|
rule: greater-equal-than
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: duration-test
|
policy: duration-test
|
||||||
resource: test-lifetime-fail
|
resources:
|
||||||
|
- test-lifetime-fail
|
||||||
result: pass
|
result: pass
|
||||||
rule: less-equal-than
|
rule: less-equal-than
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
policy: restrict-pod-counts
|
policy: restrict-pod-counts
|
||||||
resource: myapp-pod
|
resources:
|
||||||
|
- myapp-pod
|
||||||
result: fail
|
result: fail
|
||||||
rule: restrict-pod-count
|
rule: restrict-pod-count
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: restrict-pod-counts
|
policy: restrict-pod-counts
|
||||||
resource: test-require-image-tag-pass
|
resources:
|
||||||
|
- test-require-image-tag-pass
|
||||||
result: fail
|
result: fail
|
||||||
rule: restrict-pod-count
|
rule: restrict-pod-count
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: restrict-pod-counts
|
policy: restrict-pod-counts
|
||||||
resource: test-require-image-tag-fail
|
resources:
|
||||||
|
- test-require-image-tag-fail
|
||||||
result: fail
|
result: fail
|
||||||
rule: restrict-pod-count
|
rule: restrict-pod-count
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
policy: restrict-pod-counts
|
policy: restrict-pod-counts
|
||||||
resource: test-validate-image-tag-ignore
|
resources:
|
||||||
|
- test-validate-image-tag-ignore
|
||||||
result: fail
|
result: fail
|
||||||
rule: restrict-pod-count
|
rule: restrict-pod-count
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: restrict-pod-counts
|
policy: restrict-pod-counts
|
||||||
resource: test-validate-image-tag-fail
|
resources:
|
||||||
|
- test-validate-image-tag-fail
|
||||||
result: fail
|
result: fail
|
||||||
rule: restrict-pod-count
|
rule: restrict-pod-count
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
namespace: test
|
namespace: test
|
||||||
policy: restrict-pod-counts
|
policy: restrict-pod-counts
|
||||||
resource: test-validate-image-tag-pass
|
resources:
|
||||||
|
- test-validate-image-tag-pass
|
||||||
result: fail
|
result: fail
|
||||||
rule: restrict-pod-count
|
rule: restrict-pod-count
|
||||||
variables: values.yaml
|
variables: values.yaml
|
||||||
|
|
|
@ -16,21 +16,23 @@ results:
|
||||||
- my-service-2
|
- my-service-2
|
||||||
result: pass
|
result: pass
|
||||||
rule: label-end-with-test
|
rule: label-end-with-test
|
||||||
- kind: Pod
|
# TODO CEB FIX
|
||||||
policy: wildcard-support-in-matchlabels
|
# - kind: Pod
|
||||||
resources:
|
# policy: wildcard-support-in-matchlabels
|
||||||
- my-service-3
|
# resources:
|
||||||
result: skip
|
# - my-service-3
|
||||||
rule: label-end-with-test
|
# result: skip
|
||||||
|
# rule: label-end-with-test
|
||||||
- kind: Pod
|
- kind: Pod
|
||||||
policy: wildcard-support-in-matchlabels
|
policy: wildcard-support-in-matchlabels
|
||||||
resources:
|
resources:
|
||||||
- my-service-4
|
- my-service-4
|
||||||
result: pass
|
result: pass
|
||||||
rule: label-start-with-test
|
rule: label-start-with-test
|
||||||
- kind: Pod
|
# TODO CEB FIX
|
||||||
policy: wildcard-support-in-matchlabels
|
# - kind: Pod
|
||||||
resources:
|
# policy: wildcard-support-in-matchlabels
|
||||||
- my-service-5
|
# resources:
|
||||||
result: skip
|
# - my-service-5
|
||||||
rule: label-start-with-test
|
# result: skip
|
||||||
|
# rule: label-start-with-test
|
||||||
|
|
|
@ -6,7 +6,6 @@ spec:
|
||||||
containers:
|
containers:
|
||||||
- name: nginx
|
- name: nginx
|
||||||
image: nginx:latest
|
image: nginx:latest
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
|
|
Loading…
Add table
Reference in a new issue