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

Merge pull request #2559 from vyankyGH/Fix/Foreach_issue

Fix : Foreach fails the whole policy if the list is not there
Signed-off-by: ShutingZhao <shutting06@gmail.com>
This commit is contained in:
Jim Bugwadia 2021-10-19 10:01:45 -07:00 committed by ShutingZhao
parent 5df903e34e
commit c4c29bc6ad
2 changed files with 85 additions and 38 deletions

View file

@ -157,28 +157,23 @@ func newValidator(log logr.Logger, ctx *PolicyContext, rule *kyverno.Rule) *vali
}
}
func newForeachValidator(log logr.Logger, ctx *PolicyContext, rule *kyverno.Rule) []*validator {
func newForeachValidator(log logr.Logger, ctx *PolicyContext, rule *kyverno.Rule, foreachIndex int) *validator {
ruleCopy := rule.DeepCopy()
var val []*validator
for _, foreach := range ruleCopy.Validation.ForEachValidation {
anyAllConditions, err := common.ToMap(foreach.AnyAllConditions)
if err != nil {
log.Error(err, "failed to convert ruleCopy.Validation.ForEachValidation.AnyAllConditions")
}
temp := validator{
log: log,
ctx: ctx,
rule: ruleCopy,
contextEntries: foreach.Context,
anyAllConditions: anyAllConditions,
pattern: foreach.Pattern,
anyPattern: foreach.AnyPattern,
deny: foreach.Deny,
}
val = append(val, &temp)
foreach := ruleCopy.Validation.ForEachValidation
anyAllConditions, err := common.ToMap(foreach[foreachIndex].AnyAllConditions)
if err != nil {
log.Error(err, "failed to convert ruleCopy.Validation.ForEachValidation.AnyAllConditions")
}
return &validator{
log: log,
ctx: ctx,
rule: ruleCopy,
contextEntries: foreach[foreachIndex].Context,
anyAllConditions: anyAllConditions,
pattern: foreach[foreachIndex].Pattern,
anyPattern: foreach[foreachIndex].AnyPattern,
deny: foreach[foreachIndex].Deny,
}
// Variable substitution expects JSON data, so we convert to a map
return val
}
func (v *validator) validate() *response.RuleResponse {
@ -228,11 +223,11 @@ func (v *validator) validateForEach() *response.RuleResponse {
return nil
}
for _, foreach := range foreachList {
for foreachIndex, foreach := range foreachList {
elements, err := evaluateList(foreach.List, v.ctx.JSONContext)
if err != nil {
msg := fmt.Sprintf("failed to evaluate list %s", foreach.List)
return ruleError(v.rule, utils.Validation, msg, err)
v.log.Info("failed to evaluate list", "list", foreach.List, "error", err.Error())
continue
}
v.ctx.JSONContext.Checkpoint()
@ -247,22 +242,19 @@ func (v *validator) validateForEach() *response.RuleResponse {
return ruleError(v.rule, utils.Validation, "failed to process foreach", err)
}
foreachValidatorList := newForeachValidator(v.log, ctx, v.rule)
for _, foreachValidator := range foreachValidatorList {
r := foreachValidator.validate()
if r == nil {
v.log.Info("skipping rule due to empty result")
continue
} else if r.Status == response.RuleStatusSkip {
v.log.Info("skipping rule as preconditions were not met")
continue
} else if r.Status != response.RuleStatusPass {
msg := fmt.Sprintf("validation failed in foreach rule for %v", r.Message)
return ruleResponse(v.rule, utils.Validation, msg, r.Status)
}
applyCount++
foreach := newForeachValidator(v.log, ctx, v.rule, foreachIndex)
r := foreach.validate()
if r == nil {
v.log.Info("skipping rule due to empty result")
continue
} else if r.Status == response.RuleStatusSkip {
v.log.Info("skipping rule as preconditions were not met")
continue
} else if r.Status != response.RuleStatusPass {
msg := fmt.Sprintf("validation failed in foreach rule for %v", r.Message)
return ruleResponse(v.rule, utils.Validation, msg, r.Status)
}
applyCount++
}
}

View file

@ -2934,6 +2934,61 @@ func Test_outof_foreach_element_validation(t *testing.T) {
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusError)
}
func Test_foreach_skip_initContainer_pass(t *testing.T) {
resourceRaw := []byte(`{"apiVersion": "v1",
"kind": "Deployment",
"metadata": {"name": "test"},
"spec": { "template": { "spec": {
"containers": [
{"name": "podvalid", "image": "nginx"}
]
}}}}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-images"
},
"spec": {
"validationFailureAction": "enforce",
"background": false,
"rules": [
{
"name": "check-registry",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"message": "unknown registry",
"foreach": [
{
"list": "request.object.spec.template.spec.containers",
"pattern": {
"image": "nginx"
}
},
{
"list": "request.object.spec.template.spec..initContainers",
"pattern": {
"image": "trusted-registry.io/*"
}
}
]
}
}
]
}
}`)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusPass)
}
func testForEach(t *testing.T, policyraw []byte, resourceRaw []byte, msg string, status response.RuleStatus) {
var policy kyverno.ClusterPolicy
assert.NilError(t, json.Unmarshal(policyraw, &policy))