2020-03-11 18:14:23 -07:00
|
|
|
package validate
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2021-10-02 16:53:02 -07:00
|
|
|
"strings"
|
2020-03-11 18:14:23 -07:00
|
|
|
|
2021-10-29 18:13:20 +02:00
|
|
|
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
|
2020-10-07 11:12:31 -07:00
|
|
|
commonAnchors "github.com/kyverno/kyverno/pkg/engine/anchor/common"
|
|
|
|
"github.com/kyverno/kyverno/pkg/policy/common"
|
2020-03-11 18:14:23 -07:00
|
|
|
)
|
|
|
|
|
2021-10-02 16:53:02 -07:00
|
|
|
// Validate validates a 'validate' rule
|
2020-03-11 18:14:23 -07:00
|
|
|
type Validate struct {
|
|
|
|
// rule to hold 'validate' rule specifications
|
2021-10-02 16:53:02 -07:00
|
|
|
rule *kyverno.Validation
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//NewValidateFactory returns a new instance of Mutate validation checker
|
2021-10-02 16:53:02 -07:00
|
|
|
func NewValidateFactory(rule *kyverno.Validation) *Validate {
|
2020-03-11 18:14:23 -07:00
|
|
|
m := Validate{
|
|
|
|
rule: rule,
|
|
|
|
}
|
2021-10-02 16:53:02 -07:00
|
|
|
|
2020-03-11 18:14:23 -07:00
|
|
|
return &m
|
|
|
|
}
|
|
|
|
|
|
|
|
//Validate validates the 'validate' rule
|
|
|
|
func (v *Validate) Validate() (string, error) {
|
2021-10-02 16:53:02 -07:00
|
|
|
if err := v.validateElements(); err != nil {
|
2020-03-11 18:14:23 -07:00
|
|
|
// no need to proceed ahead
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2021-10-02 16:53:02 -07:00
|
|
|
if v.rule.Pattern != nil {
|
|
|
|
if path, err := common.ValidatePattern(v.rule.Pattern, "/", []commonAnchors.IsAnchor{commonAnchors.IsConditionAnchor, commonAnchors.IsExistenceAnchor, commonAnchors.IsEqualityAnchor, commonAnchors.IsNegationAnchor, commonAnchors.IsGlobalAnchor}); err != nil {
|
2020-03-11 18:14:23 -07:00
|
|
|
return fmt.Sprintf("pattern.%s", path), err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-02 16:53:02 -07:00
|
|
|
if v.rule.AnyPattern != nil {
|
|
|
|
anyPattern, err := v.rule.DeserializeAnyPattern()
|
2020-11-13 16:25:51 -08:00
|
|
|
if err != nil {
|
2021-02-19 09:09:41 -08:00
|
|
|
return "anyPattern", fmt.Errorf("failed to deserialize anyPattern, expect array: %v", err)
|
2020-11-13 16:25:51 -08:00
|
|
|
}
|
|
|
|
for i, pattern := range anyPattern {
|
2021-09-13 18:59:28 +03:00
|
|
|
if path, err := common.ValidatePattern(pattern, "/", []commonAnchors.IsAnchor{commonAnchors.IsConditionAnchor, commonAnchors.IsExistenceAnchor, commonAnchors.IsEqualityAnchor, commonAnchors.IsNegationAnchor, commonAnchors.IsGlobalAnchor}); err != nil {
|
2020-03-11 18:14:23 -07:00
|
|
|
return fmt.Sprintf("anyPattern[%d].%s", i, path), err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-02 16:53:02 -07:00
|
|
|
|
|
|
|
if v.rule.ForEachValidation != nil {
|
2021-10-14 12:50:52 +05:30
|
|
|
for _, foreach := range v.rule.ForEachValidation {
|
|
|
|
if err := v.validateForEach(foreach); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2021-10-02 16:53:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-11 18:14:23 -07:00
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
2021-10-02 16:53:02 -07:00
|
|
|
func (v *Validate) validateElements() error {
|
|
|
|
count := validationElemCount(v.rule)
|
2021-10-02 16:57:40 -07:00
|
|
|
if count == 0 {
|
2021-10-02 16:53:02 -07:00
|
|
|
return fmt.Errorf("one of pattern, anyPattern, deny, foreach must be specified")
|
|
|
|
}
|
|
|
|
|
|
|
|
if count > 1 {
|
|
|
|
return fmt.Errorf("only one of pattern, anyPattern, deny, foreach can be specified")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func validationElemCount(v *kyverno.Validation) int {
|
|
|
|
if v == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
count := 0
|
|
|
|
if v.Pattern != nil {
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
|
|
|
|
if v.AnyPattern != nil {
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
|
|
|
|
if v.Deny != nil {
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
|
|
|
|
if v.ForEachValidation != nil {
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
|
|
|
|
return count
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Validate) validateForEach(foreach *kyverno.ForEachValidation) error {
|
|
|
|
if foreach.List == "" {
|
|
|
|
return fmt.Errorf("foreach.list is required")
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
|
|
|
|
2021-10-02 16:53:02 -07:00
|
|
|
if !strings.HasPrefix(foreach.List, "request.object") {
|
2021-10-12 23:29:20 +02:00
|
|
|
return fmt.Errorf("foreach.list must start with 'request.object' e.g. 'request.object.spec.containers'")
|
2021-10-02 16:53:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
count := foreachElemCount(foreach)
|
2021-10-02 16:57:40 -07:00
|
|
|
if count == 0 {
|
2021-10-02 16:53:02 -07:00
|
|
|
return fmt.Errorf("one of pattern, anyPattern, deny must be specified")
|
|
|
|
}
|
|
|
|
|
|
|
|
if count > 1 {
|
|
|
|
return fmt.Errorf("only one of pattern, anyPattern, deny can be specified")
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2021-10-02 16:53:02 -07:00
|
|
|
|
|
|
|
func foreachElemCount(foreach *kyverno.ForEachValidation) int {
|
|
|
|
if foreach == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
count := 0
|
|
|
|
if foreach.Pattern != nil {
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
|
|
|
|
if foreach.AnyPattern != nil {
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
|
|
|
|
if foreach.Deny != nil {
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
|
|
|
|
return count
|
|
|
|
}
|