diff --git a/definitions/crds/crds.yaml b/definitions/crds/crds.yaml index 5348a11804..de85fe6090 100644 --- a/definitions/crds/crds.yaml +++ b/definitions/crds/crds.yaml @@ -233,7 +233,10 @@ spec: key: type: string value: - type: string + anyOf: + - type: string + - type: array + items: {} generate: type: object required: diff --git a/definitions/install.yaml b/definitions/install.yaml index 39e84d76e2..25a25249d2 100644 --- a/definitions/install.yaml +++ b/definitions/install.yaml @@ -235,7 +235,10 @@ spec: - NotIn type: string value: - type: string + anyOf: + - type: string + - type: array + items: {} required: - key - operator diff --git a/definitions/install_debug.yaml b/definitions/install_debug.yaml index 9269d940af..4b3fe2b877 100644 --- a/definitions/install_debug.yaml +++ b/definitions/install_debug.yaml @@ -235,7 +235,10 @@ spec: - NotIn type: string value: - type: string + anyOf: + - type: string + - type: array + items: {} required: - key - operator diff --git a/go.sum b/go.sum index 44177b474b..d33ddb15e4 100644 --- a/go.sum +++ b/go.sum @@ -1068,6 +1068,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gotest.tools v1.4.0 h1:BjtEgfuw8Qyd+jPvQz8CfoxiO/UjFEidWinwEXZiWv0= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/engine/variables/operator/in.go b/pkg/engine/variables/operator/in.go index dd874914da..ec54e43f5c 100644 --- a/pkg/engine/variables/operator/in.go +++ b/pkg/engine/variables/operator/in.go @@ -2,9 +2,7 @@ package operator import ( "fmt" - "math" "reflect" - "strconv" "github.com/go-logr/logr" "github.com/nirmata/kyverno/pkg/engine/context" @@ -27,131 +25,76 @@ type InHandler struct { } //Evaluate evaluates expression with In Operator -func (eh InHandler) Evaluate(key, value interface{}) bool { +func (in InHandler) Evaluate(key, value interface{}) bool { var err error //TODO: decouple variables from evaluation // substitute the variables - if key, err = eh.subHandler(eh.log, eh.ctx, key); err != nil { + if key, err = in.subHandler(in.log, in.ctx, key); err != nil { // Failed to resolve the variable - eh.log.Error(err, "Failed to resolve variable", "variable", key) + in.log.Error(err, "Failed to resolve variable", "variable", key) return false } - if value, err = eh.subHandler(eh.log, eh.ctx, value); err != nil { + if value, err = in.subHandler(in.log, in.ctx, value); err != nil { // Failed to resolve the variable - eh.log.Error(err, "Failed to resolve variable", "variable", value) + in.log.Error(err, "Failed to resolve variable", "variable", value) return false } - // key and value need to be of same type + // key should be avaliable in value switch typedKey := key.(type) { - case bool: - return eh.validateValuewithBoolPattern(typedKey, value) - case int: - return eh.validateValuewithIntPattern(int64(typedKey), value) - case int64: - return eh.validateValuewithIntPattern(typedKey, value) - case float64: - return eh.validateValuewithFloatPattern(typedKey, value) case string: - return eh.validateValuewithStringPattern(typedKey, value) - case map[string]interface{}: - return eh.validateValueWithMapPattern(typedKey, value) + return in.validateValuewithStringPattern(typedKey, value) + default: + in.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey)) + return false + } +} + +func (in InHandler) validateValuewithStringPattern(key string, value interface{}) (keyExists bool) { + invalidType, keyExists := ValidateStringPattern(key, value) + if invalidType { + in.log.Info("expected type []string", "value", value, "type", fmt.Sprintf("%T", value)) + return false + } + + return keyExists +} + +func ValidateStringPattern(key string, value interface{}) (invalidType bool, keyExists bool) { + stringType := reflect.TypeOf("") + switch valuesAvaliable := value.(type) { case []interface{}: - return eh.validateValueWithSlicePattern(typedKey, value) + for _, val := range valuesAvaliable { + if reflect.TypeOf(val) != stringType { + return true, false + } + if key == val { + keyExists = true + } + } default: - eh.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey)) - return false + return true, false } + + return invalidType, keyExists } -func (eh InHandler) validateValueWithSlicePattern(key []interface{}, value interface{}) bool { - if val, ok := value.([]interface{}); ok { - return reflect.DeepEqual(key, val) - } - eh.log.Info("Expected type []interface{}", "value", value, "type", fmt.Sprintf("%T", value)) +func (in InHandler) validateValuewithBoolPattern(key bool, value interface{}) bool { return false } -func (eh InHandler) validateValueWithMapPattern(key map[string]interface{}, value interface{}) bool { - if val, ok := value.(map[string]interface{}); ok { - return reflect.DeepEqual(key, val) - } - eh.log.Info("Expected type map[string]interface{}", "value", value, "type", fmt.Sprintf("%T", value)) +func (in InHandler) validateValuewithIntPattern(key int64, value interface{}) bool { return false } -func (eh InHandler) validateValuewithStringPattern(key string, value interface{}) bool { - if val, ok := value.(string); ok { - return key == val - } - - eh.log.Info("Expected type string", "value", value, "type", fmt.Sprintf("%T", value)) +func (in InHandler) validateValuewithFloatPattern(key float64, value interface{}) bool { return false } -func (eh InHandler) validateValuewithFloatPattern(key float64, value interface{}) bool { - switch typedValue := value.(type) { - case int: - // check that float has not fraction - if key == math.Trunc(key) { - return int(key) == typedValue - } - eh.log.Info("Expected type float, found int", "typedValue", typedValue) - case int64: - // check that float has not fraction - if key == math.Trunc(key) { - return int64(key) == typedValue - } - eh.log.Info("Expected type float, found int", "typedValue", typedValue) - case float64: - return typedValue == key - case string: - // extract float from string - float64Num, err := strconv.ParseFloat(typedValue, 64) - if err != nil { - eh.log.Error(err, "Failed to parse float64 from string") - return false - } - return float64Num == key - default: - eh.log.Info("Expected type float", "value", value, "type", fmt.Sprintf("%T", value)) - return false - } +func (in InHandler) validateValueWithMapPattern(key map[string]interface{}, value interface{}) bool { return false } -func (eh InHandler) validateValuewithBoolPattern(key bool, value interface{}) bool { - typedValue, ok := value.(bool) - if !ok { - eh.log.Info("Expected type bool", "value", value, "type", fmt.Sprintf("%T", value)) - return false - } - return key == typedValue -} - -func (eh InHandler) validateValuewithIntPattern(key int64, value interface{}) bool { - switch typedValue := value.(type) { - case int: - return int64(typedValue) == key - case int64: - return typedValue == key - case float64: - // check that float has no fraction - if typedValue == math.Trunc(typedValue) { - return int64(typedValue) == key - } - eh.log.Info("Expected type int, found float", "value", typedValue, "type", fmt.Sprintf("%T", typedValue)) - return false - case string: - // extract in64 from string - int64Num, err := strconv.ParseInt(typedValue, 10, 64) - if err != nil { - eh.log.Error(err, "Failed to parse int64 from string") - return false - } - return int64Num == key - default: - eh.log.Info("Expected type int", "value", value, "type", fmt.Sprintf("%T", value)) - return false - } +func (in InHandler) validateValueWithSlicePattern(key []interface{}, value interface{}) bool { + return false } diff --git a/pkg/engine/variables/operator/notin.go b/pkg/engine/variables/operator/notin.go index c0057dec60..368a8e7972 100644 --- a/pkg/engine/variables/operator/notin.go +++ b/pkg/engine/variables/operator/notin.go @@ -2,9 +2,6 @@ package operator import ( "fmt" - "math" - "reflect" - "strconv" "github.com/go-logr/logr" "github.com/nirmata/kyverno/pkg/engine/context" @@ -27,129 +24,62 @@ type NotInHandler struct { } //Evaluate evaluates expression with NotIn Operator -func (neh NotInHandler) Evaluate(key, value interface{}) bool { +func (nin NotInHandler) Evaluate(key, value interface{}) bool { var err error //TODO: decouple variables from evaluation // substitute the variables - if key, err = neh.subHandler(neh.log, neh.ctx, key); err != nil { + if key, err = nin.subHandler(nin.log, nin.ctx, key); err != nil { // Failed to resolve the variable - neh.log.Error(err, "Failed to resolve variable", "variable", key) + nin.log.Error(err, "Failed to resolve variable", "variable", key) return false } - if value, err = neh.subHandler(neh.log, neh.ctx, value); err != nil { + if value, err = nin.subHandler(nin.log, nin.ctx, value); err != nil { // Failed to resolve the variable - neh.log.Error(err, "Failed to resolve variable", "variable", value) + nin.log.Error(err, "Failed to resolve variable", "variable", value) return false } // key and value need to be of same type switch typedKey := key.(type) { - case bool: - return neh.validateValuewithBoolPattern(typedKey, value) - case int: - return neh.validateValuewithIntPattern(int64(typedKey), value) - case int64: - return neh.validateValuewithIntPattern(typedKey, value) - case float64: - return neh.validateValuewithFloatPattern(typedKey, value) case string: - return neh.validateValuewithStringPattern(typedKey, value) - case map[string]interface{}: - return neh.validateValueWithMapPattern(typedKey, value) - case []interface{}: - return neh.validateValueWithSlicePattern(typedKey, value) + return nin.validateValuewithStringPattern(typedKey, value) default: - neh.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey)) + nin.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey)) return false } + } -func (neh NotInHandler) validateValueWithSlicePattern(key []interface{}, value interface{}) bool { - if val, ok := value.([]interface{}); ok { - return !reflect.DeepEqual(key, val) +func (nin NotInHandler) validateValuewithStringPattern(key string, value interface{}) bool { + invalidType, keyExists := ValidateStringPattern(key, value) + if invalidType { + nin.log.Info("expected type []string", "value", value, "type", fmt.Sprintf("%T", value)) + return false } - neh.log.Info("Expected type []interface{}", "value", value, "type", fmt.Sprintf("%T", value)) + + if !keyExists { + fmt.Println(".....return true......") + return true + } + fmt.Println(".....return false......") return false } -func (neh NotInHandler) validateValueWithMapPattern(key map[string]interface{}, value interface{}) bool { - if val, ok := value.(map[string]interface{}); ok { - return !reflect.DeepEqual(key, val) - } - neh.log.Info("Expected type map[string]interface{}", "value", value, "type", fmt.Sprintf("%T", value)) +func (nin NotInHandler) validateValuewithBoolPattern(key bool, value interface{}) bool { return false } -func (neh NotInHandler) validateValuewithStringPattern(key string, value interface{}) bool { - if val, ok := value.(string); ok { - return key != val - } - neh.log.Info("Expected type string", "value", value, "type", fmt.Sprintf("%T", value)) +func (nin NotInHandler) validateValuewithIntPattern(key int64, value interface{}) bool { return false } -func (neh NotInHandler) validateValuewithFloatPattern(key float64, value interface{}) bool { - switch typedValue := value.(type) { - case int: - // check that float has not fraction - if key == math.Trunc(key) { - return int(key) != typedValue - } - neh.log.Info("Expected type float, found int", "typedValue", typedValue) - case int64: - // check that float has not fraction - if key == math.Trunc(key) { - return int64(key) != typedValue - } - neh.log.Info("Expected type float, found int", "typedValue", typedValue) - case float64: - return typedValue != key - case string: - // extract float from string - float64Num, err := strconv.ParseFloat(typedValue, 64) - if err != nil { - neh.log.Error(err, "Failed to parse float64 from string") - return false - } - return float64Num != key - default: - neh.log.Info("Expected type float", "value", value, "type", fmt.Sprintf("%T", value)) - return false - } +func (nin NotInHandler) validateValuewithFloatPattern(key float64, value interface{}) bool { return false } -func (neh NotInHandler) validateValuewithBoolPattern(key bool, value interface{}) bool { - typedValue, ok := value.(bool) - if !ok { - neh.log.Info("Expected type bool", "value", value, "type", fmt.Sprintf("%T", value)) - return false - } - return key != typedValue +func (nin NotInHandler) validateValueWithMapPattern(key map[string]interface{}, value interface{}) bool { + return false } -func (neh NotInHandler) validateValuewithIntPattern(key int64, value interface{}) bool { - switch typedValue := value.(type) { - case int: - return int64(typedValue) != key - case int64: - return typedValue != key - case float64: - // check that float has no fraction - if typedValue == math.Trunc(typedValue) { - return int64(typedValue) != key - } - neh.log.Info("Expected type int, found float", "value", typedValue, "type", fmt.Sprintf("%T", typedValue)) - return false - case string: - // extract in64 from string - int64Num, err := strconv.ParseInt(typedValue, 10, 64) - if err != nil { - neh.log.Error(err, "Failed to parse int64 from string") - return false - } - return int64Num != key - default: - neh.log.Info("Expected type int", "value", value, "type", fmt.Sprintf("%T", value)) - return false - } +func (nin NotInHandler) validateValueWithSlicePattern(key []interface{}, value interface{}) bool { + return false }