1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-05 07:26:55 +00:00

add messages and set rule to skip when pattern does not match

Signed-off-by: Jim Bugwadia <jim@nirmata.com>
This commit is contained in:
Jim Bugwadia 2021-09-30 23:34:04 -07:00
parent 6ae3063038
commit 1ebd2c99f2
3 changed files with 44 additions and 24 deletions

View file

@ -335,7 +335,7 @@ func checkCondition(logger logr.Logger, pattern *yaml.RNode, resource *yaml.RNod
return err return err
} }
err, _ = validate.MatchPattern(logger, resourceInterface, patternInterface) err = validate.MatchPattern(logger, resourceInterface, patternInterface)
if err != nil { if err != nil {
return err return err
} }

View file

@ -12,9 +12,24 @@ import (
"github.com/kyverno/kyverno/pkg/engine/wildcards" "github.com/kyverno/kyverno/pkg/engine/wildcards"
) )
type PatternError struct {
Err error
Path string
Skip bool
}
func (e *PatternError) Error() string {
if e.Err == nil {
return ""
}
return e.Err.Error()
}
// MatchPattern is a start of element-by-element pattern validation process. // MatchPattern is a start of element-by-element pattern validation process.
// It assumes that validation is started from root, so "/" is passed // It assumes that validation is started from root, so "/" is passed
func MatchPattern(logger logr.Logger, resource, pattern interface{}) (error, string) { func MatchPattern(logger logr.Logger, resource, pattern interface{}) error {
// newAnchorMap - to check anchor key has values // newAnchorMap - to check anchor key has values
ac := common.NewAnchorMap() ac := common.NewAnchorMap()
elemPath, err := validateResourceElement(logger, resource, pattern, pattern, "/", ac) elemPath, err := validateResourceElement(logger, resource, pattern, pattern, "/", ac)
@ -22,19 +37,19 @@ func MatchPattern(logger logr.Logger, resource, pattern interface{}) (error, str
// if conditional or global anchors report errors, the rule does not apply to the resource // if conditional or global anchors report errors, the rule does not apply to the resource
if common.IsConditionalAnchorError(err.Error()) || common.IsGlobalAnchorError(err.Error()) { if common.IsConditionalAnchorError(err.Error()) || common.IsGlobalAnchorError(err.Error()) {
logger.V(3).Info("skipping resource as anchor does not apply", "msg", ac.AnchorError.Error()) logger.V(3).Info("skipping resource as anchor does not apply", "msg", ac.AnchorError.Error())
return nil, "" return &PatternError{nil, "", true}
} }
// check if an anchor defined in the policy rule is missing in the resource // check if an anchor defined in the policy rule is missing in the resource
if ac.IsAnchorError() { if ac.IsAnchorError() {
logger.V(3).Info("missing anchor in resource") logger.V(3).Info("missing anchor in resource")
return err, "" return &PatternError{err, "", false}
} }
return err, elemPath return &PatternError{err, elemPath, false}
} }
return nil, "" return &PatternError{nil, "", false}
} }
// validateResourceElement detects the element type (map, array, nil, string, int, bool, float) // validateResourceElement detects the element type (map, array, nil, string, int, bool, float)

View file

@ -193,7 +193,7 @@ func (v *validator) validate() *response.RuleResponse {
if err != nil { if err != nil {
return ruleError(v.rule, "failed to evaluate preconditions", err) return ruleError(v.rule, "failed to evaluate preconditions", err)
} else if !preconditionsPassed { } else if !preconditionsPassed {
return ruleResponse(v.rule, "", response.RuleStatusSkip) return ruleResponse(v.rule, "preconditions not met", response.RuleStatusSkip)
} }
if v.pattern != nil || v.anyPattern != nil { if v.pattern != nil || v.anyPattern != nil {
@ -222,7 +222,7 @@ func (v *validator) validateForEach() *response.RuleResponse {
if err != nil { if err != nil {
return ruleError(v.rule, "failed to evaluate preconditions", err) return ruleError(v.rule, "failed to evaluate preconditions", err)
} else if !preconditionsPassed { } else if !preconditionsPassed {
return ruleResponse(v.rule, "", response.RuleStatusSkip) return ruleResponse(v.rule, "preconditions not met", response.RuleStatusSkip)
} }
foreach := v.rule.Validation.ForEachValidation foreach := v.rule.Validation.ForEachValidation
@ -266,10 +266,10 @@ func (v *validator) validateForEach() *response.RuleResponse {
} }
if applyCount == 0 { if applyCount == 0 {
return ruleResponse(v.rule, "", response.RuleStatusSkip) return ruleResponse(v.rule, "rule skipped", response.RuleStatusSkip)
} }
return ruleResponse(v.rule, "", response.RuleStatusPass) return ruleResponse(v.rule, "rule passed", response.RuleStatusPass)
} }
func addElementToContext(ctx *PolicyContext, e interface{}) error { func addElementToContext(ctx *PolicyContext, e interface{}) error {
@ -436,13 +436,16 @@ func isSameRuleResponse(r1 *response.RuleResponse, r2 *response.RuleResponse) bo
// validatePatterns validate pattern and anyPattern // validatePatterns validate pattern and anyPattern
func (v *validator) validatePatterns(resource unstructured.Unstructured) *response.RuleResponse { func (v *validator) validatePatterns(resource unstructured.Unstructured) *response.RuleResponse {
if v.pattern != nil { if v.pattern != nil {
if err, path := validate.MatchPattern(v.log, resource.Object, v.pattern); err != nil { if err := validate.MatchPattern(v.log, resource.Object, v.pattern); err != nil {
v.log.V(3).Info("validation error", "path", path, "error", err.Error())
if path == "" {
return ruleResponse(v.rule, v.buildErrorMessage(err, ""), response.RuleStatusError)
}
return ruleResponse(v.rule, v.buildErrorMessage(err, path), response.RuleStatusFail) if pe, ok := err.(*validate.PatternError); ok{
v.log.V(3).Info("validation error", "path", pe.Path, "error", err.Error())
if pe.Path == "" {
return ruleResponse(v.rule, v.buildErrorMessage(err, ""), response.RuleStatusError)
}
return ruleResponse(v.rule, v.buildErrorMessage(err, pe.Path), response.RuleStatusFail)
}
} }
v.log.V(4).Info("successfully processed rule") v.log.V(4).Info("successfully processed rule")
@ -461,19 +464,21 @@ func (v *validator) validatePatterns(resource unstructured.Unstructured) *respon
} }
for idx, pattern := range anyPatterns { for idx, pattern := range anyPatterns {
err, path := validate.MatchPattern(v.log, resource.Object, pattern) err := validate.MatchPattern(v.log, resource.Object, pattern)
if err == nil { if err == nil {
msg := fmt.Sprintf("validation rule '%s' anyPattern[%d] passed.", v.rule.Name, idx) msg := fmt.Sprintf("validation rule '%s' anyPattern[%d] passed.", v.rule.Name, idx)
return ruleResponse(v.rule, msg, response.RuleStatusPass) return ruleResponse(v.rule, msg, response.RuleStatusPass)
} }
v.log.V(3).Info("validation rule failed", "anyPattern[%d]", idx, "path", path) if pe, ok := err.(*validate.PatternError); ok {
if path == "" { v.log.V(3).Info("validation rule failed", "anyPattern[%d]", idx, "path", pe.Path)
patternErr := fmt.Errorf("Rule %s[%d] failed: %s.", v.rule.Name, idx, err.Error()) if pe.Path == "" {
failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr) patternErr := fmt.Errorf("Rule %s[%d] failed: %s.", v.rule.Name, idx, err.Error())
} else { failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr)
patternErr := fmt.Errorf("Rule %s[%d] failed at path %s.", v.rule.Name, idx, path) } else {
failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr) patternErr := fmt.Errorf("Rule %s[%d] failed at path %s.", v.rule.Name, idx, pe.Path)
failedAnyPatternsErrors = append(failedAnyPatternsErrors, patternErr)
}
} }
} }