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:
142
vendor/github.com/open-policy-agent/opa/topdown/reachable.go
generated
vendored
Normal file
142
vendor/github.com/open-policy-agent/opa/topdown/reachable.go
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2020 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package topdown
|
||||
|
||||
import (
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/topdown/builtins"
|
||||
)
|
||||
|
||||
// Helper: sets of vertices can be represented as Arrays or Sets.
|
||||
func foreachVertex(collection *ast.Term, f func(*ast.Term)) {
|
||||
switch v := collection.Value.(type) {
|
||||
case ast.Set:
|
||||
v.Foreach(f)
|
||||
case *ast.Array:
|
||||
v.Foreach(f)
|
||||
}
|
||||
}
|
||||
|
||||
// numberOfEdges returns the number of elements of an array or a set (of edges)
|
||||
func numberOfEdges(collection *ast.Term) int {
|
||||
switch v := collection.Value.(type) {
|
||||
case ast.Set:
|
||||
return v.Len()
|
||||
case *ast.Array:
|
||||
return v.Len()
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func builtinReachable(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error {
|
||||
// Error on wrong types for args.
|
||||
graph, err := builtins.ObjectOperand(args[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var queue []*ast.Term
|
||||
switch initial := args[1].Value.(type) {
|
||||
case *ast.Array, ast.Set:
|
||||
foreachVertex(ast.NewTerm(initial), func(t *ast.Term) {
|
||||
queue = append(queue, t)
|
||||
})
|
||||
default:
|
||||
return builtins.NewOperandTypeErr(2, initial, "{array, set}")
|
||||
}
|
||||
|
||||
// This is the set of nodes we have reached.
|
||||
reached := ast.NewSet()
|
||||
|
||||
// Keep going as long as we have nodes in the queue.
|
||||
for len(queue) > 0 {
|
||||
// Get the edges for this node. If the node was not in the graph,
|
||||
// `edges` will be `nil` and we can ignore it.
|
||||
node := queue[0]
|
||||
if edges := graph.Get(node); edges != nil {
|
||||
// Add all the newly discovered neighbors.
|
||||
foreachVertex(edges, func(neighbor *ast.Term) {
|
||||
if !reached.Contains(neighbor) {
|
||||
queue = append(queue, neighbor)
|
||||
}
|
||||
})
|
||||
// Mark the node as reached.
|
||||
reached.Add(node)
|
||||
}
|
||||
queue = queue[1:]
|
||||
}
|
||||
|
||||
return iter(ast.NewTerm(reached))
|
||||
}
|
||||
|
||||
// pathBuilder is called recursively to build an array of paths that are reachable from the root
|
||||
func pathBuilder(graph ast.Object, root *ast.Term, path []*ast.Term, paths []*ast.Term, reached ast.Set) []*ast.Term {
|
||||
if edges := graph.Get(root); edges != nil {
|
||||
path = append(path, root)
|
||||
|
||||
if numberOfEdges(edges) >= 1 {
|
||||
foreachVertex(edges, func(neighbor *ast.Term) {
|
||||
if reached.Contains(neighbor) {
|
||||
// If we've already reached this node, return current path (avoid infinite recursion)
|
||||
paths = append(paths, path...)
|
||||
} else {
|
||||
reached.Add(root)
|
||||
paths = pathBuilder(graph, neighbor, path, paths, reached)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
paths = append(paths, path...)
|
||||
}
|
||||
} else {
|
||||
// Node is nonexistent (not in graph). Commit the current path (without adding this root)
|
||||
paths = append(paths, path...)
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
func builtinReachablePaths(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error {
|
||||
// Error on wrong types for args.
|
||||
graph, err := builtins.ObjectOperand(args[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This is a queue that holds all nodes we still need to visit. It is
|
||||
// initialised to the initial set of nodes we start out with.
|
||||
var queue []*ast.Term
|
||||
switch initial := args[1].Value.(type) {
|
||||
case *ast.Array, ast.Set:
|
||||
foreachVertex(ast.NewTerm(initial), func(t *ast.Term) {
|
||||
queue = append(queue, t)
|
||||
})
|
||||
default:
|
||||
return builtins.NewOperandTypeErr(2, initial, "{array, set}")
|
||||
}
|
||||
|
||||
results := ast.NewSet()
|
||||
|
||||
for _, node := range queue {
|
||||
// Find reachable paths from edges in root node in queue and append arrays to the results set
|
||||
if edges := graph.Get(node); edges != nil {
|
||||
if numberOfEdges(edges) >= 1 {
|
||||
foreachVertex(edges, func(neighbor *ast.Term) {
|
||||
paths := pathBuilder(graph, neighbor, []*ast.Term{node}, []*ast.Term{}, ast.NewSet(node))
|
||||
results.Add(ast.ArrayTerm(paths...))
|
||||
})
|
||||
} else {
|
||||
results.Add(ast.ArrayTerm(node))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iter(ast.NewTerm(results))
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterBuiltinFunc(ast.ReachableBuiltin.Name, builtinReachable)
|
||||
RegisterBuiltinFunc(ast.ReachablePathsBuiltin.Name, builtinReachablePaths)
|
||||
}
|
||||
Reference in New Issue
Block a user