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

Add parse_json function the decode json strings (#2941)

Signed-off-by: Sambhav Kothari <sambhavs.email@gmail.com>
This commit is contained in:
Sambhav Kothari 2022-01-10 21:42:02 +00:00 committed by GitHub
parent 8350aadc58
commit 6b9798f76f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 129 additions and 1 deletions

View file

@ -2,6 +2,7 @@ package jmespath
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"path/filepath"
@ -57,6 +58,7 @@ var (
pathCanonicalize = "path_canonicalize"
truncate = "truncate"
semverCompare = "semver_compare"
parseJson = "parse_json"
)
const errorPrefix = "JMESPath function '%s': "
@ -262,6 +264,13 @@ func getFunctions() []*gojmespath.FunctionEntry {
},
Handler: jpSemverCompare,
},
{
Name: parseJson,
Arguments: []ArgSpec{
{Types: []JpType{JpString}},
},
Handler: jpParseJson,
},
}
}
@ -665,6 +674,16 @@ func jpSemverCompare(arguments []interface{}) (interface{}, error) {
return false, nil
}
func jpParseJson(arguments []interface{}) (interface{}, error) {
input, err := validateArg(parseJson, arguments, 0, reflect.String)
if err != nil {
return nil, err
}
var output interface{}
err = json.Unmarshal([]byte(input.String()), &output)
return output, err
}
// InterfaceToString casts an interface to a string type
func ifaceToString(iface interface{}) (string, error) {
switch i := iface.(type) {
@ -686,7 +705,7 @@ func ifaceToString(iface interface{}) (string, error) {
func validateArg(f string, arguments []interface{}, index int, expectedType reflect.Kind) (reflect.Value, error) {
arg := reflect.ValueOf(arguments[index])
if arg.Type().Kind() != expectedType {
return reflect.Value{}, fmt.Errorf(invalidArgumentTypeError, equalFold, index+1, expectedType.String())
return reflect.Value{}, fmt.Errorf(invalidArgumentTypeError, f, index+1, expectedType.String())
}
return arg, nil

View file

@ -43,6 +43,68 @@ func Test_Compare(t *testing.T) {
}
}
func Test_ParseJsonSerde(t *testing.T) {
testCases := []string{
`{"a":"b"}`,
`true`,
`[1,2,3,{"a":"b"}]`,
`null`,
`[]`,
`{}`,
`0`,
`1.2`,
`[1.2,true,{"a":{"a":"b"}}]`,
}
for _, tc := range testCases {
t.Run(tc, func(t *testing.T) {
jp, err := New(fmt.Sprintf(`to_string(parse_json('%s'))`, tc))
fmt.Println(err)
assert.NilError(t, err)
result, err := jp.Search("")
fmt.Println(err)
assert.NilError(t, err)
assert.Equal(t, result, tc)
})
}
}
func Test_ParseJsonComplex(t *testing.T) {
testCases := []struct {
input string
expectedResult interface{}
}{
{
input: `parse_json('{"a": "b"}').a`,
expectedResult: "b",
},
{
input: `parse_json('{"a": [1, 2, 3, 4]}').a[0]`,
expectedResult: 1.0,
},
{
input: `parse_json('[1, 2, {"a": {"b": {"c": [1, 2]}}}]')[2].a.b.c[1]`,
expectedResult: 2.0,
},
}
for _, tc := range testCases {
t.Run(tc.input, func(t *testing.T) {
jp, err := New(tc.input)
fmt.Println(err)
assert.NilError(t, err)
result, err := jp.Search("")
fmt.Println(err)
assert.NilError(t, err)
assert.Equal(t, result, tc.expectedResult)
})
}
}
func Test_EqualFold(t *testing.T) {
testCases := []struct {
jmesPath string

View file

@ -74,3 +74,24 @@ spec:
- key: "{{ path_canonicalize(element.hostPath.path) }}"
operator: Equals
value: "\\var\\run\\containerd\\containerd.sock"
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: test-parse-json
spec:
validationFailureAction: enforce
background: false
rules:
- name: test-json-parsing-jmespath
match:
resources:
kinds:
- ConfigMap
validate:
message: "Test JMESPath"
deny:
conditions:
- key: "{{request.object.metadata.annotations.test | parse_json(@).a }}"
operator: NotEquals
value: b

View file

@ -51,3 +51,19 @@ spec:
mountPath: /sock
- name: test
mountPath: /test
---
apiVersion: v1
kind: ConfigMap
metadata:
name: valid-test
annotations:
test: |
{"a": "b"}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: invalid-test
annotations:
test: |
{"a": "not-b"}

View file

@ -29,3 +29,13 @@ results:
resource: mount-containerd-sock
kind: Pod
status: fail
- policy: test-parse-json
rule: test-json-parsing-jmespath
resource: valid-test
kind: ConfigMap
result: pass
- policy: test-parse-json
rule: test-json-parsing-jmespath
resource: invalid-test
kind: ConfigMap
result: fail