mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
feat: add image_normalize filter (#6911)
* feat: add image_normalize filter Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * tests Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
cf2502e1ea
commit
dbbdc1b96c
8 changed files with 133 additions and 47 deletions
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kyverno/kyverno/pkg/config"
|
||||||
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
|
@ -34,7 +35,7 @@ func Command() *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
func printFunctions(names ...string) {
|
func printFunctions(names ...string) {
|
||||||
functions := jmespath.GetFunctions()
|
functions := jmespath.GetFunctions(config.NewDefaultConfiguration(false))
|
||||||
slices.SortFunc(functions, func(a, b jmespath.FunctionEntry) bool {
|
slices.SortFunc(functions, func(a, b jmespath.FunctionEntry) bool {
|
||||||
return a.String() < b.String()
|
return a.String() < b.String()
|
||||||
})
|
})
|
||||||
|
|
|
@ -82,7 +82,7 @@ func Test_Add(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.test)
|
jp, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -228,7 +228,7 @@ func Test_Sum(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.test)
|
jp, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -327,7 +327,7 @@ func Test_Subtract(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.test)
|
jp, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -426,7 +426,7 @@ func Test_Multiply(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.test)
|
jp, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -588,7 +588,7 @@ func Test_Divide(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.test)
|
jp, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -744,7 +744,7 @@ func Test_Modulo(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.test)
|
jp, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
|
|
@ -20,6 +20,8 @@ import (
|
||||||
trunc "github.com/aquilax/truncate"
|
trunc "github.com/aquilax/truncate"
|
||||||
"github.com/blang/semver/v4"
|
"github.com/blang/semver/v4"
|
||||||
gojmespath "github.com/jmespath/go-jmespath"
|
gojmespath "github.com/jmespath/go-jmespath"
|
||||||
|
"github.com/kyverno/kyverno/pkg/config"
|
||||||
|
imageutils "github.com/kyverno/kyverno/pkg/utils/image"
|
||||||
wildcard "github.com/kyverno/kyverno/pkg/utils/wildcard"
|
wildcard "github.com/kyverno/kyverno/pkg/utils/wildcard"
|
||||||
regen "github.com/zach-klippenstein/goregen"
|
regen "github.com/zach-klippenstein/goregen"
|
||||||
"golang.org/x/crypto/cryptobyte"
|
"golang.org/x/crypto/cryptobyte"
|
||||||
|
@ -66,9 +68,10 @@ var (
|
||||||
objectFromLists = "object_from_lists"
|
objectFromLists = "object_from_lists"
|
||||||
random = "random"
|
random = "random"
|
||||||
x509_decode = "x509_decode"
|
x509_decode = "x509_decode"
|
||||||
|
imageNormalize = "image_normalize"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetFunctions() []FunctionEntry {
|
func GetFunctions(configuration config.Configuration) []FunctionEntry {
|
||||||
return []FunctionEntry{{
|
return []FunctionEntry{{
|
||||||
FunctionEntry: gojmespath.FunctionEntry{
|
FunctionEntry: gojmespath.FunctionEntry{
|
||||||
Name: compare,
|
Name: compare,
|
||||||
|
@ -541,6 +544,16 @@ func GetFunctions() []FunctionEntry {
|
||||||
},
|
},
|
||||||
ReturnType: []jpType{jpString},
|
ReturnType: []jpType{jpString},
|
||||||
Note: "returns the result of rounding time down to a multiple of duration",
|
Note: "returns the result of rounding time down to a multiple of duration",
|
||||||
|
}, {
|
||||||
|
FunctionEntry: gojmespath.FunctionEntry{
|
||||||
|
Name: imageNormalize,
|
||||||
|
Arguments: []argSpec{
|
||||||
|
{Types: []jpType{jpString}},
|
||||||
|
},
|
||||||
|
Handler: jpImageNormalize(configuration),
|
||||||
|
},
|
||||||
|
ReturnType: []jpType{jpString},
|
||||||
|
Note: "normalizes an image reference",
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1099,3 +1112,15 @@ func jpX509Decode(arguments []interface{}) (interface{}, error) {
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func jpImageNormalize(configuration config.Configuration) gojmespath.JpFunction {
|
||||||
|
return func(arguments []interface{}) (interface{}, error) {
|
||||||
|
if image, err := validateArg(imageNormalize, arguments, 0, reflect.String); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if infos, err := imageutils.GetImageInfo(image.String(), configuration); err != nil {
|
||||||
|
return nil, formatError(genericError, imageNormalize, err)
|
||||||
|
} else {
|
||||||
|
return infos.String(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,9 +7,12 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kyverno/kyverno/pkg/config"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var cfg = config.NewDefaultConfiguration(false)
|
||||||
|
|
||||||
func Test_Compare(t *testing.T) {
|
func Test_Compare(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
jmesPath string
|
jmesPath string
|
||||||
|
@ -30,7 +33,7 @@ func Test_Compare(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.jmesPath, func(t *testing.T) {
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.jmesPath)
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -57,7 +60,7 @@ func Test_ParseJsonSerde(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc, func(t *testing.T) {
|
t.Run(tc, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(fmt.Sprintf(`to_string(parse_json('%s'))`, tc))
|
jp, err := newJMESPath(cfg, fmt.Sprintf(`to_string(parse_json('%s'))`, tc))
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -88,7 +91,7 @@ func Test_ParseJsonComplex(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.input, func(t *testing.T) {
|
t.Run(tc.input, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.input)
|
jp, err := newJMESPath(cfg, tc.input)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -165,7 +168,7 @@ bar: null
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.input, func(t *testing.T) {
|
t.Run(tc.input, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(fmt.Sprintf(`parse_yaml('%s')`, tc.input))
|
jp, err := newJMESPath(cfg, fmt.Sprintf(`parse_yaml('%s')`, tc.input))
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -194,7 +197,7 @@ func Test_EqualFold(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.jmesPath, func(t *testing.T) {
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.jmesPath)
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -231,7 +234,7 @@ func Test_Replace(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.jmesPath, func(t *testing.T) {
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.jmesPath)
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -245,7 +248,7 @@ func Test_Replace(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_ReplaceAll(t *testing.T) {
|
func Test_ReplaceAll(t *testing.T) {
|
||||||
jp, err := newJMESPath("replace_all('Lorem ipsum dolor sit amet', 'ipsum', 'muspi')")
|
jp, err := newJMESPath(cfg, "replace_all('Lorem ipsum dolor sit amet', 'ipsum', 'muspi')")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -276,7 +279,7 @@ func Test_ToUpper(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.jmesPath, func(t *testing.T) {
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.jmesPath)
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -309,7 +312,7 @@ func Test_ToLower(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.jmesPath, func(t *testing.T) {
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.jmesPath)
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -323,7 +326,7 @@ func Test_ToLower(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Trim(t *testing.T) {
|
func Test_Trim(t *testing.T) {
|
||||||
jp, err := newJMESPath("trim('¡¡¡Hello, Gophers!!!', '!¡')")
|
jp, err := newJMESPath(cfg, "trim('¡¡¡Hello, Gophers!!!', '!¡')")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -394,7 +397,7 @@ func Test_TrimPrefix(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Split(t *testing.T) {
|
func Test_Split(t *testing.T) {
|
||||||
jp, err := newJMESPath("split('Hello, Gophers', ', ')")
|
jp, err := newJMESPath(cfg, "split('Hello, Gophers', ', ')")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -407,7 +410,7 @@ func Test_Split(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_HasPrefix(t *testing.T) {
|
func Test_HasPrefix(t *testing.T) {
|
||||||
jp, err := newJMESPath("starts_with('Gophers', 'Go')")
|
jp, err := newJMESPath(cfg, "starts_with('Gophers', 'Go')")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -419,7 +422,7 @@ func Test_HasPrefix(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_HasSuffix(t *testing.T) {
|
func Test_HasSuffix(t *testing.T) {
|
||||||
jp, err := newJMESPath("ends_with('Amigo', 'go')")
|
jp, err := newJMESPath(cfg, "ends_with('Amigo', 'go')")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -434,7 +437,7 @@ func Test_RegexMatch(t *testing.T) {
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
data["foo"] = "hgf'b1a2r'b12g"
|
data["foo"] = "hgf'b1a2r'b12g"
|
||||||
|
|
||||||
query, err := newJMESPath("regex_match('12.*', foo)")
|
query, err := newJMESPath(cfg, "regex_match('12.*', foo)")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := query.Search(data)
|
result, err := query.Search(data)
|
||||||
|
@ -446,7 +449,7 @@ func Test_RegexMatchWithNumber(t *testing.T) {
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
data["foo"] = -12.0
|
data["foo"] = -12.0
|
||||||
|
|
||||||
query, err := newJMESPath("regex_match('12.*', abs(foo))")
|
query, err := newJMESPath(cfg, "regex_match('12.*', abs(foo))")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := query.Search(data)
|
result, err := query.Search(data)
|
||||||
|
@ -458,7 +461,7 @@ func Test_PatternMatch(t *testing.T) {
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
data["foo"] = "prefix-foo"
|
data["foo"] = "prefix-foo"
|
||||||
|
|
||||||
query, err := newJMESPath("pattern_match('prefix-*', foo)")
|
query, err := newJMESPath(cfg, "pattern_match('prefix-*', foo)")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := query.Search(data)
|
result, err := query.Search(data)
|
||||||
|
@ -470,7 +473,7 @@ func Test_PatternMatchWithNumber(t *testing.T) {
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
data["foo"] = -12.0
|
data["foo"] = -12.0
|
||||||
|
|
||||||
query, err := newJMESPath("pattern_match('12*', abs(foo))")
|
query, err := newJMESPath(cfg, "pattern_match('12*', abs(foo))")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := query.Search(data)
|
result, err := query.Search(data)
|
||||||
|
@ -497,7 +500,7 @@ func Test_RegexReplaceAll(t *testing.T) {
|
||||||
var resource interface{}
|
var resource interface{}
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
err := json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
query, err := newJMESPath(`regex_replace_all('([Hh]e|G)l', spec.field, '${2}G')`)
|
query, err := newJMESPath(cfg, `regex_replace_all('([Hh]e|G)l', spec.field, '${2}G')`)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search(resource)
|
res, err := query.Search(resource)
|
||||||
|
@ -528,7 +531,7 @@ func Test_RegexReplaceAllLiteral(t *testing.T) {
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
err := json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
query, err := newJMESPath(`regex_replace_all_literal('[Hh]el?', spec.field, 'G')`)
|
query, err := newJMESPath(cfg, `regex_replace_all_literal('[Hh]el?', spec.field, 'G')`)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search(resource)
|
res, err := query.Search(resource)
|
||||||
|
@ -583,7 +586,7 @@ func Test_LabelMatch(t *testing.T) {
|
||||||
err := json.Unmarshal(tc.resource, &resource)
|
err := json.Unmarshal(tc.resource, &resource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
query, err := newJMESPath("label_match(`" + tc.test + "`, metadata.labels)")
|
query, err := newJMESPath(cfg, "label_match(`"+tc.test+"`, metadata.labels)")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search(resource)
|
res, err := query.Search(resource)
|
||||||
|
@ -627,7 +630,7 @@ func Test_JpToBoolean(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Base64Decode(t *testing.T) {
|
func Test_Base64Decode(t *testing.T) {
|
||||||
jp, err := newJMESPath("base64_decode('SGVsbG8sIHdvcmxkIQ==')")
|
jp, err := newJMESPath(cfg, "base64_decode('SGVsbG8sIHdvcmxkIQ==')")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -639,7 +642,7 @@ func Test_Base64Decode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Base64Encode(t *testing.T) {
|
func Test_Base64Encode(t *testing.T) {
|
||||||
jp, err := newJMESPath("base64_encode('Hello, world!')")
|
jp, err := newJMESPath(cfg, "base64_encode('Hello, world!')")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -669,7 +672,7 @@ func Test_Base64Decode_Secret(t *testing.T) {
|
||||||
err := json.Unmarshal(resourceRaw, &resource)
|
err := json.Unmarshal(resourceRaw, &resource)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
query, err := newJMESPath(`base64_decode(data.example1)`)
|
query, err := newJMESPath(cfg, `base64_decode(data.example1)`)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search(resource)
|
res, err := query.Search(resource)
|
||||||
|
@ -744,7 +747,7 @@ func Test_PathCanonicalize(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.jmesPath, func(t *testing.T) {
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.jmesPath)
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -793,7 +796,7 @@ func Test_Truncate(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.jmesPath, func(t *testing.T) {
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.jmesPath)
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -830,7 +833,7 @@ func Test_SemverCompare(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.jmesPath, func(t *testing.T) {
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.jmesPath)
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -877,7 +880,7 @@ func Test_Items(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
query, err := newJMESPath("items(`" + tc.object + "`,`" + tc.keyName + "`,`" + tc.valName + "`)")
|
query, err := newJMESPath(cfg, "items(`"+tc.object+"`,`"+tc.keyName+"`,`"+tc.valName+"`)")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search("")
|
res, err := query.Search("")
|
||||||
|
@ -928,7 +931,7 @@ func Test_ObjectFromLists(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
query, err := newJMESPath("object_from_lists(`" + tc.keys + "`,`" + tc.values + "`)")
|
query, err := newJMESPath(cfg, "object_from_lists(`"+tc.keys+"`,`"+tc.values+"`)")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
res, err := query.Search("")
|
res, err := query.Search("")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
@ -1022,7 +1025,7 @@ UFOZZVoELaasWS559wy8og39Eq21dDMynb8Bndn/
|
||||||
}}
|
}}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.jmesPath, func(t *testing.T) {
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
jp, err := newJMESPath(tc.jmesPath)
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
result, err := jp.Search("")
|
result, err := jp.Search("")
|
||||||
|
@ -1396,3 +1399,59 @@ func Test_jpfToLower(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ImageNormalize(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
jmesPath string
|
||||||
|
expectedResult string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
jmesPath: "image_normalize('nginx')",
|
||||||
|
expectedResult: "docker.io/nginx:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jmesPath: "image_normalize('docker.io/nginx')",
|
||||||
|
expectedResult: "docker.io/nginx:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jmesPath: "image_normalize('docker.io/library/nginx')",
|
||||||
|
expectedResult: "docker.io/library/nginx:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jmesPath: "image_normalize('ghcr.io/library/nginx')",
|
||||||
|
expectedResult: "ghcr.io/library/nginx:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jmesPath: "image_normalize('ghcr.io/nginx')",
|
||||||
|
expectedResult: "ghcr.io/nginx:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jmesPath: "image_normalize('ghcr.io/nginx:latest')",
|
||||||
|
expectedResult: "ghcr.io/nginx:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jmesPath: "image_normalize('ghcr.io/nginx:1.2')",
|
||||||
|
expectedResult: "ghcr.io/nginx:1.2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jmesPath: "image_normalize('')",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.jmesPath, func(t *testing.T) {
|
||||||
|
jp, err := newJMESPath(cfg, tc.jmesPath)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
result, err := jp.Search("")
|
||||||
|
if tc.wantErr {
|
||||||
|
assert.Error(t, err, "JMESPath function 'image_normalize': bad image: docker.io/: invalid reference format")
|
||||||
|
} else {
|
||||||
|
assert.NilError(t, err)
|
||||||
|
res, ok := result.(string)
|
||||||
|
assert.Assert(t, ok)
|
||||||
|
assert.Equal(t, res, tc.expectedResult)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ func New(configuration config.Configuration) Interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i implementation) Query(query string) (Query, error) {
|
func (i implementation) Query(query string) (Query, error) {
|
||||||
return newJMESPath(query)
|
return newJMESPath(i.configuration, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i implementation) Search(query string, data interface{}) (interface{}, error) {
|
func (i implementation) Search(query string, data interface{}) (interface{}, error) {
|
||||||
|
|
|
@ -2,14 +2,15 @@ package jmespath
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gojmespath "github.com/jmespath/go-jmespath"
|
gojmespath "github.com/jmespath/go-jmespath"
|
||||||
|
"github.com/kyverno/kyverno/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newJMESPath(query string) (*gojmespath.JMESPath, error) {
|
func newJMESPath(configuration config.Configuration, query string) (*gojmespath.JMESPath, error) {
|
||||||
jp, err := gojmespath.Compile(query)
|
jp, err := gojmespath.Compile(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, function := range GetFunctions() {
|
for _, function := range GetFunctions(configuration) {
|
||||||
jp.Register(function.FunctionEntry)
|
jp.Register(function.FunctionEntry)
|
||||||
}
|
}
|
||||||
return jp, nil
|
return jp, nil
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TestNew(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
_, err := newJMESPath(tt.args.query)
|
_, err := newJMESPath(cfg, tt.args.query)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
|
|
@ -25,7 +25,7 @@ func Test_TimeSince(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
query, err := newJMESPath(tc.test)
|
query, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search("")
|
res, err := query.Search("")
|
||||||
|
@ -55,7 +55,7 @@ func Test_TimeToCron(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
query, err := newJMESPath(tc.test)
|
query, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search("")
|
res, err := query.Search("")
|
||||||
|
@ -85,7 +85,7 @@ func Test_TimeAdd(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
query, err := newJMESPath(tc.test)
|
query, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search("")
|
res, err := query.Search("")
|
||||||
|
@ -115,7 +115,7 @@ func Test_TimeParse(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
query, err := newJMESPath(tc.test)
|
query, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search("")
|
res, err := query.Search("")
|
||||||
|
@ -145,7 +145,7 @@ func Test_TimeUtc(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
query, err := newJMESPath(tc.test)
|
query, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search("")
|
res, err := query.Search("")
|
||||||
|
@ -171,7 +171,7 @@ func Test_TimeDiff(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
query, err := newJMESPath(tc.test)
|
query, err := newJMESPath(cfg, tc.test)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
res, err := query.Search("")
|
res, err := query.Search("")
|
||||||
|
|
Loading…
Reference in a new issue