1
0
Fork 0
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:
yinka 2023-01-16 16:23:36 +01:00 committed by GitHub
parent c5976fcc57
commit fcf27bb035
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 178 additions and 8 deletions

View file

@ -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

View file

@ -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)
}

View file

@ -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) ||

View file

@ -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) {

View 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

View 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"

View 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"

View file

@ -0,0 +1,6 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
apply:
- policy.yaml
assert:
- policy-assert.yaml

View file

@ -0,0 +1,5 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
apply:
- file: resource.yaml
shouldFail: true

View 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)

View file

@ -0,0 +1,9 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-value
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View 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"

View 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"