update dependencies (#6267)
Signed-off-by: hongming <coder.scala@gmail.com>
This commit is contained in:
139
vendor/github.com/open-policy-agent/opa/ast/parser.go
generated
vendored
139
vendor/github.com/open-policy-agent/opa/ast/parser.go
generated
vendored
@@ -17,7 +17,7 @@ import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/open-policy-agent/opa/ast/internal/scanner"
|
||||
"github.com/open-policy-agent/opa/ast/internal/tokens"
|
||||
@@ -30,6 +30,8 @@ var RegoV1CompatibleRef = Ref{VarTerm("rego"), StringTerm("v1")}
|
||||
// RegoVersion defines the Rego syntax requirements for a module.
|
||||
type RegoVersion int
|
||||
|
||||
const DefaultRegoVersion = RegoVersion(0)
|
||||
|
||||
const (
|
||||
// RegoV0 is the default, original Rego syntax.
|
||||
RegoV0 RegoVersion = iota
|
||||
@@ -43,6 +45,33 @@ const (
|
||||
RegoV1
|
||||
)
|
||||
|
||||
func (v RegoVersion) Int() int {
|
||||
if v == RegoV1 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (v RegoVersion) String() string {
|
||||
switch v {
|
||||
case RegoV0:
|
||||
return "v0"
|
||||
case RegoV1:
|
||||
return "v1"
|
||||
case RegoV0CompatV1:
|
||||
return "v0v1"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func RegoVersionFromInt(i int) RegoVersion {
|
||||
if i == 1 {
|
||||
return RegoV1
|
||||
}
|
||||
return RegoV0
|
||||
}
|
||||
|
||||
// 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().
|
||||
@@ -290,6 +319,31 @@ func (p *Parser) Parse() ([]Statement, []*Comment, Errors) {
|
||||
for k, v := range futureKeywords {
|
||||
allowedFutureKeywords[k] = v
|
||||
}
|
||||
|
||||
// For sake of error reporting, we still need to check that keywords in capabilities are known,
|
||||
for _, kw := range p.po.Capabilities.FutureKeywords {
|
||||
if _, ok := futureKeywords[kw]; !ok {
|
||||
return nil, nil, Errors{
|
||||
&Error{
|
||||
Code: ParseErr,
|
||||
Message: fmt.Sprintf("illegal capabilities: unknown keyword: %v", kw),
|
||||
Location: nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
// and that explicitly requested future keywords are known.
|
||||
for _, kw := range p.po.FutureKeywords {
|
||||
if _, ok := allowedFutureKeywords[kw]; !ok {
|
||||
return nil, nil, Errors{
|
||||
&Error{
|
||||
Code: ParseErr,
|
||||
Message: fmt.Sprintf("unknown future keyword: %v", kw),
|
||||
Location: nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, kw := range p.po.Capabilities.FutureKeywords {
|
||||
var ok bool
|
||||
@@ -582,7 +636,12 @@ func (p *Parser) parseImport() *Import {
|
||||
|
||||
path := imp.Path.Value.(Ref)
|
||||
|
||||
if !RootDocumentNames.Contains(path[0]) && !FutureRootDocument.Equal(path[0]) && !RegoRootDocument.Equal(path[0]) {
|
||||
switch {
|
||||
case RootDocumentNames.Contains(path[0]):
|
||||
case FutureRootDocument.Equal(path[0]):
|
||||
case RegoRootDocument.Equal(path[0]):
|
||||
default:
|
||||
p.hint("if this is unexpected, try updating OPA")
|
||||
p.errorf(imp.Path.Location, "unexpected import path, must begin with one of: %v, got: %v",
|
||||
RootDocumentNames.Union(NewSet(FutureRootDocument, RegoRootDocument)),
|
||||
path[0])
|
||||
@@ -654,6 +713,10 @@ func (p *Parser) parseRules() []*Rule {
|
||||
|
||||
// p[x] if ... becomes a single-value rule p[x]
|
||||
if hasIf && !usesContains && len(rule.Head.Ref()) == 2 {
|
||||
if !rule.Head.Ref()[1].IsGround() && len(rule.Head.Args) == 0 {
|
||||
rule.Head.Key = rule.Head.Ref()[1]
|
||||
}
|
||||
|
||||
if rule.Head.Value == nil {
|
||||
rule.Head.generatedValue = true
|
||||
rule.Head.Value = BooleanTerm(true).SetLocation(rule.Head.Location)
|
||||
@@ -717,6 +780,8 @@ func (p *Parser) parseRules() []*Rule {
|
||||
case usesContains:
|
||||
rule.Body = NewBody(NewExpr(BooleanTerm(true).SetLocation(rule.Location)).SetLocation(rule.Location))
|
||||
rule.generatedBody = true
|
||||
rule.Location = rule.Head.Location
|
||||
|
||||
return []*Rule{&rule}
|
||||
|
||||
default:
|
||||
@@ -929,12 +994,10 @@ func (p *Parser) parseHead(defaultRule bool) (*Head, bool) {
|
||||
p.illegal("expected rule value term (e.g., %s[%s] = <VALUE> { ... })", name, head.Key)
|
||||
}
|
||||
case tokens.Assign:
|
||||
s := p.save()
|
||||
p.scan()
|
||||
head.Assign = true
|
||||
head.Value = p.parseTermInfixCall()
|
||||
if head.Value == nil {
|
||||
p.restore(s)
|
||||
switch {
|
||||
case len(head.Args) > 0:
|
||||
p.illegal("expected function value term (e.g., %s(...) := <VALUE> { ... })", name)
|
||||
@@ -2118,6 +2181,7 @@ func (p *Parser) doScan(skipws bool) {
|
||||
p.s.loc.Col = pos.Col
|
||||
p.s.loc.Offset = pos.Offset
|
||||
p.s.loc.Text = p.s.Text(pos.Offset, pos.End)
|
||||
p.s.loc.Tabs = pos.Tabs
|
||||
|
||||
for _, err := range errs {
|
||||
p.error(p.s.Loc(), err.Message)
|
||||
@@ -2247,12 +2311,10 @@ type rawAnnotation struct {
|
||||
Organizations []string `yaml:"organizations"`
|
||||
RelatedResources []interface{} `yaml:"related_resources"`
|
||||
Authors []interface{} `yaml:"authors"`
|
||||
Schemas []rawSchemaAnnotation `yaml:"schemas"`
|
||||
Schemas []map[string]any `yaml:"schemas"`
|
||||
Custom map[string]interface{} `yaml:"custom"`
|
||||
}
|
||||
|
||||
type rawSchemaAnnotation map[string]interface{}
|
||||
|
||||
type metadataParser struct {
|
||||
buf *bytes.Buffer
|
||||
comments []*Comment
|
||||
@@ -2283,9 +2345,8 @@ func (b *metadataParser) Parse() (*Annotations, error) {
|
||||
var comment *Comment
|
||||
match := yamlLineErrRegex.FindStringSubmatch(err.Error())
|
||||
if len(match) == 2 {
|
||||
n, err2 := strconv.Atoi(match[1])
|
||||
index, err2 := strconv.Atoi(match[1])
|
||||
if err2 == nil {
|
||||
index := n - 1 // line numbering is 1-based so subtract one from row
|
||||
if index >= len(b.comments) {
|
||||
comment = b.comments[len(b.comments)-1]
|
||||
} else {
|
||||
@@ -2294,6 +2355,11 @@ func (b *metadataParser) Parse() (*Annotations, error) {
|
||||
b.loc = comment.Location
|
||||
}
|
||||
}
|
||||
|
||||
if match == nil && len(b.comments) > 0 {
|
||||
b.loc = b.comments[0].Location
|
||||
}
|
||||
|
||||
return nil, augmentYamlError(err, b.comments)
|
||||
}
|
||||
|
||||
@@ -2330,7 +2396,7 @@ func (b *metadataParser) Parse() (*Annotations, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case map[interface{}]interface{}:
|
||||
case map[string]any:
|
||||
w, err := convertYAMLMapKeyTypes(v, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid schema definition: %w", err)
|
||||
@@ -2361,11 +2427,27 @@ func (b *metadataParser) Parse() (*Annotations, error) {
|
||||
}
|
||||
|
||||
result.Location = b.loc
|
||||
|
||||
// recreate original text of entire metadata block for location text attribute
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString("# METADATA\n")
|
||||
|
||||
lines := bytes.Split(b.buf.Bytes(), []byte{'\n'})
|
||||
|
||||
for _, line := range lines[:len(lines)-1] {
|
||||
sb.WriteString("# ")
|
||||
sb.Write(line)
|
||||
sb.WriteByte('\n')
|
||||
}
|
||||
|
||||
result.Location.Text = []byte(strings.TrimSuffix(sb.String(), "\n"))
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// augmentYamlError augments a YAML error with hints intended to help the user figure out the cause of an otherwise cryptic error.
|
||||
// These are hints, instead of proper errors, because they are educated guesses, and aren't guaranteed to be correct.
|
||||
// augmentYamlError augments a YAML error with hints intended to help the user figure out the cause of an otherwise
|
||||
// cryptic error. These are hints, instead of proper errors, because they are educated guesses, and aren't guaranteed
|
||||
// to be correct.
|
||||
func augmentYamlError(err error, comments []*Comment) error {
|
||||
// Adding hints for when key/value ':' separator isn't suffixed with a legal YAML space symbol
|
||||
for _, comment := range comments {
|
||||
@@ -2398,10 +2480,11 @@ func augmentYamlError(err error, comments []*Comment) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func unwrapPair(pair map[string]interface{}) (k string, v interface{}) {
|
||||
for k, v = range pair {
|
||||
func unwrapPair(pair map[string]interface{}) (string, interface{}) {
|
||||
for k, v := range pair {
|
||||
return k, v
|
||||
}
|
||||
return
|
||||
return "", nil
|
||||
}
|
||||
|
||||
var errInvalidSchemaRef = fmt.Errorf("invalid schema reference")
|
||||
@@ -2518,11 +2601,11 @@ func parseAuthorString(s string) (*AuthorAnnotation, error) {
|
||||
return &AuthorAnnotation{Name: name, Email: email}, nil
|
||||
}
|
||||
|
||||
func convertYAMLMapKeyTypes(x interface{}, path []string) (interface{}, error) {
|
||||
func convertYAMLMapKeyTypes(x any, path []string) (any, error) {
|
||||
var err error
|
||||
switch x := x.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
result := make(map[string]interface{}, len(x))
|
||||
case map[any]any:
|
||||
result := make(map[string]any, len(x))
|
||||
for k, v := range x {
|
||||
str, ok := k.(string)
|
||||
if !ok {
|
||||
@@ -2534,7 +2617,7 @@ func convertYAMLMapKeyTypes(x interface{}, path []string) (interface{}, error) {
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
case []interface{}:
|
||||
case []any:
|
||||
for i := range x {
|
||||
x[i], err = convertYAMLMapKeyTypes(x[i], append(path, fmt.Sprintf("%d", i)))
|
||||
if err != nil {
|
||||
@@ -2556,6 +2639,11 @@ var futureKeywords = map[string]tokens.Token{
|
||||
"if": tokens.If,
|
||||
}
|
||||
|
||||
func IsFutureKeyword(s string) bool {
|
||||
_, ok := futureKeywords[s]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (p *Parser) futureImport(imp *Import, allowedFutureKeywords map[string]tokens.Token) {
|
||||
path := imp.Path.Value.(Ref)
|
||||
|
||||
@@ -2608,15 +2696,16 @@ func (p *Parser) regoV1Import(imp *Import) {
|
||||
return
|
||||
}
|
||||
|
||||
if p.po.RegoVersion == RegoV1 {
|
||||
// We're parsing for Rego v1, where the 'rego.v1' import is a no-op.
|
||||
path := imp.Path.Value.(Ref)
|
||||
|
||||
// v1 is only valid option
|
||||
if len(path) == 1 || !path[1].Equal(RegoV1CompatibleRef[1]) || len(path) > 2 {
|
||||
p.errorf(imp.Path.Location, "invalid import `%s`, must be `%s`", path, 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)
|
||||
if p.po.RegoVersion == RegoV1 {
|
||||
// We're parsing for Rego v1, where the 'rego.v1' import is a no-op.
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user