mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +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:
parent
5c50191d8a
commit
4c251bcffd
5 changed files with 98 additions and 4 deletions
|
@ -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{})
|
||||
|
||||
|
|
|
@ -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(`
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue