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:
parent
5df903e34e
commit
c4c29bc6ad
2 changed files with 85 additions and 38 deletions
|
@ -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++
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in a new issue