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

@@ -2,13 +2,20 @@ package topdown
import (
"context"
"crypto/rand"
"io"
"sort"
"time"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/metrics"
"github.com/open-policy-agent/opa/resolver"
"github.com/open-policy-agent/opa/storage"
"github.com/open-policy-agent/opa/topdown/builtins"
"github.com/open-policy-agent/opa/topdown/cache"
"github.com/open-policy-agent/opa/topdown/copypropagation"
"github.com/open-policy-agent/opa/topdown/print"
"github.com/open-policy-agent/opa/tracing"
)
// QueryResultSet represents a collection of results returned by a query.
@@ -20,23 +27,35 @@ type QueryResult map[ast.Var]*ast.Term
// Query provides a configurable interface for performing query evaluation.
type Query struct {
cancel Cancel
query ast.Body
queryCompiler ast.QueryCompiler
compiler *ast.Compiler
store storage.Store
txn storage.Transaction
input *ast.Term
tracers []Tracer
unknowns []*ast.Term
partialNamespace string
metrics metrics.Metrics
instr *Instrumentation
disableInlining []ast.Ref
genvarprefix string
runtime *ast.Term
builtins map[string]*Builtin
indexing bool
seed io.Reader
time time.Time
cancel Cancel
query ast.Body
queryCompiler ast.QueryCompiler
compiler *ast.Compiler
store storage.Store
txn storage.Transaction
input *ast.Term
external *resolverTrie
tracers []QueryTracer
plugTraceVars bool
unknowns []*ast.Term
partialNamespace string
skipSaveNamespace bool
metrics metrics.Metrics
instr *Instrumentation
disableInlining []ast.Ref
shallowInlining bool
genvarprefix string
runtime *ast.Term
builtins map[string]*Builtin
indexing bool
earlyExit bool
interQueryBuiltinCache cache.InterQueryCache
ndBuiltinCache builtins.NDBCache
strictBuiltinErrors bool
printHook print.Hook
tracingOpts tracing.Options
}
// Builtin represents a built-in function that queries can call.
@@ -51,6 +70,8 @@ func NewQuery(query ast.Body) *Query {
query: query,
genvarprefix: ast.WildcardPrefix,
indexing: true,
earlyExit: true,
external: newResolverTrie(),
}
}
@@ -94,8 +115,31 @@ func (q *Query) WithInput(input *ast.Term) *Query {
}
// WithTracer adds a query tracer to use during evaluation. This is optional.
// Deprecated: Use WithQueryTracer instead.
func (q *Query) WithTracer(tracer Tracer) *Query {
qt, ok := tracer.(QueryTracer)
if !ok {
qt = WrapLegacyTracer(tracer)
}
return q.WithQueryTracer(qt)
}
// WithQueryTracer adds a query tracer to use during evaluation. This is optional.
// Disabled QueryTracers will be ignored.
func (q *Query) WithQueryTracer(tracer QueryTracer) *Query {
if !tracer.Enabled() {
return q
}
q.tracers = append(q.tracers, tracer)
// If *any* of the tracers require local variable metadata we need to
// enabled plugging local trace variables.
conf := tracer.Config()
if conf.PlugLocalVars {
q.plugTraceVars = true
}
return q
}
@@ -128,6 +172,13 @@ func (q *Query) WithPartialNamespace(ns string) *Query {
return q
}
// WithSkipPartialNamespace disables namespacing of saved support rules that are generated
// from the original policy (rules which are completely synthetic are still namespaced.)
func (q *Query) WithSkipPartialNamespace(yes bool) *Query {
q.skipSaveNamespace = yes
return q
}
// WithDisableInlining adds a set of paths to the query that should be excluded from
// inlining. Inlining during partial evaluation can be expensive in some cases
// (e.g., when a cross-product is computed.) Disabling inlining avoids expensive
@@ -137,6 +188,14 @@ func (q *Query) WithDisableInlining(paths []ast.Ref) *Query {
return q
}
// WithShallowInlining disables aggressive inlining performed during partial evaluation.
// When shallow inlining is enabled rules that depend (transitively) on unknowns are not inlined.
// Only rules/values that are completely known will be inlined.
func (q *Query) WithShallowInlining(yes bool) *Query {
q.shallowInlining = yes
return q
}
// WithRuntime sets the runtime data to execute the query with. The runtime data
// can be returned by the `opa.runtime` built-in function.
func (q *Query) WithRuntime(runtime *ast.Term) *Query {
@@ -158,6 +217,61 @@ func (q *Query) WithIndexing(enabled bool) *Query {
return q
}
// WithEarlyExit will enable or disable using 'early exit' for the evaluation
// of the query. The default is enabled.
func (q *Query) WithEarlyExit(enabled bool) *Query {
q.earlyExit = enabled
return q
}
// WithSeed sets a reader that will seed randomization required by built-in functions.
// If a seed is not provided crypto/rand.Reader is used.
func (q *Query) WithSeed(r io.Reader) *Query {
q.seed = r
return q
}
// WithTime sets the time that will be returned by the time.now_ns() built-in function.
func (q *Query) WithTime(x time.Time) *Query {
q.time = x
return q
}
// WithInterQueryBuiltinCache sets the inter-query cache that built-in functions can utilize.
func (q *Query) WithInterQueryBuiltinCache(c cache.InterQueryCache) *Query {
q.interQueryBuiltinCache = c
return q
}
// WithNDBuiltinCache sets the non-deterministic builtin cache.
func (q *Query) WithNDBuiltinCache(c builtins.NDBCache) *Query {
q.ndBuiltinCache = c
return q
}
// WithStrictBuiltinErrors tells the evaluator to treat all built-in function errors as fatal errors.
func (q *Query) WithStrictBuiltinErrors(yes bool) *Query {
q.strictBuiltinErrors = yes
return q
}
// WithResolver configures an external resolver to use for the given ref.
func (q *Query) WithResolver(ref ast.Ref, r resolver.Resolver) *Query {
q.external.Put(ref, r)
return q
}
func (q *Query) WithPrintHook(h print.Hook) *Query {
q.printHook = h
return q
}
// WithDistributedTracingOpts sets the options to be used by distributed tracing.
func (q *Query) WithDistributedTracingOpts(tr tracing.Options) *Query {
q.tracingOpts = tr
return q
}
// PartialRun executes partial evaluation on the query with respect to unknown
// values. Partial evaluation attempts to evaluate as much of the query as
// possible without requiring values for the unknowns set on the query. The
@@ -169,45 +283,79 @@ func (q *Query) PartialRun(ctx context.Context) (partials []ast.Body, support []
if q.partialNamespace == "" {
q.partialNamespace = "partial" // lazily initialize partial namespace
}
if q.seed == nil {
q.seed = rand.Reader
}
if !q.time.IsZero() {
q.time = time.Now()
}
if q.metrics == nil {
q.metrics = metrics.New()
}
f := &queryIDFactory{}
b := newBindings(0, q.instr)
e := &eval{
ctx: ctx,
cancel: q.cancel,
query: q.query,
queryCompiler: q.queryCompiler,
queryIDFact: f,
queryID: f.Next(),
bindings: b,
compiler: q.compiler,
store: q.store,
baseCache: newBaseCache(),
targetStack: newRefStack(),
txn: q.txn,
input: q.input,
tracers: q.tracers,
instr: q.instr,
builtins: q.builtins,
builtinCache: builtins.Cache{},
virtualCache: newVirtualCache(),
saveSet: newSaveSet(q.unknowns, b, q.instr),
saveStack: newSaveStack(),
saveSupport: newSaveSupport(),
saveNamespace: ast.StringTerm(q.partialNamespace),
ctx: ctx,
metrics: q.metrics,
seed: q.seed,
time: ast.NumberTerm(int64ToJSONNumber(q.time.UnixNano())),
cancel: q.cancel,
query: q.query,
queryCompiler: q.queryCompiler,
queryIDFact: f,
queryID: f.Next(),
bindings: b,
compiler: q.compiler,
store: q.store,
baseCache: newBaseCache(),
targetStack: newRefStack(),
txn: q.txn,
input: q.input,
external: q.external,
tracers: q.tracers,
traceEnabled: len(q.tracers) > 0,
plugTraceVars: q.plugTraceVars,
instr: q.instr,
builtins: q.builtins,
builtinCache: builtins.Cache{},
functionMocks: newFunctionMocksStack(),
interQueryBuiltinCache: q.interQueryBuiltinCache,
ndBuiltinCache: q.ndBuiltinCache,
virtualCache: newVirtualCache(),
comprehensionCache: newComprehensionCache(),
saveSet: newSaveSet(q.unknowns, b, q.instr),
saveStack: newSaveStack(),
saveSupport: newSaveSupport(),
saveNamespace: ast.StringTerm(q.partialNamespace),
skipSaveNamespace: q.skipSaveNamespace,
inliningControl: &inliningControl{
shallow: q.shallowInlining,
},
genvarprefix: q.genvarprefix,
runtime: q.runtime,
indexing: q.indexing,
earlyExit: q.earlyExit,
builtinErrors: &builtinErrors{},
printHook: q.printHook,
}
if len(q.disableInlining) > 0 {
e.disableInlining = [][]ast.Ref{q.disableInlining}
e.inliningControl.PushDisable(q.disableInlining, false)
}
e.caller = e
q.startTimer(metrics.RegoPartialEval)
defer q.stopTimer(metrics.RegoPartialEval)
q.metrics.Timer(metrics.RegoPartialEval).Start()
defer q.metrics.Timer(metrics.RegoPartialEval).Stop()
livevars := ast.NewVarSet()
for _, t := range q.unknowns {
switch v := t.Value.(type) {
case ast.Var:
livevars.Add(v)
case ast.Ref:
livevars.Add(v[0].Value.(ast.Var))
}
}
ast.WalkVars(q.query, func(x ast.Var) bool {
if !x.IsGenerated() {
@@ -216,7 +364,7 @@ func (q *Query) PartialRun(ctx context.Context) (partials []ast.Body, support []
return false
})
p := copypropagation.New(livevars)
p := copypropagation.New(livevars).WithCompiler(q.compiler)
err = e.Run(func(e *eval) error {
@@ -230,10 +378,10 @@ func (q *Query) PartialRun(ctx context.Context) (partials []ast.Body, support []
// Include bindings as exprs so that when caller evals the result, they
// can obtain values for the vars in their query.
bindingExprs := []*ast.Expr{}
e.bindings.Iter(e.bindings, func(a, b *ast.Term) error {
_ = e.bindings.Iter(e.bindings, func(a, b *ast.Term) error {
bindingExprs = append(bindingExprs, ast.Equality.Expr(a, b))
return nil
})
}) // cannot return error
// Sort binding expressions so that results are deterministic.
sort.Slice(bindingExprs, func(i, j int) bool {
@@ -244,12 +392,32 @@ func (q *Query) PartialRun(ctx context.Context) (partials []ast.Body, support []
body.Append(bindingExprs[i])
}
partials = append(partials, applyCopyPropagation(p, e.instr, body))
// Skip this rule body if it fails to type-check.
// Type-checking failure means the rule body will never succeed.
if !e.compiler.PassesTypeCheck(body) {
return nil
}
if !q.shallowInlining {
body = applyCopyPropagation(p, e.instr, body)
}
partials = append(partials, body)
return nil
})
support = e.saveSupport.List()
if q.strictBuiltinErrors && len(e.builtinErrors.errs) > 0 {
err = e.builtinErrors.errs[0]
}
for i := range support {
sort.Slice(support[i].Rules, func(j, k int) bool {
return support[i].Rules[j].Compare(support[i].Rules[k]) < 0
})
}
return partials, support, err
}
@@ -266,52 +434,68 @@ func (q *Query) Run(ctx context.Context) (QueryResultSet, error) {
// Iter executes the query and invokes the iter function with query results
// produced by evaluating the query.
func (q *Query) Iter(ctx context.Context, iter func(QueryResult) error) error {
if q.seed == nil {
q.seed = rand.Reader
}
if q.time.IsZero() {
q.time = time.Now()
}
if q.metrics == nil {
q.metrics = metrics.New()
}
f := &queryIDFactory{}
e := &eval{
ctx: ctx,
cancel: q.cancel,
query: q.query,
queryCompiler: q.queryCompiler,
queryIDFact: f,
queryID: f.Next(),
bindings: newBindings(0, q.instr),
compiler: q.compiler,
store: q.store,
baseCache: newBaseCache(),
targetStack: newRefStack(),
txn: q.txn,
input: q.input,
tracers: q.tracers,
instr: q.instr,
builtins: q.builtins,
builtinCache: builtins.Cache{},
virtualCache: newVirtualCache(),
genvarprefix: q.genvarprefix,
runtime: q.runtime,
indexing: q.indexing,
ctx: ctx,
metrics: q.metrics,
seed: q.seed,
time: ast.NumberTerm(int64ToJSONNumber(q.time.UnixNano())),
cancel: q.cancel,
query: q.query,
queryCompiler: q.queryCompiler,
queryIDFact: f,
queryID: f.Next(),
bindings: newBindings(0, q.instr),
compiler: q.compiler,
store: q.store,
baseCache: newBaseCache(),
targetStack: newRefStack(),
txn: q.txn,
input: q.input,
external: q.external,
tracers: q.tracers,
traceEnabled: len(q.tracers) > 0,
plugTraceVars: q.plugTraceVars,
instr: q.instr,
builtins: q.builtins,
builtinCache: builtins.Cache{},
functionMocks: newFunctionMocksStack(),
interQueryBuiltinCache: q.interQueryBuiltinCache,
ndBuiltinCache: q.ndBuiltinCache,
virtualCache: newVirtualCache(),
comprehensionCache: newComprehensionCache(),
genvarprefix: q.genvarprefix,
runtime: q.runtime,
indexing: q.indexing,
earlyExit: q.earlyExit,
builtinErrors: &builtinErrors{},
printHook: q.printHook,
tracingOpts: q.tracingOpts,
}
e.caller = e
q.startTimer(metrics.RegoQueryEval)
q.metrics.Timer(metrics.RegoQueryEval).Start()
err := e.Run(func(e *eval) error {
qr := QueryResult{}
e.bindings.Iter(nil, func(k, v *ast.Term) error {
_ = e.bindings.Iter(nil, func(k, v *ast.Term) error {
qr[k.Value.(ast.Var)] = v
return nil
})
}) // cannot return error
return iter(qr)
})
q.stopTimer(metrics.RegoQueryEval)
if q.strictBuiltinErrors && err == nil && len(e.builtinErrors.errs) > 0 {
err = e.builtinErrors.errs[0]
}
q.metrics.Timer(metrics.RegoQueryEval).Stop()
return err
}
func (q *Query) startTimer(name string) {
if q.metrics != nil {
q.metrics.Timer(name).Start()
}
}
func (q *Query) stopTimer(name string) {
if q.metrics != nil {
q.metrics.Timer(name).Stop()
}
}