1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-05 15:37:19 +00:00

update validation logic

This commit is contained in:
Jim Bugwadia 2020-12-23 15:10:07 -08:00
parent d0347afa59
commit e2f10c6f83
30 changed files with 393 additions and 377 deletions

View file

@ -15,14 +15,19 @@ import (
//Interface to manage context operations //Interface to manage context operations
type Interface interface { type Interface interface {
//AddJSON merges the json with context
// AddJSON merges the json with context
AddJSON(dataRaw []byte) error AddJSON(dataRaw []byte) error
//AddResource merges resource json under request.object
// AddResource merges resource json under request.object
AddResource(dataRaw []byte) error AddResource(dataRaw []byte) error
//AddUserInfo merges userInfo json under kyverno.userInfo
// AddUserInfo merges userInfo json under kyverno.userInfo
AddUserInfo(userInfo kyverno.UserInfo) error AddUserInfo(userInfo kyverno.UserInfo) error
//AddSA merges serrviceaccount
AddSA(userName string) error // AddServiceAccount merges ServiceAccount types
AddServiceAccount(userName string) error
EvalInterface EvalInterface
} }
@ -126,8 +131,8 @@ func (ctx *Context) AddUserInfo(userRequestInfo kyverno.RequestInfo) error {
return ctx.AddJSON(objRaw) return ctx.AddJSON(objRaw)
} }
//AddSA removes prefix 'system:serviceaccount:' and namespace, then loads only SA name and SA namespace //AddServiceAccount removes prefix 'system:serviceaccount:' and namespace, then loads only SA name and SA namespace
func (ctx *Context) AddSA(userName string) error { func (ctx *Context) AddServiceAccount(userName string) error {
saPrefix := "system:serviceaccount:" saPrefix := "system:serviceaccount:"
var sa string var sa string
saName := "" saName := ""

View file

@ -93,7 +93,7 @@ func Test_addResourceAndUserContext(t *testing.T) {
t.Error("exected result does not match") t.Error("exected result does not match")
} }
// Add service account Name // Add service account Name
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username) err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View file

@ -12,16 +12,16 @@ import (
// 1. validate variables to be substitute in the general ruleInfo (match,exclude,condition) // 1. validate variables to be substitute in the general ruleInfo (match,exclude,condition)
// - the caller has to check the ruleResponse to determine whether the path exist // - the caller has to check the ruleResponse to determine whether the path exist
// 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed // 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed
func Generate(policyContext PolicyContext) (resp response.EngineResponse) { func Generate(policyContext PolicyContext) (resp *response.EngineResponse) {
return filterRules(policyContext) return filterRules(policyContext)
} }
func filterRules(policyContext PolicyContext) response.EngineResponse { func filterRules(policyContext PolicyContext) *response.EngineResponse {
kind := policyContext.NewResource.GetKind() kind := policyContext.NewResource.GetKind()
name := policyContext.NewResource.GetName() name := policyContext.NewResource.GetName()
namespace := policyContext.NewResource.GetNamespace() namespace := policyContext.NewResource.GetNamespace()
resp := response.EngineResponse{ resp := &response.EngineResponse{
PolicyResponse: response.PolicyResponse{ PolicyResponse: response.PolicyResponse{
Policy: policyContext.Policy.Name, Policy: policyContext.Policy.Name,
Resource: response.ResourceSpec{ Resource: response.ResourceSpec{
@ -57,7 +57,7 @@ func filterRule(rule kyverno.Rule, policyContext PolicyContext) *response.RuleRe
newResource := policyContext.NewResource newResource := policyContext.NewResource
oldResource := policyContext.OldResource oldResource := policyContext.OldResource
admissionInfo := policyContext.AdmissionInfo admissionInfo := policyContext.AdmissionInfo
ctx := policyContext.Context ctx := policyContext.JSONContext
resCache := policyContext.ResourceCache resCache := policyContext.ResourceCache
jsonContext := policyContext.JSONContext jsonContext := policyContext.JSONContext
excludeGroupRole := policyContext.ExcludeGroupRole excludeGroupRole := policyContext.ExcludeGroupRole

View file

@ -22,11 +22,12 @@ const (
) )
// Mutate performs mutation. Overlay first and then mutation patches // Mutate performs mutation. Overlay first and then mutation patches
func Mutate(policyContext PolicyContext) (resp response.EngineResponse) { func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
resp = &response.EngineResponse{}
startTime := time.Now() startTime := time.Now()
policy := policyContext.Policy policy := policyContext.Policy
patchedResource := policyContext.NewResource patchedResource := policyContext.NewResource
ctx := policyContext.Context ctx := policyContext.JSONContext
resCache := policyContext.ResourceCache resCache := policyContext.ResourceCache
jsonContext := policyContext.JSONContext jsonContext := policyContext.JSONContext
@ -35,10 +36,10 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
logger.V(4).Info("start policy processing", "startTime", startTime) logger.V(4).Info("start policy processing", "startTime", startTime)
startMutateResultResponse(&resp, policy, patchedResource) startMutateResultResponse(resp, policy, patchedResource)
defer endMutateResultResponse(logger, &resp, startTime) defer endMutateResultResponse(logger, resp, startTime)
if SkipPolicyApplication(policy, patchedResource) { if ManagedPodResource(policy, patchedResource) {
logger.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", policy.GetName()) logger.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", policy.GetName())
resp.PatchedResource = patchedResource resp.PatchedResource = patchedResource
return return
@ -58,6 +59,7 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
if len(policyContext.ExcludeGroupRole) > 0 { if len(policyContext.ExcludeGroupRole) > 0 {
excludeResource = policyContext.ExcludeGroupRole excludeResource = policyContext.ExcludeGroupRole
} }
if err := MatchesResourceDescription(patchedResource, rule, policyContext.AdmissionInfo, excludeResource); err != nil { if err := MatchesResourceDescription(patchedResource, rule, policyContext.AdmissionInfo, excludeResource); err != nil {
logger.V(3).Info("resource not matched", "reason", err.Error()) logger.V(3).Info("resource not matched", "reason", err.Error())
continue continue
@ -79,7 +81,6 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
} }
mutation := rule.Mutation.DeepCopy() mutation := rule.Mutation.DeepCopy()
mutateHandler := mutate.CreateMutateHandler(rule.Name, mutation, patchedResource, ctx, logger) mutateHandler := mutate.CreateMutateHandler(rule.Name, mutation, patchedResource, ctx, logger)
ruleResponse, patchedResource = mutateHandler.Handle() ruleResponse, patchedResource = mutateHandler.Handle()
if ruleResponse.Success { if ruleResponse.Success {
@ -87,11 +88,12 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
if ruleResponse.Patches == nil { if ruleResponse.Patches == nil {
continue continue
} }
logger.V(4).Info("mutate rule applied successfully", "ruleName", rule.Name) logger.V(4).Info("mutate rule applied successfully", "ruleName", rule.Name)
} }
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse) resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
incrementAppliedRuleCount(&resp) incrementAppliedRuleCount(resp)
} }
resp.PatchedResource = patchedResource resp.PatchedResource = patchedResource
@ -103,9 +105,11 @@ func incrementAppliedRuleCount(resp *response.EngineResponse) {
} }
func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, resource unstructured.Unstructured) { func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, resource unstructured.Unstructured) {
// set policy information if resp == nil {
return
}
resp.PolicyResponse.Policy = policy.Name resp.PolicyResponse.Policy = policy.Name
// resource details
resp.PolicyResponse.Resource.Name = resource.GetName() resp.PolicyResponse.Resource.Name = resource.GetName()
resp.PolicyResponse.Resource.Namespace = resource.GetNamespace() resp.PolicyResponse.Resource.Namespace = resource.GetNamespace()
resp.PolicyResponse.Resource.Kind = resource.GetKind() resp.PolicyResponse.Resource.Kind = resource.GetKind()
@ -113,6 +117,10 @@ func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.Clu
} }
func endMutateResultResponse(logger logr.Logger, resp *response.EngineResponse, startTime time.Time) { func endMutateResultResponse(logger logr.Logger, resp *response.EngineResponse, startTime time.Time) {
if resp == nil {
return
}
resp.PolicyResponse.ProcessingTime = time.Since(startTime) resp.PolicyResponse.ProcessingTime = time.Since(startTime)
logger.V(4).Info("finished processing policy", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "mutationRulesApplied", resp.PolicyResponse.RulesAppliedCount) logger.V(4).Info("finished processing policy", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "mutationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
} }

View file

@ -84,9 +84,9 @@ func Test_VariableSubstitutionOverlay(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
policyContext := PolicyContext{ policyContext := &PolicyContext{
Policy: policy, Policy: policy,
Context: ctx, JSONContext: ctx,
NewResource: *resourceUnstructured} NewResource: *resourceUnstructured}
er := Mutate(policyContext) er := Mutate(policyContext)
t.Log(string(expectedPatch)) t.Log(string(expectedPatch))
@ -155,9 +155,9 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
err = ctx.AddResource(resourceRaw) err = ctx.AddResource(resourceRaw)
assert.NilError(t, err) assert.NilError(t, err)
policyContext := PolicyContext{ policyContext := &PolicyContext{
Policy: policy, Policy: policy,
Context: ctx, JSONContext: ctx,
NewResource: *resourceUnstructured} NewResource: *resourceUnstructured}
er := Mutate(policyContext) er := Mutate(policyContext)
expectedErrorStr := "variable request.object.metadata.name1 not resolved at path /spec/name" expectedErrorStr := "variable request.object.metadata.name1 not resolved at path /spec/name"

View file

@ -26,9 +26,6 @@ type PolicyContext struct {
// Dynamic client - used by generate // Dynamic client - used by generate
Client *client.Client Client *client.Client
// Contexts to store resources
Context context.EvalInterface
// Config handler // Config handler
ExcludeGroupRole []string ExcludeGroupRole []string

View file

@ -269,10 +269,15 @@ func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef k
return nil return nil
} }
func copyConditions(original []kyverno.Condition) []kyverno.Condition { func copyConditions(original []kyverno.Condition) []kyverno.Condition {
if original == nil || len(original) == 0 {
return []kyverno.Condition{}
}
var copy []kyverno.Condition var copy []kyverno.Condition
for _, condition := range original { for _, condition := range original {
copy = append(copy, *condition.DeepCopy()) copy = append(copy, *condition.DeepCopy())
} }
return copy return copy
} }
@ -288,10 +293,10 @@ func excludeResource(resource unstructured.Unstructured) bool {
return false return false
} }
// SkipPolicyApplication returns true: // ManagedPodResource returns true:
// - if the policy has auto-gen annotation && resource == Pod // - if the policy has auto-gen annotation && resource == Pod
// - if the auto-gen contains cronJob && resource == Job // - if the auto-gen contains cronJob && resource == Job
func SkipPolicyApplication(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) bool { func ManagedPodResource(policy kyverno.ClusterPolicy, resource unstructured.Unstructured) bool {
if policy.HasAutoGenAnnotation() && excludeResource(resource) { if policy.HasAutoGenAnnotation() && excludeResource(resource) {
return true return true
} }

View file

@ -14,238 +14,192 @@ import (
"github.com/kyverno/kyverno/pkg/engine/utils" "github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/engine/validate" "github.com/kyverno/kyverno/pkg/engine/validate"
"github.com/kyverno/kyverno/pkg/engine/variables" "github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/resourcecache"
"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"
) )
//Validate applies validation rules from policy on the resource //Validate applies validation rules from policy on the resource
func Validate(policyContext PolicyContext) (resp response.EngineResponse) { func Validate(policyContext *PolicyContext) (resp *response.EngineResponse) {
resp = &response.EngineResponse{}
startTime := time.Now() startTime := time.Now()
policy := policyContext.Policy
newR := policyContext.NewResource
oldR := policyContext.OldResource
ctx := policyContext.Context
admissionInfo := policyContext.AdmissionInfo
resCache := policyContext.ResourceCache
jsonContext := policyContext.JSONContext
logger := log.Log.WithName("EngineValidate").WithValues("policy", policy.Name)
if reflect.DeepEqual(newR, unstructured.Unstructured{}) {
logger = logger.WithValues("kind", oldR.GetKind(), "namespace", oldR.GetNamespace(), "name", oldR.GetName())
} else {
logger = logger.WithValues("kind", newR.GetKind(), "namespace", newR.GetNamespace(), "name", newR.GetName())
}
logger := buildLogger(policyContext)
logger.V(4).Info("start processing", "startTime", startTime) logger.V(4).Info("start processing", "startTime", startTime)
defer func() { defer func() {
buildResponse(logger, policyContext, resp, startTime)
logger.V(4).Info("finished processing", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
}()
return validateResource(logger, policyContext)
}
func buildLogger(ctx *PolicyContext) logr.Logger {
logger := log.Log.WithName("EngineValidate").WithValues("policy", ctx.Policy.Name)
if reflect.DeepEqual(ctx.NewResource, unstructured.Unstructured{}) {
logger = logger.WithValues("kind", ctx.OldResource.GetKind(), "namespace", ctx.OldResource.GetNamespace(), "name", ctx.OldResource.GetName())
} else {
logger = logger.WithValues("kind", ctx.NewResource.GetKind(), "namespace", ctx.NewResource.GetNamespace(), "name", ctx.NewResource.GetName())
}
return logger
}
func buildResponse(logger logr.Logger, ctx *PolicyContext, resp *response.EngineResponse, startTime time.Time) {
if reflect.DeepEqual(resp, response.EngineResponse{}) { if reflect.DeepEqual(resp, response.EngineResponse{}) {
return return
} }
var resource unstructured.Unstructured var resource unstructured.Unstructured
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) { if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
// for delete requests patched resource will be oldR since newR is empty // for delete requests patched resource will be oldResource since newResource is empty
if reflect.DeepEqual(newR, unstructured.Unstructured{}) { if reflect.DeepEqual(ctx.NewResource, unstructured.Unstructured{}) {
resource = oldR resource = ctx.OldResource
} else { } else {
resource = newR resource = ctx.NewResource
} }
} }
for i := range resp.PolicyResponse.Rules { for i := range resp.PolicyResponse.Rules {
messageInterface, err := variables.SubstituteVars(logger, ctx, resp.PolicyResponse.Rules[i].Message) messageInterface, err := variables.SubstituteVars(logger, ctx.JSONContext, resp.PolicyResponse.Rules[i].Message)
if err != nil { if err != nil {
logger.V(4).Info("failed to substitute variables", "error", err.Error()) logger.V(4).Info("failed to substitute variables", "error", err.Error())
continue continue
} }
resp.PolicyResponse.Rules[i].Message, _ = messageInterface.(string) resp.PolicyResponse.Rules[i].Message, _ = messageInterface.(string)
} }
resp.PatchedResource = resource resp.PatchedResource = resource
startResultResponse(&resp, policy, resource) setResponse(resp, ctx.Policy, resource, startTime)
endResultResponse(logger, &resp, startTime)
}()
// If request is delete, newR will be empty
if reflect.DeepEqual(newR, unstructured.Unstructured{}) {
return *isRequestDenied(logger, ctx, policy, oldR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext)
}
if denyResp := isRequestDenied(logger, ctx, policy, newR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext); !denyResp.IsSuccessful() {
return *denyResp
}
if reflect.DeepEqual(oldR, unstructured.Unstructured{}) {
return *validateResource(logger, ctx, policy, newR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext)
}
oldResponse := validateResource(logger, ctx, policy, oldR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext)
newResponse := validateResource(logger, ctx, policy, newR, admissionInfo, policyContext.ExcludeGroupRole, resCache, jsonContext)
if !isSameResponse(oldResponse, newResponse) {
return *newResponse
}
return response.EngineResponse{}
} }
func startResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, newR unstructured.Unstructured) { func setResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, startTime time.Time) {
// set policy information
resp.PolicyResponse.Policy = policy.Name resp.PolicyResponse.Policy = policy.Name
// resource details resp.PolicyResponse.Resource.Name = resource.GetName()
resp.PolicyResponse.Resource.Name = newR.GetName() resp.PolicyResponse.Resource.Namespace = resource.GetNamespace()
resp.PolicyResponse.Resource.Namespace = newR.GetNamespace() resp.PolicyResponse.Resource.Kind = resource.GetKind()
resp.PolicyResponse.Resource.Kind = newR.GetKind() resp.PolicyResponse.Resource.APIVersion = resource.GetAPIVersion()
resp.PolicyResponse.Resource.APIVersion = newR.GetAPIVersion()
resp.PolicyResponse.ValidationFailureAction = policy.Spec.ValidationFailureAction resp.PolicyResponse.ValidationFailureAction = policy.Spec.ValidationFailureAction
}
func endResultResponse(log logr.Logger, resp *response.EngineResponse, startTime time.Time) {
resp.PolicyResponse.ProcessingTime = time.Since(startTime) resp.PolicyResponse.ProcessingTime = time.Since(startTime)
log.V(4).Info("finished processing", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
} }
func incrementAppliedCount(resp *response.EngineResponse) { func incrementAppliedCount(resp *response.EngineResponse) {
// rules applied successfully count
resp.PolicyResponse.RulesAppliedCount++ resp.PolicyResponse.RulesAppliedCount++
} }
func isRequestDenied(log logr.Logger, ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) *response.EngineResponse { func validateResource(log logr.Logger, ctx *PolicyContext) *response.EngineResponse {
resp := &response.EngineResponse{} resp := &response.EngineResponse{}
if SkipPolicyApplication(policy, resource) { if ManagedPodResource(ctx.Policy, ctx.NewResource) {
log.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", policy.GetName()) log.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", ctx.Policy.GetName())
return resp return resp
} }
excludeResource := []string{}
if len(excludeGroupRole) > 0 { for _, rule := range ctx.Policy.Spec.Rules {
excludeResource = excludeGroupRole
}
for _, rule := range policy.Spec.Rules {
if !rule.HasValidate() { if !rule.HasValidate() {
continue continue
} }
// add configmap json data to context // add configmap json data to context
if err := AddResourceToContext(log, rule.Context, resCache, jsonContext); err != nil { if err := AddResourceToContext(log, rule.Context, ctx.ResourceCache, ctx.JSONContext); err != nil {
log.V(4).Info("cannot add configmaps to context", "reason", err.Error()) log.V(4).Info("cannot add configmaps to context", "reason", err.Error())
continue continue
} }
if err := MatchesResourceDescription(resource, rule, admissionInfo, excludeResource); err != nil { if !matches(log, rule, ctx) {
log.V(4).Info("resource fails the match description", "reason", err.Error())
continue
}
preconditionsCopy := copyConditions(rule.Conditions)
if !variables.EvaluateConditions(log, ctx, preconditionsCopy) {
log.V(4).Info("resource fails the preconditions")
continue
}
if rule.Validation.Deny != nil {
denyConditionsCopy := copyConditions(rule.Validation.Deny.Conditions)
if len(rule.Validation.Deny.Conditions) == 0 || variables.EvaluateConditions(log, ctx, denyConditionsCopy) {
ruleResp := response.RuleResponse{
Name: rule.Name,
Type: utils.Validation.String(),
Message: rule.Validation.Message,
Success: false,
}
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResp)
}
continue
}
}
return resp
}
func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) *response.EngineResponse {
resp := &response.EngineResponse{}
if SkipPolicyApplication(policy, resource) {
log.V(5).Info("skip applying policy as direct changes to pods managed by workload controllers are not allowed", "policy", policy.GetName())
return resp
}
excludeResource := []string{}
if len(excludeGroupRole) > 0 {
excludeResource = excludeGroupRole
}
for _, rule := range policy.Spec.Rules {
if !rule.HasValidate() {
continue
}
// check if the resource satisfies the filter conditions defined in the rule
if err := MatchesResourceDescription(resource, rule, admissionInfo, excludeResource); err != nil {
log.V(4).Info("resource fails the match description", "reason", err.Error())
continue
}
// add configmap json data to context
if err := AddResourceToContext(log, rule.Context, resCache, jsonContext); err != nil {
log.V(4).Info("cannot add configmaps to context", "reason", err.Error())
continue continue
} }
// operate on the copy of the conditions, as we perform variable substitution // operate on the copy of the conditions, as we perform variable substitution
preconditionsCopy := copyConditions(rule.Conditions) preconditionsCopy := copyConditions(rule.Conditions)
// evaluate pre-conditions // evaluate pre-conditions
// - handle variable substitutions // - handle variable substitutions
if !variables.EvaluateConditions(log, ctx, preconditionsCopy) { if !variables.EvaluateConditions(log, ctx.JSONContext, preconditionsCopy) {
log.V(4).Info("resource fails the preconditions") log.V(4).Info("resource fails the preconditions")
continue continue
} }
if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil { if rule.Validation.Pattern != nil || rule.Validation.AnyPattern != nil {
ruleResponse := validatePatterns(log, ctx, resource, rule) ruleResponse := validateResourceWithRule(log, ctx, rule)
if common.IsConditionalAnchorError(ruleResponse.Message) { if !common.IsConditionalAnchorError(ruleResponse.Message) {
continue
}
incrementAppliedCount(resp) incrementAppliedCount(resp)
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse) resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResponse)
} }
} else if rule.Validation.Deny != nil {
// validate new resource if available - otherwise old resource
resource := ctx.NewResource
if reflect.DeepEqual(resource, unstructured.Unstructured{}) {
resource = ctx.OldResource
} }
denyConditionsCopy := copyConditions(rule.Validation.Deny.Conditions)
deny := variables.EvaluateConditions(log, ctx.JSONContext, denyConditionsCopy)
ruleResp := response.RuleResponse{
Name: rule.Name,
Type: utils.Validation.String(),
Message: rule.Validation.Message,
Success: !deny,
}
incrementAppliedCount(resp)
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, ruleResp)
}
}
return resp return resp
} }
func isSameResponse(oldResponse, newResponse *response.EngineResponse) bool { func validateResourceWithRule(log logr.Logger, ctx *PolicyContext, rule kyverno.Rule) (resp response.RuleResponse) {
// if the response are same then return true if reflect.DeepEqual(ctx.OldResource, unstructured.Unstructured{}) {
return isSamePolicyResponse(oldResponse.PolicyResponse, newResponse.PolicyResponse) return validatePatterns(log, ctx.JSONContext, ctx.NewResource, rule)
}
oldResp := validatePatterns(log, ctx.JSONContext, ctx.OldResource, rule)
newResp := validatePatterns(log, ctx.JSONContext, ctx.NewResource, rule)
if !isSameRuleResponse(oldResp, newResp) {
return newResp
}
return response.RuleResponse{}
} }
func isSamePolicyResponse(oldPolicyRespone, newPolicyResponse response.PolicyResponse) bool { // matches checks if either the new or old resource satisfies the filter conditions defined in the rule
// can skip policy and resource checks as they will be same func matches(logger logr.Logger, rule kyverno.Rule, ctx *PolicyContext) bool {
// compare rules err := MatchesResourceDescription(ctx.NewResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole)
return isSameRules(oldPolicyRespone.Rules, newPolicyResponse.Rules) if err == nil {
return true
}
if !reflect.DeepEqual(ctx.OldResource, unstructured.Unstructured{}) {
err := MatchesResourceDescription(ctx.OldResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole)
if err == nil {
return true
}
}
logger.V(4).Info("resource fails the match description", "reason", err.Error())
return false
} }
func isSameRules(oldRules []response.RuleResponse, newRules []response.RuleResponse) bool { func isSameRuleResponse(r1 response.RuleResponse, r2 response.RuleResponse) bool {
if len(oldRules) != len(newRules) { if r1.Name != r2.Name {
return false return false
} }
// as the rules are always processed in order the indices wil be same
for idx, oldrule := range oldRules { if r1.Type != r2.Type {
newrule := newRules[idx]
// Name
if oldrule.Name != newrule.Name {
return false return false
} }
// Type
if oldrule.Type != newrule.Type { if r1.Message != r2.Message {
return false return false
} }
// Message
if oldrule.Message != newrule.Message { if r1.Success != r2.Success {
return false return false
} }
// skip patches
if oldrule.Success != newrule.Success {
return false
}
}
return true return true
} }

File diff suppressed because one or more lines are too long

View file

@ -17,13 +17,13 @@ func Evaluate(log logr.Logger, ctx context.EvalInterface, condition kyverno.Cond
return handle.Evaluate(condition.Key, condition.Value) return handle.Evaluate(condition.Key, condition.Value)
} }
//EvaluateConditions evaluates multiple conditions //EvaluateConditions evaluates multiple conditions as a logical AND operation
func EvaluateConditions(log logr.Logger, ctx context.EvalInterface, conditions []kyverno.Condition) bool { func EvaluateConditions(log logr.Logger, ctx context.EvalInterface, conditions []kyverno.Condition) bool {
// AND the conditions
for _, condition := range conditions { for _, condition := range conditions {
if !Evaluate(log, ctx, condition) { if !Evaluate(log, ctx, condition) {
return false return false
} }
} }
return true return true
} }

View file

@ -115,7 +115,7 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
return nil, err return nil, err
} }
err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username) err = ctx.AddServiceAccount(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
if err != nil { if err != nil {
logger.Error(err, "failed to load UserInfo in context") logger.Error(err, "failed to load UserInfo in context")
return nil, err return nil, err
@ -124,7 +124,6 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
policyContext := engine.PolicyContext{ policyContext := engine.PolicyContext{
NewResource: resource, NewResource: resource,
Policy: *policyObj, Policy: *policyObj,
Context: ctx,
AdmissionInfo: gr.Spec.Context.UserRequestInfo, AdmissionInfo: gr.Spec.Context.UserRequestInfo,
ExcludeGroupRole: c.Config.GetExcludeGroupRole(), ExcludeGroupRole: c.Config.GetExcludeGroupRole(),
ExcludeResourceFunc: c.Config.ToFilter, ExcludeResourceFunc: c.Config.ToFilter,
@ -187,7 +186,6 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
// - - substitute values // - - substitute values
policy := policyContext.Policy policy := policyContext.Policy
resource := policyContext.NewResource resource := policyContext.NewResource
ctx := policyContext.Context
resCache := policyContext.ResourceCache resCache := policyContext.ResourceCache
jsonContext := policyContext.JSONContext jsonContext := policyContext.JSONContext
@ -222,7 +220,7 @@ func (c *Controller) applyGeneratePolicy(log logr.Logger, policyContext engine.P
return nil, err return nil, err
} }
genResource, err := applyRule(log, c.client, rule, resource, ctx, policy.Name, gr, processExisting) genResource, err := applyRule(log, c.client, rule, resource, jsonContext, policy.Name, gr, processExisting)
if err != nil { if err != nil {
log.Error(err, "failed to apply generate rule", "policy", policy.Name, log.Error(err, "failed to apply generate rule", "policy", policy.Name,
"rule", rule.Name, "resource", resource.GetName()) "rule", rule.Name, "resource", resource.GetName())

View file

@ -144,7 +144,9 @@ func Command() *cobra.Command {
return cmd return cmd
} }
func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, mutateLogPath string, variablesString string, valuesFile string, namespace string, policyPaths []string) (validateEngineResponses []response.EngineResponse, rc *resultCounts, resources []*unstructured.Unstructured, skippedPolicies []SkippedPolicy, err error) { func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, mutateLogPath string,
variablesString string, valuesFile string, namespace string, policyPaths []string) (validateEngineResponses []*response.EngineResponse, rc *resultCounts, resources []*unstructured.Unstructured, skippedPolicies []SkippedPolicy, err error) {
kubernetesConfig := genericclioptions.NewConfigFlags(true) kubernetesConfig := genericclioptions.NewConfigFlags(true)
if valuesFile != "" && variablesString != "" { if valuesFile != "" && variablesString != "" {
@ -230,8 +232,8 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
} }
rc = &resultCounts{} rc = &resultCounts{}
engineResponses := make([]response.EngineResponse, 0) engineResponses := make([]*response.EngineResponse, 0)
validateEngineResponses = make([]response.EngineResponse, 0) validateEngineResponses = make([]*response.EngineResponse, 0)
skippedPolicies = make([]SkippedPolicy, 0) skippedPolicies = make([]SkippedPolicy, 0)
for _, policy := range mutatedPolicies { for _, policy := range mutatedPolicies {
@ -276,6 +278,7 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
if err != nil { if err != nil {
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err) return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
} }
engineResponses = append(engineResponses, ers...) engineResponses = append(engineResponses, ers...)
validateEngineResponses = append(validateEngineResponses, validateErs) validateEngineResponses = append(validateEngineResponses, validateErs)
} }
@ -407,7 +410,7 @@ func getResourceAccordingToResourcePath(resourcePaths []string, cluster bool, po
} }
// printReportOrViolation - printing policy report/violations // printReportOrViolation - printing policy report/violations
func printReportOrViolation(policyReport bool, validateEngineResponses []response.EngineResponse, rc *resultCounts, resourcePaths []string, resourcesLen int, skippedPolicies []SkippedPolicy) { func printReportOrViolation(policyReport bool, validateEngineResponses []*response.EngineResponse, rc *resultCounts, resourcePaths []string, resourcesLen int, skippedPolicies []SkippedPolicy) {
if policyReport { if policyReport {
os.Setenv("POLICY-TYPE", pkgCommon.PolicyReport) os.Setenv("POLICY-TYPE", pkgCommon.PolicyReport)
resps := buildPolicyReports(validateEngineResponses, skippedPolicies) resps := buildPolicyReports(validateEngineResponses, skippedPolicies)
@ -435,9 +438,12 @@ func printReportOrViolation(policyReport bool, validateEngineResponses []respons
} }
// applyPolicyOnResource - function to apply policy on resource // applyPolicyOnResource - function to apply policy on resource
func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured, mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, rc *resultCounts, policyReport bool) ([]response.EngineResponse, response.EngineResponse, error) { func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured,
mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string,
rc *resultCounts, policyReport bool) ([]*response.EngineResponse, *response.EngineResponse, error) {
responseError := false responseError := false
engineResponses := make([]response.EngineResponse, 0) engineResponses := make([]*response.EngineResponse, 0)
resPath := fmt.Sprintf("%s/%s/%s", resource.GetNamespace(), resource.GetKind(), resource.GetName()) resPath := fmt.Sprintf("%s/%s/%s", resource.GetNamespace(), resource.GetKind(), resource.GetName())
log.Log.V(3).Info("applying policy on resource", "policy", policy.Name, "resource", resPath) log.Log.V(3).Info("applying policy on resource", "policy", policy.Name, "resource", resPath)
@ -457,7 +463,7 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
ctx.AddJSON(jsonData) ctx.AddJSON(jsonData)
} }
mutateResponse := engine.Mutate(engine.PolicyContext{Policy: *policy, NewResource: *resource, Context: ctx}) mutateResponse := engine.Mutate(&engine.PolicyContext{Policy: *policy, NewResource: *resource, JSONContext: ctx})
engineResponses = append(engineResponses, mutateResponse) engineResponses = append(engineResponses, mutateResponse)
if !mutateResponse.IsSuccessful() { if !mutateResponse.IsSuccessful() {
@ -483,7 +489,7 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
} else { } else {
err := printMutatedOutput(mutateLogPath, mutateLogPathIsDir, string(yamlEncodedResource), resource.GetName()+"-mutated") err := printMutatedOutput(mutateLogPath, mutateLogPathIsDir, string(yamlEncodedResource), resource.GetName()+"-mutated")
if err != nil { if err != nil {
return engineResponses, response.EngineResponse{}, sanitizederror.NewWithError("failed to print mutated result", err) return engineResponses, &response.EngineResponse{}, sanitizederror.NewWithError("failed to print mutated result", err)
} }
fmt.Printf("\n\nMutation:\nMutation has been applied successfully. Check the files.") fmt.Printf("\n\nMutation:\nMutation has been applied successfully. Check the files.")
} }
@ -499,7 +505,8 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
} }
} }
validateResponse := engine.Validate(engine.PolicyContext{Policy: *policy, NewResource: mutateResponse.PatchedResource, Context: ctx}) policyCtx := &engine.PolicyContext{Policy: *policy, NewResource: mutateResponse.PatchedResource, JSONContext: ctx}
validateResponse := engine.Validate(policyCtx)
if !policyReport { if !policyReport {
if !validateResponse.IsSuccessful() { if !validateResponse.IsSuccessful() {
fmt.Printf("\npolicy %s -> resource %s failed: \n", policy.Name, resPath) fmt.Printf("\npolicy %s -> resource %s failed: \n", policy.Name, resPath)

View file

@ -20,7 +20,7 @@ import (
const clusterpolicyreport = "clusterpolicyreport" const clusterpolicyreport = "clusterpolicyreport"
// resps is the engine responses generated for a single policy // resps is the engine responses generated for a single policy
func buildPolicyReports(resps []response.EngineResponse, skippedPolicies []SkippedPolicy) (res []*unstructured.Unstructured) { func buildPolicyReports(resps []*response.EngineResponse, skippedPolicies []SkippedPolicy) (res []*unstructured.Unstructured) {
var raw []byte var raw []byte
var err error var err error
@ -107,7 +107,7 @@ func buildPolicyReports(resps []response.EngineResponse, skippedPolicies []Skipp
// buildPolicyResults returns a string-PolicyReportResult map // buildPolicyResults returns a string-PolicyReportResult map
// the key of the map is one of "clusterpolicyreport", "policyreport-ns-<namespace>" // the key of the map is one of "clusterpolicyreport", "policyreport-ns-<namespace>"
func buildPolicyResults(resps []response.EngineResponse) map[string][]*report.PolicyReportResult { func buildPolicyResults(resps []*response.EngineResponse) map[string][]*report.PolicyReportResult {
results := make(map[string][]*report.PolicyReportResult) results := make(map[string][]*report.PolicyReportResult)
infos := policyreport.GeneratePRsFromEngineResponse(resps, log.Log) infos := policyreport.GeneratePRsFromEngineResponse(resps, log.Log)

View file

@ -14,7 +14,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
) )
var engineResponses = []response.EngineResponse{ var engineResponses = []*response.EngineResponse{
{ {
PatchedResource: unstructured.Unstructured{ PatchedResource: unstructured.Unstructured{
Object: map[string]interface{}{ Object: map[string]interface{}{

View file

@ -19,7 +19,8 @@ import (
) )
// applyPolicy applies policy on a resource // applyPolicy applies policy on a resource
func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, logger logr.Logger, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface) (responses []response.EngineResponse) { func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured,
logger logr.Logger, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface) (responses []*response.EngineResponse) {
startTime := time.Now() startTime := time.Now()
defer func() { defer func() {
name := resource.GetKind() + "/" + resource.GetName() name := resource.GetKind() + "/" + resource.GetName()
@ -31,8 +32,8 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
logger.V(3).Info("applyPolicy", "resource", name, "processingTime", time.Since(startTime).String()) logger.V(3).Info("applyPolicy", "resource", name, "processingTime", time.Since(startTime).String())
}() }()
var engineResponses []response.EngineResponse var engineResponses []*response.EngineResponse
var engineResponseMutation, engineResponseValidation response.EngineResponse var engineResponseMutation, engineResponseValidation *response.EngineResponse
var err error var err error
ctx := context.NewContext() ctx := context.NewContext()
@ -41,20 +42,27 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
logger.Error(err, "enable to add transform resource to ctx") logger.Error(err, "enable to add transform resource to ctx")
} }
engineResponseMutation, err = mutation(policy, resource, ctx, logger, resCache, ctx) engineResponseMutation, err = mutation(policy, resource, logger, resCache, ctx)
if err != nil { if err != nil {
logger.Error(err, "failed to process mutation rule") logger.Error(err, "failed to process mutation rule")
} }
engineResponseValidation = engine.Validate(engine.PolicyContext{Policy: policy, Context: ctx, NewResource: resource, ExcludeGroupRole: excludeGroupRole, ResourceCache: resCache, JSONContext: ctx}) engineResponseValidation = engine.Validate(&engine.PolicyContext{Policy: policy, NewResource: resource, ExcludeGroupRole: excludeGroupRole, ResourceCache: resCache, JSONContext: ctx})
engineResponses = append(engineResponses, mergeRuleRespose(engineResponseMutation, engineResponseValidation)) engineResponses = append(engineResponses, mergeRuleRespose(engineResponseMutation, engineResponseValidation))
return engineResponses return engineResponses
} }
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, ctx context.EvalInterface, log logr.Logger, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) (response.EngineResponse, error) { func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, log logr.Logger, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) (*response.EngineResponse, error) {
engineResponse := engine.Mutate(engine.PolicyContext{Policy: policy, NewResource: resource, Context: ctx, ResourceCache: resCache, JSONContext: jsonContext}) policyContext := &engine.PolicyContext{
Policy: policy,
NewResource: resource,
ResourceCache: resCache,
JSONContext: jsonContext,
}
engineResponse := engine.Mutate(policyContext)
if !engineResponse.IsSuccessful() { if !engineResponse.IsSuccessful() {
log.V(4).Info("failed to apply mutation rules; reporting them") log.V(4).Info("failed to apply mutation rules; reporting them")
return engineResponse, nil return engineResponse, nil
@ -69,11 +77,11 @@ func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured,
} }
// getFailedOverallRuleInfo gets detailed info for over-all mutation failure // getFailedOverallRuleInfo gets detailed info for over-all mutation failure
func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse response.EngineResponse, log logr.Logger) (response.EngineResponse, error) { func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse *response.EngineResponse, log logr.Logger) (*response.EngineResponse, error) {
rawResource, err := resource.MarshalJSON() rawResource, err := resource.MarshalJSON()
if err != nil { if err != nil {
log.Error(err, "failed to marshall resource") log.Error(err, "failed to marshall resource")
return response.EngineResponse{}, err return &response.EngineResponse{}, err
} }
// resource does not match so there was a mutation rule violated // resource does not match so there was a mutation rule violated
@ -85,14 +93,14 @@ func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse
patch, err := jsonpatch.DecodePatch(utils.JoinPatches(patches)) patch, err := jsonpatch.DecodePatch(utils.JoinPatches(patches))
if err != nil { if err != nil {
log.Error(err, "failed to decode JSON patch", "patches", patches) log.Error(err, "failed to decode JSON patch", "patches", patches)
return response.EngineResponse{}, err return &response.EngineResponse{}, err
} }
// apply the patches returned by mutate to the original resource // apply the patches returned by mutate to the original resource
patchedResource, err := patch.Apply(rawResource) patchedResource, err := patch.Apply(rawResource)
if err != nil { if err != nil {
log.Error(err, "failed to apply JSON patch", "patches", patches) log.Error(err, "failed to apply JSON patch", "patches", patches)
return response.EngineResponse{}, err return &response.EngineResponse{}, err
} }
if !jsonpatch.Equal(patchedResource, rawResource) { if !jsonpatch.Equal(patchedResource, rawResource) {
@ -126,7 +134,7 @@ func extractPatchPath(patches [][]byte, log logr.Logger) string {
return strings.Join(resultPath, ";") return strings.Join(resultPath, ";")
} }
func mergeRuleRespose(mutation, validation response.EngineResponse) response.EngineResponse { func mergeRuleRespose(mutation, validation *response.EngineResponse) *response.EngineResponse {
mutation.PolicyResponse.Rules = append(mutation.PolicyResponse.Rules, validation.PolicyResponse.Rules...) mutation.PolicyResponse.Rules = append(mutation.PolicyResponse.Rules, validation.PolicyResponse.Rules...)
return mutation return mutation
} }

View file

@ -59,7 +59,7 @@ func (pc *PolicyController) applyAndReportPerNamespace(policy *kyverno.ClusterPo
return return
} }
var engineResponses []response.EngineResponse var engineResponses []*response.EngineResponse
for _, resource := range rMap { for _, resource := range rMap {
responses := pc.applyPolicy(policy, resource, logger) responses := pc.applyPolicy(policy, resource, logger)
engineResponses = append(engineResponses, responses...) engineResponses = append(engineResponses, responses...)
@ -68,7 +68,7 @@ func (pc *PolicyController) applyAndReportPerNamespace(policy *kyverno.ClusterPo
pc.report(policy.Name, engineResponses, logger) pc.report(policy.Name, engineResponses, logger)
} }
func (pc *PolicyController) applyPolicy(policy *kyverno.ClusterPolicy, resource unstructured.Unstructured, logger logr.Logger) (engineResponses []response.EngineResponse) { func (pc *PolicyController) applyPolicy(policy *kyverno.ClusterPolicy, resource unstructured.Unstructured, logger logr.Logger) (engineResponses []*response.EngineResponse) {
// pre-processing, check if the policy and resource version has been processed before // pre-processing, check if the policy and resource version has been processed before
if !pc.rm.ProcessResource(policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion()) { if !pc.rm.ProcessResource(policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion()) {
logger.V(4).Info("policy and resource already processed", "policyResourceVersion", policy.ResourceVersion, "resourceResourceVersion", resource.GetResourceVersion(), "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName()) logger.V(4).Info("policy and resource already processed", "policyResourceVersion", policy.ResourceVersion, "resourceResourceVersion", resource.GetResourceVersion(), "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
@ -86,7 +86,7 @@ func (pc *PolicyController) applyPolicy(policy *kyverno.ClusterPolicy, resource
// excludeAutoGenResources filter out the pods / jobs with ownerReference // excludeAutoGenResources filter out the pods / jobs with ownerReference
func excludeAutoGenResources(policy kyverno.ClusterPolicy, resourceMap map[string]unstructured.Unstructured, log logr.Logger) { func excludeAutoGenResources(policy kyverno.ClusterPolicy, resourceMap map[string]unstructured.Unstructured, log logr.Logger) {
for uid, r := range resourceMap { for uid, r := range resourceMap {
if engine.SkipPolicyApplication(policy, r) { if engine.ManagedPodResource(policy, r) {
log.V(4).Info("exclude resource", "namespace", r.GetNamespace(), "kind", r.GetKind(), "name", r.GetName()) log.V(4).Info("exclude resource", "namespace", r.GetNamespace(), "kind", r.GetKind(), "name", r.GetName())
delete(resourceMap, uid) delete(resourceMap, uid)
} }

View file

@ -9,7 +9,7 @@ import (
"github.com/kyverno/kyverno/pkg/policyreport" "github.com/kyverno/kyverno/pkg/policyreport"
) )
func (pc *PolicyController) report(policy string, engineResponses []response.EngineResponse, logger logr.Logger) { func (pc *PolicyController) report(policy string, engineResponses []*response.EngineResponse, logger logr.Logger) {
eventInfos := generateEvents(logger, engineResponses) eventInfos := generateEvents(logger, engineResponses)
pc.eventGen.Add(eventInfos...) pc.eventGen.Add(eventInfos...)
@ -22,7 +22,7 @@ func (pc *PolicyController) report(policy string, engineResponses []response.Eng
logger.V(4).Info("added a request to RCR generator", "key", info.ToKey()) logger.V(4).Info("added a request to RCR generator", "key", info.ToKey())
} }
func generateEvents(log logr.Logger, ers []response.EngineResponse) []event.Info { func generateEvents(log logr.Logger, ers []*response.EngineResponse) []event.Info {
var eventInfos []event.Info var eventInfos []event.Info
for _, er := range ers { for _, er := range ers {
if er.IsSuccessful() { if er.IsSuccessful() {
@ -33,7 +33,7 @@ func generateEvents(log logr.Logger, ers []response.EngineResponse) []event.Info
return eventInfos return eventInfos
} }
func generateEventsPerEr(log logr.Logger, er response.EngineResponse) []event.Info { func generateEventsPerEr(log logr.Logger, er *response.EngineResponse) []event.Info {
var eventInfos []event.Info var eventInfos []event.Info
logger := log.WithValues("policy", er.PolicyResponse.Policy, "kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace, "name", er.PolicyResponse.Resource.Name) logger := log.WithValues("policy", er.PolicyResponse.Policy, "kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace, "name", er.PolicyResponse.Resource.Name)

View file

@ -41,7 +41,7 @@ func generatePolicyReportName(ns string) string {
} }
//GeneratePRsFromEngineResponse generate Violations from engine responses //GeneratePRsFromEngineResponse generate Violations from engine responses
func GeneratePRsFromEngineResponse(ers []response.EngineResponse, log logr.Logger) (pvInfos []Info) { func GeneratePRsFromEngineResponse(ers []*response.EngineResponse, log logr.Logger) (pvInfos []Info) {
for _, er := range ers { for _, er := range ers {
// ignore creation of PV for resources that are yet to be assigned a name // ignore creation of PV for resources that are yet to be assigned a name
if er.PolicyResponse.Resource.Name == "" { if er.PolicyResponse.Resource.Name == "" {
@ -210,7 +210,7 @@ func calculateSummary(results []*report.PolicyReportResult) (summary report.Poli
return return
} }
func buildPVInfo(er response.EngineResponse) Info { func buildPVInfo(er *response.EngineResponse) Info {
info := Info{ info := Info{
PolicyName: er.PolicyResponse.Policy, PolicyName: er.PolicyResponse.Policy,
Namespace: er.PatchedResource.GetNamespace(), Namespace: er.PatchedResource.GetNamespace(),
@ -224,7 +224,7 @@ func buildPVInfo(er response.EngineResponse) Info {
return info return info
} }
func buildViolatedRules(er response.EngineResponse) []kyverno.ViolatedRule { func buildViolatedRules(er *response.EngineResponse) []kyverno.ViolatedRule {
var violatedRules []kyverno.ViolatedRule var violatedRules []kyverno.ViolatedRule
for _, rule := range er.PolicyResponse.Rules { for _, rule := range er.PolicyResponse.Rules {
vrule := kyverno.ViolatedRule{ vrule := kyverno.ViolatedRule{

View file

@ -126,9 +126,7 @@ func runTestCase(t *testing.T, tc scaseT) bool {
t.FailNow() t.FailNow()
} }
var er response.EngineResponse er := engine.Mutate(&engine.PolicyContext{Policy: *policy, NewResource: *resource, ExcludeGroupRole: []string{}})
er = engine.Mutate(engine.PolicyContext{Policy: *policy, NewResource: *resource, ExcludeGroupRole: []string{}})
t.Log("---Mutation---") t.Log("---Mutation---")
validateResource(t, er.PatchedResource, tc.Expected.Mutation.PatchedResource) validateResource(t, er.PatchedResource, tc.Expected.Mutation.PatchedResource)
validateResponse(t, er.PolicyResponse, tc.Expected.Mutation.PolicyResponse) validateResponse(t, er.PolicyResponse, tc.Expected.Mutation.PolicyResponse)
@ -138,7 +136,7 @@ func runTestCase(t *testing.T, tc scaseT) bool {
resource = &er.PatchedResource resource = &er.PatchedResource
} }
er = engine.Validate(engine.PolicyContext{Policy: *policy, NewResource: *resource, ExcludeGroupRole: []string{}}) er = engine.Validate(&engine.PolicyContext{Policy: *policy, NewResource: *resource, ExcludeGroupRole: []string{}})
t.Log("---Validation---") t.Log("---Validation---")
validateResponse(t, er.PolicyResponse, tc.Expected.Validation.PolicyResponse) validateResponse(t, er.PolicyResponse, tc.Expected.Validation.PolicyResponse)
@ -235,7 +233,7 @@ func validateResponse(t *testing.T, er response.PolicyResponse, expected respons
// rules // rules
if len(er.Rules) != len(expected.Rules) { if len(er.Rules) != len(expected.Rules) {
t.Errorf("rule count error, er.Rules=%d, expected.Rules=%d", len(er.Rules), len(expected.Rules)) t.Errorf("rule count error, er.Rules=%v, expected.Rules=%v", er.Rules, expected.Rules)
return return
} }
if len(er.Rules) == len(expected.Rules) { if len(er.Rules) == len(expected.Rules) {

View file

@ -36,7 +36,7 @@ var operationToPastTense = map[string]string{
"test": "tested", "test": "tested",
} }
func generateAnnotationPatches(engineResponses []response.EngineResponse, log logr.Logger) []byte { func generateAnnotationPatches(engineResponses []*response.EngineResponse, log logr.Logger) []byte {
var annotations map[string]string var annotations map[string]string
for _, er := range engineResponses { for _, er := range engineResponses {
@ -94,7 +94,7 @@ func generateAnnotationPatches(engineResponses []response.EngineResponse, log lo
return patchByte return patchByte
} }
func annotationFromEngineResponses(engineResponses []response.EngineResponse, log logr.Logger) []byte { func annotationFromEngineResponses(engineResponses []*response.EngineResponse, log logr.Logger) []byte {
var annotationContent = make(map[string]string) var annotationContent = make(map[string]string)
for _, engineResponse := range engineResponses { for _, engineResponse := range engineResponses {
if !engineResponse.IsSuccessful() { if !engineResponse.IsSuccessful() {

View file

@ -26,8 +26,8 @@ func newPolicyResponse(policy, rule string, patchesStr []string, success bool) r
} }
} }
func newEngineResponse(policy, rule string, patchesStr []string, success bool, annotation map[string]string) response.EngineResponse { func newEngineResponse(policy, rule string, patchesStr []string, success bool, annotation map[string]string) *response.EngineResponse {
return response.EngineResponse{ return &response.EngineResponse{
PatchedResource: unstructured.Unstructured{ PatchedResource: unstructured.Unstructured{
Object: map[string]interface{}{ Object: map[string]interface{}{
"metadata": map[string]interface{}{ "metadata": map[string]interface{}{
@ -43,7 +43,7 @@ func Test_empty_annotation(t *testing.T) {
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }` patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, true, nil) engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, true, nil)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log) annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches := `{"op":"add","path":"/metadata/annotations","value":{"policies.kyverno.io/patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}` expectedPatches := `{"op":"add","path":"/metadata/annotations","value":{"policies.kyverno.io/patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}`
assert.Assert(t, string(annPatches) == expectedPatches) assert.Assert(t, string(annPatches) == expectedPatches)
} }
@ -55,7 +55,7 @@ func Test_exist_annotation(t *testing.T) {
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }` patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, true, annotation) engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, true, annotation)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log) annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches := `{"op":"add","path":"/metadata/annotations","value":{"policies.kyverno.io/patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}` expectedPatches := `{"op":"add","path":"/metadata/annotations","value":{"policies.kyverno.io/patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}`
assert.Assert(t, string(annPatches) == expectedPatches) assert.Assert(t, string(annPatches) == expectedPatches)
@ -68,7 +68,7 @@ func Test_exist_kyverno_annotation(t *testing.T) {
patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }` patchStr := `{ "op": "replace", "path": "/spec/containers/0/imagePullPolicy", "value": "IfNotPresent" }`
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, true, annotation) engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{patchStr}, true, annotation)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log) annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
expectedPatches := `{"op":"add","path":"/metadata/annotations","value":{"policies.kyverno.io/patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}` expectedPatches := `{"op":"add","path":"/metadata/annotations","value":{"policies.kyverno.io/patches":"default-imagepullpolicy.mutate-container.kyverno.io: replaced /spec/containers/0/imagePullPolicy\n"}}`
assert.Assert(t, string(annPatches) == expectedPatches) assert.Assert(t, string(annPatches) == expectedPatches)
@ -80,11 +80,11 @@ func Test_annotation_nil_patch(t *testing.T) {
} }
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", nil, true, annotation) engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", nil, true, annotation)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log) annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
assert.Assert(t, annPatches == nil) assert.Assert(t, annPatches == nil)
engineResponseNew := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{""}, true, annotation) engineResponseNew := newEngineResponse("mutate-container", "default-imagepullpolicy", []string{""}, true, annotation)
annPatchesNew := generateAnnotationPatches([]response.EngineResponse{engineResponseNew}, log.Log) annPatchesNew := generateAnnotationPatches([]*response.EngineResponse{engineResponseNew}, log.Log)
assert.Assert(t, annPatchesNew == nil) assert.Assert(t, annPatchesNew == nil)
} }
@ -94,7 +94,7 @@ func Test_annotation_failed_Patch(t *testing.T) {
} }
engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", nil, false, annotation) engineResponse := newEngineResponse("mutate-container", "default-imagepullpolicy", nil, false, annotation)
annPatches := generateAnnotationPatches([]response.EngineResponse{engineResponse}, log.Log) annPatches := generateAnnotationPatches([]*response.EngineResponse{engineResponse}, log.Log)
assert.Assert(t, annPatches == nil) assert.Assert(t, annPatches == nil)
} }

View file

@ -16,7 +16,7 @@ import (
) )
// isResponseSuccessful return true if all responses are successful // isResponseSuccessful return true if all responses are successful
func isResponseSuccessful(engineReponses []response.EngineResponse) bool { func isResponseSuccessful(engineReponses []*response.EngineResponse) bool {
for _, er := range engineReponses { for _, er := range engineReponses {
if !er.IsSuccessful() { if !er.IsSuccessful() {
return false return false
@ -27,7 +27,7 @@ func isResponseSuccessful(engineReponses []response.EngineResponse) bool {
// returns true -> if there is even one policy that blocks resource request // returns true -> if there is even one policy that blocks resource request
// returns false -> if all the policies are meant to report only, we dont block resource request // returns false -> if all the policies are meant to report only, we dont block resource request
func toBlockResource(engineReponses []response.EngineResponse, log logr.Logger) bool { func toBlockResource(engineReponses []*response.EngineResponse, log logr.Logger) bool {
for _, er := range engineReponses { for _, er := range engineReponses {
if !er.IsSuccessful() && er.PolicyResponse.ValidationFailureAction == common.Enforce { if !er.IsSuccessful() && er.PolicyResponse.ValidationFailureAction == common.Enforce {
log.Info("spec.ValidationFailureAction set to enforce blocking resource request", "policy", er.PolicyResponse.Policy) log.Info("spec.ValidationFailureAction set to enforce blocking resource request", "policy", er.PolicyResponse.Policy)
@ -39,7 +39,7 @@ func toBlockResource(engineReponses []response.EngineResponse, log logr.Logger)
} }
// getEnforceFailureErrorMsg gets the error messages for failed enforce policy // getEnforceFailureErrorMsg gets the error messages for failed enforce policy
func getEnforceFailureErrorMsg(engineResponses []response.EngineResponse) string { func getEnforceFailureErrorMsg(engineResponses []*response.EngineResponse) string {
policyToRule := make(map[string]interface{}) policyToRule := make(map[string]interface{})
var resourceName string var resourceName string
for _, er := range engineResponses { for _, er := range engineResponses {
@ -61,7 +61,7 @@ func getEnforceFailureErrorMsg(engineResponses []response.EngineResponse) string
} }
// getErrorMsg gets all failed engine response message // getErrorMsg gets all failed engine response message
func getErrorMsg(engineReponses []response.EngineResponse) string { func getErrorMsg(engineReponses []*response.EngineResponse) string {
var str []string var str []string
var resourceInfo string var resourceInfo string

View file

@ -29,7 +29,7 @@ import (
func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, policies []*kyverno.ClusterPolicy, ctx *context.Context, userRequestInfo kyverno.RequestInfo, dynamicConfig config.Interface) { func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, policies []*kyverno.ClusterPolicy, ctx *context.Context, userRequestInfo kyverno.RequestInfo, dynamicConfig config.Interface) {
logger := ws.log.WithValues("action", "generation", "uid", request.UID, "kind", request.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation) logger := ws.log.WithValues("action", "generation", "uid", request.UID, "kind", request.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation)
logger.V(4).Info("incoming request") logger.V(4).Info("incoming request")
var engineResponses []response.EngineResponse var engineResponses []*response.EngineResponse
if len(policies) == 0 { if len(policies) == 0 {
return return
@ -44,7 +44,6 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
NewResource: new, NewResource: new,
OldResource: old, OldResource: old,
AdmissionInfo: userRequestInfo, AdmissionInfo: userRequestInfo,
Context: ctx,
ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(), ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(),
ExcludeResourceFunc: ws.configHandler.ToFilter, ExcludeResourceFunc: ws.configHandler.ToFilter,
ResourceCache: ws.resCache, ResourceCache: ws.resCache,
@ -86,7 +85,7 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
return return
} }
func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse response.EngineResponse) { func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse *response.EngineResponse) {
logger.V(4).Info("querying all generate requests") logger.V(4).Info("querying all generate requests")
selector := labels.SelectorFromSet(labels.Set(map[string]string{ selector := labels.SelectorFromSet(labels.Set(map[string]string{
"policyName": engineResponse.PolicyResponse.Policy, "policyName": engineResponse.PolicyResponse.Policy,
@ -110,7 +109,7 @@ func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse response.En
} }
func applyGenerateRequest(gnGenerator generate.GenerateRequests, userRequestInfo kyverno.RequestInfo, func applyGenerateRequest(gnGenerator generate.GenerateRequests, userRequestInfo kyverno.RequestInfo,
action v1beta1.Operation, engineResponses ...response.EngineResponse) (failedGenerateRequest []generateRequestResponse) { action v1beta1.Operation, engineResponses ...*response.EngineResponse) (failedGenerateRequest []generateRequestResponse) {
for _, er := range engineResponses { for _, er := range engineResponses {
gr := transform(userRequestInfo, er) gr := transform(userRequestInfo, er)
@ -122,8 +121,7 @@ func applyGenerateRequest(gnGenerator generate.GenerateRequests, userRequestInfo
return return
} }
func transform(userRequestInfo kyverno.RequestInfo, er response.EngineResponse) kyverno.GenerateRequestSpec { func transform(userRequestInfo kyverno.RequestInfo, er *response.EngineResponse) kyverno.GenerateRequestSpec {
gr := kyverno.GenerateRequestSpec{ gr := kyverno.GenerateRequestSpec{
Policy: er.PolicyResponse.Policy, Policy: er.PolicyResponse.Policy,
Resource: kyverno.ResourceSpec{ Resource: kyverno.ResourceSpec{
@ -135,11 +133,12 @@ func transform(userRequestInfo kyverno.RequestInfo, er response.EngineResponse)
UserRequestInfo: userRequestInfo, UserRequestInfo: userRequestInfo,
}, },
} }
return gr return gr
} }
type generateStats struct { type generateStats struct {
resp response.EngineResponse resp *response.EngineResponse
} }
func (gs generateStats) PolicyName() string { func (gs generateStats) PolicyName() string {

View file

@ -36,11 +36,10 @@ func (ws *WebhookServer) HandleMutation(
logger := ws.log.WithValues("action", "mutate", "resource", resourceName, "operation", request.Operation) logger := ws.log.WithValues("action", "mutate", "resource", resourceName, "operation", request.Operation)
var patches [][]byte var patches [][]byte
var engineResponses []response.EngineResponse var engineResponses []*response.EngineResponse
policyContext := engine.PolicyContext{ policyContext := &engine.PolicyContext{
NewResource: resource, NewResource: resource,
AdmissionInfo: userRequestInfo, AdmissionInfo: userRequestInfo,
Context: ctx,
ExcludeGroupRole: ws.configHandler.GetExcludeGroupRole(), ExcludeGroupRole: ws.configHandler.GetExcludeGroupRole(),
ExcludeResourceFunc: ws.configHandler.ToFilter, ExcludeResourceFunc: ws.configHandler.ToFilter,
ResourceCache: ws.resCache, ResourceCache: ws.resCache,
@ -117,7 +116,7 @@ func (ws *WebhookServer) HandleMutation(
} }
type mutateStats struct { type mutateStats struct {
resp response.EngineResponse resp *response.EngineResponse
namespace string namespace string
} }

View file

@ -12,11 +12,11 @@ import (
func Test_GenerateStats(t *testing.T) { func Test_GenerateStats(t *testing.T) {
testCase := struct { testCase := struct {
generateStats []response.EngineResponse generateStats []*response.EngineResponse
expectedOutput []byte expectedOutput []byte
}{ }{
expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"494ns","rulesFailedCount":1,"rulesAppliedCount":1,"ruleStatus":[{"ruleName":"rule5","averageExecutionTime":"243ns","appliedCount":1},{"ruleName":"rule6","averageExecutionTime":"251ns","failedCount":1}]},"policy2":{"averageExecutionTime":"433ns","rulesFailedCount":1,"rulesAppliedCount":1,"ruleStatus":[{"ruleName":"rule5","averageExecutionTime":"222ns","appliedCount":1},{"ruleName":"rule6","averageExecutionTime":"211ns","failedCount":1}]}}`), expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"494ns","rulesFailedCount":1,"rulesAppliedCount":1,"ruleStatus":[{"ruleName":"rule5","averageExecutionTime":"243ns","appliedCount":1},{"ruleName":"rule6","averageExecutionTime":"251ns","failedCount":1}]},"policy2":{"averageExecutionTime":"433ns","rulesFailedCount":1,"rulesAppliedCount":1,"ruleStatus":[{"ruleName":"rule5","averageExecutionTime":"222ns","appliedCount":1},{"ruleName":"rule6","averageExecutionTime":"211ns","failedCount":1}]}}`),
generateStats: []response.EngineResponse{ generateStats: []*response.EngineResponse{
{ {
PolicyResponse: response.PolicyResponse{ PolicyResponse: response.PolicyResponse{
Policy: "policy1", Policy: "policy1",
@ -79,11 +79,11 @@ func Test_GenerateStats(t *testing.T) {
func Test_MutateStats(t *testing.T) { func Test_MutateStats(t *testing.T) {
testCase := struct { testCase := struct {
mutateStats []response.EngineResponse mutateStats []*response.EngineResponse
expectedOutput []byte expectedOutput []byte
}{ }{
expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"494ns","rulesFailedCount":1,"rulesAppliedCount":1,"resourcesMutatedCount":1,"ruleStatus":[{"ruleName":"rule1","averageExecutionTime":"243ns","appliedCount":1,"resourcesMutatedCount":1},{"ruleName":"rule2","averageExecutionTime":"251ns","failedCount":1}]},"policy2":{"averageExecutionTime":"433ns","rulesFailedCount":1,"rulesAppliedCount":1,"resourcesMutatedCount":1,"ruleStatus":[{"ruleName":"rule1","averageExecutionTime":"222ns","appliedCount":1,"resourcesMutatedCount":1},{"ruleName":"rule2","averageExecutionTime":"211ns","failedCount":1}]}}`), expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"494ns","rulesFailedCount":1,"rulesAppliedCount":1,"resourcesMutatedCount":1,"ruleStatus":[{"ruleName":"rule1","averageExecutionTime":"243ns","appliedCount":1,"resourcesMutatedCount":1},{"ruleName":"rule2","averageExecutionTime":"251ns","failedCount":1}]},"policy2":{"averageExecutionTime":"433ns","rulesFailedCount":1,"rulesAppliedCount":1,"resourcesMutatedCount":1,"ruleStatus":[{"ruleName":"rule1","averageExecutionTime":"222ns","appliedCount":1,"resourcesMutatedCount":1},{"ruleName":"rule2","averageExecutionTime":"211ns","failedCount":1}]}}`),
mutateStats: []response.EngineResponse{ mutateStats: []*response.EngineResponse{
{ {
PolicyResponse: response.PolicyResponse{ PolicyResponse: response.PolicyResponse{
Policy: "policy1", Policy: "policy1",
@ -145,11 +145,11 @@ func Test_MutateStats(t *testing.T) {
func Test_ValidateStats(t *testing.T) { func Test_ValidateStats(t *testing.T) {
testCase := struct { testCase := struct {
validateStats []response.EngineResponse validateStats []*response.EngineResponse
expectedOutput []byte expectedOutput []byte
}{ }{
expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"494ns","rulesFailedCount":1,"rulesAppliedCount":1,"resourcesBlockedCount":1,"ruleStatus":[{"ruleName":"rule3","averageExecutionTime":"243ns","appliedCount":1},{"ruleName":"rule4","averageExecutionTime":"251ns","failedCount":1,"resourcesBlockedCount":1}]},"policy2":{"averageExecutionTime":"433ns","rulesFailedCount":1,"rulesAppliedCount":1,"ruleStatus":[{"ruleName":"rule3","averageExecutionTime":"222ns","appliedCount":1},{"ruleName":"rule4","averageExecutionTime":"211ns","failedCount":1}]}}`), expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"494ns","rulesFailedCount":1,"rulesAppliedCount":1,"resourcesBlockedCount":1,"ruleStatus":[{"ruleName":"rule3","averageExecutionTime":"243ns","appliedCount":1},{"ruleName":"rule4","averageExecutionTime":"251ns","failedCount":1,"resourcesBlockedCount":1}]},"policy2":{"averageExecutionTime":"433ns","rulesFailedCount":1,"rulesAppliedCount":1,"ruleStatus":[{"ruleName":"rule3","averageExecutionTime":"222ns","appliedCount":1},{"ruleName":"rule4","averageExecutionTime":"211ns","failedCount":1}]}}`),
validateStats: []response.EngineResponse{ validateStats: []*response.EngineResponse{
{ {
PolicyResponse: response.PolicyResponse{ PolicyResponse: response.PolicyResponse{
Policy: "policy1", Policy: "policy1",

View file

@ -10,7 +10,7 @@ import (
) )
//generateEvents generates event info for the engine responses //generateEvents generates event info for the engine responses
func generateEvents(engineResponses []response.EngineResponse, blocked, onUpdate bool, log logr.Logger) []event.Info { func generateEvents(engineResponses []*response.EngineResponse, blocked, onUpdate bool, log logr.Logger) []event.Info {
var events []event.Info var events []event.Info
// - Admission-Response is SUCCESS // - Admission-Response is SUCCESS

View file

@ -330,7 +330,7 @@ func (ws *WebhookServer) ResourceMutation(request *v1beta1.AdmissionRequest) *v1
if err != nil { if err != nil {
logger.Error(err, "failed to load userInfo in context") logger.Error(err, "failed to load userInfo in context")
} }
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username) err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
if err != nil { if err != nil {
logger.Error(err, "failed to load service account in context") logger.Error(err, "failed to load service account in context")
} }
@ -441,7 +441,7 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
if err != nil { if err != nil {
logger.Error(err, "failed to load userInfo in context") logger.Error(err, "failed to load userInfo in context")
} }
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username) err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
if err != nil { if err != nil {
logger.Error(err, "failed to load service account in context") logger.Error(err, "failed to load service account in context")
} }

View file

@ -166,7 +166,7 @@ func (h *auditHandler) process(request *v1beta1.AdmissionRequest) error {
if err != nil { if err != nil {
return errors.Wrap(err, "failed to load userInfo in context") return errors.Wrap(err, "failed to load userInfo in context")
} }
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username) err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to load service account in context") return errors.Wrap(err, "failed to load service account in context")
} }

View file

@ -68,10 +68,9 @@ func HandleValidation(
return true, "" return true, ""
} }
policyContext := engine.PolicyContext{ policyContext := &engine.PolicyContext{
NewResource: newR, NewResource: newR,
OldResource: oldR, OldResource: oldR,
Context: ctx,
AdmissionInfo: userRequestInfo, AdmissionInfo: userRequestInfo,
ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(), ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(),
ExcludeResourceFunc: dynamicConfig.ToFilter, ExcludeResourceFunc: dynamicConfig.ToFilter,
@ -79,7 +78,7 @@ func HandleValidation(
JSONContext: ctx, JSONContext: ctx,
} }
var engineResponses []response.EngineResponse var engineResponses []*response.EngineResponse
for _, policy := range policies { for _, policy := range policies {
logger.V(3).Info("evaluating policy", "policy", policy.Name) logger.V(3).Info("evaluating policy", "policy", policy.Name)
@ -152,7 +151,7 @@ func buildDeletionPrInfo(oldR unstructured.Unstructured) policyreport.Info {
} }
type validateStats struct { type validateStats struct {
resp response.EngineResponse resp *response.EngineResponse
namespace string namespace string
} }

View file

@ -10,7 +10,7 @@ expected:
kind: Pod kind: Pod
apiVersion: v1 apiVersion: v1
# this is set to pass resource NS check # this is set to pass resource NS check
# actual valiation is defined through rule success=false # actual validation is defined through rule success=false
namespace: 'default' namespace: 'default'
name: myapp-pod name: myapp-pod
rules: rules: