1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-01-20 18:52:16 +00:00
kyverno/pkg/engine/utils/foreach.go
Vishal Choudhary 3af0e461f0
fix: deepcopy patched resource in foreach mutate (#10252)
* fix: deepcopy patched resource to avoid indirect reversal of its elements

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: copy elements while reversing

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: copy resources inside foreach

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* add test

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* add test

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

---------

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>
Signed-off-by: Jim Bugwadia <jim@nirmata.com>
Co-authored-by: Jim Bugwadia <jim@nirmata.com>
2024-05-20 14:45:21 +08:00

66 lines
2 KiB
Go

package utils
import (
"fmt"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jsonutils"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func EvaluateList(jmesPath string, ctx enginecontext.EvalInterface) ([]interface{}, error) {
i, err := ctx.Query(jmesPath)
if err != nil {
return nil, err
}
l, ok := i.([]interface{})
if !ok {
return []interface{}{i}, nil
}
return l, nil
}
// InvertElements inverts the order of elements for patchStrategicMerge policies
// as kustomize patch reverses the order of patch resources.
func InvertElements(elements []interface{}) []interface{} {
elementsCopy := make([]interface{}, len(elements))
for i := range elements {
elementsCopy[i] = elements[len(elements)-i-1]
}
return elementsCopy
}
func AddElementToContext(ctx engineapi.PolicyContext, element interface{}, index, nesting int, elementScope *bool) error {
data, err := jsonutils.DocumentToUntyped(element)
if err != nil {
return err
}
if err := ctx.JSONContext().AddElement(data, index, nesting); err != nil {
return fmt.Errorf("failed to add element (%v) to JSON context: %w", element, err)
}
dataMap, ok := data.(map[string]interface{})
// We set scoped to true by default if the data is a map
// otherwise we do not do element scoped foreach unless the user
// has explicitly set it to true
scoped := ok
// If the user has explicitly provided an element scope
// we check if data is a map or not. In case it is not a map and the user
// has set elementscoped to true, we throw an error.
// Otherwise we set the value to what is specified by the user.
if elementScope != nil {
if *elementScope && !ok {
return fmt.Errorf("cannot use elementScope=true foreach rules for elements that are not maps, expected type=map got type=%T", data)
}
scoped = *elementScope
}
if scoped {
u := unstructured.Unstructured{}
u.SetUnstructuredContent(dataMap)
ctx.SetElement(u)
}
return nil
}