diff --git a/api/kyverno/v1/violated_rule_types.go b/api/kyverno/v1/violated_rule_types.go
deleted file mode 100755
index 945cf419cb..0000000000
--- a/api/kyverno/v1/violated_rule_types.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package v1
-
-// ViolatedRule stores the information regarding the rule.
-type ViolatedRule struct {
- // Name specifies violated rule name.
- Name string `json:"name" yaml:"name"`
-
- // Type specifies violated rule type.
- Type string `json:"type" yaml:"type"`
-
- // Message specifies violation message.
- // +optional
- Message string `json:"message" yaml:"message"`
-
- // Status shows the rule response status
- Status string `json:"status" yaml:"status"`
-}
diff --git a/api/kyverno/v1/zz_generated.deepcopy.go b/api/kyverno/v1/zz_generated.deepcopy.go
index 96142f8650..4c5c990fc5 100755
--- a/api/kyverno/v1/zz_generated.deepcopy.go
+++ b/api/kyverno/v1/zz_generated.deepcopy.go
@@ -1423,18 +1423,3 @@ func (in *Variable) DeepCopy() *Variable {
in.DeepCopyInto(out)
return out
}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ViolatedRule) DeepCopyInto(out *ViolatedRule) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ViolatedRule.
-func (in *ViolatedRule) DeepCopy() *ViolatedRule {
- if in == nil {
- return nil
- }
- out := new(ViolatedRule)
- in.DeepCopyInto(out)
- return out
-}
diff --git a/cmd/cli/kubectl-kyverno/apply/apply_command.go b/cmd/cli/kubectl-kyverno/apply/apply_command.go
index b23fc74a55..3fddb5d931 100644
--- a/cmd/cli/kubectl-kyverno/apply/apply_command.go
+++ b/cmd/cli/kubectl-kyverno/apply/apply_command.go
@@ -16,8 +16,10 @@ import (
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
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/pkg/autogen"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
+ engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/openapi"
policy2 "github.com/kyverno/kyverno/pkg/policy"
gitutils "github.com/kyverno/kyverno/pkg/utils/git"
@@ -175,7 +177,7 @@ func Command() *cobra.Command {
return err
}
- PrintReportOrViolation(applyCommandConfig.PolicyReport, rc, applyCommandConfig.ResourcePaths, len(resources), skipInvalidPolicies, applyCommandConfig.Stdin, pvInfos, applyCommandConfig.warnExitCode, applyCommandConfig.warnNoPassed)
+ PrintReportOrViolation(applyCommandConfig.PolicyReport, rc, applyCommandConfig.ResourcePaths, len(resources), skipInvalidPolicies, applyCommandConfig.Stdin, pvInfos, applyCommandConfig.warnExitCode, applyCommandConfig.warnNoPassed, applyCommandConfig.AuditWarn)
return nil
},
}
@@ -199,7 +201,7 @@ func Command() *cobra.Command {
return cmd
}
-func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, resources []*unstructured.Unstructured, skipInvalidPolicies SkippedInvalidPolicies, pvInfos []common.Info, err error) {
+func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, resources []*unstructured.Unstructured, skipInvalidPolicies SkippedInvalidPolicies, responses []engineapi.EngineResponse, err error) {
store.SetMock(true)
store.SetRegistryAccess(c.RegistryAccess)
if c.Cluster {
@@ -208,48 +210,48 @@ func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, reso
fs := memfs.New()
if c.ValuesFile != "" && c.VariablesString != "" {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("pass the values either using set flag or values_file flag", err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("pass the values either using set flag or values_file flag", err)
}
variables, globalValMap, valuesMap, namespaceSelectorMap, subresources, err := common.GetVariable(c.VariablesString, c.ValuesFile, fs, false, "")
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("failed to decode yaml", err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("failed to decode yaml", err)
}
- return rc, resources, skipInvalidPolicies, pvInfos, err
+ return rc, resources, skipInvalidPolicies, responses, err
}
openApiManager, err := openapi.NewManager(log.Log)
if err != nil {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("failed to initialize openAPIController", err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("failed to initialize openAPIController", err)
}
var dClient dclient.Interface
if c.Cluster {
restConfig, err := config.CreateClientConfigWithContext(c.KubeConfig, c.Context)
if err != nil {
- return rc, resources, skipInvalidPolicies, pvInfos, err
+ return rc, resources, skipInvalidPolicies, responses, err
}
kubeClient, err := kubernetes.NewForConfig(restConfig)
if err != nil {
- return rc, resources, skipInvalidPolicies, pvInfos, err
+ return rc, resources, skipInvalidPolicies, responses, err
}
dynamicClient, err := dynamic.NewForConfig(restConfig)
if err != nil {
- return rc, resources, skipInvalidPolicies, pvInfos, err
+ return rc, resources, skipInvalidPolicies, responses, err
}
dClient, err = dclient.NewClient(context.Background(), dynamicClient, kubeClient, 15*time.Minute)
if err != nil {
- return rc, resources, skipInvalidPolicies, pvInfos, err
+ return rc, resources, skipInvalidPolicies, responses, err
}
}
if len(c.PolicyPaths) == 0 {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("require policy", err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("require policy", err)
}
if (len(c.PolicyPaths) > 0 && c.PolicyPaths[0] == "-") && len(c.ResourcePaths) > 0 && c.ResourcePaths[0] == "-" {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("a stdin pipe can be used for either policies or resources, not both", err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("a stdin pipe can be used for either policies or resources, not both", err)
}
var policies []kyvernov1.PolicyInterface
@@ -282,7 +284,7 @@ func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, reso
}
policyYamls, err := gitutils.ListYamls(fs, gitPathToYamls)
if err != nil {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("failed to list YAMLs in repository", err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("failed to list YAMLs in repository", err)
}
sort.Strings(policyYamls)
c.PolicyPaths = policyYamls
@@ -294,15 +296,15 @@ func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, reso
}
if len(c.ResourcePaths) == 0 && !c.Cluster {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("resource file(s) or cluster required", err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("resource file(s) or cluster required", err)
}
mutateLogPathIsDir, err := checkMutateLogPath(c.MutateLogPath)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("failed to create file/folder", err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("failed to create file/folder", err)
}
- return rc, resources, skipInvalidPolicies, pvInfos, err
+ return rc, resources, skipInvalidPolicies, responses, err
}
// empty the previous contents of the file just in case if the file already existed before with some content(so as to perform overwrites)
@@ -313,15 +315,15 @@ func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, reso
_, err := os.OpenFile(c.MutateLogPath, os.O_TRUNC|os.O_WRONLY, 0o600) // #nosec G304
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("failed to truncate the existing file at "+c.MutateLogPath, err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("failed to truncate the existing file at "+c.MutateLogPath, err)
}
- return rc, resources, skipInvalidPolicies, pvInfos, err
+ return rc, resources, skipInvalidPolicies, responses, err
}
}
err = common.PrintMutatedPolicy(policies)
if err != nil {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("failed to marshal mutated policy", err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("failed to marshal mutated policy", err)
}
resources, err = common.GetResourceAccordingToResourcePath(fs, c.ResourcePaths, c.Cluster, policies, dClient, c.Namespace, c.PolicyReport, false, "")
@@ -331,7 +333,7 @@ func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, reso
}
if (len(resources) > 1 || len(policies) > 1) && c.VariablesString != "" {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError("currently `set` flag supports variable for single policy applied on single resource ", nil)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError("currently `set` flag supports variable for single policy applied on single resource ", nil)
}
// get the user info as request info from a different file
@@ -415,7 +417,7 @@ func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, reso
for _, resource := range resources {
thisPolicyResourceValues, err := common.CheckVariableForPolicy(valuesMap, globalValMap, policy.GetName(), resource.GetName(), resource.GetKind(), variables, kindOnwhichPolicyIsApplied, variable)
if err != nil {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError(fmt.Sprintf("policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag", policy.GetName(), resource.GetName()), err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError(fmt.Sprintf("policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag", policy.GetName(), resource.GetName()), err)
}
applyPolicyConfig := common.ApplyPolicyConfig{
Policy: policy,
@@ -433,15 +435,60 @@ func (c *ApplyCommandConfig) applyCommandHelper() (rc *common.ResultCounts, reso
AuditWarn: c.AuditWarn,
Subresources: subresources,
}
- _, info, err := common.ApplyPolicyOnResource(applyPolicyConfig)
+ ers, err := common.ApplyPolicyOnResource(applyPolicyConfig)
if err != nil {
- return rc, resources, skipInvalidPolicies, pvInfos, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.GetName(), resource.GetName()).Error(), err)
+ return rc, resources, skipInvalidPolicies, responses, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.GetName(), resource.GetName()).Error(), err)
+ }
+ for _, response := range ers {
+ if !response.IsEmpty() {
+ for _, rule := range autogen.ComputeRules(response.Policy) {
+ if rule.HasValidate() || rule.HasVerifyImageChecks() || rule.HasVerifyImages() {
+ ruleFoundInEngineResponse := false
+ for _, valResponseRule := range response.PolicyResponse.Rules {
+ if rule.Name == valResponseRule.Name() {
+ ruleFoundInEngineResponse = true
+ switch valResponseRule.Status() {
+ case engineapi.RuleStatusPass:
+ rc.Pass++
+ case engineapi.RuleStatusFail:
+ ann := policy.GetAnnotations()
+ if scored, ok := ann[kyvernov1.AnnotationPolicyScored]; ok && scored == "false" {
+ rc.Warn++
+ break
+ } else if applyPolicyConfig.AuditWarn && response.GetValidationFailureAction().Audit() {
+ rc.Warn++
+ } else {
+ rc.Fail++
+ }
+ case engineapi.RuleStatusError:
+ rc.Error++
+ case engineapi.RuleStatusWarn:
+ rc.Warn++
+ case engineapi.RuleStatusSkip:
+ rc.Skip++
+ }
+ continue
+ }
+ }
+ if !ruleFoundInEngineResponse {
+ rc.Skip++
+ response.PolicyResponse.Rules = append(response.PolicyResponse.Rules,
+ *engineapi.RuleSkip(
+ rule.Name,
+ engineapi.Validation,
+ rule.Validation.Message,
+ ),
+ )
+ }
+ }
+ }
+ }
+ responses = append(responses, response)
}
- pvInfos = append(pvInfos, info)
}
}
- return rc, resources, skipInvalidPolicies, pvInfos, nil
+ return rc, resources, skipInvalidPolicies, responses, nil
}
// checkMutateLogPath - checking path for printing mutated resource (-o flag)
@@ -467,7 +514,7 @@ func checkMutateLogPath(mutateLogPath string) (mutateLogPathIsDir bool, err erro
}
// PrintReportOrViolation - printing policy report/violations
-func PrintReportOrViolation(policyReport bool, rc *common.ResultCounts, resourcePaths []string, resourcesLen int, skipInvalidPolicies SkippedInvalidPolicies, stdin bool, pvInfos []common.Info, warnExitCode int, warnNoPassed bool) {
+func PrintReportOrViolation(policyReport bool, rc *common.ResultCounts, resourcePaths []string, resourcesLen int, skipInvalidPolicies SkippedInvalidPolicies, stdin bool, engineResponses []engineapi.EngineResponse, warnExitCode int, warnNoPassed bool, auditWarn bool) {
divider := "----------------------------------------------------------------------"
if len(skipInvalidPolicies.skipped) > 0 {
@@ -488,7 +535,7 @@ func PrintReportOrViolation(policyReport bool, rc *common.ResultCounts, resource
}
if policyReport {
- resps := buildPolicyReports(pvInfos)
+ resps := buildPolicyReports(auditWarn, engineResponses...)
if len(resps) > 0 || resourcesLen == 0 {
fmt.Println(divider)
fmt.Println("POLICY REPORT:")
@@ -502,8 +549,7 @@ func PrintReportOrViolation(policyReport bool, rc *common.ResultCounts, resource
}
} else {
if !stdin {
- fmt.Printf("\npass: %d, fail: %d, warn: %d, error: %d, skip: %d \n",
- rc.Pass, rc.Fail, rc.Warn, rc.Error, rc.Skip)
+ fmt.Printf("\npass: %d, fail: %d, warn: %d, error: %d, skip: %d \n", rc.Pass, rc.Fail, rc.Warn, rc.Error, rc.Skip)
}
}
diff --git a/cmd/cli/kubectl-kyverno/apply/apply_command_test.go b/cmd/cli/kubectl-kyverno/apply/apply_command_test.go
index 48e3e5e2af..76345ae78e 100644
--- a/cmd/cli/kubectl-kyverno/apply/apply_command_test.go
+++ b/cmd/cli/kubectl-kyverno/apply/apply_command_test.go
@@ -206,7 +206,7 @@ func Test_Apply(t *testing.T) {
_, _, _, info, err := tc.config.applyCommandHelper()
assert.NilError(t, err, desc)
- resps := buildPolicyReports(info)
+ resps := buildPolicyReports(tc.config.AuditWarn, info...)
assert.Assert(t, len(resps) > 0, "policy reports should not be empty: %s", desc)
for i, resp := range resps {
compareSummary(tc.expectedPolicyReports[i].Summary, resp.UnstructuredContent()["summary"].(map[string]interface{}), desc)
diff --git a/cmd/cli/kubectl-kyverno/apply/report.go b/cmd/cli/kubectl-kyverno/apply/report.go
index 1d31a1456f..cfd4b3bbc1 100644
--- a/cmd/cli/kubectl-kyverno/apply/report.go
+++ b/cmd/cli/kubectl-kyverno/apply/report.go
@@ -8,24 +8,22 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
- "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/log"
)
const clusterpolicyreport = "clusterpolicyreport"
// resps is the engine responses generated for a single policy
-func buildPolicyReports(pvInfos []common.Info) (res []*unstructured.Unstructured) {
+func buildPolicyReports(auditWarn bool, engineResponses ...engineapi.EngineResponse) (res []*unstructured.Unstructured) {
var raw []byte
var err error
- resultsMap := buildPolicyResults(pvInfos)
+ resultsMap := buildPolicyResults(auditWarn, engineResponses...)
for scope, result := range resultsMap {
if scope == clusterpolicyreport {
report := &policyreportv1alpha2.ClusterPolicyReport{
@@ -74,46 +72,63 @@ func buildPolicyReports(pvInfos []common.Info) (res []*unstructured.Unstructured
// buildPolicyResults returns a string-PolicyReportResult map
// the key of the map is one of "clusterpolicyreport", "policyreport-ns-"
-func buildPolicyResults(infos []common.Info) map[string][]policyreportv1alpha2.PolicyReportResult {
+func buildPolicyResults(auditWarn bool, engineResponses ...engineapi.EngineResponse) map[string][]policyreportv1alpha2.PolicyReportResult {
results := make(map[string][]policyreportv1alpha2.PolicyReportResult)
now := metav1.Timestamp{Seconds: time.Now().Unix()}
- for _, info := range infos {
+ for _, engineResponse := range engineResponses {
+ policy := engineResponse.Policy
var appname string
- ns := info.Namespace
+ ns := policy.GetNamespace()
if ns != "" {
appname = fmt.Sprintf("policyreport-ns-%s", ns)
} else {
appname = clusterpolicyreport
}
- for _, infoResult := range info.Results {
- for _, rule := range infoResult.Rules {
- if rule.Type != string(engineapi.Validation) {
- continue
- }
-
- result := policyreportv1alpha2.PolicyReportResult{
- Policy: info.PolicyName,
- Resources: []corev1.ObjectReference{
- {
- Kind: infoResult.Resource.Kind,
- Namespace: infoResult.Resource.Namespace,
- APIVersion: infoResult.Resource.APIVersion,
- Name: infoResult.Resource.Name,
- UID: types.UID(infoResult.Resource.UID),
- },
- },
- Scored: true,
- }
-
- result.Rule = rule.Name
- result.Message = rule.Message
- result.Result = policyreportv1alpha2.PolicyResult(rule.Status)
- result.Source = kyvernov1.ValueKyvernoApp
- result.Timestamp = now
- results[appname] = append(results[appname], result)
+ for _, ruleResponse := range engineResponse.PolicyResponse.Rules {
+ if ruleResponse.RuleType() != engineapi.Validation {
+ continue
}
+
+ result := policyreportv1alpha2.PolicyReportResult{
+ Policy: policy.GetName(),
+ Resources: []corev1.ObjectReference{
+ {
+ Kind: engineResponse.Resource.GetKind(),
+ Namespace: engineResponse.Resource.GetNamespace(),
+ APIVersion: engineResponse.Resource.GetAPIVersion(),
+ Name: engineResponse.Resource.GetName(),
+ UID: engineResponse.Resource.GetUID(),
+ },
+ },
+ Scored: true,
+ }
+
+ ann := engineResponse.Policy.GetAnnotations()
+ 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, ok := ann[kyvernov1.AnnotationPolicyScored]; ok && scored == "false" {
+ result.Result = policyreportv1alpha2.StatusWarn
+ } else if auditWarn && engineResponse.GetValidationFailureAction().Audit() {
+ result.Result = policyreportv1alpha2.StatusWarn
+ } else {
+ result.Result = policyreportv1alpha2.StatusFail
+ }
+ } else {
+ fmt.Println(ruleResponse)
+ }
+
+ result.Rule = ruleResponse.Name()
+ result.Message = ruleResponse.Message()
+ result.Source = kyvernov1.ValueKyvernoApp
+ result.Timestamp = now
+ results[appname] = append(results[appname], result)
}
}
diff --git a/cmd/cli/kubectl-kyverno/apply/report_test.go b/cmd/cli/kubectl-kyverno/apply/report_test.go
index 34ea473f93..4f5c175603 100644
--- a/cmd/cli/kubectl-kyverno/apply/report_test.go
+++ b/cmd/cli/kubectl-kyverno/apply/report_test.go
@@ -6,8 +6,6 @@ import (
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
preport "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
- "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
- kyvCommon "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"gotest.tools/assert"
v1 "k8s.io/api/core/v1"
@@ -84,8 +82,6 @@ var rawPolicy = []byte(`
`)
func Test_buildPolicyReports(t *testing.T) {
- rc := &kyvCommon.ResultCounts{}
- var pvInfos []common.Info
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
@@ -106,10 +102,7 @@ func Test_buildPolicyReports(t *testing.T) {
),
)
- info := kyvCommon.ProcessValidateEngineResponse(&policy, &er, "", rc, true, false)
- pvInfos = append(pvInfos, info)
-
- reports := buildPolicyReports(pvInfos)
+ reports := buildPolicyReports(false, er)
assert.Assert(t, len(reports) == 1, len(reports))
for _, report := range reports {
@@ -132,8 +125,6 @@ func Test_buildPolicyReports(t *testing.T) {
}
func Test_buildPolicyResults(t *testing.T) {
- rc := &kyvCommon.ResultCounts{}
- var pvInfos []common.Info
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
@@ -153,10 +144,7 @@ func Test_buildPolicyResults(t *testing.T) {
),
)
- info := kyvCommon.ProcessValidateEngineResponse(&policy, &er, "", rc, true, false)
- pvInfos = append(pvInfos, info)
-
- results := buildPolicyResults(pvInfos)
+ results := buildPolicyResults(false, er)
for _, result := range results {
assert.Assert(t, len(result) == 2, len(result))
diff --git a/cmd/cli/kubectl-kyverno/test/test_command.go b/cmd/cli/kubectl-kyverno/test/test_command.go
index c4d019c8bc..29621de323 100644
--- a/cmd/cli/kubectl-kyverno/test/test_command.go
+++ b/cmd/cli/kubectl-kyverno/test/test_command.go
@@ -11,7 +11,6 @@ import (
"regexp"
"sort"
"strings"
- "time"
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/memfs"
@@ -33,7 +32,6 @@ import (
"github.com/spf13/cobra"
"golang.org/x/exp/slices"
corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/yaml"
"sigs.k8s.io/controller-runtime/pkg/log"
@@ -189,7 +187,7 @@ func Command() *cobra.Command {
manifest.PrintValidate()
} else {
store.SetRegistryAccess(registryAccess)
- _, err = testCommandExecute(dirPath, fileName, gitBranch, testCase, failOnly, removeColor)
+ _, err = testCommandExecute(dirPath, fileName, gitBranch, testCase, failOnly, removeColor, false)
if err != nil {
log.Log.V(3).Info("a directory is required")
return err
@@ -232,7 +230,15 @@ type testFilter struct {
var ftable []Table
-func testCommandExecute(dirPath []string, fileName string, gitBranch string, testCase string, failOnly bool, removeColor bool) (rc *resultCounts, err error) {
+func testCommandExecute(
+ dirPath []string,
+ fileName string,
+ gitBranch string,
+ testCase string,
+ failOnly bool,
+ removeColor bool,
+ auditWarn bool,
+) (rc *resultCounts, err error) {
var errors []error
fs := memfs.New()
rc = &resultCounts{}
@@ -352,7 +358,7 @@ func testCommandExecute(dirPath []string, fileName string, gitBranch string, tes
errors = append(errors, sanitizederror.NewWithError("failed to convert to JSON", err))
continue
}
- if err := applyPoliciesFromPath(fs, policyBytes, true, policyresoucePath, rc, openApiManager, tf, failOnly, removeColor); err != nil {
+ if err := applyPoliciesFromPath(fs, policyBytes, true, policyresoucePath, rc, openApiManager, tf, failOnly, removeColor, auditWarn); err != nil {
return rc, sanitizederror.NewWithError("failed to apply test command", err)
}
}
@@ -364,7 +370,7 @@ func testCommandExecute(dirPath []string, fileName string, gitBranch string, tes
} else {
var testFiles int
path := filepath.Clean(dirPath[0])
- errors = getLocalDirTestFiles(fs, path, fileName, rc, &testFiles, openApiManager, tf, failOnly, removeColor)
+ errors = getLocalDirTestFiles(fs, path, fileName, rc, &testFiles, openApiManager, tf, failOnly, removeColor, auditWarn)
if testFiles == 0 {
fmt.Printf("\n No test files found. Please provide test YAML files named kyverno-test.yaml \n")
@@ -393,7 +399,18 @@ func testCommandExecute(dirPath []string, fileName string, gitBranch string, tes
return rc, nil
}
-func getLocalDirTestFiles(fs billy.Filesystem, path, fileName string, rc *resultCounts, testFiles *int, openApiManager openapi.Manager, tf *testFilter, failOnly, removeColor bool) []error {
+func getLocalDirTestFiles(
+ fs billy.Filesystem,
+ path string,
+ fileName string,
+ rc *resultCounts,
+ testFiles *int,
+ openApiManager openapi.Manager,
+ tf *testFilter,
+ failOnly bool,
+ removeColor bool,
+ auditWarn bool,
+) []error {
var errors []error
files, err := os.ReadDir(path)
@@ -402,7 +419,7 @@ func getLocalDirTestFiles(fs billy.Filesystem, path, fileName string, rc *result
}
for _, file := range files {
if file.IsDir() {
- getLocalDirTestFiles(fs, filepath.Join(path, file.Name()), fileName, rc, testFiles, openApiManager, tf, failOnly, removeColor)
+ getLocalDirTestFiles(fs, filepath.Join(path, file.Name()), fileName, rc, testFiles, openApiManager, tf, failOnly, removeColor, auditWarn)
continue
}
if file.Name() == fileName {
@@ -418,7 +435,7 @@ func getLocalDirTestFiles(fs billy.Filesystem, path, fileName string, rc *result
errors = append(errors, sanitizederror.NewWithError("failed to convert json", err))
continue
}
- if err := applyPoliciesFromPath(fs, valuesBytes, false, path, rc, openApiManager, tf, failOnly, removeColor); err != nil {
+ if err := applyPoliciesFromPath(fs, valuesBytes, false, path, rc, openApiManager, tf, failOnly, removeColor, auditWarn); err != nil {
errors = append(errors, sanitizederror.NewWithError(fmt.Sprintf("failed to apply test command from file %s", file.Name()), err))
continue
}
@@ -427,9 +444,15 @@ func getLocalDirTestFiles(fs billy.Filesystem, path, fileName string, rc *result
return errors
}
-func buildPolicyResults(engineResponses []*engineapi.EngineResponse, testResults []api.TestResults, infos []common.Info, policyResourcePath string, fs billy.Filesystem, isGit bool) (map[string]policyreportv1alpha2.PolicyReportResult, []api.TestResults) {
- results := make(map[string]policyreportv1alpha2.PolicyReportResult)
- now := metav1.Timestamp{Seconds: time.Now().Unix()}
+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 {
policyName := resp.Policy.GetName()
@@ -573,75 +596,85 @@ func buildPolicyResults(engineResponses []*engineapi.EngineResponse, testResults
results[resultKey] = result
}
}
- }
- for _, rule := range resp.PolicyResponse.Rules {
- if rule.RuleType() != engineapi.Mutation {
- continue
- }
-
- var resultsKey []string
- var resultKey string
- var result policyreportv1alpha2.PolicyReportResult
- resultsKey = GetAllPossibleResultsKey(policyNamespace, policyName, rule.Name(), resourceNamespace, resourceKind, resourceName)
- for _, key := range resultsKey {
- if val, ok := results[key]; ok {
- result = val
- resultKey = key
- } else {
+ for _, rule := range resp.PolicyResponse.Rules {
+ if rule.RuleType() != engineapi.Mutation || test.Rule != rule.Name() {
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 _, info := range infos {
- for _, infoResult := range info.Results {
- for _, rule := range infoResult.Rules {
- if rule.Type != string(engineapi.Validation) && rule.Type != string(engineapi.ImageVerify) {
- continue
- }
-
- var result policyreportv1alpha2.PolicyReportResult
- var resultsKeys []string
+ var resultsKey []string
var resultKey string
- resultsKeys = GetAllPossibleResultsKey("", info.PolicyName, rule.Name, infoResult.Resource.Namespace, infoResult.Resource.Kind, infoResult.Resource.Name)
- for _, key := range resultsKeys {
+ var result policyreportv1alpha2.PolicyReportResult
+ resultsKey = GetAllPossibleResultsKey(policyNamespace, policyName, rule.Name(), resourceNamespace, resourceKind, resourceName)
+ 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() {
+ continue
}
- result.Rule = rule.Name
- result.Result = policyreportv1alpha2.PolicyResult(rule.Status)
- result.Source = kyvernov1.ValueKyvernoApp
- result.Timestamp = now
- results[resultKey] = result
+ var resultsKey []string
+ var resultKey string
+ var result policyreportv1alpha2.PolicyReportResult
+ resultsKey = GetAllPossibleResultsKey(policyNamespace, policyName, rule.Name(), resourceNamespace, resourceKind, resourceName)
+ for _, key := range resultsKey {
+ if val, ok := results[key]; ok {
+ result = val
+ resultKey = key
+ } else {
+ continue
+ }
+
+ ann := resp.Policy.GetAnnotations()
+ 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, ok := ann[kyvernov1.AnnotationPolicyScored]; ok && scored == "false" {
+ 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
}
@@ -707,7 +740,7 @@ func getAndCompareResource(path string, engineResource unstructured.Unstructured
return status
}
-func buildMessage(resp *engineapi.EngineResponse) string {
+func buildMessage(resp engineapi.EngineResponse) string {
var bldr strings.Builder
for _, ruleResp := range resp.PolicyResponse.Rules {
fmt.Fprintf(&bldr, " %s: %s \n", ruleResp.Name(), ruleResp.Status())
@@ -730,12 +763,22 @@ func getFullPath(paths []string, policyResourcePath string, isGit bool) []string
return paths
}
-func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool, policyResourcePath string, rc *resultCounts, openApiManager openapi.Manager, tf *testFilter, failOnly, removeColor bool) (err error) {
- engineResponses := make([]*engineapi.EngineResponse, 0)
+func applyPoliciesFromPath(
+ fs billy.Filesystem,
+ policyBytes []byte,
+ isGit bool,
+ policyResourcePath string,
+ rc *resultCounts,
+ openApiManager openapi.Manager,
+ tf *testFilter,
+ failOnly bool,
+ removeColor bool,
+ auditWarn bool,
+) (err error) {
+ engineResponses := make([]engineapi.EngineResponse, 0)
var dClient dclient.Interface
values := &api.Test{}
var variablesString string
- var pvInfos []common.Info
var resultCounts common.ResultCounts
store.SetMock(true)
@@ -911,15 +954,14 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
Client: dClient,
Subresources: subresources,
}
- ers, info, err := common.ApplyPolicyOnResource(applyPolicyConfig)
+ ers, err := common.ApplyPolicyOnResource(applyPolicyConfig)
if err != nil {
return sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.GetName(), resource.GetName()).Error(), err)
}
engineResponses = append(engineResponses, ers...)
- pvInfos = append(pvInfos, info)
}
}
- resultsMap, testResults := buildPolicyResults(engineResponses, values.Results, pvInfos, policyResourcePath, fs, isGit)
+ resultsMap, testResults := buildPolicyResults(engineResponses, values.Results, policyResourcePath, fs, isGit, auditWarn)
resultErr := printTestResult(resultsMap, testResults, rc, failOnly, removeColor)
if resultErr != nil {
return sanitizederror.NewWithError("failed to print test result:", resultErr)
diff --git a/cmd/cli/kubectl-kyverno/utils/common/common.go b/cmd/cli/kubectl-kyverno/utils/common/common.go
index 8f90f21f2a..644023e06d 100644
--- a/cmd/cli/kubectl-kyverno/utils/common/common.go
+++ b/cmd/cli/kubectl-kyverno/utils/common/common.go
@@ -14,7 +14,6 @@ import (
"github.com/go-git/go-billy/v5"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
- policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
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/pkg/autogen"
@@ -369,8 +368,8 @@ func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit
}
// ApplyPolicyOnResource - function to apply policy on resource
-func ApplyPolicyOnResource(c ApplyPolicyConfig) ([]*engineapi.EngineResponse, Info, error) {
- var engineResponses []*engineapi.EngineResponse
+func ApplyPolicyOnResource(c ApplyPolicyConfig) ([]engineapi.EngineResponse, error) {
+ var engineResponses []engineapi.EngineResponse
namespaceLabels := make(map[string]string)
operationIsDelete := false
@@ -416,7 +415,7 @@ OuterLoop:
resourceNamespace := c.Resource.GetNamespace()
namespaceLabels = c.NamespaceSelectorMap[c.Resource.GetNamespace()]
if resourceNamespace != "default" && len(namespaceLabels) < 1 {
- return engineResponses, Info{}, sanitizederror.NewWithError(fmt.Sprintf("failed to get namespace labels for resource %s. use --values-file flag to pass the namespace labels", c.Resource.GetName()), nil)
+ return engineResponses, sanitizederror.NewWithError(fmt.Sprintf("failed to get namespace labels for resource %s. use --values-file flag to pass the namespace labels", c.Resource.GetName()), nil)
}
}
@@ -492,12 +491,12 @@ OuterLoop:
WithResourceKind(gvk, subresource)
mutateResponse := eng.Mutate(context.Background(), policyContext)
- engineResponses = append(engineResponses, &mutateResponse)
+ engineResponses = append(engineResponses, mutateResponse)
err = processMutateEngineResponse(c, &mutateResponse, resPath)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
- return engineResponses, Info{}, sanitizederror.NewWithError("failed to print mutated result", err)
+ return engineResponses, sanitizederror.NewWithError("failed to print mutated result", err)
}
}
@@ -510,21 +509,20 @@ OuterLoop:
policyContext = policyContext.WithNewResource(mutateResponse.PatchedResource)
- var info Info
var validateResponse engineapi.EngineResponse
if policyHasValidate {
validateResponse = eng.Validate(context.Background(), policyContext)
- info = ProcessValidateEngineResponse(c.Policy, &validateResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)
+ ProcessValidateEngineResponse(c.Policy, validateResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)
}
if !validateResponse.IsEmpty() {
- engineResponses = append(engineResponses, &validateResponse)
+ engineResponses = append(engineResponses, validateResponse)
}
verifyImageResponse, _ := eng.VerifyAndPatchImages(context.TODO(), policyContext)
if !verifyImageResponse.IsEmpty() {
- engineResponses = append(engineResponses, &verifyImageResponse)
- info = ProcessValidateEngineResponse(c.Policy, &verifyImageResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)
+ engineResponses = append(engineResponses, verifyImageResponse)
+ ProcessValidateEngineResponse(c.Policy, verifyImageResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)
}
var policyHasGenerate bool
@@ -543,12 +541,66 @@ OuterLoop:
} else {
generateResponse.PolicyResponse.Rules = newRuleResponse
}
- engineResponses = append(engineResponses, &generateResponse)
+ engineResponses = append(engineResponses, generateResponse)
}
updateResultCounts(c.Policy, &generateResponse, resPath, c.Rc, c.AuditWarn)
}
- return engineResponses, info, nil
+ return engineResponses, nil
+}
+
+func ProcessValidateEngineResponse(policy kyvernov1.PolicyInterface, validateResponse engineapi.EngineResponse, resPath string, rc *ResultCounts, policyReport bool, auditWarn bool) {
+ printCount := 0
+ for _, policyRule := range autogen.ComputeRules(policy) {
+ ruleFoundInEngineResponse := false
+ if !policyRule.HasValidate() && !policyRule.HasVerifyImageChecks() && !policyRule.HasVerifyImages() {
+ continue
+ }
+
+ for i, valResponseRule := range validateResponse.PolicyResponse.Rules {
+ if policyRule.Name == valResponseRule.Name() {
+ ruleFoundInEngineResponse = true
+ switch valResponseRule.Status() {
+ case engineapi.RuleStatusPass:
+ rc.Pass++
+ case engineapi.RuleStatusFail:
+ auditWarning := false
+ ann := policy.GetAnnotations()
+ if scored, ok := ann[kyvernov1.AnnotationPolicyScored]; ok && scored == "false" {
+ rc.Warn++
+ break
+ } else if auditWarn && validateResponse.GetValidationFailureAction().Audit() {
+ rc.Warn++
+ auditWarning = true
+ } else {
+ rc.Fail++
+ }
+ if !policyReport {
+ if printCount < 1 {
+ if auditWarning {
+ fmt.Printf("\npolicy %s -> resource %s failed as audit warning: \n", policy.GetName(), resPath)
+ } else {
+ fmt.Printf("\npolicy %s -> resource %s failed: \n", policy.GetName(), resPath)
+ }
+ printCount++
+ }
+
+ fmt.Printf("%d. %s: %s \n", i+1, valResponseRule.Name(), valResponseRule.Message())
+ }
+ case engineapi.RuleStatusError:
+ rc.Error++
+ case engineapi.RuleStatusWarn:
+ rc.Warn++
+ case engineapi.RuleStatusSkip:
+ rc.Skip++
+ }
+ continue
+ }
+ }
+ if !ruleFoundInEngineResponse {
+ rc.Skip++
+ }
+ }
}
// PrintMutatedOutput - function to print output in provided file or directory
@@ -697,105 +749,6 @@ func GetResourceAccordingToResourcePath(fs billy.Filesystem, resourcePaths []str
return resources, err
}
-func ProcessValidateEngineResponse(policy kyvernov1.PolicyInterface, validateResponse *engineapi.EngineResponse, resPath string, rc *ResultCounts, policyReport bool, auditWarn bool) Info {
- var violatedRules []kyvernov1.ViolatedRule
-
- printCount := 0
- for _, policyRule := range autogen.ComputeRules(policy) {
- ruleFoundInEngineResponse := false
- if !policyRule.HasValidate() && !policyRule.HasVerifyImageChecks() && !policyRule.HasVerifyImages() {
- continue
- }
-
- for i, valResponseRule := range validateResponse.PolicyResponse.Rules {
- if policyRule.Name == valResponseRule.Name() {
- ruleFoundInEngineResponse = true
- vrule := kyvernov1.ViolatedRule{
- Name: valResponseRule.Name(),
- Type: string(valResponseRule.RuleType()),
- Message: valResponseRule.Message(),
- }
-
- switch valResponseRule.Status() {
- case engineapi.RuleStatusPass:
- rc.Pass++
- vrule.Status = policyreportv1alpha2.StatusPass
-
- case engineapi.RuleStatusFail:
- auditWarning := false
- ann := policy.GetAnnotations()
- if scored, ok := ann[kyvernov1.AnnotationPolicyScored]; ok && scored == "false" {
- rc.Warn++
- vrule.Status = policyreportv1alpha2.StatusWarn
- break
- } else if auditWarn && validateResponse.GetValidationFailureAction().Audit() {
- rc.Warn++
- auditWarning = true
- vrule.Status = policyreportv1alpha2.StatusWarn
- } else {
- rc.Fail++
- vrule.Status = policyreportv1alpha2.StatusFail
- }
-
- if !policyReport {
- if printCount < 1 {
- if auditWarning {
- fmt.Printf("\npolicy %s -> resource %s failed as audit warning: \n", policy.GetName(), resPath)
- } else {
- fmt.Printf("\npolicy %s -> resource %s failed: \n", policy.GetName(), resPath)
- }
- printCount++
- }
-
- fmt.Printf("%d. %s: %s \n", i+1, valResponseRule.Name(), valResponseRule.Message())
- }
-
- case engineapi.RuleStatusError:
- rc.Error++
- vrule.Status = policyreportv1alpha2.StatusError
-
- case engineapi.RuleStatusWarn:
- rc.Warn++
- vrule.Status = policyreportv1alpha2.StatusWarn
-
- case engineapi.RuleStatusSkip:
- rc.Skip++
- vrule.Status = policyreportv1alpha2.StatusSkip
- }
-
- violatedRules = append(violatedRules, vrule)
- continue
- }
- }
-
- if !ruleFoundInEngineResponse {
- rc.Skip++
- vruleSkip := kyvernov1.ViolatedRule{
- Name: policyRule.Name,
- Type: "Validation",
- Message: policyRule.Validation.Message,
- Status: policyreportv1alpha2.StatusSkip,
- }
- violatedRules = append(violatedRules, vruleSkip)
- }
- }
- return buildPVInfo(validateResponse, violatedRules)
-}
-
-func buildPVInfo(er *engineapi.EngineResponse, violatedRules []kyvernov1.ViolatedRule) Info {
- info := Info{
- PolicyName: er.Policy.GetName(),
- Namespace: er.PatchedResource.GetNamespace(),
- Results: []EngineResponseResult{
- {
- Resource: er.GetResourceSpec(),
- Rules: violatedRules,
- },
- },
- }
- return info
-}
-
func updateResultCounts(policy kyvernov1.PolicyInterface, engineResponse *engineapi.EngineResponse, resPath string, rc *ResultCounts, auditWarn bool) {
printCount := 0
for _, policyRule := range autogen.ComputeRules(policy) {
diff --git a/cmd/cli/kubectl-kyverno/utils/common/info.go b/cmd/cli/kubectl-kyverno/utils/common/info.go
deleted file mode 100644
index 83f83a0bdb..0000000000
--- a/cmd/cli/kubectl-kyverno/utils/common/info.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package common
-
-import (
- kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
- engineapi "github.com/kyverno/kyverno/pkg/engine/api"
-)
-
-// Info stores the policy application results for all matched resources
-// Namespace is set to empty "" if resource is cluster wide resource
-type Info struct {
- PolicyName string
- Namespace string
- Results []EngineResponseResult
-}
-
-type EngineResponseResult struct {
- Resource engineapi.ResourceSpec
- Rules []kyvernov1.ViolatedRule
-}
diff --git a/docs/user/crd/index.html b/docs/user/crd/index.html
index 5efdcf8c02..48b5010140 100644
--- a/docs/user/crd/index.html
+++ b/docs/user/crd/index.html
@@ -3866,67 +3866,6 @@ expression evaluates to nil
-ViolatedRule
-
-
-
ViolatedRule stores the information regarding the rule.
-
-
-
-
-Field |
-Description |
-
-
-
-
-
-name
-
-string
-
- |
-
- Name specifies violated rule name.
- |
-
-
-
-type
-
-string
-
- |
-
- Type specifies violated rule type.
- |
-
-
-
-message
-
-string
-
- |
-
-(Optional)
- Message specifies violation message.
- |
-
-
-
-status
-
-string
-
- |
-
- Status shows the rule response status
- |
-
-
-
-
kyverno.io/v1alpha2
Package v1alpha2 contains API Schema definitions for the policy v1alpha2 API group