1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-29 02:45:06 +00:00

Add pattern_match custom JMESPath function analogous to regex_match (#2717)

* Add `pattern_match` custom JMESPath function analogous to `regex_match`

Signed-off-by: Sebastian Widmer <sebastian.widmer@vshn.net>

* Add CLI test for the custom `pattern_match` function

Signed-off-by: Sebastian Widmer <sebastian.widmer@vshn.net>
This commit is contained in:
Sebastian Widmer 2021-11-29 17:13:07 +01:00 committed by GitHub
parent 5c50191d8a
commit 4c251bcffd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 98 additions and 4 deletions

View file

@ -11,6 +11,7 @@ import (
"time"
gojmespath "github.com/jmespath/go-jmespath"
"github.com/minio/pkg/wildcard"
)
var (
@ -39,6 +40,7 @@ var (
regexReplaceAll = "regex_replace_all"
regexReplaceAllLiteral = "regex_replace_all_literal"
regexMatch = "regex_match"
patternMatch = "pattern_match"
labelMatch = "label_match"
add = "add"
subtract = "subtract"
@ -149,6 +151,14 @@ func getFunctions() []*gojmespath.FunctionEntry {
},
Handler: jpRegexMatch,
},
{
Name: patternMatch,
Arguments: []ArgSpec{
{Types: []JpType{JpString}},
{Types: []JpType{JpString, JpNumber}},
},
Handler: jpPatternMatch,
},
{
// Validates if label (param1) would match pod/host/etc labels (param2)
Name: labelMatch,
@ -420,6 +430,20 @@ func jpRegexMatch(arguments []interface{}) (interface{}, error) {
return regexp.Match(regex.String(), []byte(src))
}
func jpPatternMatch(arguments []interface{}) (interface{}, error) {
pattern, err := validateArg(regexMatch, arguments, 0, reflect.String)
if err != nil {
return nil, err
}
src, err := ifaceToString(arguments[1])
if err != nil {
return nil, fmt.Errorf(invalidArgumentTypeError, regexMatch, 2, "String or Real")
}
return wildcard.Match(pattern.String(), src), nil
}
func jpLabelMatch(arguments []interface{}) (interface{}, error) {
labelMap, ok := arguments[0].(map[string]interface{})

View file

@ -268,6 +268,30 @@ func Test_RegexMatchWithNumber(t *testing.T) {
assert.Equal(t, true, result)
}
func Test_PatternMatch(t *testing.T) {
data := make(map[string]interface{})
data["foo"] = "prefix-foo"
query, err := New("pattern_match('prefix-*', foo)")
assert.NilError(t, err)
result, err := query.Search(data)
assert.NilError(t, err)
assert.Equal(t, true, result)
}
func Test_PatternMatchWithNumber(t *testing.T) {
data := make(map[string]interface{})
data["foo"] = -12.0
query, err := New("pattern_match('12*', abs(foo))")
assert.NilError(t, err)
result, err := query.Search(data)
assert.NilError(t, err)
assert.Equal(t, true, result)
}
func Test_RegexReplaceAll(t *testing.T) {
resourceRaw := []byte(`
{

View file

@ -17,3 +17,25 @@ spec:
- key: "{{base64_decode(request.object.data.value)}}"
operator: NotEquals
value: "{{request.object.metadata.labels.value}}"
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: pattern-match
spec:
validationFailureAction: enforce
background: false
rules:
- match:
all:
- resources:
kinds:
- Namespace
name: label-must-match-pattern
validate:
deny:
conditions:
all:
- key: "{{pattern_match('prefix-*', request.object.metadata.labels.value)}}"
operator: Equals
value: false

View file

@ -1,7 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: test-match
name: base64-test-match
labels:
value: hello
type: Opaque
@ -11,9 +11,23 @@ data:
apiVersion: v1
kind: Secret
metadata:
name: test-no-match
name: base64-test-no-match
labels:
value: hello
type: Opaque
data:
value: Z29vZGJ5ZQ==
---
apiVersion: v1
kind: Namespace
metadata:
name: pattern-match-test-match
labels:
value: prefix-test
---
apiVersion: v1
kind: Namespace
metadata:
name: pattern-match-test-no-match
labels:
value: test

View file

@ -6,11 +6,21 @@ resources:
results:
- policy: base64
rule: secret-value-must-match-label
resource: test-match
resource: base64-test-match
kind: Secret
status: pass
- policy: base64
rule: secret-value-must-match-label
resource: test-no-match
resource: base64-test-no-match
kind: Secret
status: fail
- policy: pattern-match
rule: label-must-match-pattern
resource: pattern-match-test-match
kind: Namespace
status: pass
- policy: pattern-match
rule: label-must-match-pattern
resource: pattern-match-test-no-match
kind: Namespace
status: fail