mirror of
https://github.com/kyverno/kyverno.git
synced 2025-04-08 10:04:25 +00:00
resolved conditional anchor issue and added validation to pattern labels (#1060)
* resolved conditional anchor issue and added validation to pattern labels * restored IsConditionAnchor * added annotation and anypattern validation * added conditional anchor key checker * reverted docs * fixed tests * modified validation * modified validate condition check
This commit is contained in:
parent
b067f41d02
commit
a827f88dc7
17 changed files with 297 additions and 92 deletions
documentation
pkg
engine
anchor
common
mutate
utils
validate
policy
|
@ -121,10 +121,10 @@ For conditional anchors, the child element is considered to be part of the "if"
|
|||
pattern:
|
||||
metadata:
|
||||
labels:
|
||||
allow-docker: true
|
||||
allow-docker: "true"
|
||||
spec:
|
||||
(volumes):
|
||||
(hostPath):
|
||||
- (hostPath):
|
||||
path: "/var/run/docker.sock"
|
||||
````
|
||||
|
||||
|
|
|
@ -5,26 +5,28 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
"github.com/nirmata/kyverno/pkg/engine/common"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
//ValidationHandler for element processes
|
||||
type ValidationHandler interface {
|
||||
Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error)
|
||||
Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error)
|
||||
}
|
||||
|
||||
type resourceElementHandler = func(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string) (string, error)
|
||||
type resourceElementHandler = func(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string, ac *common.AnchorKey) (string, error)
|
||||
|
||||
//CreateElementHandler factory to process elements
|
||||
func CreateElementHandler(element string, pattern interface{}, path string) ValidationHandler {
|
||||
switch {
|
||||
case IsConditionAnchor(element):
|
||||
case commonAnchors.IsConditionAnchor(element):
|
||||
return NewConditionAnchorHandler(element, pattern, path)
|
||||
case IsExistenceAnchor(element):
|
||||
case commonAnchors.IsExistenceAnchor(element):
|
||||
return NewExistenceHandler(element, pattern, path)
|
||||
case IsEqualityAnchor(element):
|
||||
case commonAnchors.IsEqualityAnchor(element):
|
||||
return NewEqualityHandler(element, pattern, path)
|
||||
case IsNegationAnchor(element):
|
||||
case commonAnchors.IsNegationAnchor(element):
|
||||
return NewNegationHandler(element, pattern, path)
|
||||
default:
|
||||
return NewDefaultHandler(element, pattern, path)
|
||||
|
@ -48,8 +50,8 @@ type NegationHandler struct {
|
|||
}
|
||||
|
||||
//Handle process negation handler
|
||||
func (nh NegationHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
||||
anchorKey := removeAnchor(nh.anchor)
|
||||
func (nh NegationHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) {
|
||||
anchorKey := commonAnchors.RemoveAnchor(nh.anchor)
|
||||
currentPath := nh.path + anchorKey + "/"
|
||||
// if anchor is present in the resource then fail
|
||||
if _, ok := resourceMap[anchorKey]; ok {
|
||||
|
@ -77,13 +79,13 @@ type EqualityHandler struct {
|
|||
}
|
||||
|
||||
//Handle processed condition anchor
|
||||
func (eh EqualityHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
||||
anchorKey := removeAnchor(eh.anchor)
|
||||
func (eh EqualityHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) {
|
||||
anchorKey := commonAnchors.RemoveAnchor(eh.anchor)
|
||||
currentPath := eh.path + anchorKey + "/"
|
||||
// check if anchor is present in resource
|
||||
if value, ok := resourceMap[anchorKey]; ok {
|
||||
// validate the values of the pattern
|
||||
returnPath, err := handler(log.Log, value, eh.pattern, originPattern, currentPath)
|
||||
returnPath, err := handler(log.Log, value, eh.pattern, originPattern, currentPath, ac)
|
||||
if err != nil {
|
||||
return returnPath, err
|
||||
}
|
||||
|
@ -109,14 +111,14 @@ type DefaultHandler struct {
|
|||
}
|
||||
|
||||
//Handle process non anchor element
|
||||
func (dh DefaultHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
||||
func (dh DefaultHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) {
|
||||
currentPath := dh.path + dh.element + "/"
|
||||
if dh.pattern == "*" && resourceMap[dh.element] != nil {
|
||||
return "", nil
|
||||
} else if dh.pattern == "*" && resourceMap[dh.element] == nil {
|
||||
return dh.path, fmt.Errorf("Validation rule failed at %s, Field %s is not present", dh.path, dh.element)
|
||||
} else {
|
||||
path, err := handler(log.Log, resourceMap[dh.element], dh.pattern, originPattern, currentPath)
|
||||
path, err := handler(log.Log, resourceMap[dh.element], dh.pattern, originPattern, currentPath, ac)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
@ -141,13 +143,13 @@ type ConditionAnchorHandler struct {
|
|||
}
|
||||
|
||||
//Handle processed condition anchor
|
||||
func (ch ConditionAnchorHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
||||
anchorKey := removeAnchor(ch.anchor)
|
||||
func (ch ConditionAnchorHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) {
|
||||
anchorKey := commonAnchors.RemoveAnchor(ch.anchor)
|
||||
currentPath := ch.path + anchorKey + "/"
|
||||
// check if anchor is present in resource
|
||||
if value, ok := resourceMap[anchorKey]; ok {
|
||||
// validate the values of the pattern
|
||||
returnPath, err := handler(log.Log, value, ch.pattern, originPattern, currentPath)
|
||||
returnPath, err := handler(log.Log, value, ch.pattern, originPattern, currentPath, ac)
|
||||
if err != nil {
|
||||
return returnPath, err
|
||||
}
|
||||
|
@ -174,9 +176,9 @@ type ExistenceHandler struct {
|
|||
}
|
||||
|
||||
//Handle processes the existence anchor handler
|
||||
func (eh ExistenceHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
|
||||
func (eh ExistenceHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) {
|
||||
// skip is used by existence anchor to not process further if condition is not satisfied
|
||||
anchorKey := removeAnchor(eh.anchor)
|
||||
anchorKey := commonAnchors.RemoveAnchor(eh.anchor)
|
||||
currentPath := eh.path + anchorKey + "/"
|
||||
// check if anchor is present in resource
|
||||
if value, ok := resourceMap[anchorKey]; ok {
|
||||
|
@ -193,7 +195,7 @@ func (eh ExistenceHandler) Handle(handler resourceElementHandler, resourceMap ma
|
|||
if !ok {
|
||||
return currentPath, fmt.Errorf("Invalid pattern type %T: Pattern has to be of type map to compare against items in resource", eh.pattern)
|
||||
}
|
||||
return validateExistenceListResource(handler, typedResource, typedPatternMap, originPattern, currentPath)
|
||||
return validateExistenceListResource(handler, typedResource, typedPatternMap, originPattern, currentPath, ac)
|
||||
default:
|
||||
return currentPath, fmt.Errorf("Invalid resource type %T: Existence ^ () anchor can be used only on list/array type resource", value)
|
||||
}
|
||||
|
@ -201,12 +203,12 @@ func (eh ExistenceHandler) Handle(handler resourceElementHandler, resourceMap ma
|
|||
return "", nil
|
||||
}
|
||||
|
||||
func validateExistenceListResource(handler resourceElementHandler, resourceList []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string) (string, error) {
|
||||
func validateExistenceListResource(handler resourceElementHandler, resourceList []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string, ac *common.AnchorKey) (string, error) {
|
||||
// the idea is atleast on the elements in the array should satisfy the pattern
|
||||
// if non satisfy then throw an error
|
||||
for i, resourceElement := range resourceList {
|
||||
currentPath := path + strconv.Itoa(i) + "/"
|
||||
_, err := handler(log.Log, resourceElement, patternMap, originPattern, currentPath)
|
||||
_, err := handler(log.Log, resourceElement, patternMap, originPattern, currentPath, ac)
|
||||
if err == nil {
|
||||
// condition is satisfied, dont check further
|
||||
return "", nil
|
||||
|
@ -221,7 +223,7 @@ func GetAnchorsResourcesFromMap(patternMap map[string]interface{}) (map[string]i
|
|||
anchors := map[string]interface{}{}
|
||||
resources := map[string]interface{}{}
|
||||
for key, value := range patternMap {
|
||||
if IsConditionAnchor(key) || IsExistenceAnchor(key) || IsEqualityAnchor(key) || IsNegationAnchor(key) {
|
||||
if commonAnchors.IsConditionAnchor(key) || commonAnchors.IsExistenceAnchor(key) || commonAnchors.IsEqualityAnchor(key) || commonAnchors.IsNegationAnchor(key) {
|
||||
anchors[key] = value
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package anchor
|
||||
package common
|
||||
|
||||
// IsAnchor is a function handler
|
||||
type IsAnchor func(str string) bool
|
||||
|
@ -58,7 +58,7 @@ func IsExistenceAnchor(str string) bool {
|
|||
return (str[:len(left)] == left && str[len(str)-len(right):] == right)
|
||||
}
|
||||
|
||||
func removeAnchor(key string) string {
|
||||
func RemoveAnchor(key string) string {
|
||||
if IsConditionAnchor(key) {
|
||||
return key[1 : len(key)-1]
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package anchor
|
||||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
73
pkg/engine/common/anchorKey.go
Normal file
73
pkg/engine/common/anchorKey.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
)
|
||||
|
||||
// AnchorKey - contains map of anchors
|
||||
type AnchorKey struct {
|
||||
// anchorMap - for each anchor key in the patterns it will maintains information if the key exists in the resource
|
||||
// if anchor key of the pattern exists in the resource then (key)=true else (key)=false
|
||||
anchorMap map[string]bool
|
||||
// AnchorError - used in validate to break execution of the recursion when if condition fails
|
||||
AnchorError error
|
||||
}
|
||||
|
||||
// NewAnchorMap -initialize anchorMap
|
||||
func NewAnchorMap() *AnchorKey {
|
||||
return &AnchorKey{anchorMap: make(map[string]bool)}
|
||||
}
|
||||
|
||||
// IsAnchorError - if any of the anchor key doesn't exists in the resource then it will return true
|
||||
// if any of (key)=false then return IsAnchorError() as true
|
||||
// if all the keys exists in the pattern exists in resource then return IsAnchorError() as false
|
||||
func (ac *AnchorKey) IsAnchorError() bool {
|
||||
for _, v := range ac.anchorMap {
|
||||
if v == false {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CheckAnchorInResource
|
||||
// Check if condition anchor key has values
|
||||
func (ac *AnchorKey) CheckAnchorInResource(pattern interface{}, resource interface{}) {
|
||||
switch typed := pattern.(type) {
|
||||
case map[string]interface{}:
|
||||
for key := range typed {
|
||||
if common.IsConditionAnchor(key) || common.IsExistenceAnchor(key) || common.IsNegationAnchor(key) {
|
||||
val, ok := ac.anchorMap[key]
|
||||
if !ok {
|
||||
ac.anchorMap[key] = false
|
||||
} else if ok && val == true {
|
||||
continue
|
||||
}
|
||||
if doesAnchorsKeyHasValue(key, resource) {
|
||||
ac.anchorMap[key] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if anchor key has value in resource
|
||||
func doesAnchorsKeyHasValue(key string, resource interface{}) bool {
|
||||
akey := common.RemoveAnchor(key)
|
||||
switch typed := resource.(type) {
|
||||
case map[string]interface{}:
|
||||
if _, ok := typed[akey]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
case []interface{}:
|
||||
for _, value := range typed {
|
||||
if doesAnchorsKeyHasValue(key, value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ import (
|
|||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
"github.com/nirmata/kyverno/pkg/engine/response"
|
||||
"github.com/nirmata/kyverno/pkg/engine/utils"
|
||||
)
|
||||
|
@ -192,7 +192,7 @@ func applyOverlayToMap(resourceMap, overlayMap map[string]interface{}, path stri
|
|||
for key, value := range overlayMap {
|
||||
// skip anchor element because it has condition, not
|
||||
// the value that must replace resource value
|
||||
if anchor.IsConditionAnchor(key) {
|
||||
if commonAnchors.IsConditionAnchor(key) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ func applyOverlayToMap(resourceMap, overlayMap map[string]interface{}, path stri
|
|||
currentPath := path + noAnchorKey + "/"
|
||||
resourcePart, ok := resourceMap[noAnchorKey]
|
||||
|
||||
if ok && !anchor.IsAddingAnchor(key) {
|
||||
if ok && !commonAnchors.IsAddingAnchor(key) {
|
||||
// Key exists - go down through the overlay and resource trees
|
||||
patches, err := applyOverlay(resourcePart, value, currentPath)
|
||||
if err != nil {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
"github.com/nirmata/kyverno/pkg/engine/validate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
@ -85,7 +85,7 @@ func checkConditionOnArray(resource, overlay []interface{}, path string) (string
|
|||
func validateConditionAnchorMap(resourceMap, anchors map[string]interface{}, path string) (string, overlayError) {
|
||||
for key, overlayValue := range anchors {
|
||||
// skip if key does not have condition anchor
|
||||
if !anchor.IsConditionAnchor(key) {
|
||||
if !commonAnchors.IsConditionAnchor(key) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package mutate
|
|||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
)
|
||||
|
||||
type buffer struct {
|
||||
|
@ -22,11 +22,11 @@ func (buff buffer) MarshalJSON() ([]byte, error) {
|
|||
|
||||
// removeAnchor remove special characters around anchored key
|
||||
func removeAnchor(key string) string {
|
||||
if anchor.IsConditionAnchor(key) {
|
||||
if commonAnchors.IsConditionAnchor(key) {
|
||||
return key[1 : len(key)-1]
|
||||
}
|
||||
|
||||
if anchor.IsExistenceAnchor(key) || anchor.IsAddingAnchor(key) || anchor.IsEqualityAnchor(key) || anchor.IsNegationAnchor(key) {
|
||||
if commonAnchors.IsExistenceAnchor(key) || commonAnchors.IsAddingAnchor(key) || commonAnchors.IsEqualityAnchor(key) || commonAnchors.IsNegationAnchor(key) {
|
||||
return key[2 : len(key)-1]
|
||||
}
|
||||
|
||||
|
@ -52,9 +52,9 @@ func getAnchorAndElementsFromMap(anchorsMap map[string]interface{}) (map[string]
|
|||
anchors := make(map[string]interface{})
|
||||
elementsWithoutanchor := make(map[string]interface{})
|
||||
for key, value := range anchorsMap {
|
||||
if anchor.IsConditionAnchor(key) {
|
||||
if commonAnchors.IsConditionAnchor(key) {
|
||||
anchors[key] = value
|
||||
} else if !anchor.IsAddingAnchor(key) {
|
||||
} else if !commonAnchors.IsAddingAnchor(key) {
|
||||
elementsWithoutanchor[key] = value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
commonAnchor "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
@ -115,7 +115,7 @@ func GetAnchorsFromMap(anchorsMap map[string]interface{}) map[string]interface{}
|
|||
result := make(map[string]interface{})
|
||||
|
||||
for key, value := range anchorsMap {
|
||||
if anchor.IsConditionAnchor(key) {
|
||||
if commonAnchor.IsConditionAnchor(key) {
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
|
|
54
pkg/engine/validate/utils.go
Normal file
54
pkg/engine/validate/utils.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package validate
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
)
|
||||
|
||||
// Checks if pattern has anchors
|
||||
func hasNestedAnchors(pattern interface{}) bool {
|
||||
switch typed := pattern.(type) {
|
||||
case map[string]interface{}:
|
||||
if anchors := getAnchorsFromMap(typed); len(anchors) > 0 {
|
||||
return true
|
||||
}
|
||||
for _, value := range typed {
|
||||
if hasNestedAnchors(value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case []interface{}:
|
||||
for _, value := range typed {
|
||||
if hasNestedAnchors(value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// getSortedNestedAnchorResource - sorts anchors key
|
||||
func getSortedNestedAnchorResource(resources map[string]interface{}) *list.List {
|
||||
sortedResourceKeys := list.New()
|
||||
for k, v := range resources {
|
||||
if hasNestedAnchors(v) {
|
||||
sortedResourceKeys.PushFront(k)
|
||||
}
|
||||
sortedResourceKeys.PushBack(k)
|
||||
}
|
||||
return sortedResourceKeys
|
||||
}
|
||||
|
||||
// getAnchorsFromMap gets the anchor map
|
||||
func getAnchorsFromMap(anchorsMap map[string]interface{}) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for key, value := range anchorsMap {
|
||||
if commonAnchors.IsConditionAnchor(key) || commonAnchors.IsExistenceAnchor(key) || commonAnchors.IsEqualityAnchor(key) || commonAnchors.IsNegationAnchor(key) {
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
|
@ -10,15 +10,21 @@ import (
|
|||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
"github.com/nirmata/kyverno/pkg/engine/common"
|
||||
"github.com/nirmata/kyverno/pkg/engine/operator"
|
||||
)
|
||||
|
||||
// ValidateResourceWithPattern is a start of element-by-element validation process
|
||||
// It assumes that validation is started from root, so "/" is passed
|
||||
func ValidateResourceWithPattern(log logr.Logger, resource, pattern interface{}) (string, error) {
|
||||
path, err := validateResourceElement(log, resource, pattern, pattern, "/")
|
||||
// newAnchorMap - to check anchor key has values
|
||||
ac := common.NewAnchorMap()
|
||||
path, err := validateResourceElement(log, resource, pattern, pattern, "/", ac)
|
||||
if err != nil {
|
||||
return path, err
|
||||
if !ac.IsAnchorError() {
|
||||
return path, err
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
|
@ -27,7 +33,7 @@ func ValidateResourceWithPattern(log logr.Logger, resource, pattern interface{})
|
|||
// validateResourceElement detects the element type (map, array, nil, string, int, bool, float)
|
||||
// and calls corresponding handler
|
||||
// Pattern tree and resource tree can have different structure. In this case validation fails
|
||||
func validateResourceElement(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string) (string, error) {
|
||||
func validateResourceElement(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string, ac *common.AnchorKey) (string, error) {
|
||||
var err error
|
||||
switch typedPatternElement := patternElement.(type) {
|
||||
// map
|
||||
|
@ -37,8 +43,9 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
|
|||
log.V(4).Info("Pattern and resource have different structures.", "path", path, "expected", fmt.Sprintf("%T", patternElement), "current", fmt.Sprintf("%T", resourceElement))
|
||||
return path, fmt.Errorf("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, patternElement, resourceElement)
|
||||
}
|
||||
|
||||
return validateMap(log, typedResourceElement, typedPatternElement, originPattern, path)
|
||||
// CheckAnchorInResource - check anchor anchor key exists in resource and update the AnchorKey fields.
|
||||
ac.CheckAnchorInResource(typedPatternElement, typedResourceElement)
|
||||
return validateMap(log, typedResourceElement, typedPatternElement, originPattern, path, ac)
|
||||
// array
|
||||
case []interface{}:
|
||||
typedResourceElement, ok := resourceElement.([]interface{})
|
||||
|
@ -46,8 +53,7 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
|
|||
log.V(4).Info("Pattern and resource have different structures.", "path", path, "expected", fmt.Sprintf("%T", patternElement), "current", fmt.Sprintf("%T", resourceElement))
|
||||
return path, fmt.Errorf("Validation rule Failed at path %s, resource does not satisfy the expected overlay pattern", path)
|
||||
}
|
||||
|
||||
return validateArray(log, typedResourceElement, typedPatternElement, originPattern, path)
|
||||
return validateArray(log, typedResourceElement, typedPatternElement, originPattern, path, ac)
|
||||
// elementary values
|
||||
case string, float64, int, int64, bool, nil:
|
||||
/*Analyze pattern */
|
||||
|
@ -72,7 +78,7 @@ func validateResourceElement(log logr.Logger, resourceElement, patternElement, o
|
|||
|
||||
// If validateResourceElement detects map element inside resource and pattern trees, it goes to validateMap
|
||||
// For each element of the map we must detect the type again, so we pass these elements to validateResourceElement
|
||||
func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string) (string, error) {
|
||||
func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}, origPattern interface{}, path string, ac *common.AnchorKey) (string, error) {
|
||||
// check if there is anchor in pattern
|
||||
// Phase 1 : Evaluate all the anchors
|
||||
// Phase 2 : Evaluate non-anchors
|
||||
|
@ -85,23 +91,31 @@ func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}
|
|||
// - Existence
|
||||
// - Equality
|
||||
handler := anchor.CreateElementHandler(key, patternElement, path)
|
||||
handlerPath, err := handler.Handle(validateResourceElement, resourceMap, origPattern)
|
||||
handlerPath, err := handler.Handle(validateResourceElement, resourceMap, origPattern, ac)
|
||||
// if there are resource values at same level, then anchor acts as conditional instead of a strict check
|
||||
// but if there are non then its a if then check
|
||||
if err != nil {
|
||||
// If Conditional anchor fails then we dont process the resources
|
||||
if anchor.IsConditionAnchor(key) {
|
||||
// If Conditional anchor fails then we don't process the resources
|
||||
if commonAnchors.IsConditionAnchor(key) {
|
||||
ac.AnchorError = err
|
||||
log.Error(err, "condition anchor did not satisfy, wont process the resource")
|
||||
return "", nil
|
||||
}
|
||||
return handlerPath, err
|
||||
}
|
||||
}
|
||||
// If anchor fails then succeed validate and skip further validation of recursion
|
||||
if ac.AnchorError != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Evaluate resources
|
||||
for key, resourceElement := range resources {
|
||||
// get handler for resources in the pattern
|
||||
handler := anchor.CreateElementHandler(key, resourceElement, path)
|
||||
handlerPath, err := handler.Handle(validateResourceElement, resourceMap, origPattern)
|
||||
// getSortedNestedAnchorResource - keeps the anchor key to start of the list
|
||||
sortedResourceKeys := getSortedNestedAnchorResource(resources)
|
||||
for e := sortedResourceKeys.Front(); e != nil; e = e.Next() {
|
||||
key := e.Value.(string)
|
||||
handler := anchor.CreateElementHandler(key, resources[key], path)
|
||||
handlerPath, err := handler.Handle(validateResourceElement, resourceMap, origPattern, ac)
|
||||
if err != nil {
|
||||
return handlerPath, err
|
||||
}
|
||||
|
@ -109,7 +123,7 @@ func validateMap(log logr.Logger, resourceMap, patternMap map[string]interface{}
|
|||
return "", nil
|
||||
}
|
||||
|
||||
func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, originPattern interface{}, path string) (string, error) {
|
||||
func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, originPattern interface{}, path string, ac *common.AnchorKey) (string, error) {
|
||||
|
||||
if 0 == len(patternArray) {
|
||||
return path, fmt.Errorf("Pattern Array empty")
|
||||
|
@ -119,7 +133,7 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
|
|||
case map[string]interface{}:
|
||||
// This is special case, because maps in arrays can have anchors that must be
|
||||
// processed with the special way affecting the entire array
|
||||
path, err := validateArrayOfMaps(log, resourceArray, typedPatternElement, originPattern, path)
|
||||
path, err := validateArrayOfMaps(log, resourceArray, typedPatternElement, originPattern, path, ac)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
@ -128,7 +142,7 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
|
|||
if len(resourceArray) >= len(patternArray) {
|
||||
for i, patternElement := range patternArray {
|
||||
currentPath := path + strconv.Itoa(i) + "/"
|
||||
path, err := validateResourceElement(log, resourceArray[i], patternElement, originPattern, currentPath)
|
||||
path, err := validateResourceElement(log, resourceArray[i], patternElement, originPattern, currentPath, ac)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
@ -256,12 +270,12 @@ func getValueFromPattern(log logr.Logger, patternMap map[string]interface{}, key
|
|||
|
||||
// validateArrayOfMaps gets anchors from pattern array map element, applies anchors logic
|
||||
// and then validates each map due to the pattern
|
||||
func validateArrayOfMaps(log logr.Logger, resourceMapArray []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string) (string, error) {
|
||||
func validateArrayOfMaps(log logr.Logger, resourceMapArray []interface{}, patternMap map[string]interface{}, originPattern interface{}, path string, ac *common.AnchorKey) (string, error) {
|
||||
for i, resourceElement := range resourceMapArray {
|
||||
// check the types of resource element
|
||||
// expect it to be map, but can be anything ?:(
|
||||
currentPath := path + strconv.Itoa(i) + "/"
|
||||
returnpath, err := validateResourceElement(log, resourceElement, patternMap, originPattern, currentPath)
|
||||
returnpath, err := validateResourceElement(log, resourceElement, patternMap, originPattern, currentPath, ac)
|
||||
if err != nil {
|
||||
return returnpath, err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/engine/common"
|
||||
"gotest.tools/assert"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
@ -101,7 +102,7 @@ func TestValidateMap(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -197,7 +198,7 @@ func TestValidateMap_AsteriskForInt(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
t.Log(path)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -290,7 +291,7 @@ func TestValidateMap_AsteriskForMap(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -378,7 +379,7 @@ func TestValidateMap_AsteriskForArray(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -469,7 +470,7 @@ func TestValidateMap_AsteriskFieldIsMissing(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "/spec/template/spec/containers/0/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -561,7 +562,7 @@ func TestValidateMap_livenessProbeIsNull(t *testing.T) {
|
|||
err := json.Unmarshal(rawMap, &resource)
|
||||
assert.NilError(t, err)
|
||||
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -651,7 +652,7 @@ func TestValidateMap_livenessProbeIsMissing(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateMap(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -697,7 +698,7 @@ func TestValidateMapElement_TwoElementsInArrayOnePass(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
// assert.Equal(t, path, "/1/object/0/key2/")
|
||||
// assert.NilError(t, err)
|
||||
|
@ -732,7 +733,7 @@ func TestValidateMapElement_OneElementInArrayPass(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -786,7 +787,7 @@ func TestValidateMap_CorrectRelativePathInConfig(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -840,7 +841,7 @@ func TestValidateMap_RelativePathDoesNotExists(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -894,7 +895,7 @@ func TestValidateMap_OnlyAnchorsInPath(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -948,7 +949,7 @@ func TestValidateMap_MalformedReferenceOnlyDolarMark(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -1002,7 +1003,7 @@ func TestValidateMap_RelativePathWithParentheses(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
@ -1056,7 +1057,7 @@ func TestValidateMap_MalformedPath(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -1110,7 +1111,7 @@ func TestValidateMap_AbosolutePathExists(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.Assert(t, err == nil)
|
||||
}
|
||||
|
@ -1151,7 +1152,7 @@ func TestValidateMap_AbsolutePathToMetadata(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "")
|
||||
assert.Assert(t, err == nil)
|
||||
}
|
||||
|
@ -1193,7 +1194,7 @@ func TestValidateMap_AbsolutePathToMetadata_fail(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "/spec/containers/0/image/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -1247,7 +1248,7 @@ func TestValidateMap_AbosolutePathDoesNotExists(t *testing.T) {
|
|||
assert.Assert(t, json.Unmarshal(rawPattern, &pattern))
|
||||
assert.Assert(t, json.Unmarshal(rawMap, &resource))
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "/spec/containers/0/resources/requests/memory/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
@ -1351,7 +1352,7 @@ func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) {
|
|||
err = json.Unmarshal(rawMap, &resource)
|
||||
assert.NilError(t, err)
|
||||
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/")
|
||||
path, err := validateResourceElement(log.Log, resource, pattern, pattern, "/", common.NewAnchorMap())
|
||||
assert.Equal(t, path, "/0/object/0/key2/")
|
||||
assert.Assert(t, err != nil)
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ import (
|
|||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
)
|
||||
|
||||
//ValidatePattern validates the pattern
|
||||
func ValidatePattern(patternElement interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
|
||||
func ValidatePattern(patternElement interface{}, path string, supportedAnchors []commonAnchors.IsAnchor) (string, error) {
|
||||
switch typedPatternElement := patternElement.(type) {
|
||||
case map[string]interface{}:
|
||||
return validateMap(typedPatternElement, path, supportedAnchors)
|
||||
|
@ -22,7 +22,7 @@ func ValidatePattern(patternElement interface{}, path string, supportedAnchors [
|
|||
return path, fmt.Errorf("Validation rule failed at '%s', pattern contains unknown type", path)
|
||||
}
|
||||
}
|
||||
func validateMap(patternMap map[string]interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
|
||||
func validateMap(patternMap map[string]interface{}, path string, supportedAnchors []commonAnchors.IsAnchor) (string, error) {
|
||||
// check if anchors are defined
|
||||
for key, value := range patternMap {
|
||||
// if key is anchor
|
||||
|
@ -45,7 +45,7 @@ func validateMap(patternMap map[string]interface{}, path string, supportedAnchor
|
|||
|
||||
// addition check for existence anchor
|
||||
// value must be of type list
|
||||
if anchor.IsExistenceAnchor(key) {
|
||||
if commonAnchors.IsExistenceAnchor(key) {
|
||||
typedValue, ok := value.([]interface{})
|
||||
if !ok {
|
||||
return path + "/" + key, fmt.Errorf("Existence anchor should have value of type list")
|
||||
|
@ -64,7 +64,7 @@ func validateMap(patternMap map[string]interface{}, path string, supportedAnchor
|
|||
return "", nil
|
||||
}
|
||||
|
||||
func validateArray(patternArray []interface{}, path string, supportedAnchors []anchor.IsAnchor) (string, error) {
|
||||
func validateArray(patternArray []interface{}, path string, supportedAnchors []commonAnchors.IsAnchor) (string, error) {
|
||||
for i, patternElement := range patternArray {
|
||||
currentPath := path + strconv.Itoa(i) + "/"
|
||||
// lets validate the values now :)
|
||||
|
@ -75,7 +75,7 @@ func validateArray(patternArray []interface{}, path string, supportedAnchors []a
|
|||
return "", nil
|
||||
}
|
||||
|
||||
func checkAnchors(key string, supportedAnchors []anchor.IsAnchor) bool {
|
||||
func checkAnchors(key string, supportedAnchors []commonAnchors.IsAnchor) bool {
|
||||
for _, f := range supportedAnchors {
|
||||
if f(key) {
|
||||
return true
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
dclient "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
"github.com/nirmata/kyverno/pkg/engine/variables"
|
||||
"github.com/nirmata/kyverno/pkg/policy/common"
|
||||
)
|
||||
|
@ -60,7 +60,7 @@ func (g *Generate) Validate() (string, error) {
|
|||
if rule.Data != nil {
|
||||
//TODO: is this required ?? as anchors can only be on pattern and not resource
|
||||
// we can add this check by not sure if its needed here
|
||||
if path, err := common.ValidatePattern(rule.Data, "/", []anchor.IsAnchor{}); err != nil {
|
||||
if path, err := common.ValidatePattern(rule.Data, "/", []commonAnchors.IsAnchor{}); err != nil {
|
||||
return fmt.Sprintf("data.%s", path), fmt.Errorf("anchors not supported on generate resources: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
"github.com/nirmata/kyverno/pkg/policy/common"
|
||||
)
|
||||
|
||||
|
@ -36,7 +36,7 @@ func (m *Mutate) Validate() (string, error) {
|
|||
}
|
||||
// Overlay
|
||||
if rule.Overlay != nil {
|
||||
path, err := common.ValidatePattern(rule.Overlay, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsAddingAnchor})
|
||||
path, err := common.ValidatePattern(rule.Overlay, "/", []commonAnchors.IsAnchor{commonAnchors.IsConditionAnchor, commonAnchors.IsAddingAnchor})
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
|
|
@ -96,6 +96,11 @@ func Validate(policyRaw []byte, client *dclient.Client, mock bool, openAPIContro
|
|||
" the rule does not match an kind")
|
||||
}
|
||||
}
|
||||
|
||||
// Validate string values in labels
|
||||
if !isLabelAndAnnotationsString(rule) {
|
||||
return fmt.Errorf("labels and annotations supports only string values, \"use double quotes around the non string values\"")
|
||||
}
|
||||
}
|
||||
|
||||
if !mock {
|
||||
|
@ -250,6 +255,62 @@ func doesMatchAndExcludeConflict(rule kyverno.Rule) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// isLabelAndAnnotationsString :- Validate if labels and annotations contains only string values
|
||||
func isLabelAndAnnotationsString(rule kyverno.Rule) bool {
|
||||
// checkMetadata - Verify if the labels and annotations contains string value inside metadata
|
||||
checkMetadata := func(patternMap map[string]interface{}) bool {
|
||||
for k := range patternMap {
|
||||
if k == "metadata" {
|
||||
metaKey, ok := patternMap[k].(map[string]interface{})
|
||||
if ok {
|
||||
// range over metadata
|
||||
for mk := range metaKey {
|
||||
if mk == "labels" {
|
||||
labelKey, ok := metaKey[mk].(map[string]interface{})
|
||||
if ok {
|
||||
// range over labels
|
||||
for _, val := range labelKey {
|
||||
if reflect.TypeOf(val).String() != "string" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if mk == "annotations" {
|
||||
annotationKey, ok := metaKey[mk].(map[string]interface{})
|
||||
if ok {
|
||||
// range over annotations
|
||||
for _, val := range annotationKey {
|
||||
if reflect.TypeOf(val).String() != "string" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
patternMap, ok := rule.Validation.Pattern.(map[string]interface{})
|
||||
if ok {
|
||||
return checkMetadata(patternMap)
|
||||
} else if len(rule.Validation.AnyPattern) > 0 {
|
||||
anyPatterns := rule.Validation.AnyPattern
|
||||
for _, pattern := range anyPatterns {
|
||||
patternMap, ok := pattern.(map[string]interface{})
|
||||
if ok {
|
||||
ret := checkMetadata(patternMap)
|
||||
if ret == false {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func ruleOnlyDealsWithResourceMetaData(rule kyverno.Rule) bool {
|
||||
overlayMap, _ := rule.Mutation.Overlay.(map[string]interface{})
|
||||
for k := range overlayMap {
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/nirmata/kyverno/pkg/engine/anchor"
|
||||
commonAnchors "github.com/nirmata/kyverno/pkg/engine/anchor/common"
|
||||
"github.com/nirmata/kyverno/pkg/policy/common"
|
||||
)
|
||||
|
||||
|
@ -31,14 +31,14 @@ func (v *Validate) Validate() (string, error) {
|
|||
}
|
||||
|
||||
if rule.Pattern != nil {
|
||||
if path, err := common.ValidatePattern(rule.Pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
|
||||
if path, err := common.ValidatePattern(rule.Pattern, "/", []commonAnchors.IsAnchor{commonAnchors.IsConditionAnchor, commonAnchors.IsExistenceAnchor, commonAnchors.IsEqualityAnchor, commonAnchors.IsNegationAnchor}); err != nil {
|
||||
return fmt.Sprintf("pattern.%s", path), err
|
||||
}
|
||||
}
|
||||
|
||||
if len(rule.AnyPattern) != 0 {
|
||||
for i, pattern := range rule.AnyPattern {
|
||||
if path, err := common.ValidatePattern(pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
|
||||
if path, err := common.ValidatePattern(pattern, "/", []commonAnchors.IsAnchor{commonAnchors.IsConditionAnchor, commonAnchors.IsExistenceAnchor, commonAnchors.IsEqualityAnchor, commonAnchors.IsNegationAnchor}); err != nil {
|
||||
return fmt.Sprintf("anyPattern[%d].%s", i, path), err
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue