mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
v1 API
All packages, except for `cmd` and `internal`, have been moved into a new `v1` root package. Old packages are kept for backwards-compatibility reasons. All contained code is replaced with simple type aliases and proxy functions to `v1` implementations. Old packages default to the Rego v0 syntax, new `v1` packages default to the Rego v1 syntax. Signed-off-by: Johan Fylling <johan.dev@fylling.se>
This commit is contained in:
+133
@@ -3,6 +3,139 @@ run:
|
||||
|
||||
issues:
|
||||
max-same-issues: 0 # don't hide issues in CI runs because they are the same type
|
||||
exclude-rules:
|
||||
- path: ast/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: bundle/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: capabilities/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: compile/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: config/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: cover/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: debug/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: dependencies/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: download/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: format/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: hooks/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: ir/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: keys/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: loader/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: logging/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: metrics/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: plugins/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: profiler/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: refactor/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: repl/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: rego/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: resolver/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: runtime/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: schemas/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: sdk/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: server/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: storage/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: tester/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: topdown/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: tracing/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: types/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: util/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
- path: version/
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "SA1019"
|
||||
|
||||
linter-settings:
|
||||
lll:
|
||||
|
||||
@@ -479,7 +479,7 @@ check-go-module:
|
||||
.PHONY: check-yaml-tests
|
||||
check-yaml-tests:
|
||||
ifeq ($(DOCKER_RUNNING), 1)
|
||||
docker run --rm -v $(shell pwd):/data:ro,Z -w /data pipelinecomponents/yamllint:${YAML_LINT_VERSION} yamllint -f $(YAML_LINT_FORMAT) test/cases/testdata
|
||||
docker run --rm -v $(shell pwd):/data:ro,Z -w /data pipelinecomponents/yamllint:${YAML_LINT_VERSION} yamllint -f $(YAML_LINT_FORMAT) v1/test/cases/testdata
|
||||
else
|
||||
@echo "Docker not installed or running. Skipping yamllint run."
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2022 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
type (
|
||||
// Annotations represents metadata attached to other AST nodes such as rules.
|
||||
Annotations = v1.Annotations
|
||||
|
||||
// SchemaAnnotation contains a schema declaration for the document identified by the path.
|
||||
SchemaAnnotation = v1.SchemaAnnotation
|
||||
|
||||
AuthorAnnotation = v1.AuthorAnnotation
|
||||
|
||||
RelatedResourceAnnotation = v1.RelatedResourceAnnotation
|
||||
|
||||
AnnotationSet = v1.AnnotationSet
|
||||
|
||||
AnnotationsRef = v1.AnnotationsRef
|
||||
|
||||
AnnotationsRefSet = v1.AnnotationsRefSet
|
||||
|
||||
FlatAnnotationsRefSet = v1.FlatAnnotationsRefSet
|
||||
)
|
||||
|
||||
func NewAnnotationsRef(a *Annotations) *AnnotationsRef {
|
||||
return v1.NewAnnotationsRef(a)
|
||||
}
|
||||
+634
@@ -0,0 +1,634 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// Builtins is the registry of built-in functions supported by OPA.
|
||||
// Call RegisterBuiltin to add a new built-in.
|
||||
var Builtins = v1.Builtins
|
||||
|
||||
// RegisterBuiltin adds a new built-in function to the registry.
|
||||
func RegisterBuiltin(b *Builtin) {
|
||||
v1.RegisterBuiltin(b)
|
||||
}
|
||||
|
||||
// DefaultBuiltins is the registry of built-in functions supported in OPA
|
||||
// by default. When adding a new built-in function to OPA, update this
|
||||
// list.
|
||||
var DefaultBuiltins = v1.DefaultBuiltins
|
||||
|
||||
// BuiltinMap provides a convenient mapping of built-in names to
|
||||
// built-in definitions.
|
||||
var BuiltinMap = v1.BuiltinMap
|
||||
|
||||
// Deprecated: Builtins can now be directly annotated with the
|
||||
// Nondeterministic property, and when set to true, will be ignored
|
||||
// for partial evaluation.
|
||||
var IgnoreDuringPartialEval = v1.IgnoreDuringPartialEval
|
||||
|
||||
/**
|
||||
* Unification
|
||||
*/
|
||||
|
||||
// Equality represents the "=" operator.
|
||||
var Equality = v1.Equality
|
||||
|
||||
/**
|
||||
* Assignment
|
||||
*/
|
||||
|
||||
// Assign represents the assignment (":=") operator.
|
||||
var Assign = v1.Assign
|
||||
|
||||
// Member represents the `in` (infix) operator.
|
||||
var Member = v1.Member
|
||||
|
||||
// MemberWithKey represents the `in` (infix) operator when used
|
||||
// with two terms on the lhs, i.e., `k, v in obj`.
|
||||
var MemberWithKey = v1.MemberWithKey
|
||||
|
||||
var GreaterThan = v1.GreaterThan
|
||||
|
||||
var GreaterThanEq = v1.GreaterThanEq
|
||||
|
||||
// LessThan represents the "<" comparison operator.
|
||||
var LessThan = v1.LessThan
|
||||
|
||||
var LessThanEq = v1.LessThanEq
|
||||
|
||||
var NotEqual = v1.NotEqual
|
||||
|
||||
// Equal represents the "==" comparison operator.
|
||||
var Equal = v1.Equal
|
||||
|
||||
var Plus = v1.Plus
|
||||
|
||||
var Minus = v1.Minus
|
||||
|
||||
var Multiply = v1.Multiply
|
||||
|
||||
var Divide = v1.Divide
|
||||
|
||||
var Round = v1.Round
|
||||
|
||||
var Ceil = v1.Ceil
|
||||
|
||||
var Floor = v1.Floor
|
||||
|
||||
var Abs = v1.Abs
|
||||
|
||||
var Rem = v1.Rem
|
||||
|
||||
/**
|
||||
* Bitwise
|
||||
*/
|
||||
|
||||
var BitsOr = v1.BitsOr
|
||||
|
||||
var BitsAnd = v1.BitsAnd
|
||||
|
||||
var BitsNegate = v1.BitsNegate
|
||||
|
||||
var BitsXOr = v1.BitsXOr
|
||||
|
||||
var BitsShiftLeft = v1.BitsShiftLeft
|
||||
|
||||
var BitsShiftRight = v1.BitsShiftRight
|
||||
|
||||
/**
|
||||
* Sets
|
||||
*/
|
||||
|
||||
var And = v1.And
|
||||
|
||||
// Or performs a union operation on sets.
|
||||
var Or = v1.Or
|
||||
|
||||
var Intersection = v1.Intersection
|
||||
|
||||
var Union = v1.Union
|
||||
|
||||
/**
|
||||
* Aggregates
|
||||
*/
|
||||
|
||||
var Count = v1.Count
|
||||
|
||||
var Sum = v1.Sum
|
||||
|
||||
var Product = v1.Product
|
||||
|
||||
var Max = v1.Max
|
||||
|
||||
var Min = v1.Min
|
||||
|
||||
/**
|
||||
* Sorting
|
||||
*/
|
||||
|
||||
var Sort = v1.Sort
|
||||
|
||||
/**
|
||||
* Arrays
|
||||
*/
|
||||
|
||||
var ArrayConcat = v1.ArrayConcat
|
||||
|
||||
var ArraySlice = v1.ArraySlice
|
||||
|
||||
var ArrayReverse = v1.ArrayReverse
|
||||
|
||||
/**
|
||||
* Conversions
|
||||
*/
|
||||
|
||||
var ToNumber = v1.ToNumber
|
||||
|
||||
/**
|
||||
* Regular Expressions
|
||||
*/
|
||||
|
||||
var RegexMatch = v1.RegexMatch
|
||||
|
||||
var RegexIsValid = v1.RegexIsValid
|
||||
|
||||
var RegexFindAllStringSubmatch = v1.RegexFindAllStringSubmatch
|
||||
|
||||
var RegexTemplateMatch = v1.RegexTemplateMatch
|
||||
|
||||
var RegexSplit = v1.RegexSplit
|
||||
|
||||
// RegexFind takes two strings and a number, the pattern, the value and number of match values to
|
||||
// return, -1 means all match values.
|
||||
var RegexFind = v1.RegexFind
|
||||
|
||||
// GlobsMatch takes two strings regexp-style strings and evaluates to true if their
|
||||
// intersection matches a non-empty set of non-empty strings.
|
||||
// Examples:
|
||||
// - "a.a." and ".b.b" -> true.
|
||||
// - "[a-z]*" and [0-9]+" -> not true.
|
||||
var GlobsMatch = v1.GlobsMatch
|
||||
|
||||
/**
|
||||
* Strings
|
||||
*/
|
||||
|
||||
var AnyPrefixMatch = v1.AnyPrefixMatch
|
||||
|
||||
var AnySuffixMatch = v1.AnySuffixMatch
|
||||
|
||||
var Concat = v1.Concat
|
||||
|
||||
var FormatInt = v1.FormatInt
|
||||
|
||||
var IndexOf = v1.IndexOf
|
||||
|
||||
var IndexOfN = v1.IndexOfN
|
||||
|
||||
var Substring = v1.Substring
|
||||
|
||||
var Contains = v1.Contains
|
||||
|
||||
var StringCount = v1.StringCount
|
||||
|
||||
var StartsWith = v1.StartsWith
|
||||
|
||||
var EndsWith = v1.EndsWith
|
||||
|
||||
var Lower = v1.Lower
|
||||
|
||||
var Upper = v1.Upper
|
||||
|
||||
var Split = v1.Split
|
||||
|
||||
var Replace = v1.Replace
|
||||
|
||||
var ReplaceN = v1.ReplaceN
|
||||
|
||||
var RegexReplace = v1.RegexReplace
|
||||
|
||||
var Trim = v1.Trim
|
||||
|
||||
var TrimLeft = v1.TrimLeft
|
||||
|
||||
var TrimPrefix = v1.TrimPrefix
|
||||
|
||||
var TrimRight = v1.TrimRight
|
||||
|
||||
var TrimSuffix = v1.TrimSuffix
|
||||
|
||||
var TrimSpace = v1.TrimSpace
|
||||
|
||||
var Sprintf = v1.Sprintf
|
||||
|
||||
var StringReverse = v1.StringReverse
|
||||
|
||||
var RenderTemplate = v1.RenderTemplate
|
||||
|
||||
/**
|
||||
* Numbers
|
||||
*/
|
||||
|
||||
// RandIntn returns a random number 0 - n
|
||||
// Marked non-deterministic because it relies on RNG internally.
|
||||
var RandIntn = v1.RandIntn
|
||||
|
||||
var NumbersRange = v1.NumbersRange
|
||||
|
||||
var NumbersRangeStep = v1.NumbersRangeStep
|
||||
|
||||
/**
|
||||
* Units
|
||||
*/
|
||||
|
||||
var UnitsParse = v1.UnitsParse
|
||||
|
||||
var UnitsParseBytes = v1.UnitsParseBytes
|
||||
|
||||
//
|
||||
/**
|
||||
* Type
|
||||
*/
|
||||
|
||||
// UUIDRFC4122 returns a version 4 UUID string.
|
||||
// Marked non-deterministic because it relies on RNG internally.
|
||||
var UUIDRFC4122 = v1.UUIDRFC4122
|
||||
|
||||
var UUIDParse = v1.UUIDParse
|
||||
|
||||
/**
|
||||
* JSON
|
||||
*/
|
||||
|
||||
var JSONFilter = v1.JSONFilter
|
||||
|
||||
var JSONRemove = v1.JSONRemove
|
||||
|
||||
var JSONPatch = v1.JSONPatch
|
||||
|
||||
var ObjectSubset = v1.ObjectSubset
|
||||
|
||||
var ObjectUnion = v1.ObjectUnion
|
||||
|
||||
var ObjectUnionN = v1.ObjectUnionN
|
||||
|
||||
var ObjectRemove = v1.ObjectRemove
|
||||
|
||||
var ObjectFilter = v1.ObjectFilter
|
||||
|
||||
var ObjectGet = v1.ObjectGet
|
||||
|
||||
var ObjectKeys = v1.ObjectKeys
|
||||
|
||||
/*
|
||||
* Encoding
|
||||
*/
|
||||
|
||||
var JSONMarshal = v1.JSONMarshal
|
||||
|
||||
var JSONMarshalWithOptions = v1.JSONMarshalWithOptions
|
||||
|
||||
var JSONUnmarshal = v1.JSONUnmarshal
|
||||
|
||||
var JSONIsValid = v1.JSONIsValid
|
||||
|
||||
var Base64Encode = v1.Base64Encode
|
||||
|
||||
var Base64Decode = v1.Base64Decode
|
||||
|
||||
var Base64IsValid = v1.Base64IsValid
|
||||
|
||||
var Base64UrlEncode = v1.Base64UrlEncode
|
||||
|
||||
var Base64UrlEncodeNoPad = v1.Base64UrlEncodeNoPad
|
||||
|
||||
var Base64UrlDecode = v1.Base64UrlDecode
|
||||
|
||||
var URLQueryDecode = v1.URLQueryDecode
|
||||
|
||||
var URLQueryEncode = v1.URLQueryEncode
|
||||
|
||||
var URLQueryEncodeObject = v1.URLQueryEncodeObject
|
||||
|
||||
var URLQueryDecodeObject = v1.URLQueryDecodeObject
|
||||
|
||||
var YAMLMarshal = v1.YAMLMarshal
|
||||
|
||||
var YAMLUnmarshal = v1.YAMLUnmarshal
|
||||
|
||||
// YAMLIsValid verifies the input string is a valid YAML document.
|
||||
var YAMLIsValid = v1.YAMLIsValid
|
||||
|
||||
var HexEncode = v1.HexEncode
|
||||
|
||||
var HexDecode = v1.HexDecode
|
||||
|
||||
/**
|
||||
* Tokens
|
||||
*/
|
||||
|
||||
var JWTDecode = v1.JWTDecode
|
||||
|
||||
var JWTVerifyRS256 = v1.JWTVerifyRS256
|
||||
|
||||
var JWTVerifyRS384 = v1.JWTVerifyRS384
|
||||
|
||||
var JWTVerifyRS512 = v1.JWTVerifyRS512
|
||||
|
||||
var JWTVerifyPS256 = v1.JWTVerifyPS256
|
||||
|
||||
var JWTVerifyPS384 = v1.JWTVerifyPS384
|
||||
|
||||
var JWTVerifyPS512 = v1.JWTVerifyPS512
|
||||
|
||||
var JWTVerifyES256 = v1.JWTVerifyES256
|
||||
|
||||
var JWTVerifyES384 = v1.JWTVerifyES384
|
||||
|
||||
var JWTVerifyES512 = v1.JWTVerifyES512
|
||||
|
||||
var JWTVerifyHS256 = v1.JWTVerifyHS256
|
||||
|
||||
var JWTVerifyHS384 = v1.JWTVerifyHS384
|
||||
|
||||
var JWTVerifyHS512 = v1.JWTVerifyHS512
|
||||
|
||||
// Marked non-deterministic because it relies on time internally.
|
||||
var JWTDecodeVerify = v1.JWTDecodeVerify
|
||||
|
||||
// Marked non-deterministic because it relies on RNG internally.
|
||||
var JWTEncodeSignRaw = v1.JWTEncodeSignRaw
|
||||
|
||||
// Marked non-deterministic because it relies on RNG internally.
|
||||
var JWTEncodeSign = v1.JWTEncodeSign
|
||||
|
||||
/**
|
||||
* Time
|
||||
*/
|
||||
|
||||
// Marked non-deterministic because it relies on time directly.
|
||||
var NowNanos = v1.NowNanos
|
||||
|
||||
var ParseNanos = v1.ParseNanos
|
||||
|
||||
var ParseRFC3339Nanos = v1.ParseRFC3339Nanos
|
||||
|
||||
var ParseDurationNanos = v1.ParseDurationNanos
|
||||
|
||||
var Format = v1.Format
|
||||
|
||||
var Date = v1.Date
|
||||
|
||||
var Clock = v1.Clock
|
||||
|
||||
var Weekday = v1.Weekday
|
||||
|
||||
var AddDate = v1.AddDate
|
||||
|
||||
var Diff = v1.Diff
|
||||
|
||||
/**
|
||||
* Crypto.
|
||||
*/
|
||||
|
||||
var CryptoX509ParseCertificates = v1.CryptoX509ParseCertificates
|
||||
|
||||
var CryptoX509ParseAndVerifyCertificates = v1.CryptoX509ParseAndVerifyCertificates
|
||||
|
||||
var CryptoX509ParseAndVerifyCertificatesWithOptions = v1.CryptoX509ParseAndVerifyCertificatesWithOptions
|
||||
|
||||
var CryptoX509ParseCertificateRequest = v1.CryptoX509ParseCertificateRequest
|
||||
|
||||
var CryptoX509ParseKeyPair = v1.CryptoX509ParseKeyPair
|
||||
var CryptoX509ParseRSAPrivateKey = v1.CryptoX509ParseRSAPrivateKey
|
||||
|
||||
var CryptoParsePrivateKeys = v1.CryptoParsePrivateKeys
|
||||
|
||||
var CryptoMd5 = v1.CryptoMd5
|
||||
|
||||
var CryptoSha1 = v1.CryptoSha1
|
||||
|
||||
var CryptoSha256 = v1.CryptoSha256
|
||||
|
||||
var CryptoHmacMd5 = v1.CryptoHmacMd5
|
||||
|
||||
var CryptoHmacSha1 = v1.CryptoHmacSha1
|
||||
|
||||
var CryptoHmacSha256 = v1.CryptoHmacSha256
|
||||
|
||||
var CryptoHmacSha512 = v1.CryptoHmacSha512
|
||||
|
||||
var CryptoHmacEqual = v1.CryptoHmacEqual
|
||||
|
||||
/**
|
||||
* Graphs.
|
||||
*/
|
||||
|
||||
var WalkBuiltin = v1.WalkBuiltin
|
||||
|
||||
var ReachableBuiltin = v1.ReachableBuiltin
|
||||
|
||||
var ReachablePathsBuiltin = v1.ReachablePathsBuiltin
|
||||
|
||||
/**
|
||||
* Type
|
||||
*/
|
||||
|
||||
var IsNumber = v1.IsNumber
|
||||
|
||||
var IsString = v1.IsString
|
||||
|
||||
var IsBoolean = v1.IsBoolean
|
||||
|
||||
var IsArray = v1.IsArray
|
||||
|
||||
var IsSet = v1.IsSet
|
||||
|
||||
var IsObject = v1.IsObject
|
||||
|
||||
var IsNull = v1.IsNull
|
||||
|
||||
/**
|
||||
* Type Name
|
||||
*/
|
||||
|
||||
// TypeNameBuiltin returns the type of the input.
|
||||
var TypeNameBuiltin = v1.TypeNameBuiltin
|
||||
|
||||
/**
|
||||
* HTTP Request
|
||||
*/
|
||||
|
||||
// Marked non-deterministic because HTTP request results can be non-deterministic.
|
||||
var HTTPSend = v1.HTTPSend
|
||||
|
||||
/**
|
||||
* GraphQL
|
||||
*/
|
||||
|
||||
// GraphQLParse returns a pair of AST objects from parsing/validation.
|
||||
var GraphQLParse = v1.GraphQLParse
|
||||
|
||||
// GraphQLParseAndVerify returns a boolean and a pair of AST object from parsing/validation.
|
||||
var GraphQLParseAndVerify = v1.GraphQLParseAndVerify
|
||||
|
||||
// GraphQLParseQuery parses the input GraphQL query and returns a JSON
|
||||
// representation of its AST.
|
||||
var GraphQLParseQuery = v1.GraphQLParseQuery
|
||||
|
||||
// GraphQLParseSchema parses the input GraphQL schema and returns a JSON
|
||||
// representation of its AST.
|
||||
var GraphQLParseSchema = v1.GraphQLParseSchema
|
||||
|
||||
// GraphQLIsValid returns true if a GraphQL query is valid with a given
|
||||
// schema, and returns false for all other inputs.
|
||||
var GraphQLIsValid = v1.GraphQLIsValid
|
||||
|
||||
// GraphQLSchemaIsValid returns true if the input is valid GraphQL schema,
|
||||
// and returns false for all other inputs.
|
||||
var GraphQLSchemaIsValid = v1.GraphQLSchemaIsValid
|
||||
|
||||
/**
|
||||
* JSON Schema
|
||||
*/
|
||||
|
||||
// JSONSchemaVerify returns empty string if the input is valid JSON schema
|
||||
// and returns error string for all other inputs.
|
||||
var JSONSchemaVerify = v1.JSONSchemaVerify
|
||||
|
||||
// JSONMatchSchema returns empty array if the document matches the JSON schema,
|
||||
// and returns non-empty array with error objects otherwise.
|
||||
var JSONMatchSchema = v1.JSONMatchSchema
|
||||
|
||||
/**
|
||||
* Cloud Provider Helper Functions
|
||||
*/
|
||||
|
||||
var ProvidersAWSSignReqObj = v1.ProvidersAWSSignReqObj
|
||||
|
||||
/**
|
||||
* Rego
|
||||
*/
|
||||
|
||||
var RegoParseModule = v1.RegoParseModule
|
||||
|
||||
var RegoMetadataChain = v1.RegoMetadataChain
|
||||
|
||||
// RegoMetadataRule returns the metadata for the active rule
|
||||
var RegoMetadataRule = v1.RegoMetadataRule
|
||||
|
||||
/**
|
||||
* OPA
|
||||
*/
|
||||
|
||||
// Marked non-deterministic because of unpredictable config/environment-dependent results.
|
||||
var OPARuntime = v1.OPARuntime
|
||||
|
||||
/**
|
||||
* Trace
|
||||
*/
|
||||
|
||||
var Trace = v1.Trace
|
||||
|
||||
/**
|
||||
* Glob
|
||||
*/
|
||||
|
||||
var GlobMatch = v1.GlobMatch
|
||||
|
||||
var GlobQuoteMeta = v1.GlobQuoteMeta
|
||||
|
||||
/**
|
||||
* Networking
|
||||
*/
|
||||
|
||||
var NetCIDRIntersects = v1.NetCIDRIntersects
|
||||
|
||||
var NetCIDRExpand = v1.NetCIDRExpand
|
||||
|
||||
var NetCIDRContains = v1.NetCIDRContains
|
||||
|
||||
var NetCIDRContainsMatches = v1.NetCIDRContainsMatches
|
||||
|
||||
var NetCIDRMerge = v1.NetCIDRMerge
|
||||
|
||||
var NetCIDRIsValid = v1.NetCIDRIsValid
|
||||
|
||||
// Marked non-deterministic because DNS resolution results can be non-deterministic.
|
||||
var NetLookupIPAddr = v1.NetLookupIPAddr
|
||||
|
||||
/**
|
||||
* Semantic Versions
|
||||
*/
|
||||
|
||||
var SemVerIsValid = v1.SemVerIsValid
|
||||
|
||||
var SemVerCompare = v1.SemVerCompare
|
||||
|
||||
/**
|
||||
* Printing
|
||||
*/
|
||||
|
||||
// Print is a special built-in function that writes zero or more operands
|
||||
// to a message buffer. The caller controls how the buffer is displayed. The
|
||||
// operands may be of any type. Furthermore, unlike other built-in functions,
|
||||
// undefined operands DO NOT cause the print() function to fail during
|
||||
// evaluation.
|
||||
var Print = v1.Print
|
||||
|
||||
// InternalPrint represents the internal implementation of the print() function.
|
||||
// The compiler rewrites print() calls to refer to the internal implementation.
|
||||
var InternalPrint = v1.InternalPrint
|
||||
|
||||
/**
|
||||
* Deprecated built-ins.
|
||||
*/
|
||||
|
||||
// SetDiff has been replaced by the minus built-in.
|
||||
var SetDiff = v1.SetDiff
|
||||
|
||||
// NetCIDROverlap has been replaced by the `net.cidr_contains` built-in.
|
||||
var NetCIDROverlap = v1.NetCIDROverlap
|
||||
|
||||
// CastArray checks the underlying type of the input. If it is array or set, an array
|
||||
// containing the values is returned. If it is not an array, an error is thrown.
|
||||
var CastArray = v1.CastArray
|
||||
|
||||
// CastSet checks the underlying type of the input.
|
||||
// If it is a set, the set is returned.
|
||||
// If it is an array, the array is returned in set form (all duplicates removed)
|
||||
// If neither, an error is thrown
|
||||
var CastSet = v1.CastSet
|
||||
|
||||
// CastString returns input if it is a string; if not returns error.
|
||||
// For formatting variables, see sprintf
|
||||
var CastString = v1.CastString
|
||||
|
||||
// CastBoolean returns input if it is a boolean; if not returns error.
|
||||
var CastBoolean = v1.CastBoolean
|
||||
|
||||
// CastNull returns null if input is null; if not returns error.
|
||||
var CastNull = v1.CastNull
|
||||
|
||||
// CastObject returns the given object if it is null; throws an error otherwise
|
||||
var CastObject = v1.CastObject
|
||||
|
||||
// RegexMatchDeprecated declares `re_match` which has been deprecated. Use `regex.match` instead.
|
||||
var RegexMatchDeprecated = v1.RegexMatchDeprecated
|
||||
|
||||
// All takes a list and returns true if all of the items
|
||||
// are true. A collection of length 0 returns true.
|
||||
var All = v1.All
|
||||
|
||||
// Any takes a collection and returns true if any of the items
|
||||
// is true. A collection of length 0 returns false.
|
||||
var Any = v1.Any
|
||||
|
||||
// Builtin represents a built-in function supported by OPA. Every built-in
|
||||
// function is uniquely identified by a name.
|
||||
type Builtin = v1.Builtin
|
||||
@@ -0,0 +1,57 @@
|
||||
// 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 ast
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// VersonIndex contains an index from built-in function name, language feature,
|
||||
// and future rego keyword to version number. During the build, this is used to
|
||||
// create an index of the minimum version required for the built-in/feature/kw.
|
||||
type VersionIndex = v1.VersionIndex
|
||||
|
||||
// In the compiler, we used this to check that we're OK working with ref heads.
|
||||
// If this isn't present, we'll fail. This is to ensure that older versions of
|
||||
// OPA can work with policies that we're compiling -- if they don't know ref
|
||||
// heads, they wouldn't be able to parse them.
|
||||
const FeatureRefHeadStringPrefixes = v1.FeatureRefHeadStringPrefixes
|
||||
const FeatureRefHeads = v1.FeatureRefHeads
|
||||
const FeatureRegoV1Import = v1.FeatureRegoV1Import
|
||||
|
||||
// Capabilities defines a structure containing data that describes the capabilities
|
||||
// or features supported by a particular version of OPA.
|
||||
type Capabilities = v1.Capabilities
|
||||
|
||||
// WasmABIVersion captures the Wasm ABI version. Its `Minor` version is indicating
|
||||
// backwards-compatible changes.
|
||||
type WasmABIVersion = v1.WasmABIVersion
|
||||
|
||||
// CapabilitiesForThisVersion returns the capabilities of this version of OPA.
|
||||
func CapabilitiesForThisVersion() *Capabilities {
|
||||
return v1.CapabilitiesForThisVersion()
|
||||
}
|
||||
|
||||
// LoadCapabilitiesJSON loads a JSON serialized capabilities structure from the reader r.
|
||||
func LoadCapabilitiesJSON(r io.Reader) (*Capabilities, error) {
|
||||
return v1.LoadCapabilitiesJSON(r)
|
||||
}
|
||||
|
||||
// LoadCapabilitiesVersion loads a JSON serialized capabilities structure from the specific version.
|
||||
func LoadCapabilitiesVersion(version string) (*Capabilities, error) {
|
||||
return v1.LoadCapabilitiesVersion(version)
|
||||
}
|
||||
|
||||
// LoadCapabilitiesFile loads a JSON serialized capabilities structure from a file.
|
||||
func LoadCapabilitiesFile(file string) (*Capabilities, error) {
|
||||
return v1.LoadCapabilitiesFile(file)
|
||||
}
|
||||
|
||||
// LoadCapabilitiesVersions loads all capabilities versions
|
||||
func LoadCapabilitiesVersions() ([]string, error) {
|
||||
return v1.LoadCapabilitiesVersions()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2017 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// UnificationErrDetail describes a type mismatch error when two values are
|
||||
// unified (e.g., x = [1,2,y]).
|
||||
type UnificationErrDetail = v1.UnificationErrDetail
|
||||
|
||||
// RefErrUnsupportedDetail describes an undefined reference error where the
|
||||
// referenced value does not support dereferencing (e.g., scalars).
|
||||
type RefErrUnsupportedDetail = v1.RefErrUnsupportedDetail
|
||||
|
||||
// RefErrInvalidDetail describes an undefined reference error where the referenced
|
||||
// value does not support the reference operand (e.g., missing object key,
|
||||
// invalid key type, etc.)
|
||||
type RefErrInvalidDetail = v1.RefErrInvalidDetail
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// Compare returns an integer indicating whether two AST values are less than,
|
||||
// equal to, or greater than each other.
|
||||
//
|
||||
// If a is less than b, the return value is negative. If a is greater than b,
|
||||
// the return value is positive. If a is equal to b, the return value is zero.
|
||||
//
|
||||
// Different types are never equal to each other. For comparison purposes, types
|
||||
// are sorted as follows:
|
||||
//
|
||||
// nil < Null < Boolean < Number < String < Var < Ref < Array < Object < Set <
|
||||
// ArrayComprehension < ObjectComprehension < SetComprehension < Expr < SomeDecl
|
||||
// < With < Body < Rule < Import < Package < Module.
|
||||
//
|
||||
// Arrays and Refs are equal if and only if both a and b have the same length
|
||||
// and all corresponding elements are equal. If one element is not equal, the
|
||||
// return value is the same as for the first differing element. If all elements
|
||||
// are equal but a and b have different lengths, the shorter is considered less
|
||||
// than the other.
|
||||
//
|
||||
// Objects are considered equal if and only if both a and b have the same sorted
|
||||
// (key, value) pairs and are of the same length. Other comparisons are
|
||||
// consistent but not defined.
|
||||
//
|
||||
// Sets are considered equal if and only if the symmetric difference of a and b
|
||||
// is empty.
|
||||
// Other comparisons are consistent but not defined.
|
||||
func Compare(a, b interface{}) int {
|
||||
return v1.Compare(a, b)
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// CompileErrorLimitDefault is the default number errors a compiler will allow before
|
||||
// exiting.
|
||||
const CompileErrorLimitDefault = 10
|
||||
|
||||
// Compiler contains the state of a compilation process.
|
||||
type Compiler = v1.Compiler
|
||||
|
||||
// CompilerStage defines the interface for stages in the compiler.
|
||||
type CompilerStage = v1.CompilerStage
|
||||
|
||||
// CompilerEvalMode allows toggling certain stages that are only
|
||||
// needed for certain modes, Concretely, only "topdown" mode will
|
||||
// have the compiler build comprehension and rule indices.
|
||||
type CompilerEvalMode = v1.CompilerEvalMode
|
||||
|
||||
const (
|
||||
// EvalModeTopdown (default) instructs the compiler to build rule
|
||||
// and comprehension indices used by topdown evaluation.
|
||||
EvalModeTopdown = v1.EvalModeTopdown
|
||||
|
||||
// EvalModeIR makes the compiler skip the stages for comprehension
|
||||
// and rule indices.
|
||||
EvalModeIR = v1.EvalModeIR
|
||||
)
|
||||
|
||||
// CompilerStageDefinition defines a compiler stage
|
||||
type CompilerStageDefinition = v1.CompilerStageDefinition
|
||||
|
||||
// RulesOptions defines the options for retrieving rules by Ref from the
|
||||
// compiler.
|
||||
type RulesOptions = v1.RulesOptions
|
||||
|
||||
// QueryContext contains contextual information for running an ad-hoc query.
|
||||
//
|
||||
// Ad-hoc queries can be run in the context of a package and imports may be
|
||||
// included to provide concise access to data.
|
||||
type QueryContext = v1.QueryContext
|
||||
|
||||
// NewQueryContext returns a new QueryContext object.
|
||||
func NewQueryContext() *QueryContext {
|
||||
return v1.NewQueryContext()
|
||||
}
|
||||
|
||||
// QueryCompiler defines the interface for compiling ad-hoc queries.
|
||||
type QueryCompiler = v1.QueryCompiler
|
||||
|
||||
// QueryCompilerStage defines the interface for stages in the query compiler.
|
||||
type QueryCompilerStage = v1.QueryCompilerStage
|
||||
|
||||
// QueryCompilerStageDefinition defines a QueryCompiler stage
|
||||
type QueryCompilerStageDefinition = v1.QueryCompilerStageDefinition
|
||||
|
||||
// NewCompiler returns a new empty compiler.
|
||||
func NewCompiler() *Compiler {
|
||||
return v1.NewCompiler().WithDefaultRegoVersion(DefaultRegoVersion)
|
||||
}
|
||||
|
||||
// ModuleLoader defines the interface that callers can implement to enable lazy
|
||||
// loading of modules during compilation.
|
||||
type ModuleLoader = v1.ModuleLoader
|
||||
|
||||
// SafetyCheckVisitorParams defines the AST visitor parameters to use for collecting
|
||||
// variables during the safety check. This has to be exported because it's relied on
|
||||
// by the copy propagation implementation in topdown.
|
||||
var SafetyCheckVisitorParams = v1.SafetyCheckVisitorParams
|
||||
|
||||
// ComprehensionIndex specifies how the comprehension term can be indexed. The keys
|
||||
// tell the evaluator what variables to use for indexing. In the future, the index
|
||||
// could be expanded with more information that would allow the evaluator to index
|
||||
// a larger fragment of comprehensions (e.g., by closing over variables in the outer
|
||||
// query.)
|
||||
type ComprehensionIndex = v1.ComprehensionIndex
|
||||
|
||||
// ModuleTreeNode represents a node in the module tree. The module
|
||||
// tree is keyed by the package path.
|
||||
type ModuleTreeNode = v1.ModuleTreeNode
|
||||
|
||||
// TreeNode represents a node in the rule tree. The rule tree is keyed by
|
||||
// rule path.
|
||||
type TreeNode = v1.TreeNode
|
||||
|
||||
// NewRuleTree returns a new TreeNode that represents the root
|
||||
// of the rule tree populated with the given rules.
|
||||
func NewRuleTree(mtree *ModuleTreeNode) *TreeNode {
|
||||
return v1.NewRuleTree(mtree)
|
||||
}
|
||||
|
||||
// Graph represents the graph of dependencies between rules.
|
||||
type Graph = v1.Graph
|
||||
|
||||
// NewGraph returns a new Graph based on modules. The list function must return
|
||||
// the rules referred to directly by the ref.
|
||||
func NewGraph(modules map[string]*Module, list func(Ref) []*Rule) *Graph {
|
||||
return v1.NewGraph(modules, list)
|
||||
}
|
||||
|
||||
// GraphTraversal is a Traversal that understands the dependency graph
|
||||
type GraphTraversal = v1.GraphTraversal
|
||||
|
||||
// NewGraphTraversal returns a Traversal for the dependency graph
|
||||
func NewGraphTraversal(graph *Graph) *GraphTraversal {
|
||||
return v1.NewGraphTraversal(graph)
|
||||
}
|
||||
|
||||
// OutputVarsFromBody returns all variables which are the "output" for
|
||||
// the given body. For safety checks this means that they would be
|
||||
// made safe by the body.
|
||||
func OutputVarsFromBody(c *Compiler, body Body, safe VarSet) VarSet {
|
||||
return v1.OutputVarsFromBody(c, body, safe)
|
||||
}
|
||||
|
||||
// OutputVarsFromExpr returns all variables which are the "output" for
|
||||
// the given expression. For safety checks this means that they would be
|
||||
// made safe by the expr.
|
||||
func OutputVarsFromExpr(c *Compiler, expr *Expr, safe VarSet) VarSet {
|
||||
return v1.OutputVarsFromExpr(c, expr, safe)
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright 2024 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 ast
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompile_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
modules map[string]*Module
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "no module rego-version, no v1 violations",
|
||||
modules: map[string]*Module{
|
||||
"test": {
|
||||
Package: MustParsePackage(`package test`),
|
||||
Imports: MustParseImports(`import data.foo
|
||||
import data.bar`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "no module rego-version, v1 violations", // default is v0, no errors expected
|
||||
modules: map[string]*Module{
|
||||
"test": {
|
||||
Package: MustParsePackage(`package test`),
|
||||
Imports: MustParseImports(`import data.foo
|
||||
import data.bar as foo`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v0 module, v1 violations",
|
||||
modules: map[string]*Module{
|
||||
"test": MustParseModuleWithOpts(`package test
|
||||
import data.foo
|
||||
import data.bar as foo`,
|
||||
ParserOptions{RegoVersion: RegoV0}),
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module, v1 violations",
|
||||
modules: map[string]*Module{
|
||||
"test": MustParseModuleWithOpts(`package test
|
||||
import data.foo
|
||||
import data.bar as foo`,
|
||||
ParserOptions{RegoVersion: RegoV1}),
|
||||
},
|
||||
expErrs: []string{
|
||||
"3:7: rego_compile_error: import must not shadow import data.foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
compiler := NewCompiler()
|
||||
|
||||
compiler.Compile(tc.modules)
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
assertErrors(t, compiler.Errors, tc.expErrs)
|
||||
} else {
|
||||
if len(compiler.Errors) > 0 {
|
||||
t.Fatalf("Unexpected errors: %v", compiler.Errors)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertErrors(t *testing.T, actual Errors, expected []string) {
|
||||
t.Helper()
|
||||
if len(expected) != len(actual) {
|
||||
t.Fatalf("Expected %d errors, got %d:\n\n%s\n", len(expected), len(actual), actual.Error())
|
||||
}
|
||||
incorrectErrs := false
|
||||
for _, e := range expected {
|
||||
found := false
|
||||
for _, actual := range actual {
|
||||
if strings.Contains(actual.Error(), e) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
incorrectErrs = true
|
||||
}
|
||||
}
|
||||
if incorrectErrs {
|
||||
t.Fatalf("Expected errors:\n\n%s\n\nGot:\n\n%s\n", expected, actual.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
|
||||
// CompileModules takes a set of Rego modules represented as strings and
|
||||
// compiles them for evaluation. The keys of the map are used as filenames.
|
||||
func CompileModules(modules map[string]string) (*Compiler, error) {
|
||||
return CompileModulesWithOpt(modules, CompileOpts{
|
||||
ParserOptions: ParserOptions{
|
||||
RegoVersion: DefaultRegoVersion,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// CompileOpts defines a set of options for the compiler.
|
||||
type CompileOpts = v1.CompileOpts
|
||||
|
||||
// CompileModulesWithOpt takes a set of Rego modules represented as strings and
|
||||
// compiles them for evaluation. The keys of the map are used as filenames.
|
||||
func CompileModulesWithOpt(modules map[string]string, opts CompileOpts) (*Compiler, error) {
|
||||
if opts.ParserOptions.RegoVersion == RegoUndefined {
|
||||
opts.ParserOptions.RegoVersion = DefaultRegoVersion
|
||||
}
|
||||
|
||||
return v1.CompileModulesWithOpt(modules, opts)
|
||||
}
|
||||
|
||||
// MustCompileModules compiles a set of Rego modules represented as strings. If
|
||||
// the compilation process fails, this function panics.
|
||||
func MustCompileModules(modules map[string]string) *Compiler {
|
||||
return MustCompileModulesWithOpts(modules, CompileOpts{})
|
||||
}
|
||||
|
||||
// MustCompileModulesWithOpts compiles a set of Rego modules represented as strings. If
|
||||
// the compilation process fails, this function panics.
|
||||
func MustCompileModulesWithOpts(modules map[string]string, opts CompileOpts) *Compiler {
|
||||
|
||||
compiler, err := CompileModulesWithOpt(modules, opts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return compiler
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
// Copyright 2024 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 ast
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompileModules_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
modules map[string]string
|
||||
expErrs []string
|
||||
}{
|
||||
// default rego-version
|
||||
{
|
||||
note: "v0 module, no v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
p[x] {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v0 module, v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
import data.foo
|
||||
import data.bar as foo
|
||||
|
||||
p[x] {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
},
|
||||
|
||||
// cross-rego-version
|
||||
{
|
||||
note: "rego.v1 import, no v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
import rego.v1
|
||||
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "rego.v1 import, v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
import rego.v1
|
||||
|
||||
import data.foo
|
||||
import data.bar as foo
|
||||
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"test.rego:5: rego_compile_error: import must not shadow import data.foo",
|
||||
},
|
||||
},
|
||||
|
||||
// NOT default rego-version
|
||||
{
|
||||
note: "v1 module, no v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"test.rego:2: rego_parse_error: var cannot be used for rule name",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module, v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
import data.foo
|
||||
import data.bar as foo
|
||||
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"test.rego:5: rego_parse_error: var cannot be used for rule name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
_, err := CompileModules(tc.modules)
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
for _, expErr := range tc.expErrs {
|
||||
if err := err.Error(); !strings.Contains(err, expErr) {
|
||||
t.Fatalf("Expected error to contain:\n\n%s\n\nbut got:\n\n%s", expErr, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompileModulesWithOpt_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
modules map[string]string
|
||||
expErrs []string
|
||||
}{
|
||||
// default rego-version
|
||||
{
|
||||
note: "v0 module, no v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
p[x] {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v0 module, v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
import data.foo
|
||||
import data.bar as foo
|
||||
|
||||
p[x] {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
},
|
||||
|
||||
// cross-rego-version
|
||||
{
|
||||
note: "rego.v1 import, no v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
import rego.v1
|
||||
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "rego.v1 import, v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
import rego.v1
|
||||
|
||||
import data.foo
|
||||
import data.bar as foo
|
||||
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"test.rego:5: rego_compile_error: import must not shadow import data.foo",
|
||||
},
|
||||
},
|
||||
|
||||
// NOT default rego-version
|
||||
{
|
||||
note: "v1 module, no v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"test.rego:2: rego_parse_error: var cannot be used for rule name",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module, v1 compile-time violations",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
import data.foo
|
||||
import data.bar as foo
|
||||
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"test.rego:5: rego_parse_error: var cannot be used for rule name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
_, err := CompileModulesWithOpt(tc.modules, CompileOpts{EnablePrintStatements: true})
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
for _, expErr := range tc.expErrs {
|
||||
if err := err.Error(); !strings.Contains(err, expErr) {
|
||||
t.Fatalf("Expected error to contain:\n\n%s\n\nbut got:\n\n%s", expErr, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2019 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// CheckPathConflicts returns a set of errors indicating paths that
|
||||
// are in conflict with the result of the provided callable.
|
||||
func CheckPathConflicts(c *Compiler, exists func([]string) (bool, error)) Errors {
|
||||
return v1.CheckPathConflicts(c, exists)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package ast
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2017 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// TypeEnv contains type info for static analysis such as type checking.
|
||||
type TypeEnv = v1.TypeEnv
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// Errors represents a series of errors encountered during parsing, compiling,
|
||||
// etc.
|
||||
type Errors = v1.Errors
|
||||
|
||||
const (
|
||||
// ParseErr indicates an unclassified parse error occurred.
|
||||
ParseErr = v1.ParseErr
|
||||
|
||||
// CompileErr indicates an unclassified compile error occurred.
|
||||
CompileErr = v1.CompileErr
|
||||
|
||||
// TypeErr indicates a type error was caught.
|
||||
TypeErr = v1.TypeErr
|
||||
|
||||
// UnsafeVarErr indicates an unsafe variable was found during compilation.
|
||||
UnsafeVarErr = v1.UnsafeVarErr
|
||||
|
||||
// RecursionErr indicates recursion was found during compilation.
|
||||
RecursionErr = v1.RecursionErr
|
||||
)
|
||||
|
||||
// IsError returns true if err is an AST error with code.
|
||||
func IsError(code string, err error) bool {
|
||||
return v1.IsError(code, err)
|
||||
}
|
||||
|
||||
// ErrorDetails defines the interface for detailed error messages.
|
||||
type ErrorDetails = v1.ErrorDetails
|
||||
|
||||
// Error represents a single error caught during parsing, compiling, etc.
|
||||
type Error = v1.Error
|
||||
|
||||
// NewError returns a new Error object.
|
||||
func NewError(code string, loc *Location, f string, a ...interface{}) *Error {
|
||||
return v1.NewError(code, loc, f, a...)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2017 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// RuleIndex defines the interface for rule indices.
|
||||
type RuleIndex v1.RuleIndex
|
||||
|
||||
// IndexResult contains the result of an index lookup.
|
||||
type IndexResult = v1.IndexResult
|
||||
|
||||
// NewIndexResult returns a new IndexResult object.
|
||||
func NewIndexResult(kind RuleKind) *IndexResult {
|
||||
return v1.NewIndexResult(kind)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2024 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
func InternedBooleanTerm(b bool) *Term {
|
||||
return v1.InternedBooleanTerm(b)
|
||||
}
|
||||
|
||||
// InternedIntNumberTerm returns a term with the given integer value. The term is
|
||||
// cached between -1 to 512, and for values outside of that range, this function
|
||||
// is equivalent to ast.IntNumberTerm.
|
||||
func InternedIntNumberTerm(i int) *Term {
|
||||
return v1.InternedIntNumberTerm(i)
|
||||
}
|
||||
|
||||
func HasInternedIntNumberTerm(i int) bool {
|
||||
return v1.HasInternedIntNumberTerm(i)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package json
|
||||
@@ -0,0 +1,15 @@
|
||||
package json
|
||||
|
||||
import v1 "github.com/open-policy-agent/opa/v1/ast/json"
|
||||
|
||||
// Options defines the options for JSON operations,
|
||||
// currently only marshaling can be configured
|
||||
type Options = v1.Options
|
||||
|
||||
// MarshalOptions defines the options for JSON marshaling,
|
||||
// currently only toggling the marshaling of location information is supported
|
||||
type MarshalOptions = v1.MarshalOptions
|
||||
|
||||
// NodeToggle is a generic struct to allow the toggling of
|
||||
// settings for different ast node types
|
||||
type NodeToggle = v1.NodeToggle
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package location
|
||||
@@ -0,0 +1,14 @@
|
||||
// Package location defines locations in Rego source code.
|
||||
package location
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// Location records a position in source code
|
||||
type Location = v1.Location
|
||||
|
||||
// NewLocation returns a new Location object.
|
||||
func NewLocation(text []byte, file string, row int, col int) *Location {
|
||||
return v1.NewLocation(text, file, row, col)
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// ValueMap represents a key/value map between AST term values. Any type of term
|
||||
// can be used as a key in the map.
|
||||
type ValueMap = v1.ValueMap
|
||||
|
||||
// NewValueMap returns a new ValueMap.
|
||||
func NewValueMap() *ValueMap {
|
||||
return v1.NewValueMap()
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2024 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
var RegoV1CompatibleRef = v1.RegoV1CompatibleRef
|
||||
|
||||
// RegoVersion defines the Rego syntax requirements for a module.
|
||||
type RegoVersion = v1.RegoVersion
|
||||
|
||||
const DefaultRegoVersion = RegoV0
|
||||
|
||||
const (
|
||||
RegoUndefined = v1.RegoUndefined
|
||||
// RegoV0 is the default, original Rego syntax.
|
||||
RegoV0 = v1.RegoV0
|
||||
// RegoV0CompatV1 requires modules to comply with both the RegoV0 and RegoV1 syntax (as when 'rego.v1' is imported in a module).
|
||||
// Shortly, RegoV1 compatibility is required, but 'rego.v1' or 'future.keywords' must also be imported.
|
||||
RegoV0CompatV1 = v1.RegoV0CompatV1
|
||||
// RegoV1 is the Rego syntax enforced by OPA 1.0; e.g.:
|
||||
// future.keywords part of default keyword set, and don't require imports;
|
||||
// 'if' and 'contains' required in rule heads;
|
||||
// (some) strict checks on by default.
|
||||
RegoV1 = v1.RegoV1
|
||||
)
|
||||
|
||||
func RegoVersionFromInt(i int) RegoVersion {
|
||||
return v1.RegoVersionFromInt(i)
|
||||
}
|
||||
|
||||
// Parser is used to parse Rego statements.
|
||||
type Parser = v1.Parser
|
||||
|
||||
// ParserOptions defines the options for parsing Rego statements.
|
||||
type ParserOptions = v1.ParserOptions
|
||||
|
||||
// NewParser creates and initializes a Parser.
|
||||
func NewParser() *Parser {
|
||||
return v1.NewParser().WithRegoVersion(DefaultRegoVersion)
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
// Copyright 2024 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 ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// MustParseBody returns a parsed body.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseBody(input string) Body {
|
||||
return MustParseBodyWithOpts(input, ParserOptions{})
|
||||
}
|
||||
|
||||
// MustParseBodyWithOpts returns a parsed body.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseBodyWithOpts(input string, opts ParserOptions) Body {
|
||||
return v1.MustParseBodyWithOpts(input, setDefaultRegoVersion(opts))
|
||||
}
|
||||
|
||||
// MustParseExpr returns a parsed expression.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseExpr(input string) *Expr {
|
||||
parsed, err := ParseExpr(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// MustParseImports returns a slice of imports.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseImports(input string) []*Import {
|
||||
parsed, err := ParseImports(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// MustParseModule returns a parsed module.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseModule(input string) *Module {
|
||||
return MustParseModuleWithOpts(input, ParserOptions{})
|
||||
}
|
||||
|
||||
// MustParseModuleWithOpts returns a parsed module.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseModuleWithOpts(input string, opts ParserOptions) *Module {
|
||||
return v1.MustParseModuleWithOpts(input, setDefaultRegoVersion(opts))
|
||||
}
|
||||
|
||||
// MustParsePackage returns a Package.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParsePackage(input string) *Package {
|
||||
parsed, err := ParsePackage(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// MustParseStatements returns a slice of parsed statements.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseStatements(input string) []Statement {
|
||||
parsed, _, err := ParseStatements("", input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// MustParseStatement returns exactly one statement.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseStatement(input string) Statement {
|
||||
parsed, err := ParseStatement(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
func MustParseStatementWithOpts(input string, popts ParserOptions) Statement {
|
||||
return v1.MustParseStatementWithOpts(input, setDefaultRegoVersion(popts))
|
||||
}
|
||||
|
||||
// MustParseRef returns a parsed reference.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseRef(input string) Ref {
|
||||
parsed, err := ParseRef(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// MustParseRule returns a parsed rule.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseRule(input string) *Rule {
|
||||
parsed, err := ParseRule(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// MustParseRuleWithOpts returns a parsed rule.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseRuleWithOpts(input string, opts ParserOptions) *Rule {
|
||||
return v1.MustParseRuleWithOpts(input, setDefaultRegoVersion(opts))
|
||||
}
|
||||
|
||||
// MustParseTerm returns a parsed term.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseTerm(input string) *Term {
|
||||
parsed, err := ParseTerm(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// ParseRuleFromBody returns a rule if the body can be interpreted as a rule
|
||||
// definition. Otherwise, an error is returned.
|
||||
func ParseRuleFromBody(module *Module, body Body) (*Rule, error) {
|
||||
return v1.ParseRuleFromBody(module, body)
|
||||
}
|
||||
|
||||
// ParseRuleFromExpr returns a rule if the expression can be interpreted as a
|
||||
// rule definition.
|
||||
func ParseRuleFromExpr(module *Module, expr *Expr) (*Rule, error) {
|
||||
return v1.ParseRuleFromExpr(module, expr)
|
||||
}
|
||||
|
||||
// ParseCompleteDocRuleFromAssignmentExpr returns a rule if the expression can
|
||||
// be interpreted as a complete document definition declared with the assignment
|
||||
// operator.
|
||||
func ParseCompleteDocRuleFromAssignmentExpr(module *Module, lhs, rhs *Term) (*Rule, error) {
|
||||
return v1.ParseCompleteDocRuleFromAssignmentExpr(module, lhs, rhs)
|
||||
}
|
||||
|
||||
// ParseCompleteDocRuleFromEqExpr returns a rule if the expression can be
|
||||
// interpreted as a complete document definition.
|
||||
func ParseCompleteDocRuleFromEqExpr(module *Module, lhs, rhs *Term) (*Rule, error) {
|
||||
return v1.ParseCompleteDocRuleFromEqExpr(module, lhs, rhs)
|
||||
}
|
||||
|
||||
func ParseCompleteDocRuleWithDotsFromTerm(module *Module, term *Term) (*Rule, error) {
|
||||
return v1.ParseCompleteDocRuleWithDotsFromTerm(module, term)
|
||||
}
|
||||
|
||||
// ParsePartialObjectDocRuleFromEqExpr returns a rule if the expression can be
|
||||
// interpreted as a partial object document definition.
|
||||
func ParsePartialObjectDocRuleFromEqExpr(module *Module, lhs, rhs *Term) (*Rule, error) {
|
||||
return v1.ParsePartialObjectDocRuleFromEqExpr(module, lhs, rhs)
|
||||
}
|
||||
|
||||
// ParsePartialSetDocRuleFromTerm returns a rule if the term can be interpreted
|
||||
// as a partial set document definition.
|
||||
func ParsePartialSetDocRuleFromTerm(module *Module, term *Term) (*Rule, error) {
|
||||
return v1.ParsePartialSetDocRuleFromTerm(module, term)
|
||||
}
|
||||
|
||||
// ParseRuleFromCallEqExpr returns a rule if the term can be interpreted as a
|
||||
// function definition (e.g., f(x) = y => f(x) = y { true }).
|
||||
func ParseRuleFromCallEqExpr(module *Module, lhs, rhs *Term) (*Rule, error) {
|
||||
return v1.ParseRuleFromCallEqExpr(module, lhs, rhs)
|
||||
}
|
||||
|
||||
// ParseRuleFromCallExpr returns a rule if the terms can be interpreted as a
|
||||
// function returning true or some value (e.g., f(x) => f(x) = true { true }).
|
||||
func ParseRuleFromCallExpr(module *Module, terms []*Term) (*Rule, error) {
|
||||
return v1.ParseRuleFromCallExpr(module, terms)
|
||||
}
|
||||
|
||||
// ParseImports returns a slice of Import objects.
|
||||
func ParseImports(input string) ([]*Import, error) {
|
||||
return v1.ParseImports(input)
|
||||
}
|
||||
|
||||
// ParseModule returns a parsed Module object.
|
||||
// For details on Module objects and their fields, see policy.go.
|
||||
// Empty input will return nil, nil.
|
||||
func ParseModule(filename, input string) (*Module, error) {
|
||||
return ParseModuleWithOpts(filename, input, ParserOptions{})
|
||||
}
|
||||
|
||||
// ParseModuleWithOpts returns a parsed Module object, and has an additional input ParserOptions
|
||||
// For details on Module objects and their fields, see policy.go.
|
||||
// Empty input will return nil, nil.
|
||||
func ParseModuleWithOpts(filename, input string, popts ParserOptions) (*Module, error) {
|
||||
return v1.ParseModuleWithOpts(filename, input, setDefaultRegoVersion(popts))
|
||||
}
|
||||
|
||||
// ParseBody returns exactly one body.
|
||||
// If multiple bodies are parsed, an error is returned.
|
||||
func ParseBody(input string) (Body, error) {
|
||||
return ParseBodyWithOpts(input, ParserOptions{SkipRules: true})
|
||||
}
|
||||
|
||||
// ParseBodyWithOpts returns exactly one body. It does _not_ set SkipRules: true on its own,
|
||||
// but respects whatever ParserOptions it's been given.
|
||||
func ParseBodyWithOpts(input string, popts ParserOptions) (Body, error) {
|
||||
return v1.ParseBodyWithOpts(input, setDefaultRegoVersion(popts))
|
||||
}
|
||||
|
||||
// ParseExpr returns exactly one expression.
|
||||
// If multiple expressions are parsed, an error is returned.
|
||||
func ParseExpr(input string) (*Expr, error) {
|
||||
body, err := ParseBody(input)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse expression: %w", err)
|
||||
}
|
||||
if len(body) != 1 {
|
||||
return nil, fmt.Errorf("expected exactly one expression but got: %v", body)
|
||||
}
|
||||
return body[0], nil
|
||||
}
|
||||
|
||||
// ParsePackage returns exactly one Package.
|
||||
// If multiple statements are parsed, an error is returned.
|
||||
func ParsePackage(input string) (*Package, error) {
|
||||
return v1.ParsePackage(input)
|
||||
}
|
||||
|
||||
// ParseTerm returns exactly one term.
|
||||
// If multiple terms are parsed, an error is returned.
|
||||
func ParseTerm(input string) (*Term, error) {
|
||||
body, err := ParseBody(input)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse term: %w", err)
|
||||
}
|
||||
if len(body) != 1 {
|
||||
return nil, fmt.Errorf("expected exactly one term but got: %v", body)
|
||||
}
|
||||
term, ok := body[0].Terms.(*Term)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected term but got %v", body[0].Terms)
|
||||
}
|
||||
return term, nil
|
||||
}
|
||||
|
||||
// ParseRef returns exactly one reference.
|
||||
func ParseRef(input string) (Ref, error) {
|
||||
term, err := ParseTerm(input)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse ref: %w", err)
|
||||
}
|
||||
ref, ok := term.Value.(Ref)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected ref but got %v", term)
|
||||
}
|
||||
return ref, nil
|
||||
}
|
||||
|
||||
// ParseRuleWithOpts returns exactly one rule.
|
||||
// If multiple rules are parsed, an error is returned.
|
||||
func ParseRuleWithOpts(input string, opts ParserOptions) (*Rule, error) {
|
||||
return v1.ParseRuleWithOpts(input, setDefaultRegoVersion(opts))
|
||||
}
|
||||
|
||||
// ParseRule returns exactly one rule.
|
||||
// If multiple rules are parsed, an error is returned.
|
||||
func ParseRule(input string) (*Rule, error) {
|
||||
return ParseRuleWithOpts(input, ParserOptions{})
|
||||
}
|
||||
|
||||
// ParseStatement returns exactly one statement.
|
||||
// A statement might be a term, expression, rule, etc. Regardless,
|
||||
// this function expects *exactly* one statement. If multiple
|
||||
// statements are parsed, an error is returned.
|
||||
func ParseStatement(input string) (Statement, error) {
|
||||
stmts, _, err := ParseStatements("", input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(stmts) != 1 {
|
||||
return nil, fmt.Errorf("expected exactly one statement")
|
||||
}
|
||||
return stmts[0], nil
|
||||
}
|
||||
|
||||
func ParseStatementWithOpts(input string, popts ParserOptions) (Statement, error) {
|
||||
return v1.ParseStatementWithOpts(input, setDefaultRegoVersion(popts))
|
||||
}
|
||||
|
||||
// ParseStatements is deprecated. Use ParseStatementWithOpts instead.
|
||||
func ParseStatements(filename, input string) ([]Statement, []*Comment, error) {
|
||||
return ParseStatementsWithOpts(filename, input, ParserOptions{})
|
||||
}
|
||||
|
||||
// ParseStatementsWithOpts returns a slice of parsed statements. This is the
|
||||
// default return value from the parser.
|
||||
func ParseStatementsWithOpts(filename, input string, popts ParserOptions) ([]Statement, []*Comment, error) {
|
||||
return v1.ParseStatementsWithOpts(filename, input, setDefaultRegoVersion(popts))
|
||||
}
|
||||
|
||||
// ParserErrorDetail holds additional details for parser errors.
|
||||
type ParserErrorDetail = v1.ParserErrorDetail
|
||||
|
||||
func setDefaultRegoVersion(opts ParserOptions) ParserOptions {
|
||||
if opts.RegoVersion == RegoUndefined {
|
||||
opts.RegoVersion = DefaultRegoVersion
|
||||
}
|
||||
return opts
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
// Copyright 2024 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 ast_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/format"
|
||||
)
|
||||
|
||||
func TestParseModule_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
mod string
|
||||
expRules []string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0", // default rego-version
|
||||
mod: `package test
|
||||
p[x] {
|
||||
x = "a"
|
||||
}`,
|
||||
expRules: []string{"p"},
|
||||
},
|
||||
{
|
||||
note: "import rego.v1",
|
||||
mod: `package test
|
||||
import rego.v1
|
||||
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
expRules: []string{"p"},
|
||||
},
|
||||
{
|
||||
note: "v1", // NOT default rego-version
|
||||
mod: `package test
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
expErrs: []string{
|
||||
"test.rego:2: rego_parse_error: var cannot be used for rule name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
m, err := ast.ParseModule("test.rego", tc.mod)
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
for i, expErr := range tc.expErrs {
|
||||
if !strings.Contains(err.Error(), expErr) {
|
||||
t.Fatalf("Expected error %d to contain %q, got %q", i, expErr, err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if len(m.Rules) != len(tc.expRules) {
|
||||
t.Fatalf("Expected %d rules, got %d", len(tc.expRules), len(m.Rules))
|
||||
}
|
||||
for i, r := range m.Rules {
|
||||
if r.Head.Name.String() != tc.expRules[i] {
|
||||
t.Fatalf("Expected rule %q, got %q", tc.expRules[i], r.Head.Name.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseBody_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
body string
|
||||
expStmts int
|
||||
assertSame bool
|
||||
}{
|
||||
{
|
||||
note: "v0", // default rego-version
|
||||
body: `x := ["a", "b", "c"][i]
|
||||
`,
|
||||
expStmts: 1,
|
||||
assertSame: true,
|
||||
},
|
||||
{
|
||||
note: "v1", // NOT default rego-version
|
||||
body: `some x, i in ["a", "b", "c"]
|
||||
`,
|
||||
expStmts: 3,
|
||||
assertSame: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
body, err := ast.ParseBody(tc.body)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if len(body) != tc.expStmts {
|
||||
t.Fatalf("Expected %d statements, got %d:%q\n\n", tc.expStmts, len(body), body)
|
||||
}
|
||||
|
||||
if tc.assertSame {
|
||||
formatted, err := format.AstWithOpts(body, format.Opts{RegoVersion: ast.RegoV1}) // every body is v1-compatible
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if strings.Compare(string(formatted), tc.body) != 0 {
|
||||
t.Fatalf("Expected body to be %q, got %q", tc.body, string(formatted))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2024 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 ast
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParser_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
input string
|
||||
expStmtCount int
|
||||
}{
|
||||
{
|
||||
note: "v0",
|
||||
input: `package test
|
||||
p[x] {
|
||||
c = ["a", "b", "c"][i]
|
||||
}`,
|
||||
expStmtCount: 2, //package, p
|
||||
},
|
||||
{
|
||||
note: "v1",
|
||||
input: `package test
|
||||
p contains x if {
|
||||
c = ["a", "b", "c"][i]
|
||||
}`,
|
||||
// v1 Keywords are not recognized, and interpreted as individual statements
|
||||
expStmtCount: 5, //package, p, contains, x, if
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
parser := NewParser().
|
||||
WithFilename("test.rego").
|
||||
WithReader(bytes.NewBufferString(tc.input))
|
||||
stmts, _, err := parser.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if len(stmts) != tc.expStmtCount {
|
||||
t.Fatalf("Expected %d statements but got %d:\n\n%v", tc.expStmtCount, len(stmts), stmts)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
// Copyright 2024 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 ast
|
||||
|
||||
import (
|
||||
astJSON "github.com/open-policy-agent/opa/ast/json"
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// DefaultRootDocument is the default root document.
|
||||
//
|
||||
// All package directives inside source files are implicitly prefixed with the
|
||||
// DefaultRootDocument value.
|
||||
var DefaultRootDocument = v1.DefaultRootDocument
|
||||
|
||||
// InputRootDocument names the document containing query arguments.
|
||||
var InputRootDocument = v1.InputRootDocument
|
||||
|
||||
// SchemaRootDocument names the document containing external data schemas.
|
||||
var SchemaRootDocument = v1.SchemaRootDocument
|
||||
|
||||
// FunctionArgRootDocument names the document containing function arguments.
|
||||
// It's only for internal usage, for referencing function arguments between
|
||||
// the index and topdown.
|
||||
var FunctionArgRootDocument = v1.FunctionArgRootDocument
|
||||
|
||||
// FutureRootDocument names the document containing new, to-become-default,
|
||||
// features.
|
||||
var FutureRootDocument = v1.FutureRootDocument
|
||||
|
||||
// RegoRootDocument names the document containing new, to-become-default,
|
||||
// features in a future versioned release.
|
||||
var RegoRootDocument = v1.RegoRootDocument
|
||||
|
||||
// RootDocumentNames contains the names of top-level documents that can be
|
||||
// referred to in modules and queries.
|
||||
//
|
||||
// Note, the schema document is not currently implemented in the evaluator so it
|
||||
// is not registered as a root document name (yet).
|
||||
var RootDocumentNames = v1.RootDocumentNames
|
||||
|
||||
// DefaultRootRef is a reference to the root of the default document.
|
||||
//
|
||||
// All refs to data in the policy engine's storage layer are prefixed with this ref.
|
||||
var DefaultRootRef = v1.DefaultRootRef
|
||||
|
||||
// InputRootRef is a reference to the root of the input document.
|
||||
//
|
||||
// All refs to query arguments are prefixed with this ref.
|
||||
var InputRootRef = v1.InputRootRef
|
||||
|
||||
// SchemaRootRef is a reference to the root of the schema document.
|
||||
//
|
||||
// All refs to schema documents are prefixed with this ref. Note, the schema
|
||||
// document is not currently implemented in the evaluator so it is not
|
||||
// registered as a root document ref (yet).
|
||||
var SchemaRootRef = v1.SchemaRootRef
|
||||
|
||||
// RootDocumentRefs contains the prefixes of top-level documents that all
|
||||
// non-local references start with.
|
||||
var RootDocumentRefs = v1.RootDocumentRefs
|
||||
|
||||
// SystemDocumentKey is the name of the top-level key that identifies the system
|
||||
// document.
|
||||
const SystemDocumentKey = v1.SystemDocumentKey
|
||||
|
||||
// ReservedVars is the set of names that refer to implicitly ground vars.
|
||||
var ReservedVars = v1.ReservedVars
|
||||
|
||||
// Wildcard represents the wildcard variable as defined in the language.
|
||||
var Wildcard = v1.Wildcard
|
||||
|
||||
// WildcardPrefix is the special character that all wildcard variables are
|
||||
// prefixed with when the statement they are contained in is parsed.
|
||||
const WildcardPrefix = v1.WildcardPrefix
|
||||
|
||||
// Keywords contains strings that map to language keywords.
|
||||
var Keywords = v1.Keywords
|
||||
|
||||
var KeywordsV0 = v1.KeywordsV0
|
||||
|
||||
var KeywordsV1 = v1.KeywordsV1
|
||||
|
||||
func KeywordsForRegoVersion(v RegoVersion) []string {
|
||||
return v1.KeywordsForRegoVersion(v)
|
||||
}
|
||||
|
||||
// IsKeyword returns true if s is a language keyword.
|
||||
func IsKeyword(s string) bool {
|
||||
return v1.IsKeyword(s)
|
||||
}
|
||||
|
||||
func IsInKeywords(s string, keywords []string) bool {
|
||||
return v1.IsInKeywords(s, keywords)
|
||||
}
|
||||
|
||||
// IsKeywordInRegoVersion returns true if s is a language keyword.
|
||||
func IsKeywordInRegoVersion(s string, regoVersion RegoVersion) bool {
|
||||
return v1.IsKeywordInRegoVersion(s, regoVersion)
|
||||
}
|
||||
|
||||
type (
|
||||
// Node represents a node in an AST. Nodes may be statements in a policy module
|
||||
// or elements of an ad-hoc query, expression, etc.
|
||||
Node = v1.Node
|
||||
|
||||
// Statement represents a single statement in a policy module.
|
||||
Statement = v1.Statement
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
// Module represents a collection of policies (defined by rules)
|
||||
// within a namespace (defined by the package) and optional
|
||||
// dependencies on external documents (defined by imports).
|
||||
Module = v1.Module
|
||||
|
||||
// Comment contains the raw text from the comment in the definition.
|
||||
Comment = v1.Comment
|
||||
|
||||
// Package represents the namespace of the documents produced
|
||||
// by rules inside the module.
|
||||
Package = v1.Package
|
||||
|
||||
// Import represents a dependency on a document outside of the policy
|
||||
// namespace. Imports are optional.
|
||||
Import = v1.Import
|
||||
|
||||
// Rule represents a rule as defined in the language. Rules define the
|
||||
// content of documents that represent policy decisions.
|
||||
Rule = v1.Rule
|
||||
|
||||
// Head represents the head of a rule.
|
||||
Head = v1.Head
|
||||
|
||||
// Args represents zero or more arguments to a rule.
|
||||
Args = v1.Args
|
||||
|
||||
// Body represents one or more expressions contained inside a rule or user
|
||||
// function.
|
||||
Body = v1.Body
|
||||
|
||||
// Expr represents a single expression contained inside the body of a rule.
|
||||
Expr = v1.Expr
|
||||
|
||||
// SomeDecl represents a variable declaration statement. The symbols are variables.
|
||||
SomeDecl = v1.SomeDecl
|
||||
|
||||
Every = v1.Every
|
||||
|
||||
// With represents a modifier on an expression.
|
||||
With = v1.With
|
||||
)
|
||||
|
||||
// NewComment returns a new Comment object.
|
||||
func NewComment(text []byte) *Comment {
|
||||
return v1.NewComment(text)
|
||||
}
|
||||
|
||||
// IsValidImportPath returns an error indicating if the import path is invalid.
|
||||
// If the import path is valid, err is nil.
|
||||
func IsValidImportPath(v Value) (err error) {
|
||||
return v1.IsValidImportPath(v)
|
||||
}
|
||||
|
||||
// NewHead returns a new Head object. If args are provided, the first will be
|
||||
// used for the key and the second will be used for the value.
|
||||
func NewHead(name Var, args ...*Term) *Head {
|
||||
return v1.NewHead(name, args...)
|
||||
}
|
||||
|
||||
// VarHead creates a head object, initializes its Name, Location, and Options,
|
||||
// and returns the new head.
|
||||
func VarHead(name Var, location *Location, jsonOpts *astJSON.Options) *Head {
|
||||
return v1.VarHead(name, location, jsonOpts)
|
||||
}
|
||||
|
||||
// RefHead returns a new Head object with the passed Ref. If args are provided,
|
||||
// the first will be used for the value.
|
||||
func RefHead(ref Ref, args ...*Term) *Head {
|
||||
return v1.RefHead(ref, args...)
|
||||
}
|
||||
|
||||
// DocKind represents the collection of document types that can be produced by rules.
|
||||
type DocKind int
|
||||
|
||||
const (
|
||||
// CompleteDoc represents a document that is completely defined by the rule.
|
||||
CompleteDoc = v1.CompleteDoc
|
||||
|
||||
// PartialSetDoc represents a set document that is partially defined by the rule.
|
||||
PartialSetDoc = v1.PartialSetDoc
|
||||
|
||||
// PartialObjectDoc represents an object document that is partially defined by the rule.
|
||||
PartialObjectDoc = v1.PartialObjectDoc
|
||||
)
|
||||
|
||||
type RuleKind = v1.RuleKind
|
||||
|
||||
const (
|
||||
SingleValue = v1.SingleValue
|
||||
MultiValue = v1.MultiValue
|
||||
)
|
||||
|
||||
// NewBody returns a new Body containing the given expressions. The indices of
|
||||
// the immediate expressions will be reset.
|
||||
func NewBody(exprs ...*Expr) Body {
|
||||
return v1.NewBody(exprs...)
|
||||
}
|
||||
|
||||
// NewExpr returns a new Expr object.
|
||||
func NewExpr(terms interface{}) *Expr {
|
||||
return v1.NewExpr(terms)
|
||||
}
|
||||
|
||||
// NewBuiltinExpr creates a new Expr object with the supplied terms.
|
||||
// The builtin operator must be the first term.
|
||||
func NewBuiltinExpr(terms ...*Term) *Expr {
|
||||
return v1.NewBuiltinExpr(terms...)
|
||||
}
|
||||
|
||||
// Copy returns a deep copy of the AST node x. If x is not an AST node, x is returned unmodified.
|
||||
func Copy(x interface{}) interface{} {
|
||||
return v1.Copy(x)
|
||||
}
|
||||
|
||||
// RuleSet represents a collection of rules that produce a virtual document.
|
||||
type RuleSet = v1.RuleSet
|
||||
|
||||
// NewRuleSet returns a new RuleSet containing the given rules.
|
||||
func NewRuleSet(rules ...*Rule) RuleSet {
|
||||
return v1.NewRuleSet(rules...)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright 2024 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 ast
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRuleString_DefaultRegoVersion(t *testing.T) {
|
||||
// ast.Rule.String() will respect the rego-version of the ast.Module it is part of.
|
||||
|
||||
tests := []struct {
|
||||
note string
|
||||
module string
|
||||
regoVersion RegoVersion
|
||||
exp string
|
||||
}{
|
||||
{
|
||||
note: "v0",
|
||||
regoVersion: RegoV0,
|
||||
module: `package a.b.c
|
||||
|
||||
p[x] { x = "a" }`,
|
||||
exp: `p[x] { x = "a" }`,
|
||||
},
|
||||
{
|
||||
note: "v1",
|
||||
regoVersion: RegoV1,
|
||||
module: `package a.b.c
|
||||
|
||||
p contains x if { x = "a" }`,
|
||||
exp: `p contains x if { x = "a" }`,
|
||||
},
|
||||
{
|
||||
note: "default rego-version",
|
||||
module: `package a.b.c
|
||||
|
||||
p[x] { x = "a" }`,
|
||||
exp: `p[x] { x = "a" }`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
var mod *Module
|
||||
|
||||
if tc.regoVersion == RegoUndefined {
|
||||
mod = MustParseModule(tc.module)
|
||||
} else {
|
||||
mod = MustParseModuleWithOpts(tc.module, ParserOptions{RegoVersion: tc.regoVersion})
|
||||
}
|
||||
|
||||
rule := mod.Rules[0]
|
||||
act := rule.String()
|
||||
|
||||
if act != tc.exp {
|
||||
t.Fatalf("Expected:\n\n%s\n\nbut got:\n\n%s", tc.exp, act)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestModuleString(t *testing.T) {
|
||||
|
||||
// v0 module
|
||||
input := `package a.b.c
|
||||
|
||||
import data.foo.bar
|
||||
import input.xyz
|
||||
|
||||
p = true { not bar }
|
||||
q = true { xyz.abc = 2 }
|
||||
wildcard = true { bar[_] = 1 }`
|
||||
|
||||
mod := MustParseModule(input)
|
||||
|
||||
roundtrip, err := ParseModule("", mod.String())
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error while parsing roundtripped module: %v", err)
|
||||
}
|
||||
|
||||
if !roundtrip.Equal(mod) {
|
||||
t.Fatalf("Expected roundtripped to equal original but:\n\nExpected:\n\n%v\n\nDoes not equal result:\n\n%v", mod, roundtrip)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2018 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 ast
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// Pretty writes a pretty representation of the AST rooted at x to w.
|
||||
//
|
||||
// This is function is intended for debug purposes when inspecting ASTs.
|
||||
func Pretty(w io.Writer, x interface{}) {
|
||||
v1.Pretty(w, x)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2021 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// SchemaSet holds a map from a path to a schema.
|
||||
type SchemaSet = v1.SchemaSet
|
||||
|
||||
// NewSchemaSet returns an empty SchemaSet.
|
||||
func NewSchemaSet() *SchemaSet {
|
||||
return v1.NewSchemaSet()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// TypeName returns a human readable name for the AST element type.
|
||||
func TypeName(x interface{}) string {
|
||||
return v1.TypeName(x)
|
||||
}
|
||||
+306
@@ -0,0 +1,306 @@
|
||||
// Copyright 2024 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 ast
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// Location records a position in source code.
|
||||
type Location = v1.Location
|
||||
|
||||
// NewLocation returns a new Location object.
|
||||
func NewLocation(text []byte, file string, row int, col int) *Location {
|
||||
return v1.NewLocation(text, file, row, col)
|
||||
}
|
||||
|
||||
// Value declares the common interface for all Term values. Every kind of Term value
|
||||
// in the language is represented as a type that implements this interface:
|
||||
//
|
||||
// - Null, Boolean, Number, String
|
||||
// - Object, Array, Set
|
||||
// - Variables, References
|
||||
// - Array, Set, and Object Comprehensions
|
||||
// - Calls
|
||||
type Value = v1.Value
|
||||
|
||||
// InterfaceToValue converts a native Go value x to a Value.
|
||||
func InterfaceToValue(x interface{}) (Value, error) {
|
||||
return v1.InterfaceToValue(x)
|
||||
}
|
||||
|
||||
// ValueFromReader returns an AST value from a JSON serialized value in the reader.
|
||||
func ValueFromReader(r io.Reader) (Value, error) {
|
||||
return v1.ValueFromReader(r)
|
||||
}
|
||||
|
||||
// As converts v into a Go native type referred to by x.
|
||||
func As(v Value, x interface{}) error {
|
||||
return v1.As(v, x)
|
||||
}
|
||||
|
||||
// Resolver defines the interface for resolving references to native Go values.
|
||||
type Resolver = v1.Resolver
|
||||
|
||||
// ValueResolver defines the interface for resolving references to AST values.
|
||||
type ValueResolver = v1.ValueResolver
|
||||
|
||||
// UnknownValueErr indicates a ValueResolver was unable to resolve a reference
|
||||
// because the reference refers to an unknown value.
|
||||
type UnknownValueErr = v1.UnknownValueErr
|
||||
|
||||
// IsUnknownValueErr returns true if the err is an UnknownValueErr.
|
||||
func IsUnknownValueErr(err error) bool {
|
||||
return v1.IsUnknownValueErr(err)
|
||||
}
|
||||
|
||||
// ValueToInterface returns the Go representation of an AST value. The AST
|
||||
// value should not contain any values that require evaluation (e.g., vars,
|
||||
// comprehensions, etc.)
|
||||
func ValueToInterface(v Value, resolver Resolver) (interface{}, error) {
|
||||
return v1.ValueToInterface(v, resolver)
|
||||
}
|
||||
|
||||
// JSON returns the JSON representation of v. The value must not contain any
|
||||
// refs or terms that require evaluation (e.g., vars, comprehensions, etc.)
|
||||
func JSON(v Value) (interface{}, error) {
|
||||
return v1.JSON(v)
|
||||
}
|
||||
|
||||
// JSONOpt defines parameters for AST to JSON conversion.
|
||||
type JSONOpt = v1.JSONOpt
|
||||
|
||||
// JSONWithOpt returns the JSON representation of v. The value must not contain any
|
||||
// refs or terms that require evaluation (e.g., vars, comprehensions, etc.)
|
||||
func JSONWithOpt(v Value, opt JSONOpt) (interface{}, error) {
|
||||
return v1.JSONWithOpt(v, opt)
|
||||
}
|
||||
|
||||
// MustJSON returns the JSON representation of v. The value must not contain any
|
||||
// refs or terms that require evaluation (e.g., vars, comprehensions, etc.) If
|
||||
// the conversion fails, this function will panic. This function is mostly for
|
||||
// test purposes.
|
||||
func MustJSON(v Value) interface{} {
|
||||
return v1.MustJSON(v)
|
||||
}
|
||||
|
||||
// MustInterfaceToValue converts a native Go value x to a Value. If the
|
||||
// conversion fails, this function will panic. This function is mostly for test
|
||||
// purposes.
|
||||
func MustInterfaceToValue(x interface{}) Value {
|
||||
return v1.MustInterfaceToValue(x)
|
||||
}
|
||||
|
||||
// Term is an argument to a function.
|
||||
type Term = v1.Term
|
||||
|
||||
// NewTerm returns a new Term object.
|
||||
func NewTerm(v Value) *Term {
|
||||
return v1.NewTerm(v)
|
||||
}
|
||||
|
||||
// IsConstant returns true if the AST value is constant.
|
||||
func IsConstant(v Value) bool {
|
||||
return v1.IsConstant(v)
|
||||
}
|
||||
|
||||
// IsComprehension returns true if the supplied value is a comprehension.
|
||||
func IsComprehension(x Value) bool {
|
||||
return v1.IsComprehension(x)
|
||||
}
|
||||
|
||||
// ContainsRefs returns true if the Value v contains refs.
|
||||
func ContainsRefs(v interface{}) bool {
|
||||
return v1.ContainsRefs(v)
|
||||
}
|
||||
|
||||
// ContainsComprehensions returns true if the Value v contains comprehensions.
|
||||
func ContainsComprehensions(v interface{}) bool {
|
||||
return v1.ContainsComprehensions(v)
|
||||
}
|
||||
|
||||
// ContainsClosures returns true if the Value v contains closures.
|
||||
func ContainsClosures(v interface{}) bool {
|
||||
return v1.ContainsClosures(v)
|
||||
}
|
||||
|
||||
// IsScalar returns true if the AST value is a scalar.
|
||||
func IsScalar(v Value) bool {
|
||||
return v1.IsScalar(v)
|
||||
}
|
||||
|
||||
// Null represents the null value defined by JSON.
|
||||
type Null = v1.Null
|
||||
|
||||
// NullTerm creates a new Term with a Null value.
|
||||
func NullTerm() *Term {
|
||||
return v1.NullTerm()
|
||||
}
|
||||
|
||||
// Boolean represents a boolean value defined by JSON.
|
||||
type Boolean = v1.Boolean
|
||||
|
||||
// BooleanTerm creates a new Term with a Boolean value.
|
||||
func BooleanTerm(b bool) *Term {
|
||||
return v1.BooleanTerm(b)
|
||||
}
|
||||
|
||||
// Number represents a numeric value as defined by JSON.
|
||||
type Number = v1.Number
|
||||
|
||||
// NumberTerm creates a new Term with a Number value.
|
||||
func NumberTerm(n json.Number) *Term {
|
||||
return v1.NumberTerm(n)
|
||||
}
|
||||
|
||||
// IntNumberTerm creates a new Term with an integer Number value.
|
||||
func IntNumberTerm(i int) *Term {
|
||||
return v1.IntNumberTerm(i)
|
||||
}
|
||||
|
||||
// UIntNumberTerm creates a new Term with an unsigned integer Number value.
|
||||
func UIntNumberTerm(u uint64) *Term {
|
||||
return v1.UIntNumberTerm(u)
|
||||
}
|
||||
|
||||
// FloatNumberTerm creates a new Term with a floating point Number value.
|
||||
func FloatNumberTerm(f float64) *Term {
|
||||
return v1.FloatNumberTerm(f)
|
||||
}
|
||||
|
||||
// String represents a string value as defined by JSON.
|
||||
type String = v1.String
|
||||
|
||||
// StringTerm creates a new Term with a String value.
|
||||
func StringTerm(s string) *Term {
|
||||
return v1.StringTerm(s)
|
||||
}
|
||||
|
||||
// Var represents a variable as defined by the language.
|
||||
type Var = v1.Var
|
||||
|
||||
// VarTerm creates a new Term with a Variable value.
|
||||
func VarTerm(v string) *Term {
|
||||
return v1.VarTerm(v)
|
||||
}
|
||||
|
||||
// Ref represents a reference as defined by the language.
|
||||
type Ref = v1.Ref
|
||||
|
||||
// EmptyRef returns a new, empty reference.
|
||||
func EmptyRef() Ref {
|
||||
return v1.EmptyRef()
|
||||
}
|
||||
|
||||
// PtrRef returns a new reference against the head for the pointer
|
||||
// s. Path components in the pointer are unescaped.
|
||||
func PtrRef(head *Term, s string) (Ref, error) {
|
||||
return v1.PtrRef(head, s)
|
||||
}
|
||||
|
||||
// RefTerm creates a new Term with a Ref value.
|
||||
func RefTerm(r ...*Term) *Term {
|
||||
return v1.RefTerm(r...)
|
||||
}
|
||||
|
||||
func IsVarCompatibleString(s string) bool {
|
||||
return v1.IsVarCompatibleString(s)
|
||||
}
|
||||
|
||||
// QueryIterator defines the interface for querying AST documents with references.
|
||||
type QueryIterator = v1.QueryIterator
|
||||
|
||||
// ArrayTerm creates a new Term with an Array value.
|
||||
func ArrayTerm(a ...*Term) *Term {
|
||||
return v1.ArrayTerm(a...)
|
||||
}
|
||||
|
||||
// NewArray creates an Array with the terms provided. The array will
|
||||
// use the provided term slice.
|
||||
func NewArray(a ...*Term) *Array {
|
||||
return v1.NewArray(a...)
|
||||
}
|
||||
|
||||
// Array represents an array as defined by the language. Arrays are similar to the
|
||||
// same types as defined by JSON with the exception that they can contain Vars
|
||||
// and References.
|
||||
type Array = v1.Array
|
||||
|
||||
// Set represents a set as defined by the language.
|
||||
type Set = v1.Set
|
||||
|
||||
// NewSet returns a new Set containing t.
|
||||
func NewSet(t ...*Term) Set {
|
||||
return v1.NewSet(t...)
|
||||
}
|
||||
|
||||
func SetTerm(t ...*Term) *Term {
|
||||
return v1.SetTerm(t...)
|
||||
}
|
||||
|
||||
// Object represents an object as defined by the language.
|
||||
type Object = v1.Object
|
||||
|
||||
// NewObject creates a new Object with t.
|
||||
func NewObject(t ...[2]*Term) Object {
|
||||
return v1.NewObject(t...)
|
||||
}
|
||||
|
||||
// ObjectTerm creates a new Term with an Object value.
|
||||
func ObjectTerm(o ...[2]*Term) *Term {
|
||||
return v1.ObjectTerm(o...)
|
||||
}
|
||||
|
||||
func LazyObject(blob map[string]interface{}) Object {
|
||||
return v1.LazyObject(blob)
|
||||
}
|
||||
|
||||
// Item is a helper for constructing an tuple containing two Terms
|
||||
// representing a key/value pair in an Object.
|
||||
func Item(key, value *Term) [2]*Term {
|
||||
return v1.Item(key, value)
|
||||
}
|
||||
|
||||
// NOTE(philipc): The only way to get an ObjectKeyIterator should be
|
||||
// from an Object. This ensures that the iterator can have implementation-
|
||||
// specific details internally, with no contracts except to the very
|
||||
// limited interface.
|
||||
type ObjectKeysIterator = v1.ObjectKeysIterator
|
||||
|
||||
// ArrayComprehension represents an array comprehension as defined in the language.
|
||||
type ArrayComprehension = v1.ArrayComprehension
|
||||
|
||||
// ArrayComprehensionTerm creates a new Term with an ArrayComprehension value.
|
||||
func ArrayComprehensionTerm(term *Term, body Body) *Term {
|
||||
return v1.ArrayComprehensionTerm(term, body)
|
||||
}
|
||||
|
||||
// ObjectComprehension represents an object comprehension as defined in the language.
|
||||
type ObjectComprehension = v1.ObjectComprehension
|
||||
|
||||
// ObjectComprehensionTerm creates a new Term with an ObjectComprehension value.
|
||||
func ObjectComprehensionTerm(key, value *Term, body Body) *Term {
|
||||
return v1.ObjectComprehensionTerm(key, value, body)
|
||||
}
|
||||
|
||||
// SetComprehension represents a set comprehension as defined in the language.
|
||||
type SetComprehension = v1.SetComprehension
|
||||
|
||||
// SetComprehensionTerm creates a new Term with an SetComprehension value.
|
||||
func SetComprehensionTerm(term *Term, body Body) *Term {
|
||||
return v1.SetComprehensionTerm(term, body)
|
||||
}
|
||||
|
||||
// Call represents as function call in the language.
|
||||
type Call = v1.Call
|
||||
|
||||
// CallTerm returns a new Term with a Call value defined by terms. The first
|
||||
// term is the operator and the rest are operands.
|
||||
func CallTerm(terms ...*Term) *Term {
|
||||
return v1.CallTerm(terms...)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// Transformer defines the interface for transforming AST elements. If the
|
||||
// transformer returns nil and does not indicate an error, the AST element will
|
||||
// be set to nil and no transformations will be applied to children of the
|
||||
// element.
|
||||
type Transformer = v1.Transformer
|
||||
|
||||
// Transform iterates the AST and calls the Transform function on the
|
||||
// Transformer t for x before recursing.
|
||||
func Transform(t Transformer, x interface{}) (interface{}, error) {
|
||||
return v1.Transform(t, x)
|
||||
}
|
||||
|
||||
// TransformRefs calls the function f on all references under x.
|
||||
func TransformRefs(x interface{}, f func(Ref) (Value, error)) (interface{}, error) {
|
||||
return v1.TransformRefs(x, f)
|
||||
}
|
||||
|
||||
// TransformVars calls the function f on all vars under x.
|
||||
func TransformVars(x interface{}, f func(Var) (Value, error)) (interface{}, error) {
|
||||
return v1.TransformVars(x, f)
|
||||
}
|
||||
|
||||
// TransformComprehensions calls the functio nf on all comprehensions under x.
|
||||
func TransformComprehensions(x interface{}, f func(interface{}) (Value, error)) (interface{}, error) {
|
||||
return v1.TransformComprehensions(x, f)
|
||||
}
|
||||
|
||||
// GenericTransformer implements the Transformer interface to provide a utility
|
||||
// to transform AST nodes using a closure.
|
||||
type GenericTransformer = v1.GenericTransformer
|
||||
|
||||
// NewGenericTransformer returns a new GenericTransformer that will transform
|
||||
// AST nodes using the function f.
|
||||
func NewGenericTransformer(f func(x interface{}) (interface{}, error)) *GenericTransformer {
|
||||
return v1.NewGenericTransformer(f)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
|
||||
// Unify returns a set of variables that will be unified when the equality expression defined by
|
||||
// terms a and b is evaluated. The unifier assumes that variables in the VarSet safe are already
|
||||
// unified.
|
||||
func Unify(safe VarSet, a *Term, b *Term) VarSet {
|
||||
return v1.Unify(safe, a, b)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
)
|
||||
|
||||
// VarSet represents a set of variables.
|
||||
type VarSet = v1.VarSet
|
||||
|
||||
// NewVarSet returns a new VarSet containing the specified variables.
|
||||
func NewVarSet(vs ...Var) VarSet {
|
||||
return v1.NewVarSet(vs...)
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
// Copyright 2016 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 ast
|
||||
|
||||
import v1 "github.com/open-policy-agent/opa/v1/ast"
|
||||
|
||||
// Visitor defines the interface for iterating AST elements. The Visit function
|
||||
// can return a Visitor w which will be used to visit the children of the AST
|
||||
// element v. If the Visit function returns nil, the children will not be
|
||||
// visited.
|
||||
// Deprecated: use GenericVisitor or another visitor implementation
|
||||
type Visitor = v1.Visitor
|
||||
|
||||
// BeforeAndAfterVisitor wraps Visitor to provide hooks for being called before
|
||||
// and after the AST has been visited.
|
||||
// Deprecated: use GenericVisitor or another visitor implementation
|
||||
type BeforeAndAfterVisitor = v1.BeforeAndAfterVisitor
|
||||
|
||||
// Walk iterates the AST by calling the Visit function on the Visitor
|
||||
// v for x before recursing.
|
||||
// Deprecated: use GenericVisitor.Walk
|
||||
func Walk(v Visitor, x interface{}) {
|
||||
v1.Walk(v, x)
|
||||
}
|
||||
|
||||
// WalkBeforeAndAfter iterates the AST by calling the Visit function on the
|
||||
// Visitor v for x before recursing.
|
||||
// Deprecated: use GenericVisitor.Walk
|
||||
func WalkBeforeAndAfter(v BeforeAndAfterVisitor, x interface{}) {
|
||||
v1.WalkBeforeAndAfter(v, x)
|
||||
}
|
||||
|
||||
// WalkVars calls the function f on all vars under x. If the function f
|
||||
// returns true, AST nodes under the last node will not be visited.
|
||||
func WalkVars(x interface{}, f func(Var) bool) {
|
||||
v1.WalkVars(x, f)
|
||||
}
|
||||
|
||||
// WalkClosures calls the function f on all closures under x. If the function f
|
||||
// returns true, AST nodes under the last node will not be visited.
|
||||
func WalkClosures(x interface{}, f func(interface{}) bool) {
|
||||
v1.WalkClosures(x, f)
|
||||
}
|
||||
|
||||
// WalkRefs calls the function f on all references under x. If the function f
|
||||
// returns true, AST nodes under the last node will not be visited.
|
||||
func WalkRefs(x interface{}, f func(Ref) bool) {
|
||||
v1.WalkRefs(x, f)
|
||||
}
|
||||
|
||||
// WalkTerms calls the function f on all terms under x. If the function f
|
||||
// returns true, AST nodes under the last node will not be visited.
|
||||
func WalkTerms(x interface{}, f func(*Term) bool) {
|
||||
v1.WalkTerms(x, f)
|
||||
}
|
||||
|
||||
// WalkWiths calls the function f on all with modifiers under x. If the function f
|
||||
// returns true, AST nodes under the last node will not be visited.
|
||||
func WalkWiths(x interface{}, f func(*With) bool) {
|
||||
v1.WalkWiths(x, f)
|
||||
}
|
||||
|
||||
// WalkExprs calls the function f on all expressions under x. If the function f
|
||||
// returns true, AST nodes under the last node will not be visited.
|
||||
func WalkExprs(x interface{}, f func(*Expr) bool) {
|
||||
v1.WalkExprs(x, f)
|
||||
}
|
||||
|
||||
// WalkBodies calls the function f on all bodies under x. If the function f
|
||||
// returns true, AST nodes under the last node will not be visited.
|
||||
func WalkBodies(x interface{}, f func(Body) bool) {
|
||||
v1.WalkBodies(x, f)
|
||||
}
|
||||
|
||||
// WalkRules calls the function f on all rules under x. If the function f
|
||||
// returns true, AST nodes under the last node will not be visited.
|
||||
func WalkRules(x interface{}, f func(*Rule) bool) {
|
||||
v1.WalkRules(x, f)
|
||||
}
|
||||
|
||||
// WalkNodes calls the function f on all nodes under x. If the function f
|
||||
// returns true, AST nodes under the last node will not be visited.
|
||||
func WalkNodes(x interface{}, f func(Node) bool) {
|
||||
v1.WalkNodes(x, f)
|
||||
}
|
||||
|
||||
// GenericVisitor provides a utility to walk over AST nodes using a
|
||||
// closure. If the closure returns true, the visitor will not walk
|
||||
// over AST nodes under x.
|
||||
type GenericVisitor = v1.GenericVisitor
|
||||
|
||||
// NewGenericVisitor returns a new GenericVisitor that will invoke the function
|
||||
// f on AST nodes.
|
||||
func NewGenericVisitor(f func(x interface{}) bool) *GenericVisitor {
|
||||
return v1.NewGenericVisitor(f)
|
||||
}
|
||||
|
||||
// BeforeAfterVisitor provides a utility to walk over AST nodes using
|
||||
// closures. If the before closure returns true, the visitor will not
|
||||
// walk over AST nodes under x. The after closure is invoked always
|
||||
// after visiting a node.
|
||||
type BeforeAfterVisitor = v1.BeforeAfterVisitor
|
||||
|
||||
// NewBeforeAfterVisitor returns a new BeforeAndAfterVisitor that
|
||||
// will invoke the functions before and after AST nodes.
|
||||
func NewBeforeAfterVisitor(before func(x interface{}) bool, after func(x interface{})) *BeforeAfterVisitor {
|
||||
return v1.NewBeforeAfterVisitor(before, after)
|
||||
}
|
||||
|
||||
// VarVisitor walks AST nodes under a given node and collects all encountered
|
||||
// variables. The collected variables can be controlled by specifying
|
||||
// VarVisitorParams when creating the visitor.
|
||||
type VarVisitor = v1.VarVisitor
|
||||
|
||||
// VarVisitorParams contains settings for a VarVisitor.
|
||||
type VarVisitorParams = v1.VarVisitorParams
|
||||
|
||||
// NewVarVisitor returns a new VarVisitor object.
|
||||
func NewVarVisitor() *VarVisitor {
|
||||
return v1.NewVarVisitor()
|
||||
}
|
||||
+12
-12
@@ -5,11 +5,11 @@ TARGET="$2"
|
||||
|
||||
PATH_SEPARATOR="/"
|
||||
BASE_PATH=$(pwd)
|
||||
TEST_PATH="${BASE_PATH}/test/cli/smoke/namespace/data.json"
|
||||
TEST_PATH="${BASE_PATH}/v1/test/cli/smoke/namespace/data.json"
|
||||
if [[ $OPA_EXEC == *".exe" ]]; then
|
||||
PATH_SEPARATOR="\\"
|
||||
BASE_PATH=$(pwd -W)
|
||||
TEST_PATH="$(echo ${BASE_PATH}/test/cli/smoke/namespace/data.json | sed 's/^\///' | sed 's/\//\\\\/g')"
|
||||
TEST_PATH="$(echo ${BASE_PATH}/v1/test/cli/smoke/namespace/data.json | sed 's/^\///' | sed 's/\//\\\\/g')"
|
||||
BASE_PATH=$(echo ${BASE_PATH} | sed 's/^\///' | sed 's/\//\\/g')
|
||||
fi
|
||||
|
||||
@@ -47,26 +47,26 @@ assert_not_contains() {
|
||||
|
||||
opa version
|
||||
opa eval -t $TARGET 'time.now_ns()'
|
||||
opa eval --format pretty --bundle test/cli/smoke/golden-bundle.tar.gz --input test/cli/smoke/input.json data.test.result --fail
|
||||
opa exec --bundle test/cli/smoke/golden-bundle.tar.gz --decision test/result test/cli/smoke/input.json
|
||||
opa build --output o0.tar.gz test/cli/smoke/data.yaml test/cli/smoke/test.rego
|
||||
opa eval --format pretty --bundle v1/test/cli/smoke/golden-bundle.tar.gz --input v1/test/cli/smoke/input.json data.test.result --fail
|
||||
opa exec --bundle v1/test/cli/smoke/golden-bundle.tar.gz --decision test/result v1/test/cli/smoke/input.json
|
||||
opa build --output o0.tar.gz v1/test/cli/smoke/data.yaml v1/test/cli/smoke/test.rego
|
||||
echo '{"yay": "bar"}' | opa eval --format pretty --bundle o0.tar.gz -I data.test.result --fail
|
||||
opa build --optimize 1 --output o1.tar.gz test/cli/smoke/data.yaml test/cli/smoke/test.rego
|
||||
opa build --optimize 1 --output o1.tar.gz v1/test/cli/smoke/data.yaml v1/test/cli/smoke/test.rego
|
||||
echo '{"yay": "bar"}' | opa eval --format pretty --bundle o1.tar.gz -I data.test.result --fail
|
||||
opa build --optimize 2 --output o2.tar.gz test/cli/smoke/data.yaml test/cli/smoke/test.rego
|
||||
opa build --optimize 2 --output o2.tar.gz v1/test/cli/smoke/data.yaml v1/test/cli/smoke/test.rego
|
||||
echo '{"yay": "bar"}' | opa eval --format pretty --bundle o2.tar.gz -I data.test.result --fail
|
||||
|
||||
# Tar paths
|
||||
opa build --output o3.tar.gz test/cli/smoke
|
||||
github_actions_group assert_contains '/test/cli/smoke/test.rego' "$(tar -tf o3.tar.gz /test/cli/smoke/test.rego)"
|
||||
opa build --output o3.tar.gz v1/test/cli/smoke
|
||||
github_actions_group assert_contains '/v1/test/cli/smoke/test.rego' "$(tar -tf o3.tar.gz /v1/test/cli/smoke/test.rego)"
|
||||
|
||||
# Data files - correct namespaces
|
||||
echo "::group:: Data files - correct namespaces"
|
||||
assert_contains "data.namespace | test${PATH_SEPARATOR}cli${PATH_SEPARATOR}smoke${PATH_SEPARATOR}namespace${PATH_SEPARATOR}data.json" "$(opa inspect test/cli/smoke)"
|
||||
assert_contains "data.namespace | v1${PATH_SEPARATOR}test${PATH_SEPARATOR}cli${PATH_SEPARATOR}smoke${PATH_SEPARATOR}namespace${PATH_SEPARATOR}data.json" "$(opa inspect v1/test/cli/smoke)"
|
||||
echo "::endgroup::"
|
||||
|
||||
# Data files - correct root path
|
||||
echo "::group:: Data files - correct root path"
|
||||
assert_contains "${TEST_PATH}" "$(opa inspect ${BASE_PATH}/test/cli/smoke -f json)"
|
||||
assert_not_contains "\\\\${TEST_PATH}" "$(opa inspect ${BASE_PATH}/test/cli/smoke -f json)"
|
||||
assert_contains "${TEST_PATH}" "$(opa inspect ${BASE_PATH}/v1/test/cli/smoke -f json)"
|
||||
assert_not_contains "\\\\${TEST_PATH}" "$(opa inspect ${BASE_PATH}/v1/test/cli/smoke -f json)"
|
||||
echo "::endgroup::"
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
awk -F'"' '/^var Version/{print $2}' version/version.go
|
||||
awk -F'"' '/^var Version/{print $2}' v1/version/version.go
|
||||
@@ -3,4 +3,4 @@
|
||||
set -e
|
||||
# NOTE(sr): This was the only way I've found to replace the string
|
||||
# reliably on OSX and Linux.
|
||||
perl -pi -e "s/Version = \".*\"$/Version = \"$1\"/" version/version.go
|
||||
perl -pi -e "s/Version = \".*\"$/Version = \"$1\"/" v1/version/version.go
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright 2018 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 bundle implements bundle loading.
|
||||
package bundle
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
v1 "github.com/open-policy-agent/opa/v1/bundle"
|
||||
)
|
||||
|
||||
// Common file extensions and file names.
|
||||
const (
|
||||
RegoExt = v1.RegoExt
|
||||
WasmFile = v1.WasmFile
|
||||
PlanFile = v1.PlanFile
|
||||
ManifestExt = v1.ManifestExt
|
||||
SignaturesFile = v1.SignaturesFile
|
||||
|
||||
DefaultSizeLimitBytes = v1.DefaultSizeLimitBytes
|
||||
DeltaBundleType = v1.DeltaBundleType
|
||||
SnapshotBundleType = v1.SnapshotBundleType
|
||||
)
|
||||
|
||||
// Bundle represents a loaded bundle. The bundle can contain data and policies.
|
||||
type Bundle = v1.Bundle
|
||||
|
||||
// Raw contains raw bytes representing the bundle's content
|
||||
type Raw = v1.Raw
|
||||
|
||||
// Patch contains an array of objects wherein each object represents the patch operation to be
|
||||
// applied to the bundle data.
|
||||
type Patch = v1.Patch
|
||||
|
||||
// PatchOperation models a single patch operation against a document.
|
||||
type PatchOperation = v1.PatchOperation
|
||||
|
||||
// SignaturesConfig represents an array of JWTs that encapsulate the signatures for the bundle.
|
||||
type SignaturesConfig = v1.SignaturesConfig
|
||||
|
||||
// DecodedSignature represents the decoded JWT payload.
|
||||
type DecodedSignature = v1.DecodedSignature
|
||||
|
||||
// FileInfo contains the hashing algorithm used, resulting digest etc.
|
||||
type FileInfo = v1.FileInfo
|
||||
|
||||
// NewFile returns a new FileInfo.
|
||||
func NewFile(name, hash, alg string) FileInfo {
|
||||
return v1.NewFile(name, hash, alg)
|
||||
}
|
||||
|
||||
// Manifest represents the manifest from a bundle. The manifest may contain
|
||||
// metadata such as the bundle revision.
|
||||
type Manifest = v1.Manifest
|
||||
|
||||
// WasmResolver maps a wasm module to an entrypoint ref.
|
||||
type WasmResolver = v1.WasmResolver
|
||||
|
||||
// ModuleFile represents a single module contained in a bundle.
|
||||
type ModuleFile = v1.ModuleFile
|
||||
|
||||
// WasmModuleFile represents a single wasm module contained in a bundle.
|
||||
type WasmModuleFile = v1.WasmModuleFile
|
||||
|
||||
// PlanModuleFile represents a single plan module contained in a bundle.
|
||||
//
|
||||
// NOTE(tsandall): currently the plans are just opaque binary blobs. In the
|
||||
// future we could inject the entrypoints so that the plans could be executed
|
||||
// inside of OPA proper like we do for Wasm modules.
|
||||
type PlanModuleFile = v1.PlanModuleFile
|
||||
|
||||
// Reader contains the reader to load the bundle from.
|
||||
type Reader = v1.Reader
|
||||
|
||||
// NewReader is deprecated. Use NewCustomReader instead.
|
||||
func NewReader(r io.Reader) *Reader {
|
||||
return v1.NewReader(r).WithRegoVersion(ast.DefaultRegoVersion)
|
||||
}
|
||||
|
||||
// NewCustomReader returns a new Reader configured to use the
|
||||
// specified DirectoryLoader.
|
||||
func NewCustomReader(loader DirectoryLoader) *Reader {
|
||||
return v1.NewCustomReader(loader).WithRegoVersion(ast.DefaultRegoVersion)
|
||||
}
|
||||
|
||||
// Write is deprecated. Use NewWriter instead.
|
||||
func Write(w io.Writer, bundle Bundle) error {
|
||||
return v1.Write(w, bundle)
|
||||
}
|
||||
|
||||
// Writer implements bundle serialization.
|
||||
type Writer = v1.Writer
|
||||
|
||||
// NewWriter returns a bundle writer that writes to w.
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
return v1.NewWriter(w)
|
||||
}
|
||||
|
||||
// Merge accepts a set of bundles and merges them into a single result bundle. If there are
|
||||
// any conflicts during the merge (e.g., with roots) an error is returned. The result bundle
|
||||
// will have an empty revision except in the special case where a single bundle is provided
|
||||
// (and in that case the bundle is just returned unmodified.)
|
||||
func Merge(bundles []*Bundle) (*Bundle, error) {
|
||||
return MergeWithRegoVersion(bundles, ast.DefaultRegoVersion, false)
|
||||
}
|
||||
|
||||
// MergeWithRegoVersion creates a merged bundle from the provided bundles, similar to Merge.
|
||||
// If more than one bundle is provided, the rego version of the result bundle is set to the provided regoVersion.
|
||||
// Any Rego files in a bundle of conflicting rego version will be marked in the result's manifest with the rego version
|
||||
// of its original bundle. If the Rego file already had an overriding rego version, it will be preserved.
|
||||
// If a single bundle is provided, it will retain any rego version information it already had. If it has none, the
|
||||
// provided regoVersion will be applied to it.
|
||||
// If usePath is true, per-file rego-versions will be calculated using the file's ModuleFile.Path; otherwise, the file's
|
||||
// ModuleFile.URL will be used.
|
||||
func MergeWithRegoVersion(bundles []*Bundle, regoVersion ast.RegoVersion, usePath bool) (*Bundle, error) {
|
||||
if regoVersion == ast.RegoUndefined {
|
||||
regoVersion = ast.DefaultRegoVersion
|
||||
}
|
||||
|
||||
return v1.MergeWithRegoVersion(bundles, regoVersion, usePath)
|
||||
}
|
||||
|
||||
// RootPathsOverlap takes in two bundle root paths and returns true if they overlap.
|
||||
func RootPathsOverlap(pathA string, pathB string) bool {
|
||||
return v1.RootPathsOverlap(pathA, pathB)
|
||||
}
|
||||
|
||||
// RootPathsContain takes a set of bundle root paths and returns true if the path is contained.
|
||||
func RootPathsContain(roots []string, path string) bool {
|
||||
return v1.RootPathsContain(roots, path)
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright 2024 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 bundle
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/open-policy-agent/opa/internal/file/archive"
|
||||
)
|
||||
|
||||
func TestRead_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
module string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0", // v0 is the default rego-version
|
||||
module: `package example
|
||||
|
||||
p[x] {
|
||||
x := "a"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
note: "rego.v1 import",
|
||||
module: `package example
|
||||
import rego.v1
|
||||
|
||||
p contains x if {
|
||||
x := "a"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
note: "v1",
|
||||
module: `package example
|
||||
|
||||
p contains x if {
|
||||
x := "a"
|
||||
}`,
|
||||
expErrs: []string{
|
||||
"test.rego:3: rego_parse_error: var cannot be used for rule name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
module := tc.module
|
||||
files := [][2]string{
|
||||
{"test.rego", module},
|
||||
}
|
||||
|
||||
buf := archive.MustWriteTarGz(files)
|
||||
loader := NewTarballLoaderWithBaseURL(buf, "")
|
||||
br := NewCustomReader(loader)
|
||||
|
||||
bundle, err := br.Read()
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error(s):\n\n%v\n\nbut got nil", tc.expErrs)
|
||||
}
|
||||
|
||||
for _, expErr := range tc.expErrs {
|
||||
if !strings.Contains(err.Error(), expErr) {
|
||||
t.Fatalf("Expected error:\n\n%s\n\nbut got:\n\n%s", expErr, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if len(bundle.Modules) != 1 {
|
||||
t.Fatalf("expected 1 module but got %d", len(bundle.Modules))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package bundle
|
||||
@@ -0,0 +1,50 @@
|
||||
package bundle
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/open-policy-agent/opa/storage"
|
||||
v1 "github.com/open-policy-agent/opa/v1/bundle"
|
||||
)
|
||||
|
||||
// Descriptor contains information about a file and
|
||||
// can be used to read the file contents.
|
||||
type Descriptor = v1.Descriptor
|
||||
|
||||
func NewDescriptor(url, path string, reader io.Reader) *Descriptor {
|
||||
return v1.NewDescriptor(url, path, reader)
|
||||
}
|
||||
|
||||
type PathFormat = v1.PathFormat
|
||||
|
||||
const (
|
||||
Chrooted = v1.Chrooted
|
||||
SlashRooted = v1.SlashRooted
|
||||
Passthrough = v1.Passthrough
|
||||
)
|
||||
|
||||
// DirectoryLoader defines an interface which can be used to load
|
||||
// files from a directory by iterating over each one in the tree.
|
||||
type DirectoryLoader = v1.DirectoryLoader
|
||||
|
||||
// NewDirectoryLoader returns a basic DirectoryLoader implementation
|
||||
// that will load files from a given root directory path.
|
||||
func NewDirectoryLoader(root string) DirectoryLoader {
|
||||
return v1.NewDirectoryLoader(root)
|
||||
}
|
||||
|
||||
// NewTarballLoader is deprecated. Use NewTarballLoaderWithBaseURL instead.
|
||||
func NewTarballLoader(r io.Reader) DirectoryLoader {
|
||||
return v1.NewTarballLoader(r)
|
||||
}
|
||||
|
||||
// NewTarballLoaderWithBaseURL returns a new DirectoryLoader that reads
|
||||
// files out of a gzipped tar archive. The file URLs will be prefixed
|
||||
// with the baseURL.
|
||||
func NewTarballLoaderWithBaseURL(r io.Reader, baseURL string) DirectoryLoader {
|
||||
return v1.NewTarballLoaderWithBaseURL(r, baseURL)
|
||||
}
|
||||
|
||||
func NewIterator(raw []Raw) storage.Iterator {
|
||||
return v1.NewIterator(raw)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
package bundle
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
|
||||
v1 "github.com/open-policy-agent/opa/v1/bundle"
|
||||
)
|
||||
|
||||
// NewFSLoader returns a basic DirectoryLoader implementation
|
||||
// that will load files from a fs.FS interface
|
||||
func NewFSLoader(filesystem fs.FS) (DirectoryLoader, error) {
|
||||
return v1.NewFSLoader(filesystem)
|
||||
}
|
||||
|
||||
// NewFSLoaderWithRoot returns a basic DirectoryLoader implementation
|
||||
// that will load files from a fs.FS interface at the supplied root
|
||||
func NewFSLoaderWithRoot(filesystem fs.FS, root string) DirectoryLoader {
|
||||
return v1.NewFSLoaderWithRoot(filesystem, root)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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 bundle
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/bundle"
|
||||
)
|
||||
|
||||
// HashingAlgorithm represents a subset of hashing algorithms implemented in Go
|
||||
type HashingAlgorithm = v1.HashingAlgorithm
|
||||
|
||||
// Supported values for HashingAlgorithm
|
||||
const (
|
||||
MD5 = v1.MD5
|
||||
SHA1 = v1.SHA1
|
||||
SHA224 = v1.SHA224
|
||||
SHA256 = v1.SHA256
|
||||
SHA384 = v1.SHA384
|
||||
SHA512 = v1.SHA512
|
||||
SHA512224 = v1.SHA512224
|
||||
SHA512256 = v1.SHA512256
|
||||
)
|
||||
|
||||
// SignatureHasher computes a signature digest for a file with (structured or unstructured) data and policy
|
||||
type SignatureHasher = v1.SignatureHasher
|
||||
|
||||
// NewSignatureHasher returns a signature hasher suitable for a particular hashing algorithm
|
||||
func NewSignatureHasher(alg HashingAlgorithm) (SignatureHasher, error) {
|
||||
return v1.NewSignatureHasher(alg)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// 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 bundle provide helpers that assist in creating the verification and signing key configuration
|
||||
package bundle
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/bundle"
|
||||
)
|
||||
|
||||
// KeyConfig holds the keys used to sign or verify bundles and tokens
|
||||
// Moved to own package, alias kept for backwards compatibility
|
||||
type KeyConfig = v1.KeyConfig
|
||||
|
||||
// VerificationConfig represents the key configuration used to verify a signed bundle
|
||||
type VerificationConfig = v1.VerificationConfig
|
||||
|
||||
// NewVerificationConfig return a new VerificationConfig
|
||||
func NewVerificationConfig(keys map[string]*KeyConfig, id, scope string, exclude []string) *VerificationConfig {
|
||||
return v1.NewVerificationConfig(keys, id, scope, exclude)
|
||||
}
|
||||
|
||||
// SigningConfig represents the key configuration used to generate a signed bundle
|
||||
type SigningConfig = v1.SigningConfig
|
||||
|
||||
// NewSigningConfig return a new SigningConfig
|
||||
func NewSigningConfig(key, alg, claimsPath string) *SigningConfig {
|
||||
return v1.NewSigningConfig(key, alg, claimsPath)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// 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 bundle provide helpers that assist in the creating a signed bundle
|
||||
package bundle
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/bundle"
|
||||
)
|
||||
|
||||
// Signer is the interface expected for implementations that generate bundle signatures.
|
||||
type Signer v1.Signer
|
||||
|
||||
// GenerateSignedToken will retrieve the Signer implementation based on the Plugin specified
|
||||
// in SigningConfig, and call its implementation of GenerateSignedToken. The signer generates
|
||||
// a signed token given the list of files to be included in the payload and the bundle
|
||||
// signing config. The keyID if non-empty, represents the value for the "keyid" claim in the token.
|
||||
func GenerateSignedToken(files []FileInfo, sc *SigningConfig, keyID string) (string, error) {
|
||||
return v1.GenerateSignedToken(files, sc, keyID)
|
||||
}
|
||||
|
||||
// DefaultSigner is the default bundle signing implementation. It signs bundles by generating
|
||||
// a JWT and signing it using a locally-accessible private key.
|
||||
type DefaultSigner v1.DefaultSigner
|
||||
|
||||
// GetSigner returns the Signer registered under the given id
|
||||
func GetSigner(id string) (Signer, error) {
|
||||
return v1.GetSigner(id)
|
||||
}
|
||||
|
||||
// RegisterSigner registers a Signer under the given id
|
||||
func RegisterSigner(id string, s Signer) error {
|
||||
return v1.RegisterSigner(id, s)
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
// Copyright 2019 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 bundle
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/open-policy-agent/opa/storage"
|
||||
v1 "github.com/open-policy-agent/opa/v1/bundle"
|
||||
)
|
||||
|
||||
// BundlesBasePath is the storage path used for storing bundle metadata
|
||||
var BundlesBasePath = v1.BundlesBasePath
|
||||
|
||||
// Note: As needed these helpers could be memoized.
|
||||
|
||||
// ManifestStoragePath is the storage path used for the given named bundle manifest.
|
||||
func ManifestStoragePath(name string) storage.Path {
|
||||
return v1.ManifestStoragePath(name)
|
||||
}
|
||||
|
||||
// EtagStoragePath is the storage path used for the given named bundle etag.
|
||||
func EtagStoragePath(name string) storage.Path {
|
||||
return v1.EtagStoragePath(name)
|
||||
}
|
||||
|
||||
// ReadBundleNamesFromStore will return a list of bundle names which have had their metadata stored.
|
||||
func ReadBundleNamesFromStore(ctx context.Context, store storage.Store, txn storage.Transaction) ([]string, error) {
|
||||
return v1.ReadBundleNamesFromStore(ctx, store, txn)
|
||||
}
|
||||
|
||||
// WriteManifestToStore will write the manifest into the storage. This function is called when
|
||||
// the bundle is activated.
|
||||
func WriteManifestToStore(ctx context.Context, store storage.Store, txn storage.Transaction, name string, manifest Manifest) error {
|
||||
return v1.WriteManifestToStore(ctx, store, txn, name, manifest)
|
||||
}
|
||||
|
||||
// WriteEtagToStore will write the bundle etag into the storage. This function is called when the bundle is activated.
|
||||
func WriteEtagToStore(ctx context.Context, store storage.Store, txn storage.Transaction, name, etag string) error {
|
||||
return v1.WriteEtagToStore(ctx, store, txn, name, etag)
|
||||
}
|
||||
|
||||
// EraseManifestFromStore will remove the manifest from storage. This function is called
|
||||
// when the bundle is deactivated.
|
||||
func EraseManifestFromStore(ctx context.Context, store storage.Store, txn storage.Transaction, name string) error {
|
||||
return v1.EraseManifestFromStore(ctx, store, txn, name)
|
||||
}
|
||||
|
||||
// ReadWasmModulesFromStore will write Wasm module resolver metadata from the store.
|
||||
func ReadWasmModulesFromStore(ctx context.Context, store storage.Store, txn storage.Transaction, name string) (map[string][]byte, error) {
|
||||
return v1.ReadWasmModulesFromStore(ctx, store, txn, name)
|
||||
}
|
||||
|
||||
// ReadBundleRootsFromStore returns the roots in the specified bundle.
|
||||
// If the bundle is not activated, this function will return
|
||||
// storage NotFound error.
|
||||
func ReadBundleRootsFromStore(ctx context.Context, store storage.Store, txn storage.Transaction, name string) ([]string, error) {
|
||||
return v1.ReadBundleRootsFromStore(ctx, store, txn, name)
|
||||
}
|
||||
|
||||
// ReadBundleRevisionFromStore returns the revision in the specified bundle.
|
||||
// If the bundle is not activated, this function will return
|
||||
// storage NotFound error.
|
||||
func ReadBundleRevisionFromStore(ctx context.Context, store storage.Store, txn storage.Transaction, name string) (string, error) {
|
||||
return v1.ReadBundleRevisionFromStore(ctx, store, txn, name)
|
||||
}
|
||||
|
||||
// ReadBundleMetadataFromStore returns the metadata in the specified bundle.
|
||||
// If the bundle is not activated, this function will return
|
||||
// storage NotFound error.
|
||||
func ReadBundleMetadataFromStore(ctx context.Context, store storage.Store, txn storage.Transaction, name string) (map[string]interface{}, error) {
|
||||
return v1.ReadBundleMetadataFromStore(ctx, store, txn, name)
|
||||
}
|
||||
|
||||
// ReadBundleEtagFromStore returns the etag for the specified bundle.
|
||||
// If the bundle is not activated, this function will return
|
||||
// storage NotFound error.
|
||||
func ReadBundleEtagFromStore(ctx context.Context, store storage.Store, txn storage.Transaction, name string) (string, error) {
|
||||
return v1.ReadBundleEtagFromStore(ctx, store, txn, name)
|
||||
}
|
||||
|
||||
// ActivateOpts defines options for the Activate API call.
|
||||
type ActivateOpts = v1.ActivateOpts
|
||||
|
||||
// Activate the bundle(s) by loading into the given Store. This will load policies, data, and record
|
||||
// the manifest in storage. The compiler provided will have had the polices compiled on it.
|
||||
func Activate(opts *ActivateOpts) error {
|
||||
return v1.Activate(opts)
|
||||
}
|
||||
|
||||
// DeactivateOpts defines options for the Deactivate API call
|
||||
type DeactivateOpts = v1.DeactivateOpts
|
||||
|
||||
// Deactivate the bundle(s). This will erase associated data, policies, and the manifest entry from the store.
|
||||
func Deactivate(opts *DeactivateOpts) error {
|
||||
return v1.Deactivate(opts)
|
||||
}
|
||||
|
||||
// LegacyWriteManifestToStore will write the bundle manifest to the older single (unnamed) bundle manifest location.
|
||||
// Deprecated: Use WriteManifestToStore and named bundles instead.
|
||||
func LegacyWriteManifestToStore(ctx context.Context, store storage.Store, txn storage.Transaction, manifest Manifest) error {
|
||||
return v1.LegacyWriteManifestToStore(ctx, store, txn, manifest)
|
||||
}
|
||||
|
||||
// LegacyEraseManifestFromStore will erase the bundle manifest from the older single (unnamed) bundle manifest location.
|
||||
// Deprecated: Use WriteManifestToStore and named bundles instead.
|
||||
func LegacyEraseManifestFromStore(ctx context.Context, store storage.Store, txn storage.Transaction) error {
|
||||
return v1.LegacyEraseManifestFromStore(ctx, store, txn)
|
||||
}
|
||||
|
||||
// LegacyReadRevisionFromStore will read the bundle manifest revision from the older single (unnamed) bundle manifest location.
|
||||
// Deprecated: Use ReadBundleRevisionFromStore and named bundles instead.
|
||||
func LegacyReadRevisionFromStore(ctx context.Context, store storage.Store, txn storage.Transaction) (string, error) {
|
||||
return v1.LegacyReadRevisionFromStore(ctx, store, txn)
|
||||
}
|
||||
|
||||
// ActivateLegacy calls Activate for the bundles but will also write their manifest to the older unnamed store location.
|
||||
// Deprecated: Use Activate with named bundles instead.
|
||||
func ActivateLegacy(opts *ActivateOpts) error {
|
||||
return v1.ActivateLegacy(opts)
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2024 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 bundle
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/open-policy-agent/opa/internal/storage/mock"
|
||||
"github.com/open-policy-agent/opa/storage"
|
||||
)
|
||||
|
||||
func TestHasRootsOverlap(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
cases := []struct {
|
||||
note string
|
||||
storeRoots map[string]*[]string
|
||||
bundleRoots map[string]*[]string
|
||||
overlaps bool
|
||||
}{
|
||||
{
|
||||
note: "no overlap with existing roots",
|
||||
storeRoots: map[string]*[]string{"bundle1": {"a", "b"}},
|
||||
bundleRoots: map[string]*[]string{"bundle2": {"c"}},
|
||||
overlaps: false,
|
||||
},
|
||||
{
|
||||
note: "no overlap with existing roots multiple bundles",
|
||||
storeRoots: map[string]*[]string{"bundle1": {"a", "b"}},
|
||||
bundleRoots: map[string]*[]string{"bundle2": {"c"}, "bundle3": {"d"}},
|
||||
overlaps: false,
|
||||
},
|
||||
{
|
||||
note: "no overlap no existing roots",
|
||||
storeRoots: map[string]*[]string{},
|
||||
bundleRoots: map[string]*[]string{"bundle1": {"a", "b"}},
|
||||
overlaps: false,
|
||||
},
|
||||
{
|
||||
note: "no overlap without existing roots multiple bundles",
|
||||
storeRoots: map[string]*[]string{},
|
||||
bundleRoots: map[string]*[]string{"bundle1": {"a", "b"}, "bundle2": {"c"}},
|
||||
overlaps: false,
|
||||
},
|
||||
{
|
||||
note: "overlap without existing roots multiple bundles",
|
||||
storeRoots: map[string]*[]string{},
|
||||
bundleRoots: map[string]*[]string{"bundle1": {"a", "b"}, "bundle2": {"a", "c"}},
|
||||
overlaps: true,
|
||||
},
|
||||
{
|
||||
note: "overlap with existing roots",
|
||||
storeRoots: map[string]*[]string{"bundle1": {"a", "b"}},
|
||||
bundleRoots: map[string]*[]string{"bundle2": {"c", "a"}},
|
||||
overlaps: true,
|
||||
},
|
||||
{
|
||||
note: "overlap with existing roots multiple bundles",
|
||||
storeRoots: map[string]*[]string{"bundle1": {"a", "b"}},
|
||||
bundleRoots: map[string]*[]string{"bundle2": {"c", "a"}, "bundle3": {"a"}},
|
||||
overlaps: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
mockStore := mock.New()
|
||||
txn := storage.NewTransactionOrDie(ctx, mockStore, storage.WriteParams)
|
||||
|
||||
for name, roots := range tc.storeRoots {
|
||||
err := WriteManifestToStore(ctx, mockStore, txn, name, Manifest{Roots: roots})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
bundles := map[string]*Bundle{}
|
||||
for name, roots := range tc.bundleRoots {
|
||||
bundles[name] = &Bundle{
|
||||
Manifest: Manifest{
|
||||
Roots: roots,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//err := hasRootsOverlap(ctx, mockStore, txn, bundles)
|
||||
//if !tc.overlaps && err != nil {
|
||||
// t.Fatalf("unepected error: %s", err)
|
||||
//} else if tc.overlaps && (err == nil || !strings.Contains(err.Error(), "detected overlapping roots in bundle manifest")) {
|
||||
// t.Fatalf("expected overlapping roots error, got: %s", err)
|
||||
//}
|
||||
|
||||
//err = mockStore.Commit(ctx, txn)
|
||||
//if err != nil {
|
||||
// t.Fatalf("unexpected error: %s", err)
|
||||
//}
|
||||
|
||||
mockStore.AssertValid(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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 bundle provide helpers that assist in the bundle signature verification process
|
||||
package bundle
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/bundle"
|
||||
)
|
||||
|
||||
// Verifier is the interface expected for implementations that verify bundle signatures.
|
||||
type Verifier v1.Verifier
|
||||
|
||||
// VerifyBundleSignature will retrieve the Verifier implementation based
|
||||
// on the Plugin specified in SignaturesConfig, and call its implementation
|
||||
// of VerifyBundleSignature. VerifyBundleSignature verifies the bundle signature
|
||||
// using the given public keys or secret. If a signature is verified, it keeps
|
||||
// track of the files specified in the JWT payload
|
||||
func VerifyBundleSignature(sc SignaturesConfig, bvc *VerificationConfig) (map[string]FileInfo, error) {
|
||||
return v1.VerifyBundleSignature(sc, bvc)
|
||||
}
|
||||
|
||||
// DefaultVerifier is the default bundle verification implementation. It verifies bundles by checking
|
||||
// the JWT signature using a locally-accessible public key.
|
||||
type DefaultVerifier = v1.DefaultVerifier
|
||||
|
||||
// GetVerifier returns the Verifier registered under the given id
|
||||
func GetVerifier(id string) (Verifier, error) {
|
||||
return v1.GetVerifier(id)
|
||||
}
|
||||
|
||||
// RegisterVerifier registers a Verifier under the given id
|
||||
func RegisterVerifier(id string, v Verifier) error {
|
||||
return v1.RegisterVerifier(id, v)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
package capabilities
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/capabilities"
|
||||
)
|
||||
|
||||
// FS contains the embedded capabilities/ directory of the built version,
|
||||
// which has all the capabilities of previous versions:
|
||||
// "v0.18.0.json" contains the capabilities JSON of version v0.18.0, etc
|
||||
var FS = v1.FS
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package capabilities
|
||||
@@ -776,6 +776,102 @@ func TestBenchMainBadQueryE2E(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBenchMain_DefaultRegoVersion(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
note string
|
||||
module string
|
||||
query string
|
||||
expErrs []string
|
||||
}{
|
||||
// These tests are slow, so we're not being completely exhaustive here.
|
||||
{
|
||||
note: "v0 module",
|
||||
module: `package test
|
||||
a[x] {
|
||||
x := 42
|
||||
}`,
|
||||
query: `data.test.a`,
|
||||
expErrs: []string{
|
||||
"mod.rego:2: rego_parse_error: `if` keyword is required before rule body",
|
||||
"mod.rego:2: rego_parse_error: `contains` keyword is required for partial set rules",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module",
|
||||
module: `package test
|
||||
a contains x if {
|
||||
x := 42
|
||||
}`,
|
||||
query: `data.test.a`,
|
||||
},
|
||||
}
|
||||
|
||||
modes := []struct {
|
||||
name string
|
||||
e2e bool
|
||||
}{
|
||||
{
|
||||
name: "run",
|
||||
},
|
||||
{
|
||||
name: "e2e",
|
||||
e2e: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, mode := range modes {
|
||||
for _, tc := range tests {
|
||||
t.Run(fmt.Sprintf("%s, %s", tc.note, mode.name), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := map[string]string{
|
||||
"mod.rego": tc.module,
|
||||
}
|
||||
|
||||
test.WithTempFS(files, func(path string) {
|
||||
params := testBenchParams()
|
||||
_ = params.outputFormat.Set(evalPrettyOutput)
|
||||
params.e2e = mode.e2e
|
||||
|
||||
for n := range files {
|
||||
err := params.dataPaths.Set(filepath.Join(path, n))
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
args := []string{tc.query}
|
||||
|
||||
var buf bytes.Buffer
|
||||
rc, err := benchMain(args, params, &buf, &goBenchRunner{})
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
if rc == 0 {
|
||||
t.Fatalf("Expected non-zero return code")
|
||||
}
|
||||
|
||||
output := buf.String()
|
||||
for _, expErr := range tc.expErrs {
|
||||
if !strings.Contains(output, expErr) {
|
||||
t.Fatalf("Expected error:\n\n%s\n\ngot:\n\n%s", expErr, output)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
if rc != 0 {
|
||||
t.Fatalf("Unexpected return code %d, expected 0", rc)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBenchMainCompatibleFlags(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
+119
-11
@@ -225,7 +225,7 @@ func TestBuildErrorDoesNotWriteFile(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
p if { p }
|
||||
`,
|
||||
}
|
||||
@@ -252,7 +252,7 @@ func TestBuildErrorVerifyNonBundle(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
p if { p }
|
||||
`,
|
||||
}
|
||||
@@ -335,7 +335,6 @@ func TestBuildPlanWithPruneUnused(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
p contains 1
|
||||
|
||||
@@ -404,7 +403,6 @@ func TestBuildPlanWithPrintStatements(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
p if { print("hello") }
|
||||
`,
|
||||
@@ -482,7 +480,6 @@ func TestBuildPlanWithRegoEntrypointAnnotations(t *testing.T) {
|
||||
# METADATA
|
||||
# entrypoint: true
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
p contains 1
|
||||
|
||||
@@ -513,8 +510,6 @@ p[x] {
|
||||
"test.rego": `
|
||||
package test
|
||||
|
||||
import future.keywords
|
||||
|
||||
# METADATA
|
||||
# entrypoint: true
|
||||
p contains x if {
|
||||
@@ -546,8 +541,6 @@ p[i] := x {
|
||||
"test.rego": `
|
||||
package test
|
||||
|
||||
import future.keywords
|
||||
|
||||
# METADATA
|
||||
# entrypoint: true
|
||||
p[i] if {
|
||||
@@ -577,7 +570,6 @@ p.a.b if {
|
||||
files: map[string]string{
|
||||
"test.rego": `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
# METADATA
|
||||
# entrypoint: true
|
||||
@@ -593,7 +585,6 @@ p.a.b[i] := x if {
|
||||
files: map[string]string{
|
||||
"test.rego": `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
p contains 1
|
||||
|
||||
@@ -1729,6 +1720,123 @@ q contains 1 if {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
files map[string]string
|
||||
expFiles map[string]string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0 module",
|
||||
files: map[string]string{
|
||||
"test.rego": `package test
|
||||
p[x] {
|
||||
x := 42
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"test.rego:2: rego_parse_error: `if` keyword is required before rule body",
|
||||
"test.rego:2: rego_parse_error: `contains` keyword is required for partial set rules",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module",
|
||||
files: map[string]string{
|
||||
"test.rego": `package test
|
||||
|
||||
p contains x if {
|
||||
x := 42
|
||||
}`,
|
||||
},
|
||||
expFiles: map[string]string{
|
||||
".manifest": `{"revision":"","roots":[""],"rego_version":1}
|
||||
`,
|
||||
"test.rego": `package test
|
||||
|
||||
p contains x if {
|
||||
x := 42
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
test.WithTempFS(tc.files, func(root string) {
|
||||
params := newBuildParams()
|
||||
params.outputFile = path.Join(root, "bundle.tar.gz")
|
||||
|
||||
err := dobuild(params, []string{root})
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
if err == nil {
|
||||
t.Fatal("expected error but got nil")
|
||||
}
|
||||
for _, expErr := range tc.expErrs {
|
||||
if !strings.Contains(err.Error(), expErr) {
|
||||
t.Fatalf("expected error:\n\n%v\n\ngot:\n\n%v", expErr, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fl := loader.NewFileLoader()
|
||||
_, err = fl.AsBundle(params.outputFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check that manifest is not written given no input manifest and no other flags
|
||||
f, err := os.Open(params.outputFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
gr, err := gzip.NewReader(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tr := tar.NewReader(gr)
|
||||
|
||||
foundFiles := map[string]struct{}{}
|
||||
for {
|
||||
f, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
foundFiles[path.Base(f.Name)] = struct{}{}
|
||||
expectedFile := tc.expFiles[path.Base(f.Name)]
|
||||
if expectedFile != "" {
|
||||
data, err := io.ReadAll(tr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actualFile := string(data)
|
||||
if actualFile != expectedFile {
|
||||
t.Fatalf("expected file %s to be:\n\n%v\n\ngot:\n\n%v", f.Name, expectedFile, actualFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for expectedFile := range tc.expFiles {
|
||||
if _, ok := foundFiles[expectedFile]; !ok {
|
||||
t.Fatalf("expected file %s not found in bundle, got: %v", expectedFile, foundFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildWithCompatibleFlags(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
|
||||
@@ -407,6 +407,60 @@ p contains x if {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheck_DefaultRegoVersion(t *testing.T) {
|
||||
cases := []struct {
|
||||
note string
|
||||
policy string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0 module",
|
||||
policy: `package test
|
||||
a[x] {
|
||||
x := 42
|
||||
}`,
|
||||
expErrs: []string{
|
||||
"test.rego:2: rego_parse_error: `if` keyword is required before rule body",
|
||||
"test.rego:2: rego_parse_error: `contains` keyword is required for partial set rules",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module",
|
||||
policy: `package test
|
||||
a contains x if {
|
||||
x := 42
|
||||
}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": tc.policy,
|
||||
}
|
||||
|
||||
test.WithTempFS(files, func(root string) {
|
||||
params := newCheckParams()
|
||||
|
||||
err := checkModules(params, []string{root})
|
||||
switch {
|
||||
case err != nil && len(tc.expErrs) > 0:
|
||||
for _, expErr := range tc.expErrs {
|
||||
if !strings.Contains(err.Error(), expErr) {
|
||||
t.Fatalf("expected err:\n\n%v\n\ngot:\n\n%v", expErr, err)
|
||||
}
|
||||
}
|
||||
return // don't read back bundle below
|
||||
case err != nil && len(tc.expErrs) == 0:
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
case err == nil && len(tc.expErrs) > 0:
|
||||
t.Fatalf("expected error:\n\n%v\n\ngot: none", tc.expErrs)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckCompatibleFlags(t *testing.T) {
|
||||
cases := []struct {
|
||||
note string
|
||||
|
||||
@@ -16,6 +16,70 @@ import (
|
||||
"github.com/open-policy-agent/opa/v1/util/test"
|
||||
)
|
||||
|
||||
func TestDeps_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
module string
|
||||
query string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0 module",
|
||||
module: `package test
|
||||
a[x] {
|
||||
x := 42
|
||||
}`,
|
||||
query: `data.test.p`,
|
||||
expErrs: []string{
|
||||
"test.rego:2: rego_parse_error: `if` keyword is required before rule body",
|
||||
"test.rego:2: rego_parse_error: `contains` keyword is required for partial set rules",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module",
|
||||
module: `package test
|
||||
a contains x if {
|
||||
x := 42
|
||||
}`,
|
||||
query: `data.test.a`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": tc.module,
|
||||
}
|
||||
|
||||
test.WithTempFS(files, func(rootPath string) {
|
||||
params := newDepsCommandParams()
|
||||
_ = params.outputFormat.Set(depsFormatPretty)
|
||||
|
||||
for f := range files {
|
||||
_ = params.dataPaths.Set(filepath.Join(rootPath, f))
|
||||
}
|
||||
|
||||
err := deps([]string{tc.query}, params, io.Discard)
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but got nil")
|
||||
}
|
||||
for _, expErr := range tc.expErrs {
|
||||
if !strings.Contains(err.Error(), expErr) {
|
||||
t.Fatalf("Expected error:\n\n%s\n\ngot:\n\n%s", expErr, err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDepsCompatibleFlags(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
|
||||
@@ -2,5 +2,4 @@
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cmd contains the entry points for OPA commands.
|
||||
package cmd
|
||||
|
||||
+203
-77
@@ -112,7 +112,6 @@ func TestEvalExitCode(t *testing.T) {
|
||||
func TestEvalWithShowBuiltinErrors(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"x.rego": `package x
|
||||
import rego.v1
|
||||
|
||||
p if {
|
||||
1/0
|
||||
@@ -182,7 +181,6 @@ q if {
|
||||
func TestEvalWithProfiler(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"x.rego": `package x
|
||||
import rego.v1
|
||||
|
||||
p if {
|
||||
a := 1
|
||||
@@ -218,7 +216,7 @@ p if {
|
||||
|
||||
expectedNumEval := []int{3, 1, 1, 1, 1}
|
||||
expectedNumRedo := []int{3, 1, 1, 1, 1}
|
||||
expectedRow := []int{8, 7, 6, 5, 1}
|
||||
expectedRow := []int{7, 6, 5, 4, 1}
|
||||
expectedNumGenExpr := []int{3, 1, 1, 1, 1}
|
||||
|
||||
for idx, actualExprStat := range output.Profile {
|
||||
@@ -322,7 +320,7 @@ func TestEvalWithOptimize(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
default p = false
|
||||
p if { q }
|
||||
q if { input.x = data.foo }`,
|
||||
@@ -353,7 +351,6 @@ func TestEvalIssue5368(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": `
|
||||
package system
|
||||
import rego.v1
|
||||
|
||||
object_key_exists(object, key) if {
|
||||
_ = object[key]
|
||||
@@ -392,7 +389,7 @@ func TestEvalWithOptimizeBundleData(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
default p = false
|
||||
p if { q }
|
||||
q if { input.x = data.foo }`,
|
||||
@@ -567,7 +564,6 @@ func testEvalWithSchemasAnnotationButNoSchemaFlag(policy string) error {
|
||||
func TestEvalWithSchemasAnnotationButNoSchemaFlag(t *testing.T) {
|
||||
policyWithSchemaRef := `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
# METADATA
|
||||
# schemas:
|
||||
@@ -584,7 +580,6 @@ p if {
|
||||
|
||||
policyWithInlinedSchema := `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
# METADATA
|
||||
# schemas:
|
||||
@@ -730,7 +725,6 @@ func TestEvalWithJSONSchema(t *testing.T) {
|
||||
|
||||
policyWithSchemasAnnotation := `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
# METADATA
|
||||
# schemas:
|
||||
@@ -745,7 +739,6 @@ p if {
|
||||
|
||||
policyWithInlinedSchemasAnnotation := `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
# METADATA
|
||||
# schemas:
|
||||
@@ -811,7 +804,6 @@ func TestEvalWithSchemaFileWithRemoteRef(t *testing.T) {
|
||||
"input.json": input,
|
||||
"schema.json": fmt.Sprintf(schemaFmt, ts.URL),
|
||||
"p.rego": `package p
|
||||
import rego.v1
|
||||
|
||||
r if {
|
||||
input.metadata.clusterName == "NAME"
|
||||
@@ -992,7 +984,6 @@ func TestEvalWithRegoEntrypointAnnotations(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
default p = false
|
||||
# METADATA
|
||||
@@ -1220,7 +1211,6 @@ func TestEvalDebugTraceJSONOutput(t *testing.T) {
|
||||
params.disableIndexing = true
|
||||
|
||||
mod := `package x
|
||||
import rego.v1
|
||||
|
||||
p contains a if {
|
||||
a := input.z
|
||||
@@ -1295,15 +1285,15 @@ func TestEvalDebugTraceJSONOutput(t *testing.T) {
|
||||
|
||||
expectedEvalLocationsAndVars := []locationAndVars{
|
||||
{
|
||||
location: ast.NewLocation(nil, policyFile, 5, 3), // a := input.z
|
||||
location: ast.NewLocation(nil, policyFile, 4, 3), // a := input.z
|
||||
varBindings: map[string]string{"__local0__": "a"},
|
||||
},
|
||||
{
|
||||
location: ast.NewLocation(nil, policyFile, 6, 3), // a == 1
|
||||
location: ast.NewLocation(nil, policyFile, 5, 3), // a == 1
|
||||
varBindings: map[string]string{"__local0__": "a"},
|
||||
},
|
||||
{
|
||||
location: ast.NewLocation(nil, policyFile, 10, 3), // b := input.y
|
||||
location: ast.NewLocation(nil, policyFile, 9, 3), // b := input.y
|
||||
varBindings: map[string]string{"__local1__": "b"},
|
||||
},
|
||||
}
|
||||
@@ -1792,7 +1782,6 @@ func TestResetExprLocations(t *testing.T) {
|
||||
// and exprs with no location information.
|
||||
pq, err := rego.New(rego.Query("data.test.p = x"), rego.Module("test.rego", `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
default p = false
|
||||
|
||||
@@ -2134,21 +2123,12 @@ func TestEvalDiscardProfilerOutput(t *testing.T) {
|
||||
func TestPolicyWithStrictFlag(t *testing.T) {
|
||||
testsShouldError := []struct {
|
||||
note string
|
||||
v0Compatible bool
|
||||
policy string
|
||||
query string
|
||||
expectedCode string
|
||||
expectedMessage string
|
||||
}{
|
||||
{
|
||||
note: "strict mode should error on duplicate imports",
|
||||
policy: `package x
|
||||
import data.bar
|
||||
import data.bar
|
||||
foo = bar`,
|
||||
query: "data.foo",
|
||||
expectedCode: "rego_compile_error",
|
||||
expectedMessage: "import must not shadow import data.bar",
|
||||
},
|
||||
{
|
||||
note: "strict mode should error on unused imports",
|
||||
policy: `package x
|
||||
@@ -2160,10 +2140,32 @@ func TestPolicyWithStrictFlag(t *testing.T) {
|
||||
expectedMessage: "import data.foo unused",
|
||||
},
|
||||
{
|
||||
note: "strict mode should error when reserved vars data or input is used",
|
||||
note: "v0 compat, strict mode should error on duplicate imports",
|
||||
v0Compatible: true,
|
||||
policy: `package x
|
||||
import data.bar
|
||||
import data.bar
|
||||
foo = bar`,
|
||||
query: "data.foo",
|
||||
expectedCode: "rego_compile_error",
|
||||
expectedMessage: "import must not shadow import data.bar",
|
||||
},
|
||||
{
|
||||
note: "v0 compat, strict mode should error on unused imports",
|
||||
v0Compatible: true,
|
||||
policy: `package x
|
||||
import future.keywords.if
|
||||
data if { x = 1}`,
|
||||
import data.foo
|
||||
foo = 2`,
|
||||
query: "data.foo",
|
||||
expectedCode: "rego_compile_error",
|
||||
expectedMessage: "import data.foo unused",
|
||||
},
|
||||
{
|
||||
note: "v0 compat, strict mode should error when reserved vars data or input is used",
|
||||
v0Compatible: true,
|
||||
policy: `package x
|
||||
data { x = 1}`,
|
||||
query: "data.foo",
|
||||
expectedCode: "rego_compile_error",
|
||||
expectedMessage: "rules must not shadow data (use a different rule name)",
|
||||
@@ -2178,26 +2180,38 @@ func TestPolicyWithStrictFlag(t *testing.T) {
|
||||
}
|
||||
|
||||
test.WithTempFS(files, func(path string) {
|
||||
params := newEvalCommandParams()
|
||||
params.strict = true
|
||||
for _, strict := range []bool{true, false} {
|
||||
params := newEvalCommandParams()
|
||||
params.strict = strict
|
||||
params.v0Compatible = tc.v0Compatible
|
||||
|
||||
_ = params.dataPaths.Set(filepath.Join(path, "test.rego"))
|
||||
_ = params.dataPaths.Set(filepath.Join(path, "test.rego"))
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err := eval([]string{tc.query}, params, &buf)
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
var output presentation.Output
|
||||
if err := util.NewJSONDecoder(&buf).Decode(&output); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
_, err := eval([]string{tc.query}, params, &buf)
|
||||
|
||||
if code := output.Errors[0].Code; code != tc.expectedCode {
|
||||
t.Errorf("expected code '%v', got '%v'", tc.expectedCode, code)
|
||||
}
|
||||
if msg := output.Errors[0].Message; msg != tc.expectedMessage {
|
||||
t.Errorf("expected message '%v', got '%v'", tc.expectedMessage, msg)
|
||||
if strict {
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
var output presentation.Output
|
||||
if err := util.NewJSONDecoder(&buf).Decode(&output); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if code := output.Errors[0].Code; code != tc.expectedCode {
|
||||
t.Errorf("expected code '%v', got '%v'", tc.expectedCode, code)
|
||||
}
|
||||
if msg := output.Errors[0].Message; msg != tc.expectedMessage {
|
||||
t.Errorf("expected message '%v', got '%v'", tc.expectedMessage, msg)
|
||||
}
|
||||
} else if err != nil {
|
||||
var output presentation.Output
|
||||
if err := util.NewJSONDecoder(&buf).Decode(&output); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Fatal("unexpected error when non-strict:", output)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -2248,13 +2262,24 @@ func TestPolicyWithStrictFlag(t *testing.T) {
|
||||
func TestBundleWithStrictFlag(t *testing.T) {
|
||||
testsShouldError := []struct {
|
||||
note string
|
||||
v0Compatible bool
|
||||
policy string
|
||||
query string
|
||||
expectedCode string
|
||||
expectedMessage string
|
||||
}{
|
||||
{
|
||||
note: "strict mode should error on duplicate imports in this bundle",
|
||||
note: "strict mode should error on unused imports in this bundle",
|
||||
policy: `package x
|
||||
import data.foo
|
||||
foo = 2`,
|
||||
query: "data.foo",
|
||||
expectedCode: "rego_compile_error",
|
||||
expectedMessage: "import data.foo unused",
|
||||
},
|
||||
{
|
||||
note: "v0 compat, strict mode should error on duplicate imports in this bundle",
|
||||
v0Compatible: true,
|
||||
policy: `package x
|
||||
import data.bar
|
||||
import data.bar
|
||||
@@ -2264,9 +2289,9 @@ func TestBundleWithStrictFlag(t *testing.T) {
|
||||
expectedMessage: "import must not shadow import data.bar",
|
||||
},
|
||||
{
|
||||
note: "strict mode should error on unused imports in this bundle",
|
||||
note: "v0 compat, strict mode should error on unused imports in this bundle",
|
||||
v0Compatible: true,
|
||||
policy: `package x
|
||||
import future.keywords.if
|
||||
import data.foo
|
||||
foo = 2`,
|
||||
query: "data.foo",
|
||||
@@ -2274,10 +2299,10 @@ func TestBundleWithStrictFlag(t *testing.T) {
|
||||
expectedMessage: "import data.foo unused",
|
||||
},
|
||||
{
|
||||
note: "strict mode should error when reserved vars data or input is used in this bundle",
|
||||
note: "v0 compat, strict mode should error when reserved vars data or input is used in this bundle",
|
||||
v0Compatible: true,
|
||||
policy: `package x
|
||||
import future.keywords.if
|
||||
data if { x = 1}`,
|
||||
data { x = 1}`,
|
||||
query: "data.foo",
|
||||
expectedCode: "rego_compile_error",
|
||||
expectedMessage: "rules must not shadow data (use a different rule name)",
|
||||
@@ -2292,27 +2317,39 @@ func TestBundleWithStrictFlag(t *testing.T) {
|
||||
}
|
||||
|
||||
test.WithTempFS(files, func(path string) {
|
||||
params := newEvalCommandParams()
|
||||
if err := params.bundlePaths.Set(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
params.strict = true
|
||||
for _, strict := range []bool{true, false} {
|
||||
params := newEvalCommandParams()
|
||||
if err := params.bundlePaths.Set(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
params.strict = strict
|
||||
params.v0Compatible = tc.v0Compatible
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err := eval([]string{tc.query}, params, &buf)
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
var output presentation.Output
|
||||
if err := util.NewJSONDecoder(&buf).Decode(&output); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
_, err := eval([]string{tc.query}, params, &buf)
|
||||
|
||||
if code := output.Errors[0].Code; code != tc.expectedCode {
|
||||
t.Errorf("expected code '%v', got '%v'", tc.expectedCode, code)
|
||||
}
|
||||
if msg := output.Errors[0].Message; msg != tc.expectedMessage {
|
||||
t.Errorf("expected message '%v', got '%v'", tc.expectedMessage, msg)
|
||||
if strict {
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
var output presentation.Output
|
||||
if err := util.NewJSONDecoder(&buf).Decode(&output); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if code := output.Errors[0].Code; code != tc.expectedCode {
|
||||
t.Errorf("expected code '%v', got '%v'", tc.expectedCode, code)
|
||||
}
|
||||
if msg := output.Errors[0].Message; msg != tc.expectedMessage {
|
||||
t.Errorf("expected message '%v', got '%v'", tc.expectedMessage, msg)
|
||||
}
|
||||
} else if err != nil {
|
||||
var output presentation.Output
|
||||
if err := util.NewJSONDecoder(&buf).Decode(&output); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Fatal("unexpected error when non-strict:", output)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -2366,7 +2403,7 @@ func TestBundleWithStrictFlag(t *testing.T) {
|
||||
func TestIfElseIfElseNoBrace(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"bug.rego": `package bug
|
||||
import future.keywords.if
|
||||
|
||||
p if false
|
||||
else := 1 if false
|
||||
else := 2`,
|
||||
@@ -2391,7 +2428,7 @@ func TestIfElseIfElseNoBrace(t *testing.T) {
|
||||
func TestIfElseIfElseBrace(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"bug.rego": `package bug
|
||||
import future.keywords.if
|
||||
|
||||
p if false
|
||||
else := 1 if { false }
|
||||
else := 2`,
|
||||
@@ -2416,7 +2453,7 @@ func TestIfElseIfElseBrace(t *testing.T) {
|
||||
func TestIfElse(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"bug.rego": `package bug
|
||||
import future.keywords.if
|
||||
|
||||
p if false
|
||||
else := 1 `,
|
||||
}
|
||||
@@ -2468,7 +2505,7 @@ func TestElseNoIfV0(t *testing.T) {
|
||||
func TestElseIf(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"bug.rego": `package bug
|
||||
import future.keywords.if
|
||||
|
||||
p if false
|
||||
else := x if {
|
||||
x=2
|
||||
@@ -2525,7 +2562,7 @@ func TestElseIfElseV0(t *testing.T) {
|
||||
func TestUnexpectedElseIfElseErr(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"bug.rego": `package bug
|
||||
import future.keywords.if
|
||||
|
||||
p if false
|
||||
else := x if {
|
||||
x=2
|
||||
@@ -2563,7 +2600,7 @@ func TestUnexpectedElseIfElseErr(t *testing.T) {
|
||||
func TestUnexpectedElseIfErr(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"bug.rego": `package bug
|
||||
import future.keywords.if
|
||||
|
||||
q := 1 if false
|
||||
else := 2 if
|
||||
`,
|
||||
@@ -2594,6 +2631,95 @@ func TestUnexpectedElseIfErr(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestEval_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
modules map[string]string
|
||||
query string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0 module",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
a[x] {
|
||||
x := 42
|
||||
}`,
|
||||
},
|
||||
query: `data.test.a`,
|
||||
expErrs: []string{
|
||||
"test.rego:2: rego_parse_error: `if` keyword is required before rule body",
|
||||
"test.rego:2: rego_parse_error: `contains` keyword is required for partial set rules",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module",
|
||||
modules: map[string]string{
|
||||
"test.rego": `package test
|
||||
a contains x if {
|
||||
x := 42
|
||||
}`,
|
||||
},
|
||||
query: `data.test.a`,
|
||||
},
|
||||
}
|
||||
|
||||
setup := []struct {
|
||||
name string
|
||||
commandParams func(params *evalCommandParams, path string)
|
||||
}{
|
||||
{
|
||||
name: "Files",
|
||||
commandParams: func(params *evalCommandParams, path string) {
|
||||
params.dataPaths = newrepeatedStringFlag([]string{path})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Bundle",
|
||||
commandParams: func(params *evalCommandParams, path string) {
|
||||
if err := params.bundlePaths.Set(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range setup {
|
||||
for _, tc := range tests {
|
||||
t.Run(fmt.Sprintf("%s: %s", s.name, tc.note), func(t *testing.T) {
|
||||
test.WithTempFS(tc.modules, func(path string) {
|
||||
params := newEvalCommandParams()
|
||||
_ = params.outputFormat.Set(evalPrettyOutput)
|
||||
s.commandParams(¶ms, path)
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
defined, err := eval([]string{tc.query}, params, &buf)
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got none")
|
||||
}
|
||||
|
||||
actual := buf.String()
|
||||
for _, expErr := range tc.expErrs {
|
||||
if !strings.Contains(actual, expErr) {
|
||||
t.Fatalf("expected error:\n\n%v\n\ngot\n\n%v", expErr, actual)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v, buf: %s", err, buf.String())
|
||||
} else if !defined {
|
||||
t.Fatal("expected result to be defined")
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvalPolicyWithCompatibleFlags(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
|
||||
+124
-2
@@ -87,7 +87,7 @@ func TestExecDecisionOption(t *testing.T) {
|
||||
s := sdk_test.MustNewServer(sdk_test.MockBundle("/bundles/bundle.tar.gz", map[string]string{
|
||||
"test.rego": `
|
||||
package foo
|
||||
import rego.v1
|
||||
|
||||
main contains "hello"
|
||||
`,
|
||||
}))
|
||||
@@ -129,7 +129,7 @@ func TestExecBundleFlag(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"files/test.json": `{"foo": 7}`,
|
||||
"bundle/x.rego": `package system
|
||||
import rego.v1
|
||||
|
||||
main contains "hello"`,
|
||||
}
|
||||
|
||||
@@ -160,6 +160,128 @@ func TestExecBundleFlag(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestExec_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
module string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0, module",
|
||||
module: `package system
|
||||
main["hello"] {
|
||||
input.foo == "bar"
|
||||
}`,
|
||||
expErrs: []string{
|
||||
"test.rego:2: rego_parse_error: `if` keyword is required before rule body",
|
||||
"test.rego:2: rego_parse_error: `contains` keyword is required for partial set rules",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module",
|
||||
module: `package system
|
||||
main contains "hello" if {
|
||||
input.foo == "bar"
|
||||
}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.json": `{"foo": "bar"}`,
|
||||
}
|
||||
|
||||
test.WithTempFS(files, func(dir string) {
|
||||
s := sdk_test.MustNewServer(
|
||||
sdk_test.MockBundle("/bundles/bundle.tar.gz", map[string]string{"test.rego": tc.module}),
|
||||
sdk_test.RawBundles(true),
|
||||
)
|
||||
|
||||
defer s.Stop()
|
||||
|
||||
var buf bytes.Buffer
|
||||
params := exec.NewParams(&buf)
|
||||
_ = params.OutputFormat.Set("json")
|
||||
params.ConfigOverrides = []string{
|
||||
"services.test.url=" + s.URL(),
|
||||
"bundles.test.resource=/bundles/bundle.tar.gz",
|
||||
}
|
||||
|
||||
params.Paths = append(params.Paths, dir)
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
testLogger := loggingtest.New()
|
||||
params.Logger = testLogger
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
go func(expectedErrors []string) {
|
||||
err := runExecWithContext(ctx, params)
|
||||
// Note(philipc): Catch the expected cancellation
|
||||
// errors, allowing unexpected test failures through.
|
||||
if err != context.Canceled {
|
||||
var errs ast.Errors
|
||||
if errors.As(err, &errs) {
|
||||
for _, expErr := range expectedErrors {
|
||||
found := false
|
||||
for _, e := range errs {
|
||||
if strings.Contains(e.Error(), expErr) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("Could not find expected error: %s in %v", expErr, errs)
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}(tc.expErrs)
|
||||
|
||||
if !test.Eventually(t, 5*time.Second, func() bool {
|
||||
for _, expErr := range tc.expErrs {
|
||||
found := false
|
||||
for _, e := range testLogger.Entries() {
|
||||
if strings.Contains(e.Message, expErr) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}) {
|
||||
t.Fatalf("timed out waiting for logged errors:\n\n%v\n\ngot\n\n%v:", tc.expErrs, testLogger.Entries())
|
||||
}
|
||||
} else {
|
||||
err := runExec(params)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
output := util.MustUnmarshalJSON(bytes.ReplaceAll(buf.Bytes(), []byte(dir), nil))
|
||||
|
||||
exp := util.MustUnmarshalJSON([]byte(`{"result": [{
|
||||
"path": "/test.json",
|
||||
"result": ["hello"]
|
||||
}]}`))
|
||||
|
||||
if !reflect.DeepEqual(output, exp) {
|
||||
t.Fatal("Expected:", exp, "Got:", output)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecCompatibleFlags(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
|
||||
@@ -163,6 +163,7 @@ func addV0CompatibleFlag(fs *pflag.FlagSet, v1Compatible *bool, value bool) {
|
||||
|
||||
func addV1CompatibleFlag(fs *pflag.FlagSet, v1Compatible *bool, value bool) {
|
||||
fs.BoolVar(v1Compatible, "v1-compatible", value, "opt-in to OPA features and behaviors that are enabled by default in OPA v1.0")
|
||||
_ = fs.MarkHidden("v1-compatible")
|
||||
}
|
||||
|
||||
func addReadAstValuesFromStoreFlag(fs *pflag.FlagSet, readAstValuesFromStore *bool, value bool) {
|
||||
|
||||
+18
-29
@@ -118,13 +118,13 @@ func TestFmtFormatFile(t *testing.T) {
|
||||
},
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{v1Compatible: true},
|
||||
params: fmtCommandParams{},
|
||||
unformatted: unformattedV1,
|
||||
formatted: formattedV1,
|
||||
},
|
||||
{
|
||||
note: "comment in comprehension",
|
||||
params: fmtCommandParams{v1Compatible: true},
|
||||
params: fmtCommandParams{},
|
||||
unformatted: ComprehensionCommentShouldNotMoveUnformatted,
|
||||
formatted: ComprehensionCommentShouldNotMoveFormatted,
|
||||
},
|
||||
@@ -198,7 +198,7 @@ func TestFmtFormatFileNoChanges(t *testing.T) {
|
||||
},
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{v1Compatible: true},
|
||||
params: fmtCommandParams{},
|
||||
module: formattedV1,
|
||||
},
|
||||
}
|
||||
@@ -246,9 +246,8 @@ func TestFmtFailFormatFileNoChanges(t *testing.T) {
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
fail: true,
|
||||
diff: true,
|
||||
fail: true,
|
||||
diff: true,
|
||||
},
|
||||
module: formattedV1,
|
||||
},
|
||||
@@ -296,8 +295,7 @@ func TestFmtFormatFileDiff(t *testing.T) {
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
diff: true,
|
||||
diff: true,
|
||||
},
|
||||
module: formattedV1,
|
||||
},
|
||||
@@ -346,8 +344,7 @@ func TestFmtFormatFileFailToPrintDiff(t *testing.T) {
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
diff: true,
|
||||
diff: true,
|
||||
},
|
||||
module: unformattedV1,
|
||||
},
|
||||
@@ -397,8 +394,7 @@ func TestFmtFormatFileList(t *testing.T) {
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
list: true,
|
||||
list: true,
|
||||
},
|
||||
module: formattedV1,
|
||||
},
|
||||
@@ -448,9 +444,8 @@ func TestFmtFailFormatFileList(t *testing.T) {
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
fail: true,
|
||||
list: true,
|
||||
fail: true,
|
||||
list: true,
|
||||
},
|
||||
module: formattedV1,
|
||||
},
|
||||
@@ -499,9 +494,8 @@ func TestFmtFailFormatFileChangesList(t *testing.T) {
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
fail: true,
|
||||
list: true,
|
||||
fail: true,
|
||||
list: true,
|
||||
},
|
||||
module: unformattedV1,
|
||||
},
|
||||
@@ -549,8 +543,7 @@ func TestFmtFailFileNoChanges(t *testing.T) {
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
fail: true,
|
||||
fail: true,
|
||||
},
|
||||
module: formattedV1,
|
||||
},
|
||||
@@ -591,8 +584,7 @@ func TestFmtFailFileChanges(t *testing.T) {
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
fail: true,
|
||||
fail: true,
|
||||
},
|
||||
module: unformattedV1,
|
||||
},
|
||||
@@ -634,9 +626,8 @@ func TestFmtFailFileChangesDiff(t *testing.T) {
|
||||
{
|
||||
note: "v1",
|
||||
params: fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
diff: true,
|
||||
fail: true,
|
||||
diff: true,
|
||||
fail: true,
|
||||
},
|
||||
module: unformattedV1,
|
||||
},
|
||||
@@ -894,7 +885,7 @@ q := all([true, false])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFmtV1Compatible(t *testing.T) {
|
||||
func TestFmt_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
input string
|
||||
@@ -1006,9 +997,7 @@ q := all([true, false])
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
params := fmtCommandParams{
|
||||
v1Compatible: true,
|
||||
}
|
||||
params := fmtCommandParams{}
|
||||
|
||||
files := map[string]string{
|
||||
"policy.rego": tc.input,
|
||||
|
||||
+6
-1
@@ -31,14 +31,18 @@ const pageWidth = 80
|
||||
type inspectCommandParams struct {
|
||||
outputFormat *util.EnumFlag
|
||||
listAnnotations bool
|
||||
v0Compatible bool
|
||||
v1Compatible bool
|
||||
}
|
||||
|
||||
func (p *inspectCommandParams) regoVersion() ast.RegoVersion {
|
||||
if p.v0Compatible {
|
||||
return ast.RegoV0
|
||||
}
|
||||
if p.v1Compatible {
|
||||
return ast.RegoV1
|
||||
}
|
||||
return ast.RegoV0
|
||||
return ast.DefaultRegoVersion
|
||||
}
|
||||
|
||||
func newInspectCommandParams() inspectCommandParams {
|
||||
@@ -98,6 +102,7 @@ that file and summarize its structure and contents.
|
||||
|
||||
addOutputFormat(inspectCommand.Flags(), params.outputFormat)
|
||||
addListAnnotations(inspectCommand.Flags(), ¶ms.listAnnotations)
|
||||
addV0CompatibleFlag(inspectCommand.Flags(), ¶ms.v0Compatible, false)
|
||||
addV1CompatibleFlag(inspectCommand.Flags(), ¶ms.v1Compatible, false)
|
||||
RootCommand.AddCommand(inspectCommand)
|
||||
}
|
||||
|
||||
+15
-17
@@ -565,22 +565,24 @@ Custom:
|
||||
})
|
||||
}
|
||||
|
||||
func TestDoInspectV1Compatible(t *testing.T) {
|
||||
func TestDoInspect_V0Compatible(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
v1Compatible bool
|
||||
v0Compatible bool
|
||||
module string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0.x, keywords not used",
|
||||
note: "v0, keywords not used",
|
||||
v0Compatible: true,
|
||||
module: `package test
|
||||
p[v] {
|
||||
v := input.x
|
||||
}`,
|
||||
},
|
||||
{
|
||||
note: "v0.x, no keywords imported, but used",
|
||||
note: "v0, no keywords imported, but used",
|
||||
v0Compatible: true,
|
||||
module: `package test
|
||||
p contains v if {
|
||||
v := input.x
|
||||
@@ -590,7 +592,7 @@ p contains v if {
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v0.x, keywords imported",
|
||||
note: "v0, keywords imported",
|
||||
module: `package test
|
||||
import future.keywords
|
||||
p contains v if {
|
||||
@@ -598,7 +600,7 @@ p contains v if {
|
||||
}`,
|
||||
},
|
||||
{
|
||||
note: "v0.x, rego.v1 imported",
|
||||
note: "v0, rego.v1 imported",
|
||||
module: `package test
|
||||
import rego.v1
|
||||
p contains v if {
|
||||
@@ -606,8 +608,7 @@ p contains v if {
|
||||
}`,
|
||||
},
|
||||
{
|
||||
note: "v1.0, keywords not used",
|
||||
v1Compatible: true,
|
||||
note: "v1, keywords not used",
|
||||
module: `package test
|
||||
p[v] {
|
||||
v := input.x
|
||||
@@ -618,16 +619,14 @@ p[v] {
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1.0, no keywords imported",
|
||||
v1Compatible: true,
|
||||
note: "v1, no keywords imported",
|
||||
module: `package test
|
||||
p contains v if {
|
||||
v := input.x
|
||||
}`,
|
||||
},
|
||||
{
|
||||
note: "v1.0, keywords imported",
|
||||
v1Compatible: true,
|
||||
note: "v1, keywords imported",
|
||||
module: `package test
|
||||
import future.keywords
|
||||
p contains v if {
|
||||
@@ -635,8 +634,7 @@ p contains v if {
|
||||
}`,
|
||||
},
|
||||
{
|
||||
note: "v1.0, rego.v1 imported",
|
||||
v1Compatible: true,
|
||||
note: "v1, rego.v1 imported",
|
||||
module: `package test
|
||||
import rego.v1
|
||||
p contains v if {
|
||||
@@ -664,7 +662,7 @@ p contains v if {
|
||||
|
||||
var out bytes.Buffer
|
||||
params := newInspectCommandParams()
|
||||
params.v1Compatible = tc.v1Compatible
|
||||
params.v0Compatible = tc.v0Compatible
|
||||
err = params.outputFormat.Set(evalJSONOutput)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
@@ -1038,7 +1036,7 @@ func TestUnknownRefs(t *testing.T) {
|
||||
files: [][2]string{
|
||||
{
|
||||
"/policy.rego", `package test
|
||||
p {
|
||||
p if {
|
||||
foo.bar(42)
|
||||
contains("foo", "o")
|
||||
}`,
|
||||
@@ -1424,7 +1422,7 @@ func TestCallToUnknownRegoFunction(t *testing.T) {
|
||||
{"/policy.rego", `package test
|
||||
import data.x.y
|
||||
|
||||
p {
|
||||
p if {
|
||||
y(1) == true
|
||||
}
|
||||
`},
|
||||
|
||||
@@ -162,6 +162,8 @@ func dofindDefinition(params findDefinitionParams, stdin io.Reader, stdout io.Wr
|
||||
}
|
||||
}
|
||||
|
||||
// FindDefinition() will instantiate a new compiler, but we don't need to set the
|
||||
// default rego-version because the passed modules already have the rego-version from parsing.
|
||||
result, err := oracle.New().FindDefinition(oracle.DefinitionQuery{
|
||||
Buffer: bs,
|
||||
Filename: filename,
|
||||
|
||||
+1
-25
@@ -17,7 +17,6 @@ func TestOracleFindDefinition(t *testing.T) {
|
||||
cases := []struct {
|
||||
note string
|
||||
v0Compatible bool
|
||||
v1Compatible bool
|
||||
onDiskModule string
|
||||
stdin string
|
||||
paths []string
|
||||
@@ -42,8 +41,7 @@ q = true`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1",
|
||||
v1Compatible: true,
|
||||
note: "v1",
|
||||
onDiskModule: `package test
|
||||
|
||||
p if { r }
|
||||
@@ -60,27 +58,6 @@ q = true`,
|
||||
"test.rego:21",
|
||||
},
|
||||
},
|
||||
// v0 takes precedence over v1
|
||||
{
|
||||
note: "v0+v1",
|
||||
v0Compatible: true,
|
||||
v1Compatible: true,
|
||||
onDiskModule: `package test
|
||||
|
||||
p { r }
|
||||
|
||||
r = true`,
|
||||
stdin: `package test
|
||||
|
||||
p { q }
|
||||
|
||||
q = true`,
|
||||
paths: []string{
|
||||
"test.rego:10",
|
||||
"test.rego:15",
|
||||
"test.rego:18",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -102,7 +79,6 @@ q = true`,
|
||||
},
|
||||
stdinBuffer: true,
|
||||
v0Compatible: tc.v0Compatible,
|
||||
v1Compatible: tc.v1Compatible,
|
||||
}
|
||||
|
||||
stdout := bytes.NewBuffer(nil)
|
||||
|
||||
@@ -972,6 +972,58 @@ func TestParseJSONOutputComments(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse_DefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
module string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0 module",
|
||||
module: `package test
|
||||
a[x] {
|
||||
x := 42
|
||||
}`,
|
||||
expErrs: []string{
|
||||
"`if` keyword is required before rule body",
|
||||
"`contains` keyword is required for partial set rules",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 module",
|
||||
module: `package test
|
||||
a contains x if {
|
||||
x := 42
|
||||
}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": tc.module,
|
||||
}
|
||||
|
||||
_, _, stderr, _ := testParse(t, files, &parseParams{
|
||||
format: util.NewEnumFlag(parseFormatPretty, []string{parseFormatPretty, parseFormatJSON}),
|
||||
})
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
errs := string(stderr)
|
||||
for _, expErr := range tc.expErrs {
|
||||
if !strings.Contains(errs, expErr) {
|
||||
t.Fatalf("Expected error:\n\n%q\n\ngot:\n\n%s", expErr, errs)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if len(stderr) > 0 {
|
||||
t.Fatalf("Expected no stderr output, got:\n%s\n", string(stderr))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCompatibleFlags(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@ func doMove(params moveCommandParams, args []string, out io.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
formatted, err := format.Ast(mod)
|
||||
formatted, err := format.AstWithOpts(mod, format.Opts{RegoVersion: params.regoVersion()})
|
||||
if err != nil {
|
||||
return newError("failed to parse Rego source file: %v", err)
|
||||
}
|
||||
|
||||
+14
-57
@@ -16,7 +16,6 @@ func TestDoMoveRenamePackage(t *testing.T) {
|
||||
cases := []struct {
|
||||
note string
|
||||
v0Compatible bool
|
||||
v1Compatible bool
|
||||
module string
|
||||
expected *ast.Module
|
||||
}{
|
||||
@@ -41,8 +40,7 @@ func TestDoMoveRenamePackage(t *testing.T) {
|
||||
}`, ast.ParserOptions{RegoVersion: ast.RegoV0}),
|
||||
},
|
||||
{
|
||||
note: "v1",
|
||||
v1Compatible: true,
|
||||
note: "v1",
|
||||
module: `package lib.foo
|
||||
|
||||
# this is a comment
|
||||
@@ -60,28 +58,6 @@ func TestDoMoveRenamePackage(t *testing.T) {
|
||||
input.message == "hello" # this is a comment too
|
||||
}`, ast.ParserOptions{RegoVersion: ast.RegoV1}),
|
||||
},
|
||||
// v0 takes precedence over v1
|
||||
{
|
||||
note: "v0+v1",
|
||||
v0Compatible: true,
|
||||
v1Compatible: true,
|
||||
module: `package lib.foo
|
||||
|
||||
# this is a comment
|
||||
default allow = false
|
||||
|
||||
allow {
|
||||
input.message == "hello" # this is a comment too
|
||||
}`,
|
||||
expected: ast.MustParseModuleWithOpts(`package baz.bar
|
||||
|
||||
# this is a comment
|
||||
default allow = false
|
||||
|
||||
allow {
|
||||
input.message == "hello" # this is a comment too
|
||||
}`, ast.ParserOptions{RegoVersion: ast.RegoV0}),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -97,7 +73,6 @@ func TestDoMoveRenamePackage(t *testing.T) {
|
||||
params := moveCommandParams{
|
||||
mapping: newrepeatedStringFlag(mappings),
|
||||
v0Compatible: tc.v0Compatible,
|
||||
v1Compatible: tc.v1Compatible,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
@@ -107,7 +82,12 @@ func TestDoMoveRenamePackage(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
formatted := format.MustAst(tc.expected)
|
||||
var formatted []byte
|
||||
if tc.v0Compatible {
|
||||
formatted = format.MustAstWithOpts(tc.expected, format.Opts{RegoVersion: ast.RegoV0})
|
||||
} else {
|
||||
formatted = format.MustAstWithOpts(tc.expected, format.Opts{RegoVersion: ast.RegoV1})
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(formatted, buf.Bytes()) {
|
||||
t.Fatalf("Expected module:\n%v\n\nGot:\n%v\n", string(formatted), buf.String())
|
||||
@@ -121,7 +101,6 @@ func TestDoMoveOverwriteFile(t *testing.T) {
|
||||
cases := []struct {
|
||||
note string
|
||||
v0Compatible bool
|
||||
v1Compatible bool
|
||||
module string
|
||||
expected *ast.Module
|
||||
}{
|
||||
@@ -149,8 +128,7 @@ func TestDoMoveOverwriteFile(t *testing.T) {
|
||||
}`, ast.ParserOptions{RegoVersion: ast.RegoV0}),
|
||||
},
|
||||
{
|
||||
note: "v1",
|
||||
v1Compatible: true,
|
||||
note: "v1",
|
||||
module: `package lib.foo
|
||||
|
||||
import data.x.q
|
||||
@@ -171,31 +149,6 @@ func TestDoMoveOverwriteFile(t *testing.T) {
|
||||
input.message == "hello"
|
||||
}`, ast.ParserOptions{RegoVersion: ast.RegoV1}),
|
||||
},
|
||||
// v0 takes precedence over v1
|
||||
{
|
||||
note: "v0+v1",
|
||||
v0Compatible: true,
|
||||
v1Compatible: true,
|
||||
module: `package lib.foo
|
||||
|
||||
import data.x.q
|
||||
|
||||
default allow := false
|
||||
|
||||
allow {
|
||||
input.message == "hello"
|
||||
}
|
||||
`,
|
||||
expected: ast.MustParseModuleWithOpts(`package baz.bar
|
||||
|
||||
import data.hidden.q
|
||||
|
||||
default allow := false
|
||||
|
||||
allow {
|
||||
input.message == "hello"
|
||||
}`, ast.ParserOptions{RegoVersion: ast.RegoV0}),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -212,7 +165,6 @@ func TestDoMoveOverwriteFile(t *testing.T) {
|
||||
mapping: newrepeatedStringFlag(mappings),
|
||||
overwrite: true,
|
||||
v0Compatible: tc.v0Compatible,
|
||||
v1Compatible: tc.v1Compatible,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
@@ -227,7 +179,12 @@ func TestDoMoveOverwriteFile(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
actual := ast.MustParseModule(string(data))
|
||||
var actual *ast.Module
|
||||
if tc.v0Compatible {
|
||||
actual = ast.MustParseModuleWithOpts(string(data), ast.ParserOptions{RegoVersion: ast.RegoV0})
|
||||
} else {
|
||||
actual = ast.MustParseModuleWithOpts(string(data), ast.ParserOptions{RegoVersion: ast.RegoV1})
|
||||
}
|
||||
|
||||
if !tc.expected.Equal(actual) {
|
||||
t.Fatalf("Expected module:\n%v\n\nGot:\n%v\n", tc.expected, actual)
|
||||
|
||||
+2
-21
@@ -253,49 +253,31 @@ func TestRunServerUploadPolicy(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
v0Compatible bool
|
||||
v1Compatible bool
|
||||
module string
|
||||
expErr bool
|
||||
}{
|
||||
{
|
||||
note: "v0-compatible, v0 policy",
|
||||
v0Compatible: true,
|
||||
v1Compatible: false,
|
||||
module: v0Policy,
|
||||
},
|
||||
{
|
||||
note: "v0-compatible, v1 policy",
|
||||
v0Compatible: true,
|
||||
v1Compatible: false,
|
||||
module: v1Policy,
|
||||
expErr: true,
|
||||
},
|
||||
{
|
||||
note: "v1-compatible, v0 policy",
|
||||
note: "v1, v0 policy",
|
||||
v0Compatible: false,
|
||||
v1Compatible: true,
|
||||
module: v0Policy,
|
||||
expErr: true,
|
||||
},
|
||||
{
|
||||
note: "v1-compatible, v1 policy",
|
||||
note: "v1, v1 policy",
|
||||
v0Compatible: false,
|
||||
v1Compatible: true,
|
||||
module: v1Policy,
|
||||
},
|
||||
{
|
||||
note: "v0-compatible, v1-compatible, v0 policy",
|
||||
v0Compatible: true,
|
||||
v1Compatible: true,
|
||||
module: v0Policy,
|
||||
},
|
||||
{
|
||||
note: "v0-compatible, v1-compatible, v1 policy",
|
||||
v0Compatible: true,
|
||||
v1Compatible: true,
|
||||
module: v1Policy,
|
||||
expErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
@@ -304,7 +286,6 @@ func TestRunServerUploadPolicy(t *testing.T) {
|
||||
|
||||
params := newTestRunParams()
|
||||
params.rt.V0Compatible = tc.v0Compatible
|
||||
params.rt.V1Compatible = tc.v1Compatible
|
||||
|
||||
rt, err := initRuntime(ctx, params, nil, false)
|
||||
if err != nil {
|
||||
|
||||
+2
-2
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/open-policy-agent/opa/internal/pathwatcher"
|
||||
initload "github.com/open-policy-agent/opa/internal/runtime/init"
|
||||
"github.com/open-policy-agent/opa/v1/loader"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/open-policy-agent/opa/cmd/internal/env"
|
||||
@@ -27,6 +26,7 @@ import (
|
||||
"github.com/open-policy-agent/opa/v1/bundle"
|
||||
"github.com/open-policy-agent/opa/v1/compile"
|
||||
"github.com/open-policy-agent/opa/v1/cover"
|
||||
"github.com/open-policy-agent/opa/v1/loader"
|
||||
"github.com/open-policy-agent/opa/v1/storage"
|
||||
"github.com/open-policy-agent/opa/v1/storage/inmem"
|
||||
"github.com/open-policy-agent/opa/v1/tester"
|
||||
@@ -287,7 +287,7 @@ func processWatcherUpdate(ctx context.Context, testParams testCommandParams, pat
|
||||
|
||||
var loadResult *initload.LoadPathsResult
|
||||
|
||||
err := pathwatcher.ProcessWatcherUpdate(ctx, paths, removed, store, filter.Apply, testParams.bundleMode,
|
||||
err := pathwatcher.ProcessWatcherUpdateForRegoVersion(ctx, testParams.RegoVersion(), paths, removed, store, filter.Apply, testParams.bundleMode,
|
||||
func(ctx context.Context, txn storage.Transaction, loaded *initload.LoadPathsResult) error {
|
||||
if len(loaded.Files.Documents) > 0 || removed != "" {
|
||||
if err := store.Write(ctx, txn, storage.AddOp, storage.Path{}, loaded.Files.Documents); err != nil {
|
||||
|
||||
+306
-128
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -11,7 +11,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
version2 "github.com/open-policy-agent/opa/version"
|
||||
"github.com/open-policy-agent/opa/v1/ast"
|
||||
version2 "github.com/open-policy-agent/opa/v1/version"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/open-policy-agent/opa/cmd/internal/env"
|
||||
@@ -47,6 +48,7 @@ func generateCmdOutput(out io.Writer, check bool) {
|
||||
fmt.Fprintln(out, "Build Hostname: "+version2.Hostname)
|
||||
fmt.Fprintln(out, "Go Version: "+version2.GoVersion)
|
||||
fmt.Fprintln(out, "Platform: "+version2.Platform)
|
||||
fmt.Fprintln(out, "Rego Version: "+ast.DefaultRegoVersion.String())
|
||||
|
||||
var wasmAvailable string
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ func TestGenerateCmdOutputDisableCheckFlag(t *testing.T) {
|
||||
"Go Version",
|
||||
"Platform",
|
||||
"WebAssembly",
|
||||
"Rego Version",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -60,6 +61,7 @@ func TestGenerateCmdOutputWithCheckFlagNoError(t *testing.T) {
|
||||
"Latest Upstream Version",
|
||||
"Release Notes",
|
||||
"Download",
|
||||
"Rego Version",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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 compile implements bundles compilation and linking.
|
||||
package compile
|
||||
|
||||
import (
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
v1 "github.com/open-policy-agent/opa/v1/compile"
|
||||
)
|
||||
|
||||
const (
|
||||
// TargetRego is the default target. The source rego is copied (potentially
|
||||
// rewritten for optimization purpsoes) into the bundle. The target supports
|
||||
// base documents.
|
||||
TargetRego = v1.TargetRego
|
||||
|
||||
// TargetWasm is an alternative target that compiles the policy into a wasm
|
||||
// module instead of Rego. The target supports base documents.
|
||||
TargetWasm = v1.TargetWasm
|
||||
|
||||
// TargetPlan is an altertive target that compiles the policy into an
|
||||
// imperative query plan that can be further transpiled or interpreted.
|
||||
TargetPlan = v1.TargetPlan
|
||||
)
|
||||
|
||||
// Targets contains the list of targets supported by the compiler.
|
||||
var Targets = v1.Targets
|
||||
|
||||
// Compiler implements bundle compilation and linking.
|
||||
type Compiler = v1.Compiler
|
||||
|
||||
// New returns a new compiler instance that can be invoked.
|
||||
func New() *Compiler {
|
||||
return v1.New().WithRegoVersion(ast.DefaultRegoVersion)
|
||||
}
|
||||
@@ -0,0 +1,778 @@
|
||||
// Copyright 2024 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 compile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/bundle"
|
||||
"github.com/open-policy-agent/opa/internal/file/archive"
|
||||
"github.com/open-policy-agent/opa/loader"
|
||||
"github.com/open-policy-agent/opa/util/test"
|
||||
)
|
||||
|
||||
func TestCompilerDefaultRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
module string
|
||||
expRegoVersion ast.RegoVersion
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "v0", // Default rego-version
|
||||
module: `
|
||||
package test
|
||||
|
||||
p[x] {
|
||||
x = "a"
|
||||
}`,
|
||||
expRegoVersion: ast.RegoV0,
|
||||
},
|
||||
{
|
||||
note: "import rego.v1",
|
||||
module: `
|
||||
package test
|
||||
import rego.v1
|
||||
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
expRegoVersion: ast.RegoV0,
|
||||
},
|
||||
{
|
||||
note: "v1", // NOT default rego-version
|
||||
module: `
|
||||
package test
|
||||
|
||||
p contains x if {
|
||||
x = "a"
|
||||
}`,
|
||||
expRegoVersion: ast.RegoV1,
|
||||
expErrs: []string{
|
||||
"test.rego:4: rego_parse_error: var cannot be used for rule name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"test.rego": tc.module,
|
||||
}
|
||||
|
||||
for _, useMemoryFS := range []bool{false, true} {
|
||||
test.WithTestFS(files, useMemoryFS, func(root string, fsys fs.FS) {
|
||||
|
||||
compiler := New().
|
||||
WithFS(fsys).
|
||||
WithPaths(root)
|
||||
|
||||
err := compiler.Build(context.Background())
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got none")
|
||||
}
|
||||
for _, expErr := range tc.expErrs {
|
||||
if !strings.Contains(err.Error(), expErr) {
|
||||
t.Fatalf("expected error to contain:\n\n%s\n\ngot:\n\n%v", expErr, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify result is just bundle load.
|
||||
exp, err := loader.NewFileLoader().WithFS(fsys).AsBundle(root)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = exp.FormatModules(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !compiler.Bundle().Equal(*exp) {
|
||||
t.Fatalf("Expected:\n\n%v\n\nGot:\n\n%v", compiler.Bundle(), exp)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompilerLoadAsBundleWithBundleRegoVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
note string
|
||||
files map[string]string
|
||||
expErrs []string
|
||||
}{
|
||||
{
|
||||
note: "No bundle rego version (default version)",
|
||||
files: map[string]string{
|
||||
".manifest": `{}`,
|
||||
"test.rego": `package test
|
||||
import rego.v1
|
||||
p[1] if {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v0 bundle rego version",
|
||||
files: map[string]string{
|
||||
".manifest": `{"rego_version": 0}`,
|
||||
"test.rego": `package test
|
||||
p[1] {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v0 bundle rego version, missing keyword imports",
|
||||
files: map[string]string{
|
||||
".manifest": `{"rego_version": 0}`,
|
||||
"test.rego": `package test
|
||||
p contains 1 if {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"rego_parse_error: var cannot be used for rule name",
|
||||
"rego_parse_error: number cannot be used for rule name",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 bundle rego version",
|
||||
files: map[string]string{
|
||||
".manifest": `{"rego_version": 1}`,
|
||||
"test.rego": `package test
|
||||
p contains 1 if {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 bundle rego version, no keywords",
|
||||
files: map[string]string{
|
||||
".manifest": `{"rego_version": 1}`,
|
||||
"test.rego": `package test
|
||||
p[1] {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"rego_parse_error: `if` keyword is required before rule body",
|
||||
"rego_parse_error: `contains` keyword is required for partial set rules",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 bundle rego version, duplicate imports",
|
||||
files: map[string]string{
|
||||
".manifest": `{"rego_version": 1}`,
|
||||
"test.rego": `package test
|
||||
import data.foo
|
||||
import data.foo
|
||||
|
||||
p contains 1 if {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"rego_compile_error: import must not shadow import data.foo",
|
||||
},
|
||||
},
|
||||
// file overrides
|
||||
{
|
||||
note: "v0 bundle rego version, v1 file override",
|
||||
files: map[string]string{
|
||||
".manifest": `{
|
||||
"rego_version": 0,
|
||||
"file_rego_versions": {
|
||||
"*/test2.rego": 1
|
||||
}
|
||||
}`,
|
||||
"test1.rego": `package test
|
||||
p["A"] {
|
||||
input.x == 1
|
||||
}`,
|
||||
"test2.rego": `package test
|
||||
p contains "B" if {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v0 bundle rego version, v1 file override, missing file",
|
||||
files: map[string]string{
|
||||
".manifest": `{
|
||||
"rego_version": 0,
|
||||
"file_rego_versions": {
|
||||
"*/test2.rego": 1
|
||||
}
|
||||
}`,
|
||||
"test1.rego": `package test
|
||||
p["A"] {
|
||||
input.x == 1
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v0 bundle rego version, v1 file override, no keywords",
|
||||
files: map[string]string{
|
||||
".manifest": `{
|
||||
"rego_version": 0,
|
||||
"file_rego_versions": {
|
||||
"*/test2.rego": 1
|
||||
}
|
||||
}`,
|
||||
"test1.rego": `package test
|
||||
p["A"] {
|
||||
input.x == 1
|
||||
}`,
|
||||
"test2.rego": `package test
|
||||
p["B"] {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"rego_parse_error: `if` keyword is required before rule body",
|
||||
"rego_parse_error: `contains` keyword is required for partial set rules",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v0 bundle rego version, v1 file override, duplicate imports",
|
||||
files: map[string]string{
|
||||
".manifest": `{
|
||||
"rego_version": 0,
|
||||
"file_rego_versions": {
|
||||
"*/test2.rego": 1
|
||||
}
|
||||
}`,
|
||||
"test1.rego": `package test
|
||||
p["A"] {
|
||||
input.x == 1
|
||||
}`,
|
||||
"test2.rego": `package test
|
||||
import data.foo
|
||||
import data.foo
|
||||
|
||||
p contains "B" if {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"rego_compile_error: import must not shadow import data.foo",
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 bundle rego version, v0 file override",
|
||||
files: map[string]string{
|
||||
".manifest": `{
|
||||
"rego_version": 1,
|
||||
"file_rego_versions": {
|
||||
"*/test1.rego": 0
|
||||
}
|
||||
}`,
|
||||
"test1.rego": `package test
|
||||
p["A"] {
|
||||
input.x == 1
|
||||
}`,
|
||||
"test2.rego": `package test
|
||||
p contains "B" if {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "v1 bundle rego version, v0 file override, no import",
|
||||
files: map[string]string{
|
||||
".manifest": `{
|
||||
"rego_version": 1,
|
||||
"file_rego_versions": {
|
||||
"*/test1.rego": 0
|
||||
}
|
||||
}`,
|
||||
"test1.rego": `package test
|
||||
p contains "A" if {
|
||||
input.x == 1
|
||||
}`,
|
||||
"test2.rego": `package test
|
||||
p contains "B" if {
|
||||
input.x == 2
|
||||
}`,
|
||||
},
|
||||
expErrs: []string{
|
||||
"rego_parse_error: var cannot be used for rule name",
|
||||
"rego_parse_error: string cannot be used for rule name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
bundleTypeCases := []struct {
|
||||
note string
|
||||
tar bool
|
||||
}{
|
||||
{
|
||||
"bundle dir", false,
|
||||
},
|
||||
{
|
||||
"bundle tar", true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, bundleType := range bundleTypeCases {
|
||||
for _, tc := range tests {
|
||||
ctx := context.Background()
|
||||
t.Run(fmt.Sprintf("%s, %s", bundleType.note, tc.note), func(t *testing.T) {
|
||||
files := map[string]string{}
|
||||
if bundleType.tar {
|
||||
files["bundle.tar"] = ""
|
||||
} else {
|
||||
for k, v := range tc.files {
|
||||
files[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
test.WithTestFS(tc.files, false, func(root string, fsys fs.FS) {
|
||||
var path string
|
||||
if bundleType.tar {
|
||||
path = filepath.Join(root, "bundle.tar.gz")
|
||||
files := make([][2]string, 0, len(tc.files))
|
||||
for k, v := range tc.files {
|
||||
files = append(files, [2]string{k, v})
|
||||
}
|
||||
buf := archive.MustWriteTarGz(files)
|
||||
|
||||
bf, err := os.Create(path)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
_, err = bf.Write(buf.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
} else {
|
||||
path = root
|
||||
}
|
||||
|
||||
compiler := New().
|
||||
WithFS(fsys).
|
||||
WithPaths(path).
|
||||
WithAsBundle(true)
|
||||
|
||||
err := compiler.Build(ctx)
|
||||
|
||||
if len(tc.expErrs) > 0 {
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got none")
|
||||
}
|
||||
for _, expErr := range tc.expErrs {
|
||||
if !strings.Contains(err.Error(), expErr) {
|
||||
t.Fatalf("expected error to contain:\n\n%s\n\ngot:\n\n%v", expErr, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompilerBundleMergeWithBundleRegoVersion(t *testing.T) {
|
||||
regoV0 := ast.RegoV0.Int()
|
||||
regoV1 := ast.RegoV1.Int()
|
||||
regoDef := ast.RegoV0.Int()
|
||||
|
||||
tests := []struct {
|
||||
note string
|
||||
bundles []*bundle.Bundle
|
||||
regoVersion ast.RegoVersion
|
||||
expGlobalRegoVersion *int
|
||||
expFileRegoVersions map[string]int
|
||||
}{
|
||||
{
|
||||
note: "single bundle, no bundle rego version (default version)",
|
||||
bundles: []*bundle.Bundle{
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"a"},
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{},
|
||||
},
|
||||
},
|
||||
expGlobalRegoVersion: ®oDef,
|
||||
expFileRegoVersions: map[string]int{},
|
||||
},
|
||||
{
|
||||
note: "single bundle, global rego version",
|
||||
bundles: []*bundle.Bundle{
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"a"},
|
||||
RegoVersion: ®oV1,
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{},
|
||||
},
|
||||
},
|
||||
expGlobalRegoVersion: ®oV1,
|
||||
expFileRegoVersions: map[string]int{},
|
||||
},
|
||||
{
|
||||
note: "no global rego versions",
|
||||
bundles: []*bundle.Bundle{
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"a"},
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{},
|
||||
},
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"b"},
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{},
|
||||
},
|
||||
},
|
||||
regoVersion: ast.RegoV1,
|
||||
expGlobalRegoVersion: ®oV1,
|
||||
},
|
||||
{
|
||||
note: "global rego versions, v1 bundles, v0 provided",
|
||||
bundles: []*bundle.Bundle{
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"a"},
|
||||
RegoVersion: ®oV1,
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
Path: "a/test1.rego",
|
||||
URL: "a/test1.rego",
|
||||
RelativePath: "/test1.rego",
|
||||
Raw: []byte("package a"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"b"},
|
||||
RegoVersion: ®oV1,
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
Path: "b/test1.rego",
|
||||
URL: "b/test1.rego",
|
||||
RelativePath: "/test1.rego",
|
||||
Raw: []byte("package b"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
regoVersion: ast.RegoV0,
|
||||
// global rego-version in bundles are dropped in favor of the provided rego-version
|
||||
expGlobalRegoVersion: ®oV0,
|
||||
expFileRegoVersions: map[string]int{
|
||||
"/a/test1.rego": 1,
|
||||
"/b/test1.rego": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "global rego versions, v0 bundles, v1 provided",
|
||||
bundles: []*bundle.Bundle{
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"a"},
|
||||
RegoVersion: ®oV0,
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
Path: "a/test1.rego",
|
||||
URL: "a/test1.rego",
|
||||
RelativePath: "/test1.rego",
|
||||
Raw: []byte("package a"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"b"},
|
||||
RegoVersion: ®oV0,
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
Path: "b/test1.rego",
|
||||
URL: "b/test1.rego",
|
||||
RelativePath: "/test1.rego",
|
||||
Raw: []byte("package b"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
regoVersion: ast.RegoV1,
|
||||
// global rego-version in bundles are dropped in favor of the provided rego-version
|
||||
expGlobalRegoVersion: ®oV1,
|
||||
expFileRegoVersions: map[string]int{
|
||||
"/a/test1.rego": 0,
|
||||
"/b/test1.rego": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "different global rego versions",
|
||||
bundles: []*bundle.Bundle{
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"a"},
|
||||
RegoVersion: ®oV0,
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
Path: "a/test1.rego",
|
||||
URL: "a/test1.rego",
|
||||
RelativePath: "/test1.rego",
|
||||
Raw: []byte("package a"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"b"},
|
||||
RegoVersion: ®oV1,
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
Path: "b/test1.rego",
|
||||
URL: "b/test1.rego",
|
||||
RelativePath: "/test1.rego",
|
||||
Raw: []byte("package b"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
regoVersion: ast.RegoV0,
|
||||
// global rego-version in bundles are dropped in favor of the provided rego-version
|
||||
expGlobalRegoVersion: ®oV0,
|
||||
expFileRegoVersions: map[string]int{
|
||||
"/b/test1.rego": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "different global rego versions, per-file overrides",
|
||||
bundles: []*bundle.Bundle{
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"a"},
|
||||
RegoVersion: ®oV1,
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
Path: "a/test1.rego",
|
||||
URL: "a/test1.rego",
|
||||
RelativePath: "/test1.rego",
|
||||
Raw: []byte("package a"),
|
||||
},
|
||||
{
|
||||
Path: "a/test2.rego",
|
||||
URL: "a/test2.rego",
|
||||
RelativePath: "/test2.rego",
|
||||
Raw: []byte("package a"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"b"},
|
||||
RegoVersion: ®oV1,
|
||||
FileRegoVersions: map[string]int{
|
||||
"/test1.rego": 0,
|
||||
},
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
// we don't expect this file to get an individual rego-version in the result, as
|
||||
// it has the same rego-version as the global rego-version
|
||||
Path: "b/test1.rego",
|
||||
URL: "b/test1.rego",
|
||||
RelativePath: "/test1.rego",
|
||||
Raw: []byte("package b"),
|
||||
},
|
||||
{
|
||||
Path: "b/test2.rego",
|
||||
URL: "b/test2.rego",
|
||||
RelativePath: "/test2.rego",
|
||||
Raw: []byte("package b"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
RegoVersion: ®oV0,
|
||||
Roots: &[]string{"c"},
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
// we don't expect these files to get individual rego-versions in the result,
|
||||
// as they have the same rego-version as the global rego-version
|
||||
{
|
||||
Path: "c/test1.rego",
|
||||
URL: "c/test1.rego",
|
||||
RelativePath: "test1.rego",
|
||||
Raw: []byte("package c"),
|
||||
},
|
||||
{
|
||||
Path: "c/test2.rego",
|
||||
URL: "c/test2.rego",
|
||||
RelativePath: "test2.rego",
|
||||
Raw: []byte("package c"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
regoVersion: ast.RegoV0,
|
||||
// global rego-version in bundles are dropped in favor of the provided rego-version
|
||||
expGlobalRegoVersion: ®oV0,
|
||||
// rego-versions is expected for all modules with different rego-version than the global rego-version
|
||||
expFileRegoVersions: map[string]int{
|
||||
"/a/test1.rego": 1,
|
||||
"/a/test2.rego": 1,
|
||||
"/b/test2.rego": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
note: "glob per-file overrides",
|
||||
bundles: []*bundle.Bundle{
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"a"},
|
||||
RegoVersion: ®oV0,
|
||||
FileRegoVersions: map[string]int{
|
||||
"a/*": 1,
|
||||
},
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
Path: "a/foo/test.rego",
|
||||
URL: "a/foo/test.rego",
|
||||
Raw: []byte("package a"),
|
||||
},
|
||||
{
|
||||
Path: "a/bar/test.rego",
|
||||
URL: "a/bar/test.rego",
|
||||
Raw: []byte("package a"),
|
||||
},
|
||||
{
|
||||
Path: "a/baz/test.rego",
|
||||
URL: "a/baz/test.rego",
|
||||
Raw: []byte("package a"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Manifest: bundle.Manifest{
|
||||
Roots: &[]string{"b"},
|
||||
RegoVersion: ®oV1,
|
||||
FileRegoVersions: map[string]int{
|
||||
// glob should not affect files with matching path in the other bundle
|
||||
"*/bar/*": 0,
|
||||
},
|
||||
},
|
||||
Data: map[string]interface{}{},
|
||||
Modules: []bundle.ModuleFile{
|
||||
{
|
||||
Path: "b/foo/test.rego",
|
||||
URL: "b/foo/test.rego",
|
||||
Raw: []byte("package b"),
|
||||
},
|
||||
{
|
||||
Path: "b/bar/test.rego",
|
||||
URL: "b/bar/test.rego",
|
||||
Raw: []byte("package b"),
|
||||
},
|
||||
{
|
||||
Path: "b/baz/test.rego",
|
||||
URL: "b/baz/test.rego",
|
||||
Raw: []byte("package b"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
regoVersion: ast.RegoV0,
|
||||
expGlobalRegoVersion: ®oV0,
|
||||
expFileRegoVersions: map[string]int{
|
||||
"/a/foo/test.rego": 1,
|
||||
"/a/bar/test.rego": 1,
|
||||
"/a/baz/test.rego": 1,
|
||||
"/b/foo/test.rego": 1,
|
||||
"/b/baz/test.rego": 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.note, func(t *testing.T) {
|
||||
for _, b := range tc.bundles {
|
||||
b.Manifest.Init()
|
||||
for i, m := range b.Modules {
|
||||
b.Modules[i].Parsed = ast.MustParseModule(string(m.Raw))
|
||||
}
|
||||
}
|
||||
|
||||
result, err := bundle.MergeWithRegoVersion(tc.bundles, tc.regoVersion, false)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
compareRegoVersions(t, tc.expGlobalRegoVersion, result.Manifest.RegoVersion)
|
||||
|
||||
if !reflect.DeepEqual(tc.expFileRegoVersions, result.Manifest.FileRegoVersions) {
|
||||
t.Fatalf("expected file rego versions to be:\n\n%v\n\nbut got:\n\n%v", tc.expFileRegoVersions, result.Manifest.FileRegoVersions)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func compareRegoVersions(t *testing.T, exp, act *int) {
|
||||
t.Helper()
|
||||
if exp == nil {
|
||||
if act != nil {
|
||||
t.Errorf("expected no rego version, but got %v", *act)
|
||||
}
|
||||
} else {
|
||||
if act == nil {
|
||||
t.Errorf("expected rego version to be %v, but got none", *exp)
|
||||
} else if *act != *exp {
|
||||
t.Errorf("expected rego version to be %v, but got %v", *exp, *act)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package compile
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2018 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 config implements OPA configuration file parsing and validation.
|
||||
package config
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/config"
|
||||
)
|
||||
|
||||
// Config represents the configuration file that OPA can be started with.
|
||||
type Config = v1.Config
|
||||
|
||||
// ParseConfig returns a valid Config object with defaults injected. The id
|
||||
// and version parameters will be set in the labels map.
|
||||
func ParseConfig(raw []byte, id string) (*Config, error) {
|
||||
return v1.ParseConfig(raw, id)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package config
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2018 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 cover reports coverage on modules.
|
||||
package cover
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/cover"
|
||||
)
|
||||
|
||||
// Cover computes and reports on coverage.
|
||||
type Cover = v1.Cover
|
||||
|
||||
// New returns a new Cover object.
|
||||
func New() *Cover {
|
||||
return v1.New()
|
||||
}
|
||||
|
||||
// Position represents a file location.
|
||||
type Position = v1.Position
|
||||
|
||||
// PositionSlice is a collection of position that can be sorted.
|
||||
type PositionSlice = v1.PositionSlice
|
||||
|
||||
// Range represents a range of positions in a file.
|
||||
type Range = v1.Range
|
||||
|
||||
// FileReport represents a coverage report for a single file.
|
||||
type FileReport = v1.FileReport
|
||||
|
||||
// Report represents a coverage report for a set of files.
|
||||
type Report = v1.Report
|
||||
|
||||
// CoverageThresholdError represents an error raised when the global
|
||||
// code coverage percentage is lower than the specified threshold.
|
||||
type CoverageThresholdError = v1.CoverageThresholdError
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package cover
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2024 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 debug
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/debug"
|
||||
)
|
||||
|
||||
type BreakpointID = v1.BreakpointID
|
||||
|
||||
type Breakpoint = v1.Breakpoint
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2024 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 debug
|
||||
// EXPERIMENTAL: This package is under active development and is subject to change.
|
||||
package debug
|
||||
|
||||
import (
|
||||
"github.com/open-policy-agent/opa/logging"
|
||||
"github.com/open-policy-agent/opa/rego"
|
||||
v1 "github.com/open-policy-agent/opa/v1/debug"
|
||||
)
|
||||
|
||||
// Debugger is the interface for launching OPA debugger Session(s).
|
||||
// This implementation is similar in structure to the Debug Adapter Protocol (DAP)
|
||||
// to make such integrations easier, but is not intended to be a direct implementation.
|
||||
// See: https://microsoft.github.io/debug-adapter-protocol/specification
|
||||
//
|
||||
// EXPERIMENTAL: These interfaces are under active development and is subject to change.
|
||||
type Debugger = v1.Debugger
|
||||
|
||||
type Session = v1.Session
|
||||
|
||||
type DebuggerOption = v1.DebuggerOption
|
||||
|
||||
func NewDebugger(options ...DebuggerOption) Debugger {
|
||||
return v1.NewDebugger(options...)
|
||||
}
|
||||
|
||||
func SetLogger(logger logging.Logger) DebuggerOption {
|
||||
return v1.SetLogger(logger)
|
||||
}
|
||||
|
||||
func SetEventHandler(handler EventHandler) DebuggerOption {
|
||||
return v1.SetEventHandler(handler)
|
||||
}
|
||||
|
||||
type LaunchEvalProperties = v1.LaunchEvalProperties
|
||||
|
||||
type LaunchTestProperties = v1.LaunchTestProperties
|
||||
|
||||
type LaunchProperties = v1.LaunchProperties
|
||||
|
||||
type LaunchOption = v1.LaunchOption
|
||||
|
||||
// RegoOption adds a rego option to the internal Rego instance.
|
||||
// Options may be overridden by the debugger, and it is recommended to
|
||||
// use LaunchEvalProperties for commonly used options.
|
||||
func RegoOption(opt func(*rego.Rego)) LaunchOption {
|
||||
return v1.RegoOption(opt)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package debug
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2024 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 debug
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/debug"
|
||||
)
|
||||
|
||||
type EventType = v1.EventType
|
||||
|
||||
const (
|
||||
ExceptionEventType = v1.ExceptionEventType
|
||||
StdoutEventType = v1.StdoutEventType
|
||||
StoppedEventType = v1.StoppedEventType
|
||||
TerminatedEventType = v1.TerminatedEventType
|
||||
ThreadEventType = v1.ThreadEventType
|
||||
)
|
||||
|
||||
type Event = v1.Event
|
||||
|
||||
type EventHandler = v1.EventHandler
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 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 debug
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/debug"
|
||||
)
|
||||
|
||||
type FrameID = v1.FrameID
|
||||
|
||||
type StackFrame = v1.StackFrame
|
||||
|
||||
// StackTrace represents a StackFrame stack.
|
||||
type StackTrace = v1.StackTrace
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2024 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 debug
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/debug"
|
||||
)
|
||||
|
||||
type ThreadID = v1.ThreadID
|
||||
|
||||
// Thread represents a single thread of execution.
|
||||
type Thread = v1.Thread
|
||||
|
||||
// Scope represents the variable state of a StackFrame.
|
||||
type Scope = v1.Scope
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2024 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 debug
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/debug"
|
||||
)
|
||||
|
||||
type Variable = v1.Variable
|
||||
|
||||
type VarRef = v1.VarRef
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
// Copyright 2017 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 dependencies
|
||||
|
||||
import (
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
v1 "github.com/open-policy-agent/opa/v1/dependencies"
|
||||
)
|
||||
|
||||
// All returns the list of data ast.Refs that the given AST element depends on.
|
||||
func All(x interface{}) (resolved []ast.Ref, err error) {
|
||||
return v1.All(x)
|
||||
}
|
||||
|
||||
// Minimal returns the list of data ast.Refs that the given AST element depends on.
|
||||
// If an AST element depends on a ast.Ref that is a prefix of another dependency, the
|
||||
// ast.Ref that is the prefix of the other will be the only one in the returned list.
|
||||
//
|
||||
// As an example, if an element depends on data.x and data.x.y, only data.x will
|
||||
// be in the returned list.
|
||||
func Minimal(x interface{}) (resolved []ast.Ref, err error) {
|
||||
return v1.Minimal(x)
|
||||
}
|
||||
|
||||
// Base returns the list of base data documents that the given AST element depends on.
|
||||
//
|
||||
// The returned refs are always constant and are truncated at any point where they become
|
||||
// dynamic. That is, a ref like data.a.b[x] will be truncated to data.a.b.
|
||||
func Base(compiler *ast.Compiler, x interface{}) ([]ast.Ref, error) {
|
||||
return v1.Base(compiler, x)
|
||||
}
|
||||
|
||||
// Virtual returns the list of virtual data documents that the given AST element depends
|
||||
// on.
|
||||
//
|
||||
// The returned refs are always constant and are truncated at any point where they become
|
||||
// dynamic. That is, a ref like data.a.b[x] will be truncated to data.a.b.
|
||||
func Virtual(compiler *ast.Compiler, x interface{}) ([]ast.Ref, error) {
|
||||
return v1.Virtual(compiler, x)
|
||||
}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2017 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 dependencies provides functions for determining the set of ast.Refs that AST
|
||||
// elements depend on.
|
||||
//
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package dependencies
|
||||
+1
-11
@@ -64,7 +64,6 @@ opa bench <query> [flags]
|
||||
-t, --target {rego,wasm} set the runtime to exercise (default rego)
|
||||
-u, --unknowns stringArray set paths to treat as unknown during partial evaluation (default [input])
|
||||
--v0-compatible opt-in to OPA features and behaviors prior to the OPA v1.0 release. Takes precedence over --v1-compatible
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
```
|
||||
|
||||
____
|
||||
@@ -258,7 +257,6 @@ opa build <path> [<path> [...]] [flags]
|
||||
--signing-plugin string name of the plugin to use for signing/verification (see https://www.openpolicyagent.org/docs/latest/management-bundles/#signature-plugin
|
||||
-t, --target {rego,wasm,plan} set the output bundle target type (default rego)
|
||||
--v0-compatible opt-in to OPA features and behaviors prior to the OPA v1.0 release. Takes precedence over --v1-compatible
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
--verification-key string set the secret (HMAC) or path of the PEM file containing the public key (RSA and ECDSA)
|
||||
--verification-key-id string name assigned to the verification key used for bundle verification (default "default")
|
||||
--wasm-include-print enable print statements inside of WebAssembly modules compiled by the compiler
|
||||
@@ -360,7 +358,6 @@ opa check <path> [path [...]] [flags]
|
||||
-s, --schema string set schema file path or directory path
|
||||
-S, --strict enable compiler strict mode
|
||||
--v0-compatible opt-in to OPA features and behaviors prior to the OPA v1.0 release. Takes precedence over --v1-compatible
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
```
|
||||
|
||||
____
|
||||
@@ -416,7 +413,6 @@ opa deps <query> [flags]
|
||||
-f, --format {pretty,json} set output format (default pretty)
|
||||
-h, --help help for deps
|
||||
--ignore strings set file and directory names to ignore during loading (e.g., '.*' excludes hidden files)
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
```
|
||||
|
||||
____
|
||||
@@ -576,7 +572,6 @@ opa eval <query> [flags]
|
||||
--timeout duration set eval timeout (default unlimited)
|
||||
-u, --unknowns stringArray set paths to treat as unknown during partial evaluation (default [input])
|
||||
--v0-compatible opt-in to OPA features and behaviors prior to the OPA v1.0 release. Takes precedence over --v1-compatible
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
--var-values show local variable values in pretty trace output
|
||||
```
|
||||
|
||||
@@ -639,7 +634,6 @@ opa exec <path> [<path> [...]] [flags]
|
||||
-I, --stdin-input read input document from stdin rather than a static file
|
||||
--timeout duration set exec timeout with a Go-style duration, such as '5m 30s'. (default unlimited)
|
||||
--v0-compatible opt-in to OPA features and behaviors prior to the OPA v1.0 release. Takes precedence over --v1-compatible
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
```
|
||||
|
||||
____
|
||||
@@ -684,7 +678,6 @@ opa fmt [path [...]] [flags]
|
||||
-l, --list list all files who would change when formatted
|
||||
--rego-v1 format module(s) to be compatible with both Rego v1 and current OPA version)
|
||||
--v0-compatible opt-in to OPA features and behaviors prior to the OPA v1.0 release. Takes precedence over --v1-compatible
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
-w, --write overwrite the original source file
|
||||
```
|
||||
|
||||
@@ -731,7 +724,7 @@ opa inspect <path> [<path> [...]] [flags]
|
||||
-a, --annotations list annotations
|
||||
-f, --format {json,pretty} set output format (default pretty)
|
||||
-h, --help help for inspect
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
--v0-compatible opt-in to OPA features and behaviors prior to the OPA v1.0 release. Takes precedence over --v1-compatible
|
||||
```
|
||||
|
||||
____
|
||||
@@ -754,7 +747,6 @@ opa parse <path> [flags]
|
||||
-f, --format {pretty,json} set output format (default pretty)
|
||||
-h, --help help for parse
|
||||
--json-include string include or exclude optional elements. By default comments are included. Current options: locations, comments. E.g. --json-include locations,-comments will include locations and exclude comments.
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
```
|
||||
|
||||
____
|
||||
@@ -935,7 +927,6 @@ opa run [flags]
|
||||
--tls-private-key-file string set path of TLS private key file
|
||||
--unix-socket-perm string specify the permissions for the Unix domain socket if used to listen for incoming connections (default "755")
|
||||
--v0-compatible opt-in to OPA features and behaviors prior to the OPA v1.0 release. Takes precedence over --v1-compatible
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
--verification-key string set the secret (HMAC) or path of the PEM file containing the public key (RSA and ECDSA)
|
||||
--verification-key-id string name assigned to the verification key used for bundle verification (default "default")
|
||||
-w, --watch watch command line files for changes
|
||||
@@ -1155,7 +1146,6 @@ opa test <path> [path [...]] [flags]
|
||||
--threshold float set coverage threshold and exit with non-zero status if coverage is less than threshold %
|
||||
--timeout duration set test timeout (default 5s, 30s when benchmarking)
|
||||
--v0-compatible opt-in to OPA features and behaviors prior to the OPA v1.0 release. Takes precedence over --v1-compatible
|
||||
--v1-compatible opt-in to OPA features and behaviors that are enabled by default in OPA v1.0
|
||||
--var-values show local variable values in test output
|
||||
-v, --verbose set verbose reporting mode
|
||||
-w, --watch watch command line files for changes
|
||||
|
||||
@@ -69,7 +69,7 @@ export default async function localEval(groups, groupName, opaVersion) {
|
||||
// Returns 1st a function that consumes a string for the output format you want and produces an array of arguments and 2nd a map of module file names to strings that should be replaced in error messages. May throw a user-friendly error.
|
||||
async function prepEval(groups, groupName, opaVersion) {
|
||||
const {module, package: pkg, query, input, included} = getGroupData(groups, groupName)
|
||||
const base = ['eval', '--fail'] // Fail on undefined
|
||||
const base = ['eval', '--fail', '--v0-compatible'] // Fail on undefined
|
||||
const rest = []
|
||||
const moduleFilenameMap = {}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2018 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 download
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/download"
|
||||
)
|
||||
|
||||
// PollingConfig represents polling configuration for the downloader.
|
||||
type PollingConfig = v1.PollingConfig
|
||||
|
||||
// Config represents the configuration for the downloader.
|
||||
type Config = v1.Config
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package download
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2018 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 download implements low-level OPA bundle downloading.
|
||||
package download
|
||||
|
||||
import (
|
||||
"github.com/open-policy-agent/opa/plugins/rest"
|
||||
v1 "github.com/open-policy-agent/opa/v1/download"
|
||||
)
|
||||
|
||||
// Update contains the result of a download. If an error occurred, the Error
|
||||
// field will be non-nil. If a new bundle is available, the Bundle field will
|
||||
// be non-nil.
|
||||
type Update = v1.Update
|
||||
|
||||
// Downloader implements low-level OPA bundle downloading. Downloader can be
|
||||
// started and stopped. After starting, the downloader will request bundle
|
||||
// updates from the remote HTTP endpoint that the client is configured to
|
||||
// connect to.
|
||||
type Downloader = v1.Downloader
|
||||
|
||||
// New returns a new Downloader that can be started.
|
||||
func New(config Config, client rest.Client, path string) *Downloader {
|
||||
return v1.New(config, client, path)
|
||||
}
|
||||
|
||||
type HTTPError = v1.HTTPError
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build !opa_no_oci
|
||||
|
||||
package download
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/download"
|
||||
|
||||
"github.com/open-policy-agent/opa/plugins/rest"
|
||||
)
|
||||
|
||||
// NewOCI returns a new Downloader that can be started.
|
||||
func NewOCI(config Config, client rest.Client, path, storePath string) *OCIDownloader {
|
||||
return v1.NewOCI(config, client, path, storePath)
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
//go:build opa_no_oci
|
||||
|
||||
package download
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/bundle"
|
||||
"github.com/open-policy-agent/opa/plugins/rest"
|
||||
)
|
||||
|
||||
func NewOCI(Config, rest.Client, string, string) *OCIDownloader {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) WithCallback(f func(context.Context, Update)) *OCIDownloader {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) WithLogAttrs(map[string]interface{}) *OCIDownloader {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) WithBundleVerificationConfig(*bundle.VerificationConfig) *OCIDownloader {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) WithSizeLimitBytes(int64) *OCIDownloader {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) WithBundlePersistence(bool) *OCIDownloader {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) ClearCache() {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) SetCache(string) {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) Trigger(context.Context) error {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) Start(context.Context) {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (d *OCIDownloader) Stop(context.Context) {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
|
||||
func (*OCIDownloader) WithBundleParserOpts(ast.ParserOptions) *OCIDownloader {
|
||||
panic("built without OCI support")
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package download
|
||||
|
||||
import (
|
||||
v1 "github.com/open-policy-agent/opa/v1/download"
|
||||
)
|
||||
|
||||
type OCIDownloader = v1.OCIDownloader
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package features
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Deprecated: This package is intended for older projects transitioning from OPA v0.x and will remain for the lifetime of OPA v1.x, but its use is not recommended.
|
||||
// For newer features and behaviours, such as defaulting to the Rego v1 syntax, use the corresponding components in the [github.com/open-policy-agent/opa/v1] package instead.
|
||||
// See https://www.openpolicyagent.org/docs/latest/v0-compatibility/ for more information.
|
||||
package tracing
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright 2021 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 tracing
|
||||
|
||||
import (
|
||||
// Importing v1 for side effects
|
||||
_ "github.com/open-policy-agent/opa/v1/features/tracing"
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user