A bit surprising how not a single test seems to fail from this change 😅
I've added one to at least verify that the type checker does a little
better now than before. External tools like Regal can do even better :)
Fixes#8692
Signed-off-by: Anders Eknert <anders.eknert@apple.com>
Originally meant to be `array.concat_n`, but this name is better
as the behavior of this function differs from `array.concat` —
namely that `array.flatten` accepts any type of valued in the
input array. Only arrays are however flattened, and the rest
are appended directly to the flattened output.
Note that this function only flattens at the topmost level of
the input array — not recursively! A cursory look
at a few other languages suggest a single level is the common case.
But if others feel we should flstten more, I'm happy to make an update.
The C code for a Wasm implementstion here is cowboy coded, and
I did not manage to run the tests on my machine due to some
`docker` <-> `container` differences. I mostly just imitated
the existing code in the array category. I doubt it'll work
on the first try, but only CI can judge me.
Also:
- Remove `opa fmt` step from the Rego CI step, as this is done by
Regal anyway a little later in the list of tasks.
- Replace some hard-coded `docker` names in the `Makefile` with `$(DOCKER)`
- Added name of built-in function missing to the unsupportedBuiltinErr
error, as it has happened a few times now that I've used `:=` in a
query, and had no clue what built-in it referred to.
Fixes#8226
Signed-off-by: Anders Eknert <anders.eknert@apple.com>
Adding string interpolation support to the Rego language.
An interpolated string is composed of a template-string that can contain zero or more template-expressions that interpolates values into the string generated at eval-time.
Requires the `template_strings` capability feature and `internal.template_string` built-in function.
Implements: #4733
Introducing the `io.jwt.verify_eddsa` built-in, and adding support to the following built-ins:
* `io.jwt.decode_verify`
* `io.jwt.encode_sign`
* `io.jwt.encode_sign_raw`
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
Adding the ability to parameterize Rego `test_*` rules, effectively declaring multiple "test cases" within the rule, which is then individually reported (grouped under their parent rule) when running `opa test`.
Fixes: #2176
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
This adds support for rendering of templated strings utilizing Golang's text/template library.
For a given templated string and key/value mapping of template var inputs, this builtin will
inject the values into the template where they are referenced by key.
Fixes#6371
Signed-off-by: Rohan Vasavada <rohanvasavada@gmail.com>
* crypto.parse_private_keys parses private keys, returns a list of valid
keys
* consolidated getPrivateKeysFromString with getPrivateKeysFromPEMData
for crypto.x509.parse_rsa_private_key and crypto.parse_private_keys
* reworked crypto.x509.parse_rsa_private_key so that we no longer need
getPrivateKeysFromString but instead determine type of key in builtin
function and added input validation checks
Co-authored-by: Charlie Egan <git@charlieegan3.com>
Signed-off-by: Emil Volckmar Ry <emilvry@gmail.com>
crypto.x509.parse_keypair(cert, key) takes PEM/DER (base64) encoded input.
if key pair is valid, returns the tls.certificate(https://pkg.go.dev/crypto/tls#Certificate) as an object.
if key pair is invalid, returns an error.
Fixes#5853
Signed-off-by: Emil Volckmar Ry <emilvry@gmail.com>
Add crypto.hmac.equal built-in function to safelly comparing hashes generated by MD5, SHA-1, SHA-256 and SHA-512 hashing algorithms.
The built-in function is a wrapped for the function Equal of package crypto/hmac.
It's useful when you need to write a policy that requires to check hash signature for request body.
Signed-off-by: Sandokan D. Arantes <sandokandias@gmail.com>
Adds a builtin time.format to format time given in ns to a string timestamp for
the given timezone or UTC as default. The builtin takes in 3 types of arguments:
1. An integer value representing the time in nanoseconds since epoch
2. An array with the first value as integer representing the time in ns and second argument as string value representing the timezone. In the first case, when only an integer value is provided, UTC timezone is considered
The function returns a string type value of the timestamp in the RFC3339Nano format. E.g. 2022-11-23T18:20:14Z
3. An array with the first value the integer ns, the second a string timezone, and third a string for the format, to use one different from RFC3339Nano.
Signed-off-by: burnerlee <avi.aviral140@gmail.com>
This commit adds initial support for AWS's SigV4 request signing system,
which will allow OPA's existing `http.send` builtin to be used to more
conveniently query cloud resources. It automates away most of the pain
around signing the request headers and body, and is designed to compose
with `http.send` directly.
Internally, this also refactors AWS SigV4 request signing, so that the
signing logic is shared between the builtin and the REST plugin for AWS.
Fixes: #3749
Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
The `object.keys` function will return a set of all top-level keys on
a given object. Since object keys in Rego don't have the same
restrictions as names in JSON name-value pairs, we also ensure
support for non-string key types.
Fixes#5363.
Signed-off-by: Kevin Swiber <kswiber@gmail.com>
This commit adds a new GraphQL builtin for validating GraphQL schemas,
applying stronger validation rules than what the current GraphQL parsing
builtins apply by default.
Fixes: #5125
Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
This commit adds the `net.cidr_is_valid` builtin, which makes
validating network CIDR strings much easier in policies.
Example policy:
allow {
net.cidr_is_valid("192.168.0.0/24")
}
This builtin works for both IPv4 and IPv6 CIDR strings.
Signed-off-by: Ricardo Maraschini <ricardo.maraschini@gmail.com>
This commit adds support for AST objects to be usable in place of
strings for several of the GraphQL built-in functions, to improve
the composability of the GraphQL set of built-ins, and to dramatically
reduce the amount of redundant parsing when writing GraphQL policies.
Fixes: #4742
Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
This commit includes evaluator support for an opt-in, non-deterministic
builtins caching system, designed to help with future replay of decision
logs.
The cache allows early-exit in the evaluator if the builtin is
non-deterministic, and has already cached a result. Since the cache can
be pre-populated by `rego` module users, this should make offline policy
testing and future work around decision replay more straightforward.
Fixes: #1514
Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
Using null for delimiters disables delimiters in glob matching. Preferable over regex on some cases for performance reasons.
Fixes#4923.
Signed-off-by: vinhph0906 <vinhph0906@gmail.com>
Co-authored-by: Stephan Renatus <stephan.renatus@gmail.com>
`contains` provides an alternative way to declare partial sets:
p contains x {
x := { "foo": "bar"
}
which is the same as
p[x] {
x := { "foo": "bar"
}
The keyword is enabled by importing `future.keywords.contains`, and
when it _is enabled_, the format will be used for all partial sets in
that file for pretty-printing.
`if` is a new keyword allowing for more readable rule definitions:
The syntax is
NAME [if] { EXPR [EXPR...] }
and the is a shorthand allows dropping the braces around the expression
if there is only one:
NAME if EXPR
For example, this allows expressions like
allow if not deny
f(xs) if every x in xs { x != "foo" }
The one exception here are partial sets: they cannot use `if` UNLESS
they use `contains`:
p[x] { x := "foo" } # valid
p contains x { x := "bar" } # valid
p contains x if { x := "bar" } # valid
p[x] if { x := "foo" } # invalid
This is because we want to interpret that differently (as an object
rule defining `p.foo = true`) in the near future.
The formatter works in the same way: if `future.keywords.if` is imported, it
will be used where it can be used.
We don't want to be too eager when it comes to introducing syntactic sugar.
So this will be rewritten, because head and body expression are on the same
line:
p := 5 if { time.day_of_week() == "Monday" }
# => p := 5 if time.day_of_week() == "Monday"
but this won't:
p := 5 if {
time.day_of_week() == "Monday"
}
The rationale here is that if the policy author decided that they want this on
an extra line, we won't mess with it.
This also sidesteps the need to check if both the head and the single body
expression have a comment.
This change includes various docs updates. Notable exceptions are the GK docs,
since it will take a while for these keywords to be come available there; and
the frontpage: merging a PR would update the frontpage immediately, and we
don't want to show something there that isn't available in the latest release.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
This implements the new object.subset() builtin.
Based on my benchmarking, this offers a 2.77x speedup compared to
implementing the same thing in pure Rego, and is also easier to read.
Fixes#4358
Signed-off-by: Charles Daniels <charles@styra.com>
This commit vendors in github.com/vektah/gqlparser, and provides the
implementation for the following graphql built-ins:
- graphql.parse
- graphql.parse_and_verify
- graphql.parse_query
- graphql.parse_schema
- graphql.is_valid
The test suite is comprised of the classic "Star Wars" examples from the
official GraphQL docs, along with a host of syntax examples ported over
from the underlying GraphQL parser's test suite.
AST objects returned by the parse_x APIs are currently pruned for brevity.
Fixes#4283
Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
This function works on all base decimal and binary SI units of the set:
m, K/Ki, M/Mi, G/Gi, T/Ti, P/Pi, and E/Ei
Note: Unlike `units.parse_bytes`, this function is case sensitive.
Fixes open-policy-agent#1802.
Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
New functions:
* rego.metadata.chain(): returns the chain of metadata, starting from the active rule, going outward
* rego.metadata.rule(): returns the metadata for the active rule
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
Importing `future.keywords.every` will ALSO import `future.keywords.in`,
since the latter is required for the former.
This includes the formatting of the expression itself, and adding
the "future.keywors.every" import if necessary:
This would happen when pretty-printing an AST that was parsed
with ast.ParserOptions enabling the required future keyword:
The import would not be present in the *ast.Module, but it would
be required to parse the pretty-printed result.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
This new built-in functionality allows callers to find all reachable
paths in a graph based on an array or set of root nodes. See the
updates to policy-reference.md for more details and usage information.
Signed-off-by: Justin Lindh <justin.lindh@webfilings.com>
The function `array.reverse` takes an array as an argument, and returns an array with a reversed order of elements.
The function `strings.reverse` takes a string as an argument, and returns a string with a reversed order of unicode code points.
WASM support is included for both built-ins.
Fixes#3736
Signed-off-by: Kristian Svalland <kristian.svalland@gmail.com>
Add crypto.hmac.* built-in functions for the MD5, SHA-1, SHA-256 and SHA-512 hashing algorithms.
Add documentation for how to contribute new built-in functions.
Fixes: #1740
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
Since the golang stdlib function doesn't do any caching, we add the result
to the BuiltinContext.Cache so it's cached, and consistent, within a single
policy evaluation.
There is no decision made here about using netgo or netcgo: we're following
suit wrt how golang expects you to do it: From my understanding, using the
OS means for DNS resolution is the preferred way: it gives you per-host
caching, and it allows the user to affect how DNS resolution works in many
ways.
This means the same logic that applies to all other places where we resolve
domain names into addresses (notably `http.send`) applies to this built-in,
too.
Also:
* workflow/pull_request: don't fail-fast for matrix jobs
Even if one platform fails it would be interesting to see what happens
on the others.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
This commit updates the capabilities structure to include the set of
supported future keywords and enhances the parser to accept the
capabilities structure so that callers can restrict what keywords can
be opted into in the first place. This ensures that callers can verify
that policies will parse for a particular version of OPA.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
There are four variants to this: with or without 'some', and with
only one or two lhs arguments:
a) x in xs
b) k, v in xs
c) some x in xs
d) some k, v in xs
(a) and (b) are handled in the parser, and end up in the AST as
calls to `internal.member_2` and `internal.member_3`:
a) internal.member_2(x, xs)
b) internal.member_4(k, v, xs)
The backing builtin functions iterate over their last arguments,
trying to find a match. If they do, they will return `true`.
In all other cases -- no match, or a type in the last argument that
can't be iterated over (not an array, object or set), it will
return `false`.
As such, they can be used with `not` without any restrictions.
(c) and (d) are rewritten in the compiler, where x', v', and k' are
fresh local vars:
c) x' = xs[_]
d) v' = xs[k']
Since `in` is a new keyword, it's enabled gradually: for now, a new
mechanism of future keyword imports is added. There are new option
arguments in the parser methods, and there's a hook in the parser
code updating its set of enabled future keywords whenever it
encounters an import statement like
import future.keywords.in # enables only "in"
import future.keywords # enables all future keywords
Functionally, these are identical right now: there is only one
future keyword, "in".
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
The print built-in function has special-case handling in two ways:
1. Print arguments are wrapped in comprehensions at compile-time to
ensure that undefined values do not short-circuit evaluation. The
evaluator is aware of this rewriting and extracts the actual values
during evaluation.
2. Print arguments cannot contain unsafe/undeclared variables, i.e.,
vars appearing in refs inside of print args _must_ be assigned in
a previous expression in the body. This ensures that print statements
do not affect the semantics of the rule.
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
* types: Sort any elements during construction
This changes updates the implementation of the any type to sort
elements during construction. This way the Compare() function does not
have to sort elements before recursing (which can result in data races
if global type instances from the built-in function declarations or
elsewhere are compared.)
Fixes#3793
* capabilities.json: changed ordering
* internal/presentation: fix json error output
Co-authored-by: Torin Sandall <torinsandall@gmail.com>
Co-authored-by: Stephan Renatus <stephan.renatus@gmail.com>
Signed-off-by: Torin Sandall <torinsandall@gmail.com>