Upgrade dependent version: github.com/open-policy-agent/opa (#5315)
Upgrade dependent version: github.com/open-policy-agent/opa v0.18.0 -> v0.45.0 Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io>
This commit is contained in:
94
vendor/github.com/open-policy-agent/opa/topdown/object.go
generated
vendored
94
vendor/github.com/open-policy-agent/opa/topdown/object.go
generated
vendored
@@ -6,8 +6,8 @@ package topdown
|
||||
|
||||
import (
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/internal/ref"
|
||||
"github.com/open-policy-agent/opa/topdown/builtins"
|
||||
"github.com/open-policy-agent/opa/types"
|
||||
)
|
||||
|
||||
func builtinObjectUnion(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
@@ -26,6 +26,38 @@ func builtinObjectUnion(_ BuiltinContext, operands []*ast.Term, iter func(*ast.T
|
||||
return iter(ast.NewTerm(r))
|
||||
}
|
||||
|
||||
func builtinObjectUnionN(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
arr, err := builtins.ArrayOperand(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Because we need merge-with-overwrite behavior, we can iterate
|
||||
// back-to-front, and get a mostly correct set of key assignments that
|
||||
// give us the "last assignment wins, with merges" behavior we want.
|
||||
// However, if a non-object overwrites an object value anywhere in the
|
||||
// chain of assignments for a key, we have to "freeze" that key to
|
||||
// prevent accidentally picking up nested objects that could merge with
|
||||
// it from earlier in the input array.
|
||||
// Example:
|
||||
// Input: [{"a": {"b": 2}}, {"a": 4}, {"a": {"c": 3}}]
|
||||
// Want Output: {"a": {"c": 3}}
|
||||
result := ast.NewObject()
|
||||
frozenKeys := map[*ast.Term]struct{}{}
|
||||
for i := arr.Len() - 1; i >= 0; i-- {
|
||||
o, ok := arr.Elem(i).Value.(ast.Object)
|
||||
if !ok {
|
||||
return builtins.NewOperandElementErr(1, arr, arr.Elem(i).Value, "object")
|
||||
}
|
||||
mergewithOverwriteInPlace(result, o, frozenKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return iter(ast.NewTerm(result))
|
||||
}
|
||||
|
||||
func builtinObjectRemove(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
// Expect an object and an array/set/object of keys
|
||||
obj, err := builtins.ObjectOperand(operands[0].Value, 1)
|
||||
@@ -81,11 +113,29 @@ func builtinObjectGet(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Ter
|
||||
return err
|
||||
}
|
||||
|
||||
if ret := object.Get(operands[1]); ret != nil {
|
||||
return iter(ret)
|
||||
// if the get key is not an array, attempt to get the top level key for the operand value in the object
|
||||
path, err := builtins.ArrayOperand(operands[1].Value, 2)
|
||||
if err != nil {
|
||||
if ret := object.Get(operands[1]); ret != nil {
|
||||
return iter(ret)
|
||||
}
|
||||
|
||||
return iter(operands[2])
|
||||
}
|
||||
|
||||
return iter(operands[2])
|
||||
// if the path is empty, then we skip selecting nested keys and return the whole object
|
||||
if path.Len() == 0 {
|
||||
return iter(operands[0])
|
||||
}
|
||||
|
||||
// build an ast.Ref from the array and see if it matches within the object
|
||||
pathRef := ref.ArrayPath(path)
|
||||
value, err := object.Find(pathRef)
|
||||
if err != nil {
|
||||
return iter(operands[2])
|
||||
}
|
||||
|
||||
return iter(ast.NewTerm(value))
|
||||
}
|
||||
|
||||
// getObjectKeysParam returns a set of key values
|
||||
@@ -94,10 +144,11 @@ func getObjectKeysParam(arrayOrSet ast.Value) (ast.Set, error) {
|
||||
keys := ast.NewSet()
|
||||
|
||||
switch v := arrayOrSet.(type) {
|
||||
case ast.Array:
|
||||
for _, f := range v {
|
||||
case *ast.Array:
|
||||
_ = v.Iter(func(f *ast.Term) error {
|
||||
keys.Add(f)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
case ast.Set:
|
||||
_ = v.Iter(func(f *ast.Term) error {
|
||||
keys.Add(f)
|
||||
@@ -109,7 +160,7 @@ func getObjectKeysParam(arrayOrSet ast.Value) (ast.Set, error) {
|
||||
return nil
|
||||
})
|
||||
default:
|
||||
return nil, builtins.NewOperandTypeErr(2, arrayOrSet, ast.TypeName(types.Object{}), ast.TypeName(types.S), ast.TypeName(types.Array{}))
|
||||
return nil, builtins.NewOperandTypeErr(2, arrayOrSet, "object", "set", "array")
|
||||
}
|
||||
|
||||
return keys, nil
|
||||
@@ -131,8 +182,35 @@ func mergeWithOverwrite(objA, objB ast.Object) ast.Object {
|
||||
return merged
|
||||
}
|
||||
|
||||
// Modifies obj with any new keys from other, and recursively
|
||||
// merges any keys where the values are both objects.
|
||||
func mergewithOverwriteInPlace(obj, other ast.Object, frozenKeys map[*ast.Term]struct{}) {
|
||||
other.Foreach(func(k, v *ast.Term) {
|
||||
v2 := obj.Get(k)
|
||||
// The key didn't exist in other, keep the original value.
|
||||
if v2 == nil {
|
||||
obj.Insert(k, v)
|
||||
return
|
||||
}
|
||||
// The key exists in both. Merge or reject change.
|
||||
updateValueObj, ok2 := v.Value.(ast.Object)
|
||||
originalValueObj, ok1 := v2.Value.(ast.Object)
|
||||
// Both are objects? Merge recursively.
|
||||
if ok1 && ok2 {
|
||||
// Check to make sure that this key isn't frozen before merging.
|
||||
if _, ok := frozenKeys[v2]; !ok {
|
||||
mergewithOverwriteInPlace(originalValueObj, updateValueObj, frozenKeys)
|
||||
}
|
||||
} else {
|
||||
// Else, original value wins. Freeze the key.
|
||||
frozenKeys[v2] = struct{}{}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterBuiltinFunc(ast.ObjectUnion.Name, builtinObjectUnion)
|
||||
RegisterBuiltinFunc(ast.ObjectUnionN.Name, builtinObjectUnionN)
|
||||
RegisterBuiltinFunc(ast.ObjectRemove.Name, builtinObjectRemove)
|
||||
RegisterBuiltinFunc(ast.ObjectFilter.Name, builtinObjectFilter)
|
||||
RegisterBuiltinFunc(ast.ObjectGet.Name, builtinObjectGet)
|
||||
|
||||
Reference in New Issue
Block a user