1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-13 19:28:55 +00:00

Add an abstraction interface for Kyverno policies and validating admission policies (#8016)

Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
Mariam Fahmy 2023-08-15 22:41:43 +03:00 committed by GitHub
parent df7027d11c
commit 064b3588a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 220 additions and 169 deletions

View file

@ -478,7 +478,12 @@ func processSkipEngineResponses(responses []engineapi.EngineResponse, c common.A
var processedEngineResponses []engineapi.EngineResponse
for _, response := range responses {
if !response.IsEmpty() {
for _, rule := range autogen.ComputeRules(response.Policy()) {
pol := response.Policy()
if polType := pol.GetType(); polType == engineapi.ValidatingAdmissionPolicyType {
return processedEngineResponses
}
for _, rule := range autogen.ComputeRules(pol.GetPolicy().(kyvernov1.PolicyInterface)) {
if rule.HasValidate() || rule.HasVerifyImageChecks() || rule.HasVerifyImages() {
ruleFoundInEngineResponse := false
for _, valResponseRule := range response.PolicyResponse.Rules {

View file

@ -41,9 +41,9 @@ func buildPolicyReports(auditWarn bool, engineResponses ...engineapi.EngineRespo
Results: result,
Summary: reportutils.CalculateSummary(result),
}
ns := strings.ReplaceAll(scope, "policyreport-ns-", "")
policyNamespace := strings.ReplaceAll(scope, "policyreport-ns-", "")
report.SetName(scope)
report.SetNamespace(ns)
report.SetNamespace(policyNamespace)
namespaced = append(namespaced, report)
}
}
@ -58,26 +58,14 @@ func buildPolicyResults(auditWarn bool, engineResponses ...engineapi.EngineRespo
now := metav1.Timestamp{Seconds: time.Now().Unix()}
for _, engineResponse := range engineResponses {
var ns, policyName string
var ann map[string]string
isVAP := engineResponse.IsValidatingAdmissionPolicy()
if isVAP {
vap := engineResponse.ValidatingAdmissionPolicy()
ns = vap.GetNamespace()
policyName = vap.GetName()
ann = vap.GetAnnotations()
} else {
kyvernoPolicy := engineResponse.Policy()
ns = kyvernoPolicy.GetNamespace()
policyName = kyvernoPolicy.GetName()
ann = kyvernoPolicy.GetAnnotations()
}
policy := engineResponse.Policy()
policyName := policy.GetName()
policyNamespace := policy.GetNamespace()
ann := policy.GetAnnotations()
var appname string
if ns != "" {
appname = fmt.Sprintf("policyreport-ns-%s", ns)
if policyNamespace != "" {
appname = fmt.Sprintf("policyreport-ns-%s", policyNamespace)
} else {
appname = clusterpolicyreport
}
@ -121,7 +109,7 @@ func buildPolicyResults(auditWarn bool, engineResponses ...engineapi.EngineRespo
fmt.Println(ruleResponse)
}
if !isVAP {
if policy.GetType() == engineapi.KyvernoPolicyType {
result.Rule = ruleResponse.Name()
}
result.Message = ruleResponse.Message()

View file

@ -88,7 +88,7 @@ func Test_buildPolicyReports(t *testing.T) {
assert.NilError(t, err)
er := engineapi.EngineResponse{}
er = er.WithPolicy(&policy)
er = er.WithPolicy(engineapi.NewKyvernoPolicy(&policy))
er.PolicyResponse.Add(
engineapi.ExecutionStats{},
*engineapi.RuleFail(
@ -123,7 +123,7 @@ func Test_buildPolicyResults(t *testing.T) {
assert.NilError(t, err)
er := engineapi.EngineResponse{}
er = er.WithPolicy(&policy)
er = er.WithPolicy(engineapi.NewKyvernoPolicy(&policy))
er.PolicyResponse.Add(
engineapi.ExecutionStats{}, *engineapi.RuleFail(
"pods-require-account",

View file

@ -11,22 +11,10 @@ func printTable(compact, auditWarn bool, engineResponses ...engineapi.EngineResp
var resultsTable table.Table
id := 1
for _, engineResponse := range engineResponses {
var policyNamespace, policyName string
var ann map[string]string
isVAP := engineResponse.IsValidatingAdmissionPolicy()
if isVAP {
policy := engineResponse.ValidatingAdmissionPolicy()
policyNamespace = policy.GetNamespace()
policyName = policy.GetName()
ann = policy.GetAnnotations()
} else {
policy := engineResponse.Policy()
policyNamespace = policy.GetNamespace()
policyName = policy.GetName()
ann = policy.GetAnnotations()
}
policy := engineResponse.Policy()
policyName := policy.GetName()
policyNamespace := policy.GetNamespace()
ann := policy.GetAnnotations()
resourceKind := engineResponse.Resource.GetKind()
resourceNamespace := engineResponse.Resource.GetNamespace()
resourceName := engineResponse.Resource.GetName()
@ -36,7 +24,7 @@ func printTable(compact, auditWarn bool, engineResponses ...engineapi.EngineResp
row.ID = id
id++
row.Policy = color.Policy(policyNamespace, policyName)
if !isVAP {
if policy.GetType() == engineapi.KyvernoPolicyType {
row.Rule = color.Rule(ruleResponse.Name())
}
row.Resource = color.Resource(resourceKind, resourceNamespace, resourceName)

View file

@ -334,28 +334,14 @@ func buildPolicyResults(
results := map[string]policyreportv1alpha2.PolicyReportResult{}
for _, resp := range engineResponses {
var ns, name string
var ann map[string]string
policy := resp.Policy()
policyName := policy.GetName()
policyNamespace := policy.GetNamespace()
ann := policy.GetAnnotations()
isVAP := resp.IsValidatingAdmissionPolicy()
if isVAP {
vap := resp.ValidatingAdmissionPolicy()
ns = vap.GetNamespace()
name = vap.GetName()
ann = vap.GetAnnotations()
} else {
kyvernoPolicy := resp.Policy()
ns = kyvernoPolicy.GetNamespace()
name = kyvernoPolicy.GetName()
ann = kyvernoPolicy.GetAnnotations()
}
policyName := name
resourceName := resp.Resource.GetName()
resourceKind := resp.Resource.GetKind()
resourceNamespace := resp.Resource.GetNamespace()
policyNamespace := ns
var rules []string
for _, rule := range resp.PolicyResponse.Rules {

View file

@ -881,7 +881,11 @@ func GetGitBranchOrPolicyPaths(gitBranch, repoURL string, policyPaths []string)
func processEngineResponses(responses []engineapi.EngineResponse, c ApplyPolicyConfig) {
for _, response := range responses {
if !response.IsEmpty() {
for _, rule := range autogen.ComputeRules(response.Policy()) {
pol := response.Policy()
if polType := pol.GetType(); polType == engineapi.ValidatingAdmissionPolicyType {
return
}
for _, rule := range autogen.ComputeRules(pol.GetPolicy().(kyvernov1.PolicyInterface)) {
if rule.HasValidate() || rule.HasVerifyImageChecks() || rule.HasVerifyImages() {
ruleFoundInEngineResponse := false
for _, valResponseRule := range response.PolicyResponse.Rules {

View file

@ -8,7 +8,6 @@ import (
utils "github.com/kyverno/kyverno/pkg/utils/match"
"github.com/kyverno/kyverno/pkg/utils/wildcard"
"gomodules.xyz/jsonpatch/v2"
"k8s.io/api/admissionregistration/v1alpha1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@ -17,9 +16,7 @@ type EngineResponse struct {
// Resource is the original resource
Resource unstructured.Unstructured
// Policy is the original policy
policy kyvernov1.PolicyInterface
// Policy is the validating admission policy
validatingAdmissionPolicy v1alpha1.ValidatingAdmissionPolicy
policy GenericPolicy
// namespaceLabels given by policy context
namespaceLabels map[string]string
// PatchedResource is the resource patched with the engine action changes
@ -41,14 +38,14 @@ func resource(policyContext PolicyContext) unstructured.Unstructured {
func NewEngineResponseFromPolicyContext(policyContext PolicyContext) EngineResponse {
return NewEngineResponse(
resource(policyContext),
policyContext.Policy(),
NewKyvernoPolicy(policyContext.Policy()),
policyContext.NamespaceLabels(),
)
}
func NewEngineResponse(
resource unstructured.Unstructured,
policy kyvernov1.PolicyInterface,
policy GenericPolicy,
namespaceLabels map[string]string,
) EngineResponse {
return EngineResponse{
@ -59,7 +56,7 @@ func NewEngineResponse(
}
}
func (er EngineResponse) WithPolicy(policy kyvernov1.PolicyInterface) EngineResponse {
func (er EngineResponse) WithPolicy(policy GenericPolicy) EngineResponse {
er.policy = policy
return er
}
@ -79,19 +76,6 @@ func (er EngineResponse) WithPatchedResource(patchedResource unstructured.Unstru
return er
}
func NewEngineResponseWithValidatingAdmissionPolicy(
resource unstructured.Unstructured,
policy v1alpha1.ValidatingAdmissionPolicy,
namespaceLabels map[string]string,
) EngineResponse {
response := EngineResponse{
Resource: resource,
validatingAdmissionPolicy: policy,
namespaceLabels: namespaceLabels,
}
return response
}
func (er EngineResponse) WithNamespaceLabels(namespaceLabels map[string]string) EngineResponse {
er.namespaceLabels = namespaceLabels
return er
@ -101,14 +85,10 @@ func (er *EngineResponse) NamespaceLabels() map[string]string {
return er.namespaceLabels
}
func (er *EngineResponse) Policy() kyvernov1.PolicyInterface {
func (er *EngineResponse) Policy() GenericPolicy {
return er.policy
}
func (er *EngineResponse) ValidatingAdmissionPolicy() v1alpha1.ValidatingAdmissionPolicy {
return er.validatingAdmissionPolicy
}
// IsOneOf checks if any rule has status in a given list
func (er EngineResponse) IsOneOf(status ...RuleStatus) bool {
for _, r := range er.PolicyResponse.Rules {
@ -149,10 +129,6 @@ func (er EngineResponse) IsNil() bool {
return datautils.DeepEqual(er, EngineResponse{})
}
func (er EngineResponse) IsValidatingAdmissionPolicy() bool {
return !datautils.DeepEqual(er.validatingAdmissionPolicy, v1alpha1.ValidatingAdmissionPolicy{})
}
// GetPatches returns all the patches joined
func (er EngineResponse) GetPatches() []jsonpatch.JsonPatchOperation {
originalBytes, err := er.Resource.MarshalJSON()
@ -216,8 +192,13 @@ func (er EngineResponse) getRulesWithErrors(predicate func(RuleResponse) bool) [
return rules
}
// If the policy is of type ValidatingAdmissionPolicy, an empty string is returned.
func (er EngineResponse) GetValidationFailureAction() kyvernov1.ValidationFailureAction {
spec := er.Policy().GetSpec()
pol := er.Policy()
if polType := pol.GetType(); polType == ValidatingAdmissionPolicyType {
return ""
}
spec := pol.GetPolicy().(kyvernov1.PolicyInterface).GetSpec()
for _, v := range spec.ValidationFailureActionOverrides {
if !v.Action.IsValid() {
continue

View file

@ -12,7 +12,7 @@ import (
func TestEngineResponse_IsEmpty(t *testing.T) {
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -43,7 +43,7 @@ func TestEngineResponse_IsEmpty(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.IsEmpty(); got != tt.want {
t.Errorf("EngineResponse.IsEmpty() = %v, want %v", got, tt.want)
}
@ -54,7 +54,7 @@ func TestEngineResponse_IsEmpty(t *testing.T) {
func TestEngineResponse_IsNil(t *testing.T) {
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -85,7 +85,7 @@ func TestEngineResponse_IsNil(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.IsNil(); got != tt.want {
t.Errorf("EngineResponse.IsNil() = %v, want %v", got, tt.want)
}
@ -96,7 +96,7 @@ func TestEngineResponse_IsNil(t *testing.T) {
func TestEngineResponse_IsOneOf(t *testing.T) {
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -172,7 +172,7 @@ func TestEngineResponse_IsOneOf(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.IsOneOf(tt.args.status...); got != tt.want {
t.Errorf("EngineResponse.IsOneOf() = %v, want %v", got, tt.want)
}
@ -183,7 +183,7 @@ func TestEngineResponse_IsOneOf(t *testing.T) {
func TestEngineResponse_IsSuccessful(t *testing.T) {
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -245,7 +245,7 @@ func TestEngineResponse_IsSuccessful(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.IsSuccessful(); got != tt.want {
t.Errorf("EngineResponse.IsSuccessful() = %v, want %v", got, tt.want)
}
@ -256,7 +256,7 @@ func TestEngineResponse_IsSuccessful(t *testing.T) {
func TestEngineResponse_IsSkipped(t *testing.T) {
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -318,7 +318,7 @@ func TestEngineResponse_IsSkipped(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.IsSkipped(); got != tt.want {
t.Errorf("EngineResponse.IsSkipped() = %v, want %v", got, tt.want)
}
@ -329,7 +329,7 @@ func TestEngineResponse_IsSkipped(t *testing.T) {
func TestEngineResponse_IsFailed(t *testing.T) {
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -391,7 +391,7 @@ func TestEngineResponse_IsFailed(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.IsFailed(); got != tt.want {
t.Errorf("EngineResponse.IsFailed() = %v, want %v", got, tt.want)
}
@ -402,7 +402,7 @@ func TestEngineResponse_IsFailed(t *testing.T) {
func TestEngineResponse_IsError(t *testing.T) {
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -464,7 +464,7 @@ func TestEngineResponse_IsError(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.IsError(); got != tt.want {
t.Errorf("EngineResponse.IsError() = %v, want %v", got, tt.want)
}
@ -475,7 +475,7 @@ func TestEngineResponse_IsError(t *testing.T) {
func TestEngineResponse_GetFailedRules(t *testing.T) {
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -553,7 +553,7 @@ func TestEngineResponse_GetFailedRules(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.GetFailedRules(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("EngineResponse.GetFailedRules() = %v, want %v", got, tt.want)
}
@ -564,7 +564,7 @@ func TestEngineResponse_GetFailedRules(t *testing.T) {
func TestEngineResponse_GetSuccessRules(t *testing.T) {
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -669,7 +669,7 @@ func TestEngineResponse_GetSuccessRules(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.GetSuccessRules(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("EngineResponse.GetSuccessRules() = %v, want %v", got, tt.want)
}
@ -682,7 +682,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
resource.SetNamespace("foo")
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -692,25 +692,25 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
want kyvernov1.ValidationFailureAction
}{{
fields: fields{
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Audit,
},
},
}),
},
want: kyvernov1.Audit,
}, {
fields: fields{
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
},
},
}),
},
want: kyvernov1.Enforce,
}, {
fields: fields{
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -718,12 +718,12 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
Namespaces: []string{"*"},
}},
},
},
}),
},
want: kyvernov1.Audit,
}, {
fields: fields{
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -731,13 +731,13 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
Namespaces: []string{"*"},
}},
},
},
}),
},
want: kyvernov1.Enforce,
}, {
fields: fields{
PatchedResource: resource,
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -745,13 +745,13 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
Namespaces: []string{"foo"},
}},
},
},
}),
},
want: kyvernov1.Audit,
}, {
fields: fields{
PatchedResource: resource,
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -759,7 +759,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
Namespaces: []string{"bar"},
}},
},
},
}),
},
want: kyvernov1.Enforce,
}, {
@ -768,7 +768,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
"foo": "bar",
},
PatchedResource: resource,
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -780,7 +780,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
},
}},
},
},
}),
},
want: kyvernov1.Enforce,
}, {
@ -789,7 +789,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
"foo": "bar",
},
PatchedResource: resource,
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -801,7 +801,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
},
}},
},
},
}),
},
want: kyvernov1.Audit,
}, {
@ -810,7 +810,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
"foo": "bar",
},
PatchedResource: resource,
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -823,7 +823,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
},
}},
},
},
}),
},
want: kyvernov1.Enforce,
}, {
@ -832,7 +832,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
"foo": "bar",
},
PatchedResource: resource,
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -845,7 +845,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
},
}},
},
},
}),
},
want: kyvernov1.Enforce,
}, {
@ -854,7 +854,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
"foo": "bar",
},
PatchedResource: resource,
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -867,7 +867,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
},
}},
},
},
}),
},
want: kyvernov1.Audit,
}, {
@ -876,7 +876,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
"foo": "bar",
},
PatchedResource: resource,
Policy: &kyvernov1.ClusterPolicy{
GenericPolicy: NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
ValidationFailureActionOverrides: []kyvernov1.ValidationFailureActionOverride{{
@ -889,7 +889,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
},
}},
},
},
}),
},
want: kyvernov1.Audit,
}}
@ -899,7 +899,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.GetValidationFailureAction(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("EngineResponse.GetValidationFailureAction() = %v, want %v", got, tt.want)
}
@ -910,7 +910,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
// func TestEngineResponse_GetPatches(t *testing.T) {
// type fields struct {
// PatchedResource unstructured.Unstructured
// Policy kyvernov1.PolicyInterface
// GenericPolicy kyvernov1.PolicyInterface
// PolicyResponse PolicyResponse
// namespaceLabels map[string]string
// }
@ -1004,7 +1004,7 @@ func TestEngineResponse_GetValidationFailureAction(t *testing.T) {
// PatchedResource: tt.fields.PatchedResource,
// PolicyResponse: tt.fields.PolicyResponse,
// namespaceLabels: tt.fields.namespaceLabels,
// }.WithPolicy(tt.fields.Policy)
// }.WithPolicy(tt.fields.GenericPolicy)
// if got := er.GetPatches(); !reflect.DeepEqual(got, tt.want) {
// t.Errorf("EngineResponse.GetPatches() = %v, want %v", got, tt.want)
// }
@ -1026,7 +1026,7 @@ func TestEngineResponse_GetResourceSpec(t *testing.T) {
clusteredResource.SetUID("12345")
type fields struct {
PatchedResource unstructured.Unstructured
Policy kyvernov1.PolicyInterface
GenericPolicy GenericPolicy
PolicyResponse PolicyResponse
namespaceLabels map[string]string
}
@ -1062,7 +1062,7 @@ func TestEngineResponse_GetResourceSpec(t *testing.T) {
PatchedResource: tt.fields.PatchedResource,
PolicyResponse: tt.fields.PolicyResponse,
namespaceLabels: tt.fields.namespaceLabels,
}.WithPolicy(tt.fields.Policy)
}.WithPolicy(tt.fields.GenericPolicy)
if got := er.GetResourceSpec(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("EngineResponse.GetResourceSpec() = %v, want %v", got, tt.want)
}

91
pkg/engine/api/policy.go Normal file
View file

@ -0,0 +1,91 @@
package api
import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"k8s.io/api/admissionregistration/v1alpha1"
)
// PolicyType represents the type of a policy
type PolicyType string
const (
// KyvernoPolicy type for kyverno policies
KyvernoPolicyType PolicyType = "KyvernoPolicy"
// ValidatingAdmissionPolicy for validating admission policies
ValidatingAdmissionPolicyType PolicyType = "ValidatingAdmissionPolicy"
)
// GenericPolicy abstracts the policy type (Kyverno policy vs Validating admission policy)
// It is intended to be used in EngineResponse
type GenericPolicy interface {
// GetPolicy returns either kyverno policy or validating admission policy
GetPolicy() interface{}
// GetType returns policy type
GetType() PolicyType
// GetName returns policy name
GetName() string
// GetNamespace returns policy namespace
GetNamespace() string
// GetAnnotations returns policy annotations
GetAnnotations() map[string]string
}
type KyvernoPolicy struct {
policy kyvernov1.PolicyInterface
}
func (p KyvernoPolicy) GetPolicy() interface{} {
return p.policy
}
func (p KyvernoPolicy) GetType() PolicyType {
return KyvernoPolicyType
}
func (p KyvernoPolicy) GetName() string {
return p.policy.GetName()
}
func (p KyvernoPolicy) GetNamespace() string {
return p.policy.GetNamespace()
}
func (p KyvernoPolicy) GetAnnotations() map[string]string {
return p.policy.GetAnnotations()
}
func NewKyvernoPolicy(pol kyvernov1.PolicyInterface) KyvernoPolicy {
return KyvernoPolicy{
policy: pol,
}
}
type ValidatingAdmissionPolicy struct {
policy v1alpha1.ValidatingAdmissionPolicy
}
func (p ValidatingAdmissionPolicy) GetPolicy() interface{} {
return p.policy
}
func (p ValidatingAdmissionPolicy) GetType() PolicyType {
return ValidatingAdmissionPolicyType
}
func (p ValidatingAdmissionPolicy) GetName() string {
return p.policy.GetName()
}
func (p ValidatingAdmissionPolicy) GetNamespace() string {
return p.policy.GetNamespace()
}
func (p ValidatingAdmissionPolicy) GetAnnotations() map[string]string {
return p.policy.GetAnnotations()
}
func NewValidatingAdmissionPolicy(pol v1alpha1.ValidatingAdmissionPolicy) ValidatingAdmissionPolicy {
return ValidatingAdmissionPolicy{
policy: pol,
}
}

View file

@ -22,7 +22,7 @@ func (e *engine) reportMetrics(
if e.resultCounter == nil && e.durationHistogram == nil {
return
}
policy := response.Policy()
policy := response.Policy().GetPolicy().(kyvernov1.PolicyInterface)
if name, namespace, policyType, backgroundMode, validationMode, err := metrics.GetPolicyInfos(policy); err != nil {
logger.Error(err, "failed to get policy infos for metrics reporting")
} else {

View file

@ -16,10 +16,12 @@ func NewPolicyFailEvent(source Source, reason Reason, engineResponse engineapi.E
action = ResourceBlocked
}
pol := engineResponse.Policy().GetPolicy().(kyvernov1.PolicyInterface)
return Info{
Kind: getPolicyKind(engineResponse.Policy()),
Name: engineResponse.Policy().GetName(),
Namespace: engineResponse.Policy().GetNamespace(),
Kind: getPolicyKind(pol),
Name: pol.GetName(),
Namespace: pol.GetNamespace(),
RelatedAPIVersion: engineResponse.GetResourceSpec().APIVersion,
RelatedKind: engineResponse.GetResourceSpec().Kind,
RelatedName: engineResponse.GetResourceSpec().Name,
@ -77,9 +79,10 @@ func NewPolicyAppliedEvent(source Source, engineResponse engineapi.EngineRespons
res = fmt.Sprintf("%s %s", resource.GetKind(), resource.GetName())
}
hasValidate := engineResponse.Policy().GetSpec().HasValidate()
hasVerifyImages := engineResponse.Policy().GetSpec().HasVerifyImages()
hasMutate := engineResponse.Policy().GetSpec().HasMutate()
pol := engineResponse.Policy().GetPolicy().(kyvernov1.PolicyInterface)
hasValidate := pol.GetSpec().HasValidate()
hasVerifyImages := pol.GetSpec().HasVerifyImages()
hasMutate := pol.GetSpec().HasMutate()
var action Action
if hasValidate || hasVerifyImages {
@ -91,9 +94,9 @@ func NewPolicyAppliedEvent(source Source, engineResponse engineapi.EngineRespons
}
return Info{
Kind: getPolicyKind(engineResponse.Policy()),
Name: engineResponse.Policy().GetName(),
Namespace: engineResponse.Policy().GetNamespace(),
Kind: getPolicyKind(pol),
Name: pol.GetName(),
Namespace: pol.GetNamespace(),
RelatedAPIVersion: resource.GetAPIVersion(),
RelatedKind: resource.GetKind(),
RelatedName: resource.GetName(),
@ -109,7 +112,8 @@ func NewResourceViolationEvent(source Source, reason Reason, engineResponse engi
var bldr strings.Builder
defer bldr.Reset()
fmt.Fprintf(&bldr, "policy %s/%s %s: %s", engineResponse.Policy().GetName(),
pol := engineResponse.Policy().GetPolicy().(kyvernov1.PolicyInterface)
fmt.Fprintf(&bldr, "policy %s/%s %s: %s", pol.GetName(),
ruleResp.Name(), ruleResp.Status(), ruleResp.Message())
resource := engineResponse.GetResourceSpec()
@ -190,16 +194,17 @@ func NewPolicyExceptionEvents(engineResponse engineapi.EngineResponse, ruleResp
exception := ruleResp.Exception()
exceptionName, exceptionNamespace := exception.GetName(), exception.GetNamespace()
policyMessage := fmt.Sprintf("resource %s was skipped from rule %s due to policy exception %s/%s", resourceKey(engineResponse.PatchedResource), ruleResp.Name(), exceptionNamespace, exceptionName)
pol := engineResponse.Policy().GetPolicy().(kyvernov1.PolicyInterface)
var exceptionMessage string
if engineResponse.Policy().GetNamespace() == "" {
exceptionMessage = fmt.Sprintf("resource %s was skipped from policy rule %s/%s", resourceKey(engineResponse.PatchedResource), engineResponse.Policy().GetName(), ruleResp.Name())
if pol.GetNamespace() == "" {
exceptionMessage = fmt.Sprintf("resource %s was skipped from policy rule %s/%s", resourceKey(engineResponse.PatchedResource), pol.GetName(), ruleResp.Name())
} else {
exceptionMessage = fmt.Sprintf("resource %s was skipped from policy rule %s/%s/%s", resourceKey(engineResponse.PatchedResource), engineResponse.Policy().GetNamespace(), engineResponse.Policy().GetName(), ruleResp.Name())
exceptionMessage = fmt.Sprintf("resource %s was skipped from policy rule %s/%s/%s", resourceKey(engineResponse.PatchedResource), pol.GetNamespace(), pol.GetName(), ruleResp.Name())
}
policyEvent := Info{
Kind: getPolicyKind(engineResponse.Policy()),
Name: engineResponse.Policy().GetName(),
Namespace: engineResponse.Policy().GetNamespace(),
Kind: getPolicyKind(pol),
Name: pol.GetName(),
Namespace: pol.GetNamespace(),
RelatedAPIVersion: engineResponse.PatchedResource.GetAPIVersion(),
RelatedKind: engineResponse.PatchedResource.GetKind(),
RelatedName: engineResponse.PatchedResource.GetName(),

View file

@ -7,6 +7,7 @@ import (
"github.com/go-logr/logr"
"github.com/kyverno/kyverno/api/kyverno"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1alpha2 "github.com/kyverno/kyverno/api/kyverno/v1alpha2"
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
@ -86,10 +87,11 @@ func SeverityFromString(severity string) policyreportv1alpha2.PolicySeverity {
}
func EngineResponseToReportResults(response engineapi.EngineResponse) []policyreportv1alpha2.PolicyReportResult {
key, _ := cache.MetaNamespaceKeyFunc(response.Policy())
pol := response.Policy().GetPolicy().(kyvernov1.PolicyInterface)
key, _ := cache.MetaNamespaceKeyFunc(pol)
var results []policyreportv1alpha2.PolicyReportResult
for _, ruleResult := range response.PolicyResponse.Rules {
annotations := response.Policy().GetAnnotations()
annotations := pol.GetAnnotations()
result := policyreportv1alpha2.PolicyReportResult{
Source: kyverno.ValueKyvernoApp,
Policy: key,
@ -161,7 +163,8 @@ func SetResults(report kyvernov1alpha2.ReportInterface, results ...policyreportv
func SetResponses(report kyvernov1alpha2.ReportInterface, engineResponses ...engineapi.EngineResponse) {
var ruleResults []policyreportv1alpha2.PolicyReportResult
for _, result := range engineResponses {
SetPolicyLabel(report, result.Policy())
pol := result.Policy().GetPolicy().(kyvernov1.PolicyInterface)
SetPolicyLabel(report, pol)
ruleResults = append(ruleResults, EngineResponseToReportResults(result)...)
}
SetResults(report, ruleResults...)

View file

@ -155,7 +155,7 @@ func Validate(policy v1alpha1.ValidatingAdmissionPolicy, resource unstructured.U
versionedAttr, _ := admission.NewVersionedAttributes(admissionAttributes, admissionAttributes.GetKind(), nil)
validateResult := validator.Validate(context.TODO(), versionedAttr, nil, celconfig.RuntimeCELCostBudget)
engineResponse := engineapi.NewEngineResponseWithValidatingAdmissionPolicy(resource, policy, nil)
engineResponse := engineapi.NewEngineResponse(resource, engineapi.NewValidatingAdmissionPolicy(policy), nil)
policyResp := engineapi.NewPolicyResponse()
var ruleResp *engineapi.RuleResponse
isPass := true

View file

@ -46,22 +46,22 @@ func Test_getAction(t *testing.T) {
}
func TestBlockRequest(t *testing.T) {
auditPolicy := &kyvernov1.ClusterPolicy{
auditPolicy := engineapi.NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
ObjectMeta: v1.ObjectMeta{
Name: "test",
},
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Audit,
},
}
enforcePolicy := &kyvernov1.ClusterPolicy{
})
enforcePolicy := engineapi.NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
ObjectMeta: v1.ObjectMeta{
Name: "test",
},
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
},
}
})
resource := unstructured.Unstructured{
Object: map[string]interface{}{
"kind": "foo",
@ -174,14 +174,14 @@ func TestBlockRequest(t *testing.T) {
}
func TestGetBlockedMessages(t *testing.T) {
enforcePolicy := &kyvernov1.ClusterPolicy{
enforcePolicy := engineapi.NewKyvernoPolicy(&kyvernov1.ClusterPolicy{
ObjectMeta: v1.ObjectMeta{
Name: "test",
},
Spec: kyvernov1.Spec{
ValidationFailureAction: kyvernov1.Enforce,
},
}
})
resource := unstructured.Unstructured{
Object: map[string]interface{}{
"kind": "foo",

View file

@ -34,11 +34,11 @@ func TestGetWarningMessages(t *testing.T) {
*engineapi.NewRuleResponse("rule", engineapi.Validation, "message warn", engineapi.RuleStatusWarn),
},
},
}.WithPolicy(&v1.ClusterPolicy{
}.WithPolicy(engineapi.NewKyvernoPolicy(&v1.ClusterPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}),
})),
}},
want: []string{
"policy test.rule: message warn",
@ -56,11 +56,11 @@ func TestGetWarningMessages(t *testing.T) {
*engineapi.RuleSkip("rule-skip", engineapi.Validation, "message skip"),
},
},
}.WithPolicy(&v1.ClusterPolicy{
}.WithPolicy(engineapi.NewKyvernoPolicy(&v1.ClusterPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}),
})),
}},
want: []string{
"policy test.rule-warn: message warn",