mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
fix: foreach list validation (#11222)
Signed-off-by: airycanon <airycanon@airycanon.me>
This commit is contained in:
parent
819d9bf540
commit
7763ff72cf
2 changed files with 84 additions and 0 deletions
|
@ -9,12 +9,22 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// EvaluateList evaluates the context using the given JMESPath expression and returns a unified slice of interfaces.
|
||||
func EvaluateList(jmesPath string, ctx enginecontext.EvalInterface) ([]interface{}, error) {
|
||||
i, err := ctx.Query(jmesPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m, ok := i.([]map[string]interface{})
|
||||
if ok {
|
||||
l := make([]interface{}, 0, len(m))
|
||||
for _, e := range m {
|
||||
l = append(l, e)
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
l, ok := i.([]interface{})
|
||||
if !ok {
|
||||
return []interface{}{i}, nil
|
||||
|
|
|
@ -3,6 +3,9 @@ package utils
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -14,3 +17,74 @@ func Test_InvertElements(t *testing.T) {
|
|||
assert.Equal(t, "b", elemsInverted[1])
|
||||
assert.Equal(t, "c", elemsInverted[0])
|
||||
}
|
||||
|
||||
func Test_EvaluateList(t *testing.T) {
|
||||
entryName := "test_object"
|
||||
cases := []struct {
|
||||
name string
|
||||
rawData []byte
|
||||
jmesPath string
|
||||
expected interface{}
|
||||
}{
|
||||
{
|
||||
name: "slice data",
|
||||
rawData: []byte(`["test-value-1", "test-value-2"]`),
|
||||
jmesPath: entryName,
|
||||
expected: []interface{}{"test-value-1", "test-value-2"},
|
||||
},
|
||||
{
|
||||
name: "map data",
|
||||
rawData: []byte(`
|
||||
{
|
||||
"test-key-1": "test-value-1",
|
||||
"test-key-2": "test-value-2"
|
||||
}
|
||||
`),
|
||||
jmesPath: entryName + ".items(@, 'key', 'value')",
|
||||
expected: []interface{}{
|
||||
map[string]interface{}{
|
||||
"key": "test-key-1",
|
||||
"value": "test-value-1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"key": "test-key-2",
|
||||
"value": "test-value-2",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "map data with custom fields",
|
||||
rawData: []byte(`
|
||||
{
|
||||
"test-key-1": "test-value-1",
|
||||
"test-key-2": "test-value-2"
|
||||
}
|
||||
`),
|
||||
jmesPath: "test_object.items(@, 'another-key', 'another-value')",
|
||||
expected: []interface{}{
|
||||
map[string]interface{}{
|
||||
"another-key": "test-key-1",
|
||||
"another-value": "test-value-1",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"another-key": "test-key-2",
|
||||
"another-value": "test-value-2",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cfg := config.NewDefaultConfiguration(false)
|
||||
jp := jmespath.New(cfg)
|
||||
|
||||
for _, item := range cases {
|
||||
t.Run(item.name, func(t *testing.T) {
|
||||
ctx := context.NewContext(jp)
|
||||
assert.NoError(t, ctx.AddContextEntry(entryName, item.rawData))
|
||||
|
||||
list, err := EvaluateList(item.jmesPath, ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, item.expected, list)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue