mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
fix: change inrange operator regexs (#5962)
* fix inrange operator regexs Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * add support for + sign Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * add support for leftEndpoint + sign Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * update regexs Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * add range operator tests in client code Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * extract range values Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * add cases Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * add test Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * fix test Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * add cli test Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * clean up code Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * fix lint error Signed-off-by: damilola olayinka <holayinkajr@gmail.com> * fix kuttl test Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * regex nits Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Signed-off-by: damilola olayinka <holayinkajr@gmail.com> Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Co-authored-by: Charles-Edouard Brétéché <charled.breteche@gmail.com> Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
c5976fcc57
commit
fcf27bb035
13 changed files with 178 additions and 8 deletions
|
@ -26,6 +26,11 @@ const (
|
|||
NotInRange Operator = "!-"
|
||||
)
|
||||
|
||||
var (
|
||||
InRangeRegex = regexp.MustCompile(`^([-|\+]?\d+(?:\.\d+)?[A-Za-z]*)-([-|\+]?\d+(?:\.\d+)?[A-Za-z]*)$`)
|
||||
NotInRangeRegex = regexp.MustCompile(`^([-|\+]?\d+(?:\.\d+)?[A-Za-z]*)!-([-|\+]?\d+(?:\.\d+)?[A-Za-z]*)$`)
|
||||
)
|
||||
|
||||
// GetOperatorFromStringPattern parses opeartor from pattern
|
||||
func GetOperatorFromStringPattern(pattern string) Operator {
|
||||
if len(pattern) < 2 {
|
||||
|
@ -46,10 +51,10 @@ func GetOperatorFromStringPattern(pattern string) Operator {
|
|||
if pattern[:len(NotEqual)] == string(NotEqual) {
|
||||
return NotEqual
|
||||
}
|
||||
if match, _ := regexp.Match(`^(\d+(\.\d+)?)([^-]*)!-(\d+(\.\d+)?)([^-]*)$`, []byte(pattern)); match {
|
||||
if match := NotInRangeRegex.Match([]byte(pattern)); match {
|
||||
return NotInRange
|
||||
}
|
||||
if match, _ := regexp.Match(`^(\d+(\.\d+)?)([^-]*)-(\d+(\.\d+)?)([^-]*)$`, []byte(pattern)); match {
|
||||
if match := InRangeRegex.Match([]byte(pattern)); match {
|
||||
return InRange
|
||||
}
|
||||
return Equal
|
||||
|
|
|
@ -32,4 +32,23 @@ func TestGetOperatorFromStringPattern_RangeOperator(t *testing.T) {
|
|||
assert.Equal(t, GetOperatorFromStringPattern("text1024Mi!-2048Mi"), Equal)
|
||||
assert.Equal(t, GetOperatorFromStringPattern("test!-value"), Equal)
|
||||
assert.Equal(t, GetOperatorFromStringPattern("value!-*"), Equal)
|
||||
|
||||
assert.Equal(t, GetOperatorFromStringPattern("-10--8"), InRange)
|
||||
assert.Equal(t, GetOperatorFromStringPattern("-10Mi--8Mi"), InRange)
|
||||
|
||||
assert.Equal(t, GetOperatorFromStringPattern("-10!--8"), NotInRange)
|
||||
assert.Equal(t, GetOperatorFromStringPattern("-10Mi!--8Mi"), NotInRange)
|
||||
|
||||
assert.Equal(t, GetOperatorFromStringPattern("-10-+8"), InRange)
|
||||
assert.Equal(t, GetOperatorFromStringPattern("-10Mi-+8Mi"), InRange)
|
||||
|
||||
assert.Equal(t, GetOperatorFromStringPattern("-10!-+8"), NotInRange)
|
||||
assert.Equal(t, GetOperatorFromStringPattern("-10Mi!-+8Mi"), NotInRange)
|
||||
|
||||
assert.Equal(t, GetOperatorFromStringPattern("+0-+1"), InRange)
|
||||
assert.Equal(t, GetOperatorFromStringPattern("+0Mi-+1024Mi"), InRange)
|
||||
|
||||
assert.Equal(t, GetOperatorFromStringPattern("+0!-+1"), NotInRange)
|
||||
assert.Equal(t, GetOperatorFromStringPattern("+0Mi!-+1024Mi"), NotInRange)
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package pattern
|
|||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -176,21 +177,33 @@ func validateStringPattern(log logr.Logger, value interface{}, pattern string) b
|
|||
if op == operator.InRange {
|
||||
// Upon encountering InRange operator split the string by `-` and basically
|
||||
// verify the result of (x >= leftEndpoint & x <= rightEndpoint)
|
||||
endpoints := strings.Split(pattern, "-")
|
||||
return validateStringPattern(log, value, fmt.Sprintf(">= %s", endpoints[0])) &&
|
||||
validateStringPattern(log, value, fmt.Sprintf("<= %s", endpoints[1]))
|
||||
if left, right, ok := split(pattern, operator.InRangeRegex); ok {
|
||||
return validateStringPattern(log, value, fmt.Sprintf(">= %s", left)) &&
|
||||
validateStringPattern(log, value, fmt.Sprintf("<= %s", right))
|
||||
}
|
||||
return false
|
||||
} else if op == operator.NotInRange {
|
||||
// Upon encountering NotInRange operator split the string by `!-` and basically
|
||||
// verify the result of (x < leftEndpoint | x > rightEndpoint)
|
||||
endpoints := strings.Split(pattern, "!-")
|
||||
return validateStringPattern(log, value, fmt.Sprintf("< %s", endpoints[0])) ||
|
||||
validateStringPattern(log, value, fmt.Sprintf("> %s", endpoints[1]))
|
||||
if left, right, ok := split(pattern, operator.NotInRangeRegex); ok {
|
||||
return validateStringPattern(log, value, fmt.Sprintf("< %s", left)) ||
|
||||
validateStringPattern(log, value, fmt.Sprintf("> %s", right))
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
pattern := strings.TrimSpace(pattern[len(op):])
|
||||
return validateString(log, value, pattern, op)
|
||||
}
|
||||
}
|
||||
|
||||
func split(pattern string, r *regexp.Regexp) (string, string, bool) {
|
||||
match := r.FindStringSubmatch(pattern)
|
||||
if len(match) == 0 {
|
||||
return "", "", false
|
||||
}
|
||||
return match[1], match[2], true
|
||||
}
|
||||
|
||||
func validateString(log logr.Logger, value interface{}, pattern string, op operator.Operator) bool {
|
||||
return compareDuration(log, value, pattern, op) ||
|
||||
compareQuantity(log, value, pattern, op) ||
|
||||
|
|
|
@ -316,6 +316,30 @@ func TestValidateValueWithStringPattern_Ranges(t *testing.T) {
|
|||
assert.Assert(t, !validateStringPattern(logger, "256Mi", "128Mi!-512Mi"))
|
||||
assert.Assert(t, validateStringPattern(logger, "1024Mi", "128Mi!-512Mi"))
|
||||
assert.Assert(t, validateStringPattern(logger, "64Mi", "128Mi!-512Mi"))
|
||||
|
||||
assert.Assert(t, validateStringPattern(logger, -9, "-10-8"))
|
||||
assert.Assert(t, !validateStringPattern(logger, 9, "-10--8"))
|
||||
|
||||
assert.Assert(t, validateStringPattern(logger, 9, "-10!--8"))
|
||||
assert.Assert(t, validateStringPattern(logger, "9Mi", "-10Mi!--8Mi"))
|
||||
|
||||
assert.Assert(t, !validateStringPattern(logger, -9, "-10!--8"))
|
||||
|
||||
assert.Assert(t, validateStringPattern(logger, "-9Mi", "-10Mi-8Mi"))
|
||||
assert.Assert(t, validateStringPattern(logger, "9Mi", "-10Mi!-8Mi"))
|
||||
|
||||
assert.Assert(t, validateStringPattern(logger, 0, "-10-+8"))
|
||||
assert.Assert(t, validateStringPattern(logger, "7Mi", "-10Mi-+8Mi"))
|
||||
|
||||
assert.Assert(t, validateStringPattern(logger, 10, "-10!-+8"))
|
||||
assert.Assert(t, validateStringPattern(logger, "10Mi", "-10Mi!-+8Mi"))
|
||||
|
||||
assert.Assert(t, validateStringPattern(logger, 0, "+0-+1"))
|
||||
assert.Assert(t, validateStringPattern(logger, "10Mi", "+0Mi-+1024Mi"))
|
||||
|
||||
assert.Assert(t, validateStringPattern(logger, 10, "+0!-+1"))
|
||||
assert.Assert(t, validateStringPattern(logger, "1025Mi", "+0Mi!-+1024Mi"))
|
||||
|
||||
}
|
||||
|
||||
func TestValidateNumberWithStr_LessFloatAndInt(t *testing.T) {
|
||||
|
|
12
test/cli/test/rangeoperators/kyverno-test.yaml
Normal file
12
test/cli/test/rangeoperators/kyverno-test.yaml
Normal file
|
@ -0,0 +1,12 @@
|
|||
name: test-rangeoperators
|
||||
policies:
|
||||
- policy.yaml
|
||||
resources:
|
||||
- resources.yaml
|
||||
results:
|
||||
- policy: check-value
|
||||
rule: check-value
|
||||
resources:
|
||||
- test-config-fail
|
||||
kind: ConfigMap
|
||||
result: fail
|
23
test/cli/test/rangeoperators/policy.yaml
Normal file
23
test/cli/test/rangeoperators/policy.yaml
Normal file
|
@ -0,0 +1,23 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: check-value
|
||||
spec:
|
||||
validationFailureAction: enforce
|
||||
rules:
|
||||
- name: check-value
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- ConfigMap
|
||||
validate:
|
||||
message: "All data values must be in the specified range."
|
||||
pattern:
|
||||
data:
|
||||
first_value: "+2-+4"
|
||||
second_value: "-2-5"
|
||||
third_value: "100Mi!-1024Mi"
|
||||
fourth_value: "2.5-3.5"
|
||||
fifth_value: "-10--8"
|
||||
|
10
test/cli/test/rangeoperators/resources.yaml
Normal file
10
test/cli/test/rangeoperators/resources.yaml
Normal file
|
@ -0,0 +1,10 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: test-config-fail
|
||||
data:
|
||||
first_value: "3"
|
||||
second_value: "4"
|
||||
third_value: "98Mi"
|
||||
fourth_value: "2.7"
|
||||
fifth_value: "-15"
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- policy.yaml
|
||||
assert:
|
||||
- policy-assert.yaml
|
|
@ -0,0 +1,5 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: resource.yaml
|
||||
shouldFail: true
|
11
test/conformance/kuttl/rangeoperators/standard/README.md
Normal file
11
test/conformance/kuttl/rangeoperators/standard/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
## Description
|
||||
|
||||
This test creates a policy with range operators and a configmap. It uses ranges with negative and (un)signed positive integer endpoints.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
It ensures that a configmap with values not in a range are not created.
|
||||
|
||||
## Reference Issue(s)
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: check-value
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
23
test/conformance/kuttl/rangeoperators/standard/policy.yaml
Normal file
23
test/conformance/kuttl/rangeoperators/standard/policy.yaml
Normal file
|
@ -0,0 +1,23 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: check-value
|
||||
spec:
|
||||
validationFailureAction: Enforce
|
||||
rules:
|
||||
- name: check-value
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- ConfigMap
|
||||
validate:
|
||||
message: "All data values must be in the specified range."
|
||||
pattern:
|
||||
data:
|
||||
first_value: "+2-+4"
|
||||
second_value: "-2-5"
|
||||
third_value: "100Mi!-1024Mi"
|
||||
fourth_value: "2.5-3.5"
|
||||
fifth_value: "-10--8"
|
||||
|
10
test/conformance/kuttl/rangeoperators/standard/resource.yaml
Normal file
10
test/conformance/kuttl/rangeoperators/standard/resource.yaml
Normal file
|
@ -0,0 +1,10 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: test-config
|
||||
data:
|
||||
first_value: "3"
|
||||
second_value: "4"
|
||||
third_value: "98Mi"
|
||||
fourth_value: "2.7"
|
||||
fifth_value: "-15"
|
Loading…
Reference in a new issue