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:
Johan Fylling
2024-11-21 17:30:02 +01:00
parent 7bb6dbe36b
commit a179a24c48
337 changed files with 15549 additions and 629 deletions
+133
View File
@@ -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:
+1 -1
View File
@@ -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
+33
View File
@@ -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
View File
@@ -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
+57
View File
@@ -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()
}
+22
View File
@@ -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
+39
View File
@@ -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
View File
@@ -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)
}
+99
View File
@@ -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())
}
}
+48
View File
@@ -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
}
+226
View File
@@ -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)
}
}
})
}
}
+15
View File
@@ -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)
}
+8
View File
@@ -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
View File
@@ -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
+46
View File
@@ -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...)
}
+20
View File
@@ -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)
}
+24
View File
@@ -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)
}
+8
View File
@@ -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
+15
View File
@@ -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
+8
View File
@@ -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
+14
View File
@@ -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
View File
@@ -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()
}
+45
View File
@@ -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)
}
+310
View File
@@ -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
}
+127
View File
@@ -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))
}
}
})
}
}
+52
View File
@@ -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
View File
@@ -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...)
}
+85
View File
@@ -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)
}
}
+18
View File
@@ -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)
}
+17
View File
@@ -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()
}
+14
View File
@@ -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
View File
@@ -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...)
}
+46
View File
@@ -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)
}
+14
View File
@@ -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)
}
+17
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
+1 -1
View File
@@ -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
+134
View File
@@ -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)
}
+84
View File
@@ -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))
}
}
})
}
}
+8
View File
@@ -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
+50
View File
@@ -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)
}
+22
View File
@@ -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)
}
+32
View File
@@ -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)
}
+30
View File
@@ -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)
}
+35
View File
@@ -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
View File
@@ -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)
}
+104
View File
@@ -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)
})
}
}
+36
View File
@@ -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)
}
+17
View File
@@ -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
+8
View File
@@ -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
+96
View File
@@ -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
View File
@@ -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
+54
View File
@@ -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
+64
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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(&params, 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
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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(), &params.listAnnotations)
addV0CompatibleFlag(inspectCommand.Flags(), &params.v0Compatible, false)
addV1CompatibleFlag(inspectCommand.Flags(), &params.v1Compatible, false)
RootCommand.AddCommand(inspectCommand)
}
+15 -17
View File
@@ -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
}
`},
+2
View File
@@ -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
View File
@@ -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)
+52
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -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
+2
View File
@@ -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",
})
}
+37
View File
@@ -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)
}
+778
View File
@@ -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: &regoDef,
expFileRegoVersions: map[string]int{},
},
{
note: "single bundle, global rego version",
bundles: []*bundle.Bundle{
{
Manifest: bundle.Manifest{
Roots: &[]string{"a"},
RegoVersion: &regoV1,
},
Data: map[string]interface{}{},
Modules: []bundle.ModuleFile{},
},
},
expGlobalRegoVersion: &regoV1,
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: &regoV1,
},
{
note: "global rego versions, v1 bundles, v0 provided",
bundles: []*bundle.Bundle{
{
Manifest: bundle.Manifest{
Roots: &[]string{"a"},
RegoVersion: &regoV1,
},
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: &regoV1,
},
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: &regoV0,
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: &regoV0,
},
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: &regoV0,
},
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: &regoV1,
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: &regoV0,
},
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: &regoV1,
},
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: &regoV0,
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: &regoV1,
},
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: &regoV1,
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: &regoV0,
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: &regoV0,
// 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: &regoV0,
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: &regoV1,
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: &regoV0,
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)
}
}
}
+8
View File
@@ -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
+19
View File
@@ -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)
}
+8
View File
@@ -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
+37
View File
@@ -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
+8
View File
@@ -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
+13
View File
@@ -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
+52
View File
@@ -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)
}
+8
View File
@@ -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
+23
View File
@@ -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
+16
View File
@@ -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
+17
View File
@@ -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
+13
View File
@@ -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
+42
View File
@@ -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)
}
+11
View File
@@ -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
View File
@@ -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 = {}
+15
View File
@@ -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
+8
View File
@@ -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
+29
View File
@@ -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
+14
View File
@@ -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)
}
+59
View File
@@ -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")
}
+7
View File
@@ -0,0 +1,7 @@
package download
import (
v1 "github.com/open-policy-agent/opa/v1/download"
)
type OCIDownloader = v1.OCIDownloader
+8
View File
@@ -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
+8
View File
@@ -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
+10
View File
@@ -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