From 0a486a7f544a74d95ef05e72f35cd096541752ff Mon Sep 17 00:00:00 2001 From: Maxim Goncharenko <kacejot@fex.net> Date: Fri, 17 May 2019 14:03:06 +0300 Subject: [PATCH] I have finished implementing validation logic using TDD --- pkg/engine/validation.go | 89 ++++++++++++++++++++++- pkg/engine/validation_test.go | 128 +++++++++++++++++++++++++++++++++- 2 files changed, 213 insertions(+), 4 deletions(-) diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go index d5a4c62dac..40850c4e85 100644 --- a/pkg/engine/validation.go +++ b/pkg/engine/validation.go @@ -4,6 +4,8 @@ import ( "encoding/json" "fmt" "log" + "strconv" + "strings" "github.com/minio/minio/pkg/wildcard" @@ -11,6 +13,19 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// TODO: This operators are already implemented in kubernetes +type Operator string + +const ( + MoreEqual Operator = ">=" + LessEqual Operator = "<=" + NotEqual Operator = "!=" + More Operator = ">" + Less Operator = "<" +) + +// TODO: Refactor using State pattern + // Validate handles validating admission request // Checks the target resourse for rules defined in the policy func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) bool { @@ -228,8 +243,80 @@ func checkForWildcard(value, pattern string) bool { return wildcard.Match(pattern, value) } +func checkSingleOperator(value float64, operator string) bool { + if operatorVal, err := strconv.ParseFloat(operator, 64); err == nil { + return value == operatorVal + } + + if len(operator) < 2 { + fmt.Printf("Validating error: operator can't have less than 2 characters: %s\n", operator) + return false + } + + if operator[:len(MoreEqual)] == string(MoreEqual) { + operatorVal, err := strconv.ParseFloat(operator[len(MoreEqual):len(operator)], 64) + if err != nil { + fmt.Printf("Validating error: failed to parse operator value: %s\n", operator) + return false + } + + return value >= operatorVal + } + + if operator[:len(LessEqual)] == string(LessEqual) { + operatorVal, err := strconv.ParseFloat(operator[len(LessEqual):len(operator)], 64) + if err != nil { + fmt.Printf("Validating error: failed to parse operator value: %s\n", operator) + return false + } + + return value <= operatorVal + } + + if operator[:len(More)] == string(More) { + operatorVal, err := strconv.ParseFloat(operator[len(More):len(operator)], 64) + if err != nil { + fmt.Printf("Validating error: failed to parse operator value: %s\n", operator) + return false + } + + return value > operatorVal + } + + if operator[:len(Less)] == string(Less) { + operatorVal, err := strconv.ParseFloat(operator[len(Less):len(operator)], 64) + if err != nil { + fmt.Printf("Validating error: failed to parse operator value: %s\n", operator) + return false + } + + return value < operatorVal + } + + if operator[:len(NotEqual)] == string(NotEqual) { + operatorVal, err := strconv.ParseFloat(operator[len(NotEqual):len(operator)], 64) + if err != nil { + fmt.Printf("Validating error: failed to parse operator value: %s\n", operator) + return false + } + + return value != operatorVal + } + + return false +} + func checkForOperator(value float64, pattern string) bool { - return true + operators := strings.Split(pattern, "|") + + for _, operator := range operators { + operator = strings.Replace(operator, " ", "", -1) + if checkSingleOperator(value, operator) { + return true + } + } + + return false } func wrappedWithParentheses(str string) bool { diff --git a/pkg/engine/validation_test.go b/pkg/engine/validation_test.go index 5302fd6988..68d07ca73e 100644 --- a/pkg/engine/validation_test.go +++ b/pkg/engine/validation_test.go @@ -102,16 +102,138 @@ func TestCheckSingleValue_CheckFloat(t *testing.T) { assert.Assert(t, !checkSingleValue(value, pattern)) } -func TestCheckSingleValue_CheckOperatorMore(t *testing.T) { - pattern := ">10" +func TestCheckSingleValue_CheckOperatorMoreEqual(t *testing.T) { + pattern := " >= 89 " value := 89 assert.Assert(t, checkSingleValue(value, pattern)) - pattern = ">10" + pattern = ">=10.0001" floatValue := 89.901 assert.Assert(t, checkSingleValue(floatValue, pattern)) } +func TestCheckSingleValue_CheckOperatorMoreEqualFail(t *testing.T) { + pattern := " >= 90 " + value := 89 + assert.Assert(t, !checkSingleValue(value, pattern)) + + pattern = ">=910.0001" + floatValue := 89.901 + assert.Assert(t, !checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorLessEqual(t *testing.T) { + pattern := " <= 1 " + value := 1 + assert.Assert(t, checkSingleValue(value, pattern)) + + pattern = "<=10.0001" + floatValue := 1.901 + assert.Assert(t, checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorLessEqualFail(t *testing.T) { + pattern := " <= 0.1558 " + value := 1 + assert.Assert(t, !checkSingleValue(value, pattern)) + + pattern = "<=10.0001" + floatValue := 12.901 + assert.Assert(t, !checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorMore(t *testing.T) { + pattern := " > 10 " + value := 89 + assert.Assert(t, checkSingleValue(value, pattern)) + + pattern = ">10.0001" + floatValue := 89.901 + assert.Assert(t, checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorMoreFail(t *testing.T) { + pattern := " > 89 " + value := 89 + assert.Assert(t, !checkSingleValue(value, pattern)) + + pattern = ">910.0001" + floatValue := 89.901 + assert.Assert(t, !checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorLess(t *testing.T) { + pattern := " < 10 " + value := 9 + assert.Assert(t, checkSingleValue(value, pattern)) + + pattern = "<10.0001" + floatValue := 9.901 + assert.Assert(t, checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorLessFail(t *testing.T) { + pattern := " < 10 " + value := 10 + assert.Assert(t, !checkSingleValue(value, pattern)) + + pattern = "<10.0001" + floatValue := 19.901 + assert.Assert(t, !checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorNotEqual(t *testing.T) { + pattern := " != 10 " + value := 9.99999 + assert.Assert(t, checkSingleValue(value, pattern)) + + pattern = "!=10.0001" + floatValue := 10.0000 + assert.Assert(t, checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorNotEqualFail(t *testing.T) { + pattern := " != 9.99999 " + value := 9.99999 + assert.Assert(t, !checkSingleValue(value, pattern)) + + pattern = "!=10" + floatValue := 10 + assert.Assert(t, !checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorEqual(t *testing.T) { + pattern := " 10.000001 " + value := 10.000001 + assert.Assert(t, checkSingleValue(value, pattern)) + + pattern = "10.000000" + floatValue := 10 + assert.Assert(t, checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckOperatorEqualFail(t *testing.T) { + pattern := " 10.000000 " + value := 10.000001 + assert.Assert(t, !checkSingleValue(value, pattern)) + + pattern = "10.000001" + floatValue := 10 + assert.Assert(t, !checkSingleValue(floatValue, pattern)) +} + +func TestCheckSingleValue_CheckSeveralOperators(t *testing.T) { + pattern := " <-1 | 10.000001 " + value := 10.000001 + assert.Assert(t, checkSingleValue(value, pattern)) + + value = -30 + assert.Assert(t, checkSingleValue(value, pattern)) + + value = 5 + assert.Assert(t, !checkSingleValue(value, pattern)) +} + func TestCheckSingleValue_CheckWildcard(t *testing.T) { pattern := "nirmata_*" value := "nirmata_awesome"