build(deps): bump github.com/open-policy-agent/opa from 0.51.0 to 0.59.0
Bumps [github.com/open-policy-agent/opa](https://github.com/open-policy-agent/opa) from 0.51.0 to 0.59.0. - [Release notes](https://github.com/open-policy-agent/opa/releases) - [Changelog](https://github.com/open-policy-agent/opa/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-policy-agent/opa/compare/v0.51.0...v0.59.0) --- updated-dependencies: - dependency-name: github.com/open-policy-agent/opa dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
Ralf Haferkamp
parent
a6a6c22c14
commit
1f069c7c00
+133
-72
@@ -21,9 +21,12 @@ import (
|
||||
|
||||
"github.com/open-policy-agent/opa/ast/internal/scanner"
|
||||
"github.com/open-policy-agent/opa/ast/internal/tokens"
|
||||
astJSON "github.com/open-policy-agent/opa/ast/json"
|
||||
"github.com/open-policy-agent/opa/ast/location"
|
||||
)
|
||||
|
||||
var RegoV1CompatibleRef = Ref{VarTerm("rego"), StringTerm("v1")}
|
||||
|
||||
// Note: This state is kept isolated from the parser so that we
|
||||
// can do efficient shallow copies of these values when doing a
|
||||
// save() and restore().
|
||||
@@ -84,7 +87,7 @@ func (c parsedTermCache) String() string {
|
||||
s.WriteRune('{')
|
||||
var e *parsedTermCacheItem
|
||||
for e = c.m; e != nil; e = e.next {
|
||||
fmt.Fprintf(&s, "%v", e)
|
||||
s.WriteString(fmt.Sprintf("%v", e))
|
||||
}
|
||||
s.WriteRune('}')
|
||||
return s.String()
|
||||
@@ -101,37 +104,9 @@ type ParserOptions struct {
|
||||
AllFutureKeywords bool
|
||||
FutureKeywords []string
|
||||
SkipRules bool
|
||||
JSONOptions *JSONOptions
|
||||
JSONOptions *astJSON.Options
|
||||
unreleasedKeywords bool // TODO(sr): cleanup
|
||||
}
|
||||
|
||||
// JSONOptions defines the options for JSON operations,
|
||||
// currently only marshaling can be configured
|
||||
type JSONOptions struct {
|
||||
MarshalOptions JSONMarshalOptions
|
||||
}
|
||||
|
||||
// JSONMarshalOptions defines the options for JSON marshaling,
|
||||
// currently only toggling the marshaling of location information is supported
|
||||
type JSONMarshalOptions struct {
|
||||
IncludeLocation NodeToggle
|
||||
}
|
||||
|
||||
// NodeToggle is a generic struct to allow the toggling of
|
||||
// settings for different ast node types
|
||||
type NodeToggle struct {
|
||||
Term bool
|
||||
Package bool
|
||||
Comment bool
|
||||
Import bool
|
||||
Rule bool
|
||||
Head bool
|
||||
Expr bool
|
||||
SomeDecl bool
|
||||
Every bool
|
||||
With bool
|
||||
Annotations bool
|
||||
AnnotationsRef bool
|
||||
RegoV1Compatible bool
|
||||
}
|
||||
|
||||
// NewParser creates and initializes a Parser.
|
||||
@@ -207,9 +182,9 @@ func (p *Parser) WithSkipRules(skip bool) *Parser {
|
||||
return p
|
||||
}
|
||||
|
||||
// WithJSONOptions sets the JSONOptions which will be set on nodes to configure
|
||||
// WithJSONOptions sets the Options which will be set on nodes to configure
|
||||
// their JSON marshaling behavior.
|
||||
func (p *Parser) WithJSONOptions(jsonOptions *JSONOptions) *Parser {
|
||||
func (p *Parser) WithJSONOptions(jsonOptions *astJSON.Options) *Parser {
|
||||
p.po.JSONOptions = jsonOptions
|
||||
return p
|
||||
}
|
||||
@@ -356,9 +331,14 @@ func (p *Parser) Parse() ([]Statement, []*Comment, Errors) {
|
||||
s = p.save()
|
||||
|
||||
if imp := p.parseImport(); imp != nil {
|
||||
if RegoRootDocument.Equal(imp.Path.Value.(Ref)[0]) {
|
||||
p.regoV1Import(imp)
|
||||
}
|
||||
|
||||
if FutureRootDocument.Equal(imp.Path.Value.(Ref)[0]) {
|
||||
p.futureImport(imp, allowedFutureKeywords)
|
||||
}
|
||||
|
||||
stmts = append(stmts, imp)
|
||||
continue
|
||||
} else if len(p.s.errors) > 0 {
|
||||
@@ -561,9 +541,9 @@ func (p *Parser) parseImport() *Import {
|
||||
|
||||
path := imp.Path.Value.(Ref)
|
||||
|
||||
if !RootDocumentNames.Contains(path[0]) && !FutureRootDocument.Equal(path[0]) {
|
||||
if !RootDocumentNames.Contains(path[0]) && !FutureRootDocument.Equal(path[0]) && !RegoRootDocument.Equal(path[0]) {
|
||||
p.errorf(imp.Path.Location, "unexpected import path, must begin with one of: %v, got: %v",
|
||||
RootDocumentNames.Union(NewSet(FutureRootDocument)),
|
||||
RootDocumentNames.Union(NewSet(FutureRootDocument, RegoRootDocument)),
|
||||
path[0])
|
||||
return nil
|
||||
}
|
||||
@@ -609,26 +589,32 @@ func (p *Parser) parseRules() []*Rule {
|
||||
return nil
|
||||
}
|
||||
|
||||
if usesContains {
|
||||
rule.Head.keywords = append(rule.Head.keywords, tokens.Contains)
|
||||
}
|
||||
|
||||
if rule.Default {
|
||||
if !p.validateDefaultRuleValue(&rule) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(rule.Head.Args) > 0 {
|
||||
if !p.validateDefaultRuleArgs(&rule) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
rule.Body = NewBody(NewExpr(BooleanTerm(true).SetLocation(rule.Location)).SetLocation(rule.Location))
|
||||
return []*Rule{&rule}
|
||||
}
|
||||
|
||||
if usesContains && !rule.Head.Reference.IsGround() {
|
||||
p.error(p.s.Loc(), "multi-value rules need ground refs")
|
||||
return nil
|
||||
}
|
||||
|
||||
// back-compat with `p[x] { ... }``
|
||||
hasIf := p.s.tok == tokens.If
|
||||
|
||||
// p[x] if ... becomes a single-value rule p[x]
|
||||
if hasIf && !usesContains && len(rule.Head.Ref()) == 2 {
|
||||
if rule.Head.Value == nil {
|
||||
rule.Head.generatedValue = true
|
||||
rule.Head.Value = BooleanTerm(true).SetLocation(rule.Head.Location)
|
||||
} else {
|
||||
// p[x] = y if becomes a single-value rule p[x] with value y, but needs name for compat
|
||||
@@ -657,6 +643,7 @@ func (p *Parser) parseRules() []*Rule {
|
||||
|
||||
switch {
|
||||
case hasIf:
|
||||
rule.Head.keywords = append(rule.Head.keywords, tokens.If)
|
||||
p.scan()
|
||||
s := p.save()
|
||||
if expr := p.parseLiteral(); expr != nil {
|
||||
@@ -688,6 +675,7 @@ func (p *Parser) parseRules() []*Rule {
|
||||
|
||||
case usesContains:
|
||||
rule.Body = NewBody(NewExpr(BooleanTerm(true).SetLocation(rule.Location)).SetLocation(rule.Location))
|
||||
rule.generatedBody = true
|
||||
return []*Rule{&rule}
|
||||
|
||||
default:
|
||||
@@ -695,7 +683,7 @@ func (p *Parser) parseRules() []*Rule {
|
||||
}
|
||||
|
||||
if p.s.tok == tokens.Else {
|
||||
if r := rule.Head.Ref(); len(r) > 1 && !r[len(r)-1].Value.IsGround() {
|
||||
if r := rule.Head.Ref(); len(r) > 1 && !r.IsGround() {
|
||||
p.error(p.s.Loc(), "else keyword cannot be used on rules with variables in head")
|
||||
return nil
|
||||
}
|
||||
@@ -737,6 +725,7 @@ func (p *Parser) parseRules() []*Rule {
|
||||
// rule's head AST but have their location
|
||||
// set to the rule body.
|
||||
next.Head = rule.Head.Copy()
|
||||
next.Head.keywords = rule.Head.keywords
|
||||
for i := range next.Head.Args {
|
||||
if v, ok := next.Head.Args[i].Value.(Var); ok && v.IsWildcard() {
|
||||
next.Head.Args[i].Value = Var(p.genwildcard())
|
||||
@@ -756,6 +745,7 @@ func (p *Parser) parseElse(head *Head) *Rule {
|
||||
rule.SetLoc(p.s.Loc())
|
||||
|
||||
rule.Head = head.Copy()
|
||||
rule.Head.generatedValue = false
|
||||
for i := range rule.Head.Args {
|
||||
if v, ok := rule.Head.Args[i].Value.(Var); ok && v.IsWildcard() {
|
||||
rule.Head.Args[i].Value = Var(p.genwildcard())
|
||||
@@ -771,6 +761,7 @@ func (p *Parser) parseElse(head *Head) *Rule {
|
||||
|
||||
switch p.s.tok {
|
||||
case tokens.LBrace, tokens.If: // no value, but a body follows directly
|
||||
rule.Head.generatedValue = true
|
||||
rule.Head.Value = BooleanTerm(true)
|
||||
case tokens.Assign, tokens.Unify:
|
||||
rule.Head.Assign = tokens.Assign == p.s.tok
|
||||
@@ -786,42 +777,37 @@ func (p *Parser) parseElse(head *Head) *Rule {
|
||||
}
|
||||
|
||||
hasIf := p.s.tok == tokens.If
|
||||
hasLBrace := p.s.tok == tokens.LBrace
|
||||
|
||||
if hasIf {
|
||||
p.scan()
|
||||
s := p.save()
|
||||
if expr := p.parseLiteral(); expr != nil {
|
||||
// NOTE(sr): set literals are never false or undefined, so parsing this as
|
||||
// p if false else if { true }
|
||||
// ^^^^^^^^ set of one element, `true`
|
||||
// isn't valid.
|
||||
isSetLiteral := false
|
||||
if t, ok := expr.Terms.(*Term); ok {
|
||||
_, isSetLiteral = t.Value.(Set)
|
||||
}
|
||||
// expr.Term is []*Term or Every
|
||||
if !isSetLiteral {
|
||||
rule.Body.Append(expr)
|
||||
setLocRecursive(rule.Body, rule.Location)
|
||||
return &rule
|
||||
}
|
||||
}
|
||||
p.restore(s)
|
||||
}
|
||||
|
||||
if p.s.tok != tokens.LBrace {
|
||||
if !hasIf && !hasLBrace {
|
||||
rule.Body = NewBody(NewExpr(BooleanTerm(true)))
|
||||
rule.generatedBody = true
|
||||
setLocRecursive(rule.Body, rule.Location)
|
||||
return &rule
|
||||
}
|
||||
|
||||
p.scan()
|
||||
|
||||
if rule.Body = p.parseBody(tokens.RBrace); rule.Body == nil {
|
||||
return nil
|
||||
if hasIf {
|
||||
rule.Head.keywords = append(rule.Head.keywords, tokens.If)
|
||||
p.scan()
|
||||
}
|
||||
|
||||
p.scan()
|
||||
if p.s.tok == tokens.LBrace {
|
||||
p.scan()
|
||||
if rule.Body = p.parseBody(tokens.RBrace); rule.Body == nil {
|
||||
return nil
|
||||
}
|
||||
p.scan()
|
||||
} else if p.s.tok != tokens.EOF {
|
||||
expr := p.parseLiteral()
|
||||
if expr == nil {
|
||||
return nil
|
||||
}
|
||||
rule.Body.Append(expr)
|
||||
setLocRecursive(rule.Body, rule.Location)
|
||||
} else {
|
||||
p.illegal("rule body expected")
|
||||
return nil
|
||||
}
|
||||
|
||||
if p.s.tok == tokens.Else {
|
||||
if rule.Else = p.parseElse(head); rule.Else == nil {
|
||||
@@ -832,7 +818,6 @@ func (p *Parser) parseElse(head *Head) *Rule {
|
||||
}
|
||||
|
||||
func (p *Parser) parseHead(defaultRule bool) (*Head, bool) {
|
||||
|
||||
head := &Head{}
|
||||
loc := p.s.Loc()
|
||||
defer func() {
|
||||
@@ -855,7 +840,9 @@ func (p *Parser) parseHead(defaultRule bool) (*Head, bool) {
|
||||
|
||||
switch x := ref.Value.(type) {
|
||||
case Var:
|
||||
head = NewHead(x)
|
||||
// Modify the code to add the location to the head ref
|
||||
// and set the head ref's jsonOptions.
|
||||
head = VarHead(x, ref.Location, p.po.JSONOptions)
|
||||
case Ref:
|
||||
head = RefHead(x)
|
||||
case Call:
|
||||
@@ -922,6 +909,7 @@ func (p *Parser) parseHead(defaultRule bool) (*Head, bool) {
|
||||
|
||||
if head.Value == nil && head.Key == nil {
|
||||
if len(head.Ref()) != 2 || len(head.Args) > 0 {
|
||||
head.generatedValue = true
|
||||
head.Value = BooleanTerm(true).SetLocation(head.Location)
|
||||
}
|
||||
}
|
||||
@@ -2001,7 +1989,7 @@ func (p *Parser) error(loc *location.Location, reason string) {
|
||||
|
||||
func (p *Parser) errorf(loc *location.Location, f string, a ...interface{}) {
|
||||
msg := strings.Builder{}
|
||||
fmt.Fprintf(&msg, f, a...)
|
||||
msg.WriteString(fmt.Sprintf(f, a...))
|
||||
|
||||
switch len(p.s.hints) {
|
||||
case 0: // nothing to do
|
||||
@@ -2176,6 +2164,38 @@ func (p *Parser) validateDefaultRuleValue(rule *Rule) bool {
|
||||
return valid
|
||||
}
|
||||
|
||||
func (p *Parser) validateDefaultRuleArgs(rule *Rule) bool {
|
||||
|
||||
valid := true
|
||||
vars := NewVarSet()
|
||||
|
||||
vis := NewGenericVisitor(func(x interface{}) bool {
|
||||
switch x := x.(type) {
|
||||
case Var:
|
||||
if vars.Contains(x) {
|
||||
p.error(rule.Loc(), fmt.Sprintf("illegal default rule (arguments cannot be repeated %v)", x))
|
||||
valid = false
|
||||
return true
|
||||
}
|
||||
vars.Add(x)
|
||||
|
||||
case *Term:
|
||||
switch v := x.Value.(type) {
|
||||
case Var: // do nothing
|
||||
default:
|
||||
p.error(rule.Loc(), fmt.Sprintf("illegal default rule (arguments cannot contain %v)", TypeName(v)))
|
||||
valid = false
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
vis.Walk(rule.Head.Args)
|
||||
return valid
|
||||
}
|
||||
|
||||
// We explicitly use yaml unmarshalling, to accommodate for the '_' in 'related_resources',
|
||||
// which isn't handled properly by json for some reason.
|
||||
type rawAnnotation struct {
|
||||
@@ -2508,6 +2528,11 @@ func (p *Parser) futureImport(imp *Import, allowedFutureKeywords map[string]toke
|
||||
return
|
||||
}
|
||||
|
||||
if p.s.s.RegoV1Compatible() {
|
||||
p.errorf(imp.Path.Location, "the `%s` import implies `future.keywords`, these are therefore mutually exclusive", RegoV1CompatibleRef)
|
||||
return
|
||||
}
|
||||
|
||||
kwds := make([]string, 0, len(allowedFutureKeywords))
|
||||
for k := range allowedFutureKeywords {
|
||||
kwds = append(kwds, k)
|
||||
@@ -2535,3 +2560,39 @@ func (p *Parser) futureImport(imp *Import, allowedFutureKeywords map[string]toke
|
||||
p.s.s.AddKeyword(kw, allowedFutureKeywords[kw])
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) regoV1Import(imp *Import) {
|
||||
if !p.po.Capabilities.ContainsFeature(FeatureRegoV1Import) {
|
||||
p.errorf(imp.Path.Location, "invalid import, `%s` is not supported by current capabilities", RegoV1CompatibleRef)
|
||||
return
|
||||
}
|
||||
|
||||
path := imp.Path.Value.(Ref)
|
||||
|
||||
if len(path) == 1 || !path[1].Equal(RegoV1CompatibleRef[1]) || len(path) > 2 {
|
||||
p.errorf(imp.Path.Location, "invalid import, must be `%s`", RegoV1CompatibleRef)
|
||||
return
|
||||
}
|
||||
|
||||
if imp.Alias != "" {
|
||||
p.errorf(imp.Path.Location, "`rego` imports cannot be aliased")
|
||||
return
|
||||
}
|
||||
|
||||
// import all future keywords with the rego.v1 import
|
||||
kwds := make([]string, 0, len(futureKeywords))
|
||||
for k := range futureKeywords {
|
||||
kwds = append(kwds, k)
|
||||
}
|
||||
|
||||
if p.s.s.HasKeyword(futureKeywords) && !p.s.s.RegoV1Compatible() {
|
||||
// We have imported future keywords, but they didn't come from another `rego.v1` import.
|
||||
p.errorf(imp.Path.Location, "the `%s` import implies `future.keywords`, these are therefore mutually exclusive", RegoV1CompatibleRef)
|
||||
return
|
||||
}
|
||||
|
||||
p.s.s.SetRegoV1Compatible()
|
||||
for _, kw := range kwds {
|
||||
p.s.s.AddKeyword(kw, futureKeywords[kw])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user