diff --git a/pkg/engine/mutate/expression.go b/pkg/engine/mutate/expression.go deleted file mode 100644 index 4949a6f9..00000000 --- a/pkg/engine/mutate/expression.go +++ /dev/null @@ -1,65 +0,0 @@ -package mutate - -import ( - "context" - "reflect" - "regexp" - - reflectutils "github.com/kyverno/kyverno-json/pkg/utils/reflect" -) - -var ( - foreachRegex = regexp.MustCompile(`^~(\w+)?\.(.*)`) - bindingRegex = regexp.MustCompile(`(.*)\s*->\s*(\w+)$`) - escapeRegex = regexp.MustCompile(`^\\(.+)\\$`) - engineRegex = regexp.MustCompile(`^\((?:(\w+):)?(.+)\)$`) -) - -type expression struct { - foreach bool - foreachName string - statement string - binding string - engine string -} - -func parseExpressionRegex(ctx context.Context, in string) *expression { - expression := &expression{} - // 1. match foreach - if match := foreachRegex.FindStringSubmatch(in); match != nil { - expression.foreach = true - expression.foreachName = match[1] - in = match[2] - } - // 2. match binding - if match := bindingRegex.FindStringSubmatch(in); match != nil { - expression.binding = match[2] - in = match[1] - } - // 3. match escape, if there's no escaping then match engine - if match := escapeRegex.FindStringSubmatch(in); match != nil { - in = match[1] - } else { - if match := engineRegex.FindStringSubmatch(in); match != nil { - expression.engine = match[1] - // account for default engine - if expression.engine == "" { - expression.engine = "jp" - } - in = match[2] - } - } - // parse statement - expression.statement = in - if expression.statement == "" { - return nil - } - return expression -} - -func parseExpression(ctx context.Context, value any) *expression { - if reflectutils.GetKind(value) != reflect.String { - return nil - } - return parseExpressionRegex(ctx, reflect.ValueOf(value).String()) -} diff --git a/pkg/engine/mutate/mutate.go b/pkg/engine/mutate/mutate.go deleted file mode 100644 index 9224e4a5..00000000 --- a/pkg/engine/mutate/mutate.go +++ /dev/null @@ -1,13 +0,0 @@ -package mutate - -import ( - "context" - - "github.com/jmespath-community/go-jmespath/pkg/binding" - "github.com/kyverno/kyverno-json/pkg/engine/template" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -func Mutate(ctx context.Context, path *field.Path, mutation Mutation, value any, bindings binding.Bindings, opts ...template.Option) (any, error) { - return mutation.mutate(ctx, path, value, bindings, opts...) -} diff --git a/pkg/engine/mutate/mutation.go b/pkg/engine/mutate/mutation.go deleted file mode 100644 index b712f1d1..00000000 --- a/pkg/engine/mutate/mutation.go +++ /dev/null @@ -1,13 +0,0 @@ -package mutate - -import ( - "context" - - "github.com/jmespath-community/go-jmespath/pkg/binding" - "github.com/kyverno/kyverno-json/pkg/engine/template" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -type Mutation interface { - mutate(context.Context, *field.Path, any, binding.Bindings, ...template.Option) (any, error) -} diff --git a/pkg/engine/mutate/parse.go b/pkg/engine/mutate/parse.go deleted file mode 100644 index 2b8e1b4d..00000000 --- a/pkg/engine/mutate/parse.go +++ /dev/null @@ -1,112 +0,0 @@ -package mutate - -import ( - "context" - "fmt" - "reflect" - - "github.com/jmespath-community/go-jmespath/pkg/binding" - "github.com/kyverno/kyverno-json/pkg/engine/template" - reflectutils "github.com/kyverno/kyverno-json/pkg/utils/reflect" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -func Parse(ctx context.Context, mutation any) Mutation { - switch reflectutils.GetKind(mutation) { - case reflect.Slice: - node := sliceNode{} - valueOf := reflect.ValueOf(mutation) - for i := 0; i < valueOf.Len(); i++ { - node = append(node, Parse(ctx, valueOf.Index(i).Interface())) - } - return node - case reflect.Map: - node := mapNode{} - iter := reflect.ValueOf(mutation).MapRange() - for iter.Next() { - node[iter.Key().Interface()] = Parse(ctx, iter.Value().Interface()) - } - return node - default: - return &scalarNode{rhs: mutation} - } -} - -// mapNode is the mutation type represented by a map. -// it is responsible for projecting the analysed resource and passing the result to the descendant -type mapNode map[any]Mutation - -func (n mapNode) mutate(ctx context.Context, path *field.Path, value any, bindings binding.Bindings, opts ...template.Option) (any, error) { - out := map[any]any{} - for k, v := range n { - var projection any - if value != nil { - mapValue := reflect.ValueOf(value).MapIndex(reflect.ValueOf(k)) - if mapValue.IsValid() { - projection = mapValue.Interface() - } - } - inner, err := v.mutate(ctx, path.Child(fmt.Sprint(k)), projection, bindings, opts...) - if err != nil { - return nil, err - } - out[k] = inner - } - return out, nil -} - -// sliceNode is the mutation type represented by a slice. -// it first compares the length of the analysed resource with the length of the descendants. -// if lengths match all descendants are evaluated with their corresponding items. -type sliceNode []Mutation - -func (n sliceNode) mutate(ctx context.Context, path *field.Path, value any, bindings binding.Bindings, opts ...template.Option) (any, error) { - if value != nil && reflectutils.GetKind(value) != reflect.Slice && reflectutils.GetKind(value) != reflect.Array { - return nil, field.TypeInvalid(path, value, "expected a slice or array") - } else { - var out []any - for i := range n { - var projection any - if value != nil { - valueOf := reflect.ValueOf(value) - if i < valueOf.Len() { - projection = valueOf.Index(i).Interface() - } - } - inner, err := n[i].mutate(ctx, path.Index(i), projection, bindings, opts...) - if err != nil { - return nil, err - } - out = append(out, inner) - } - return out, nil - } -} - -// scalarNode is a terminal type of mutation. -// it receives a value and compares it with an expected value. -// the expected value can be the result of an expression. -type scalarNode struct { - rhs any -} - -func (n *scalarNode) mutate(ctx context.Context, path *field.Path, value any, bindings binding.Bindings, opts ...template.Option) (any, error) { - rhs := n.rhs - expression := parseExpression(ctx, rhs) - // we only project if the expression uses the engine syntax - // this is to avoid the case where the value is a map and the RHS is a string - if expression != nil && expression.engine != "" { - if expression.foreachName != "" { - return nil, field.Invalid(path, rhs, "foreach is not supported on the RHS") - } - if expression.binding != "" { - return nil, field.Invalid(path, rhs, "binding is not supported on the RHS") - } - projected, err := template.Execute(ctx, expression.statement, value, bindings, opts...) - if err != nil { - return nil, field.InternalError(path, err) - } - rhs = projected - } - return rhs, nil -} diff --git a/pkg/engine/mutate/project.go b/pkg/engine/mutate/project.go deleted file mode 100644 index b3f0f60d..00000000 --- a/pkg/engine/mutate/project.go +++ /dev/null @@ -1,63 +0,0 @@ -package mutate - -// import ( -// "context" -// "reflect" - -// "github.com/jmespath-community/go-jmespath/pkg/binding" -// "github.com/kyverno/kyverno-json/pkg/engine/template" -// reflectutils "github.com/kyverno/kyverno-json/pkg/utils/reflect" -// ) - -// type projection struct { -// foreach bool -// foreachName string -// binding string -// result any -// } - -// func project(ctx context.Context, key any, value any, bindings binding.Bindings, opts ...template.Option) (*projection, error) { -// expression := parseExpression(ctx, key) -// if expression != nil { -// if expression.engine != "" { -// projected, err := template.Execute(ctx, expression.statement, value, bindings, opts...) -// if err != nil { -// return nil, err -// } -// return &projection{ -// foreach: expression.foreach, -// foreachName: expression.foreachName, -// binding: expression.binding, -// result: projected, -// }, nil -// } else { -// if reflectutils.GetKind(value) == reflect.Map { -// mapValue := reflect.ValueOf(value).MapIndex(reflect.ValueOf(expression.statement)) -// var value any -// if mapValue.IsValid() { -// value = mapValue.Interface() -// } -// return &projection{ -// foreach: expression.foreach, -// foreachName: expression.foreachName, -// binding: expression.binding, -// result: value, -// }, nil -// } -// } -// } -// if reflectutils.GetKind(value) == reflect.Map { -// mapValue := reflect.ValueOf(value).MapIndex(reflect.ValueOf(key)) -// var value any -// if mapValue.IsValid() { -// value = mapValue.Interface() -// } -// return &projection{ -// result: value, -// }, nil -// } -// // TODO is this an error ? -// return &projection{ -// result: value, -// }, nil -// }