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:
hongzhouzi
2022-10-31 10:58:55 +08:00
committed by GitHub
parent 668fca1773
commit ef03b1e3df
363 changed files with 277341 additions and 13544 deletions

View File

@@ -93,11 +93,12 @@ func jsonRemove(a *ast.Term, b *ast.Term) (*ast.Term, error) {
return nil, err
}
return ast.NewTerm(newSet), nil
case ast.Array:
case *ast.Array:
// When indexes are removed we shift left to close empty spots in the array
// as per the JSON patch spec.
var newArray ast.Array
for i, v := range aValue {
newArray := ast.NewArray()
for i := 0; i < aValue.Len(); i++ {
v := aValue.Elem(i)
// recurse and add the diff of sub objects as needed
// Note: Keys in b will be strings for the index, eg path /a/1/b => {"a": {"1": {"b": null}}}
diffValue, err := jsonRemove(v, bObj.Get(ast.StringTerm(strconv.Itoa(i))))
@@ -105,7 +106,7 @@ func jsonRemove(a *ast.Term, b *ast.Term) (*ast.Term, error) {
return nil, err
}
if diffValue != nil {
newArray = append(newArray, diffValue)
newArray = newArray.Append(diffValue)
}
}
return ast.NewTerm(newArray), nil
@@ -142,9 +143,9 @@ func getJSONPaths(operand ast.Value) ([]ast.Ref, error) {
var paths []ast.Ref
switch v := operand.(type) {
case ast.Array:
for _, f := range v {
filter, err := parsePath(f)
case *ast.Array:
for i := 0; i < v.Len(); i++ {
filter, err := parsePath(v.Elem(i))
if err != nil {
return nil, err
}
@@ -175,15 +176,18 @@ func parsePath(path *ast.Term) (ast.Ref, error) {
var pathSegments ast.Ref
switch p := path.Value.(type) {
case ast.String:
parts := strings.Split(strings.Trim(string(p), "/"), "/")
if p == "" {
return ast.Ref{}, nil
}
parts := strings.Split(strings.TrimLeft(string(p), "/"), "/")
for _, part := range parts {
part = strings.ReplaceAll(strings.ReplaceAll(part, "~1", "/"), "~0", "~")
pathSegments = append(pathSegments, ast.StringTerm(part))
}
case ast.Array:
for _, term := range p {
case *ast.Array:
p.Foreach(func(term *ast.Term) {
pathSegments = append(pathSegments, term)
}
})
default:
return nil, builtins.NewOperandErr(2, "must be one of {set, array} containing string paths or array of path segments but got %v", ast.TypeName(p))
}
@@ -199,6 +203,12 @@ func pathsToObject(paths []ast.Ref) ast.Object {
node := root
var done bool
// If the path is an empty JSON path, skip all further processing.
if len(path) == 0 {
done = true
}
// Otherwise, we should have 1+ path segments to work with.
for i := 0; i < len(path)-1 && !done; i++ {
k := path[i]
@@ -229,7 +239,391 @@ func pathsToObject(paths []ast.Ref) ast.Object {
return root
}
// toIndex tries to convert path elements (that may be strings) into indices into
// an array.
func toIndex(arr *ast.Array, term *ast.Term) (int, error) {
i := 0
var ok bool
switch v := term.Value.(type) {
case ast.Number:
if i, ok = v.Int(); !ok {
return 0, fmt.Errorf("Invalid number type for indexing")
}
case ast.String:
if v == "-" {
return arr.Len(), nil
}
num := ast.Number(v)
if i, ok = num.Int(); !ok {
return 0, fmt.Errorf("Invalid string for indexing")
}
if v != "0" && strings.HasPrefix(string(v), "0") {
return 0, fmt.Errorf("Leading zeros are not allowed in JSON paths")
}
default:
return 0, fmt.Errorf("Invalid type for indexing")
}
return i, nil
}
// patchWorkerris a worker that modifies a direct child of a term located
// at the given key. It returns the new term, and optionally a result that
// is passed back to the caller.
type patchWorker = func(parent, key *ast.Term) (updated, result *ast.Term)
func jsonPatchTraverse(
target *ast.Term,
path ast.Ref,
worker patchWorker,
) (*ast.Term, *ast.Term) {
if len(path) < 1 {
return nil, nil
}
key := path[0]
if len(path) == 1 {
return worker(target, key)
}
success := false
var updated, result *ast.Term
switch parent := target.Value.(type) {
case ast.Object:
obj := ast.NewObject()
parent.Foreach(func(k, v *ast.Term) {
if k.Equal(key) {
if v, result = jsonPatchTraverse(v, path[1:], worker); v != nil {
obj.Insert(k, v)
success = true
}
} else {
obj.Insert(k, v)
}
})
updated = ast.NewTerm(obj)
case *ast.Array:
idx, err := toIndex(parent, key)
if err != nil {
return nil, nil
}
arr := ast.NewArray()
for i := 0; i < parent.Len(); i++ {
v := parent.Elem(i)
if idx == i {
if v, result = jsonPatchTraverse(v, path[1:], worker); v != nil {
arr = arr.Append(v)
success = true
}
} else {
arr = arr.Append(v)
}
}
updated = ast.NewTerm(arr)
case ast.Set:
set := ast.NewSet()
parent.Foreach(func(k *ast.Term) {
if k.Equal(key) {
if k, result = jsonPatchTraverse(k, path[1:], worker); k != nil {
set.Add(k)
success = true
}
} else {
set.Add(k)
}
})
updated = ast.NewTerm(set)
}
if success {
return updated, result
}
return nil, nil
}
// jsonPatchGet goes one step further than jsonPatchTraverse and returns the
// term at the location specified by the path. It is used in functions
// where we want to read a value but not manipulate its parent: for example
// jsonPatchTest and jsonPatchCopy.
//
// Because it uses jsonPatchTraverse, it makes shallow copies of the objects
// along the path. We could possibly add a signaling mechanism that we didn't
// make any changes to avoid this.
func jsonPatchGet(target *ast.Term, path ast.Ref) *ast.Term {
// Special case: get entire document.
if len(path) == 0 {
return target
}
_, result := jsonPatchTraverse(target, path, func(parent, key *ast.Term) (*ast.Term, *ast.Term) {
switch v := parent.Value.(type) {
case ast.Object:
return parent, v.Get(key)
case *ast.Array:
i, err := toIndex(v, key)
if err == nil {
return parent, v.Elem(i)
}
case ast.Set:
if v.Contains(key) {
return parent, key
}
}
return nil, nil
})
return result
}
func jsonPatchAdd(target *ast.Term, path ast.Ref, value *ast.Term) *ast.Term {
// Special case: replacing root document.
if len(path) == 0 {
return value
}
target, _ = jsonPatchTraverse(target, path, func(parent *ast.Term, key *ast.Term) (*ast.Term, *ast.Term) {
switch original := parent.Value.(type) {
case ast.Object:
obj := ast.NewObject()
original.Foreach(func(k, v *ast.Term) {
obj.Insert(k, v)
})
obj.Insert(key, value)
return ast.NewTerm(obj), nil
case *ast.Array:
idx, err := toIndex(original, key)
if err != nil || idx < 0 || idx > original.Len() {
return nil, nil
}
arr := ast.NewArray()
for i := 0; i < idx; i++ {
arr = arr.Append(original.Elem(i))
}
arr = arr.Append(value)
for i := idx; i < original.Len(); i++ {
arr = arr.Append(original.Elem(i))
}
return ast.NewTerm(arr), nil
case ast.Set:
if !key.Equal(value) {
return nil, nil
}
set := ast.NewSet()
original.Foreach(func(k *ast.Term) {
set.Add(k)
})
set.Add(key)
return ast.NewTerm(set), nil
}
return nil, nil
})
return target
}
func jsonPatchRemove(target *ast.Term, path ast.Ref) (*ast.Term, *ast.Term) {
// Special case: replacing root document.
if len(path) == 0 {
return nil, nil
}
target, removed := jsonPatchTraverse(target, path, func(parent *ast.Term, key *ast.Term) (*ast.Term, *ast.Term) {
var removed *ast.Term
switch original := parent.Value.(type) {
case ast.Object:
obj := ast.NewObject()
original.Foreach(func(k, v *ast.Term) {
if k.Equal(key) {
removed = v
} else {
obj.Insert(k, v)
}
})
return ast.NewTerm(obj), removed
case *ast.Array:
idx, err := toIndex(original, key)
if err != nil || idx < 0 || idx >= original.Len() {
return nil, nil
}
arr := ast.NewArray()
for i := 0; i < idx; i++ {
arr = arr.Append(original.Elem(i))
}
removed = original.Elem(idx)
for i := idx + 1; i < original.Len(); i++ {
arr = arr.Append(original.Elem(i))
}
return ast.NewTerm(arr), removed
case ast.Set:
set := ast.NewSet()
original.Foreach(func(k *ast.Term) {
if k.Equal(key) {
removed = k
} else {
set.Add(k)
}
})
return ast.NewTerm(set), removed
}
return nil, nil
})
if target != nil && removed != nil {
return target, removed
}
return nil, nil
}
func jsonPatchReplace(target *ast.Term, path ast.Ref, value *ast.Term) *ast.Term {
// Special case: replacing the whole document.
if len(path) == 0 {
return value
}
// Replace is specified as `remove` followed by `add`.
if target, _ = jsonPatchRemove(target, path); target == nil {
return nil
}
return jsonPatchAdd(target, path, value)
}
func jsonPatchMove(target *ast.Term, path ast.Ref, from ast.Ref) *ast.Term {
// Move is specified as `remove` followed by `add`.
target, removed := jsonPatchRemove(target, from)
if target == nil || removed == nil {
return nil
}
return jsonPatchAdd(target, path, removed)
}
func jsonPatchCopy(target *ast.Term, path ast.Ref, from ast.Ref) *ast.Term {
value := jsonPatchGet(target, from)
if value == nil {
return nil
}
return jsonPatchAdd(target, path, value)
}
func jsonPatchTest(target *ast.Term, path ast.Ref, value *ast.Term) *ast.Term {
actual := jsonPatchGet(target, path)
if actual == nil {
return nil
}
if actual.Equal(value) {
return target
}
return nil
}
func builtinJSONPatch(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
// JSON patch supports arrays, objects as well as values as the target.
target := ast.NewTerm(operands[0].Value)
// Expect an array of operations.
operations, err := builtins.ArrayOperand(operands[1].Value, 2)
if err != nil {
return err
}
// Apply operations one by one.
for i := 0; i < operations.Len(); i++ {
if object, ok := operations.Elem(i).Value.(ast.Object); ok {
getAttribute := func(attr string) (*ast.Term, error) {
if term := object.Get(ast.StringTerm(attr)); term != nil {
return term, nil
}
return nil, builtins.NewOperandErr(2, fmt.Sprintf("patch is missing '%s' attribute", attr))
}
getPathAttribute := func(attr string) (ast.Ref, error) {
term, err := getAttribute(attr)
if err != nil {
return ast.Ref{}, err
}
path, err := parsePath(term)
if err != nil {
return ast.Ref{}, err
}
return path, nil
}
// Parse operation.
opTerm, err := getAttribute("op")
if err != nil {
return err
}
op, ok := opTerm.Value.(ast.String)
if !ok {
return builtins.NewOperandErr(2, "patch attribute 'op' must be a string")
}
// Parse path.
path, err := getPathAttribute("path")
if err != nil {
return err
}
switch op {
case "add":
value, err := getAttribute("value")
if err != nil {
return err
}
target = jsonPatchAdd(target, path, value)
case "remove":
target, _ = jsonPatchRemove(target, path)
case "replace":
value, err := getAttribute("value")
if err != nil {
return err
}
target = jsonPatchReplace(target, path, value)
case "move":
from, err := getPathAttribute("from")
if err != nil {
return err
}
target = jsonPatchMove(target, path, from)
case "copy":
from, err := getPathAttribute("from")
if err != nil {
return err
}
target = jsonPatchCopy(target, path, from)
case "test":
value, err := getAttribute("value")
if err != nil {
return err
}
target = jsonPatchTest(target, path, value)
default:
return builtins.NewOperandErr(2, "must be an array of JSON-Patch objects")
}
} else {
return builtins.NewOperandErr(2, "must be an array of JSON-Patch objects")
}
// JSON patches should work atomically; and if one of them fails,
// we should not try to continue.
if target == nil {
return nil
}
}
return iter(target)
}
func init() {
RegisterBuiltinFunc(ast.JSONFilter.Name, builtinJSONFilter)
RegisterBuiltinFunc(ast.JSONRemove.Name, builtinJSONRemove)
RegisterBuiltinFunc(ast.JSONPatch.Name, builtinJSONPatch)
}