NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Go modules · #286 by repository stars
Last release today
07 Oct 2026
Ships on a steady schedule
a new release about every 8 days
Nearly every release is documented
notes for 59 of the last 60 stable releases
85 versions withdrawn
withdrawn after publishing
10 years old
4350 releases · first in 2016
This release fixes a compiler regression introduced in OPA v1.21.0.
This release fixes a compiler regression introduced in OPA v1.21.0.
some … in/every in comprehensions nested in object and set literals (#9280)A comprehension using some … in or every in its body, nested inside an object or set literal, was wrongly treated as ground, so the compiler skipped rewriting it. some … in then failed with rego_unsafe_var_error; every caused a compiler panic:
package example
p := {"k": [r.a | some r in input.xs]} # rego_unsafe_var_error: var r is unsafe
q := {[1 | every x in input.xs { x > 0 }]} # panicArray literals weren't affected, and neither were literals that contain some other non-ground term.
v1.21.1 Latest
Latest
Compare
One column per quarter.
YAML is parsed against the 1.2 core schema (breaking change)
This release contains a mix of new features and bug fixes. Notably:
Before, this was a recursion error:
package play
p[x].foo.bar if {
x := "a"
not p[x].foo.baz
}
p[x].foo.baz if {
x := "a"
false
}Rules with a variable in their head are all stored at the ground prefix of their ref, so
p[x].foo.bar and p[x].foo.baz looked like dependencies of each other. The compiler is
now less conservative and compares the ref parts past the prefix. Genuine cycles are still
reported.
The IR and Wasm targets however still return an error: they plan one function per ground
path prefix, and cannot evaluate part of a function that is still being planned.
Authored by @sspaink, reported by @tsandall
# METADATA labels for evaluated rules were only available in decision log
events. The Data API (GET/POST /v1/data) and Query API (GET/POST /v1/query) now accept a rule_labels query parameter to include the same
merged labels in the response payload, under a rule_labels key.
Authored by @srenatus
min_length (#9205)The server's gzip response compression (server.encoding.gzip) buffered an entire
incoming Write call before deciding whether to compress, so a single large write could
grow the buffer well past min_length before that decision was made. The handler is now
built on klauspost/compress/gzhttp
instead of a hand-rolled buffer and gzip.Writer pool, which caps what it buffers to
min_length (floored at 512 bytes) before streaming the remainder through the chosen
path. min_length and compression_level behave the same as before; only gzip is
negotiated, not zstd.
Authored by @srenatus
OPA parsed YAML with a library pinned to go-yaml v2, which implements YAML 1.1. Under
1.1, the bare words y, n, yes, no, on and off resolve to booleans, so a
GitHub Actions workflow loaded with --data came back with true where it should have
had on:
on: push{ "true": "push" }These words are now plain strings, as the YAML 1.2 core schema specifies. true and
false are unaffected. This applies everywhere OPA reads YAML: --data, bundles,
config files, and the yaml.unmarshal builtin.
If you were relying on yes/no/on/off being read as booleans, quote the value and
use true/false instead.
Authored by @sspaink, reported by @scnewma and @johnc-c
The type checker used to give the empty object literal {} the type
object[any: any], the empty array literal [] the type array[any], and the
empty set literal set() the type set[any], i.e. the types of a collection
that may hold anything. Every other literal is typed by its contents, so
referencing a key that isn't there is caught at compile time — but only for
non-empty literals:
obj := {"foo": "bar"}
obj.bar # rego_type_error: undefined ref: obj.bar
obj := {}
obj.bar # compilesEmpty literals are now typed as what they are: an object with no properties, an
array with no items, and a set with no members. Both examples above now fail to
compile, and so does every other way of selecting from an empty literal,
including iterating one (some x in []).
Comparing an empty object or array literal against a value whose type says it
can't be empty ({"foo": "bar"} == {}) is now a match error too, the same way
{"foo": "bar"} == {"bar": "foo"} already was. Use count(x) == 0 to test a
collection for emptiness without asserting its type. Sets are unaffected here:
set[string] describes any set of strings, the empty one included, so
{"foo"} == set() still compiles.
Authored by @sspaink, reported by @disaverio
The rule indexer now excludes rules from more kinds of expression, and builds a smaller
trie to do it with. See Use indexed statements
for what is indexed.
startswith, endswith, strings.any_prefix_match and strings.any_suffix_matchdata.groups.admins.members[input.subject]) is indexed by asking that object for thex := input; x.foo == "a") are indexed theinput.foo == "a", and a chain of assignments no longer drops the constraintcomplete rules must not produce multiple outputs error now points at the firstquery stack-trace framing mode (#9128) authored by @johanfyllingrunner.CapturePrintOutput setting never read (#9104) authored by @anderseknertif body (#9109) authored by @sspaink, reported by @anderseknertDisableUndefinedOutput setting (#9185) authored by @anderseknertGenericTransformer (#9148) authored by @anderseknertoutputVarsForExprEq (#8302) authored by @zanarellidev, reported by @johanfyllingin operator against the collection's types (#5658) authored by @sspaink, reported by @anderseknertsemver built-ins (#9004) authored by @sueun-devstrings.replace_n (#9216) authored by @andreaTPutil.MapKeys helper (#9158) authored by @anderseknerterrors.As call sites to use errors.AsType (#9106) authored by @anderseknertand/or keywords (#9115) authored by @johanfyllingNote truncated.
This release includes a bug fix for a parser regression introduced in v1.20.0, and dependency updates.
This release includes a bug fix for a parser regression introduced in v1.20.0, and dependency updates.
{ (#9140)When the and/or keywords added in v1.20.0 are imported, a statement that starts with { is
first read as an explicit operand body, and re-read as a term (a comprehension, for example) if no
and or or follows. Errors recorded during the abandoned first attempt stayed in the parser's
term cache and were reported against the successful re-read, rejecting policies that parse fine:
package example
import future.keywords
xs := [1, 2, 3]
allow if {
{
y |
some y in xs # rego_parse_error: unexpected some keyword
} == {1, 2, 3}
}The term cache is now restored along with the rest of the parser state when the operand-body guess
is abandoned. Only policies importing and or or — directly or via import future.keywords —
were affected; policies that don't import them parse unchanged.
Authored by @sspaink
3652eeb) authored by @srenatusThis release includes a bug fix for a regression introduced in v1.20.0 in comparing a number to some float values . Thanks @kmadan for reporting the i
This release includes a bug fix for a regression introduced in v1.20.0 in
comparing a number to some float values.
Thanks @kmadan for reporting the issue and submitting a fix!
This release contains a mix of new features and bug fixes. Notably:
This release contains a mix of new features and bug fixes. Notably:
and and or, for combining conditions inside a single rule bodyallow_net now restricts remote JSON Schema $ref fetching from json.match_schema and json.verify_schemaand and or (#7602)Rego gains two keywords for combining conditions inside a single rule body — a long-standing
request, and one of the larger additions to the language in some time. and and or let control
flow that previously had to be split across helper rules stay where it is read.
Before, a rule body that needed to succeed on one of several conditions meant extracting a rule:
package example
allow if {
input.method == "GET"
admin_or_public_owner
}
admin_or_public_owner if input.user.admin
admin_or_public_owner if {
input.user.owner
input.resource.public
}Now:
package example
import future.keywords.and
import future.keywords.or
# the and groups first, so this reads as:
# an admin, or an owner of a public resource
allow if {
input.method == "GET"
input.user.admin or input.user.owner and input.resource.public
}Both keywords are opt-in future keywords:
import future.keywords.and, import future.keywords.or, or import future.keywords for both.
An and/or expression either succeeds or fails; it never produces a value. So you can't assign
one to a variable, pass one to a function, or use one as the head of a comprehension.
Operands can read variables from the rule body around them, but can't create new ones for the rest
of the rule to use — wrap an operand in braces to give it a body of its own, and any variables it
creates stay inside those braces. Only as much is evaluated as needed: if the left side settles the
outcome, the right side is skipped. And when both sides of an or succeed, you still get a single
result; evaluation doesn't split in two.
Further reading:
notTry the new keywords in the Rego Playground, or in your
editor with the VS Code extension
or the IntelliJ IDEA plugin — see
Editor and IDE Support for others.
Authored by @johanfylling
allow_net applies to remote JSON Schema $refs (#8979)The allow_net
capability restricts which hosts remote JSON Schema $refs may be fetched from, but it was only
wired up on the compile-time type-checking path. Policies using neither -s schemas nor
# METADATA schemas:
annotations never reached it, and an unset allowlist permitted every host — so
json.match_schema
and json.verify_schema,
which compile schemas at evaluation time, fetched $refs from anywhere. Their schema argument can
come from input, so the host was not necessarily under the policy author's control.
The allowlist now travels with the schema loader and is checked per caller at any nesting depth.
Every redirect hop is checked too, matching http.send, and the inter-query cache key includes the
allowlist so a permissive caller cannot populate the cache for a restrictive one.
Authored by @sspaink, reported by @charlesdaniels
Coverage reports showed that a
range was uncovered, but not why: ranges skipped by rule indexing
or early exit looked identical to dead code.
Not-covered ranges are now tagged with a Kind — index_excluded or early_exit — determined
by re-evaluating with each optimization disabled and diffing the extra coverage data. Both
supplementary passes run by default when --coverage is set; the new --coverage-runs flag on
opa eval and opa test selects which of them to run, and an empty list disables them.
Authored by @charlieegan3
server.encoding and server.decoding validation to Rego (#8903) authored by @sspainkand/or logical expressions (#8683) reported and authored by @johanfyllingand/or operand bodies (#9053) authored by @sspaink, reported by @anderseknertnot operand (#9079) authored by @sspaink| infix in parens when output would be re-interpreted as comprehension (#8977) authored by @johanfyllingand/or logical keywords (#8819) reported and authored by @johanfylling(*Rego).compileModules (#9059) authored by @anderseknertand/or imports (#9066) reported and authored by @johanfyllingand()/or() set built-in calls (#9012) authored by @johanfyllingprint call (#9038) authored by @sspainkwith (#2903) authored by @sspaink, reported by @gshively11future.keywords wildcard import not including the not keyword (#9093) authored by @johanfyllingand/or expressions (#8997) authored by @sspaink, reported by @johanfyllingprint calls as and/or operands (#9047) authored by @sspainknot, and and or bodies (#9069) authored by @johanfylling{ ... | ... } not operands (#8978) authored by @johanfyllinghttp.send implementation (#8975) authored by @anderseknertenum as unsatisfiable (#8910) authored by @locker95, reported by @jwilhelm-cariadEqual implementation for *object (#9025) authored by @anderseknertstrings.Reader (#9016) authored by @anderseknertInterfaceToValue (#9021) authored by @anderseknertEqual methods (#9020) authored by @anderseknertast.NewObject (#9035) authored by @anderseknertio.Writer improvements (#9017) authored by @anderseknertendswith and replace built-in examples (#8991) authored by @locker95split and lower built-in examples (#8992) authored by @locker95glob.match indexing requirements (#8209) authored by @lopster568, reported by @anderseknertand/or keywords (#8682) reported and authored by @johanfyllingand/or keywords in Rego syntax (#9002) authored by @sspainkto_number built-in description (#8984) authored by @anderseknertmodernize linter for golangci-lint (#8996) authored by @anderseknertbuiltin.Ref() vars to a single location (#9040) authored by @anderseknertnoisy tag (#9034) authored by @srenatussort package with modern alternatives (#9013) authored by @anderseknertslices.CompareFunc for imports and annotations (#9019) authored by @anderseknertutil.WithPrefix (#9005) authored by @anderseknertusetesting options (#9072) authored by @anderseknertintrange linter, as it's covered by modernize (#9014) authored by @anderseknertand/or short-circuit tests (#9057) authored by @sspainkuri built-in compliance cases for parser edge cases (#8980) authored by @sspainkuuid.parse input format leniency (#9003) authored by @sspainkStringToByteSlice("") (#9091) authored by @srenatusgo.mod language version to 1.26 (#9051) authored by @srenatusThis release uses the latest version of Go (1.26.6) to build OPA, fixing stdlib vulnerabilities in code that OPA's HTTP handler and crypto builtins us…
This release uses the latest version of Go (1.26.6) to build OPA, fixing stdlib vulnerabilities in code that OPA's HTTP handler and crypto builtins use:
It is otherwise the same code as v1.19.0.
Note that users building their own OPA binaries and images already control the Golang version, so this is not relevant for them.
This release contains a mix of new features and bug fixes. Notably:
This release contains a mix of new features and bug fixes. Notably:
:=)strings.split_n built-in functionThe field names in the SQL emitted by the Compile API come from partially evaluated refs, so a
policy that selects a dynamic key — such as input.fruits[input.column] — puts caller-controlled
text in an identifier position. That text was emitted verbatim, which turns
WHERE fruit.name = 'allowed'into
WHERE fruit.name = 'allowed' OR 1=1 -- = 'allowed'and an application appending the filter to its query returns rows the policy denies.
Field segments that are not bare identifiers are now quoted at the UCAST-to-SQL boundary, with any
embedded quote character escaped. Ordinary column names stay unquoted, so existing filters keep
their current shape and remain case-insensitive on Postgres.
Authored by @thevilledev
:=) (#3546)The assignment operator (:=) is documented as "syntactic sugar for =, local variable creation,
and additional compiler checks," and the safety checker reflects that: after
rewriting, := is treated identically to = (unification), so an assignment's
right-hand side can be made safe by unifying "backwards" through the left-hand
side. This means policies like x := y; x = 7 compile (binding y to 7)
even though y is never assigned, and x := y; obj[x] can silently degrade an
expected constant-time lookup into full iteration.
This change makes the right-hand-side of := be treated as a read that
must be made safe by other expressions, and can no longer be satisfied through
the left-hand-side. Affected policies that previously compiled now fail with a
rego_unsafe_var_error. Reference iteration on the right-hand-side (e.g.
some k; v := obj[k]) is unaffected.
Note: this is a deliberate semantic change, not a fix to match documented
behavior — the intended semantics of := in this case were never specified.
Authored by @sspaink, reported by @tsandall
OPA's WebAssembly runtime — used by the wasm evaluation target and the WASM SDK — now runs on
the pure-Go wazero runtime instead of bytecodealliance/wasmtime-go. This
removes the cgo dependency from this path, so wasm-enabled builds no longer need a C toolchain.
Compiled policy modules are now cached process-wide, so repeated VM creation for the same policy
skips recompilation. On an Apple M4 Max this makes wasm cold start (compile + instantiate + first
eval) about 73% faster, and warm evaluation about 29% faster with ~28% fewer allocations.
Authored by @srenatus, reported by @sspaink
Top-level configuration validation and default injection (default_decision,
default_authorization_decision, labels) is now expressed as an embedded Rego policy rather than
hand-written Go, as is the validation of server.metrics and metrics_export.
The user-visible effect is that unrecognized configuration options are reported instead of being
silently ignored. A typo such as decision_log instead of decision_logs now logs a warning at
startup:
{"level":"warning","msg":"unknown configuration option \"decision_log\" encountered"}These are warnings, not errors: OPA starts as before, and sections that are intentionally
user-extensible are left alone, so extra keys there do not warn. Embedders reading configuration
through config.ParseConfig can find the same messages on Config.Warnings.
Authored by @sspaink
strings.split_n built-in function (#8344)Policies often need only the first or last few parts of a split string, but the existing split
built-in always returns every part, so the count has to be worked around with wildcards or a slice.
strings.split_n takes the first n split parts from the front or the back of the string,
depending on whether n is positive or negative:
result := strings.split_n("a.b.c.d", ".", 2)
# result == ["a", "b"]result := strings.split_n("a.b.c.d", ".", -2)
# result == ["c", "d"]If abs(n) is larger than the number of parts, all parts are returned. An n of 0 returns an
empty array.
Authored by @wonju-dev, reported by @anderseknert
Pasting a tab-indented snippet into the REPL triggered tab-completion on the pasted tab, corrupting
the input (e.g. injecting a completion candidate mid-line and producing a spurious parse error).
Fixing that requires bracketed paste, where the terminal wraps pasted text in markers so the line
reader inserts it literally instead of treating an embedded tab as a completion request. The
previous reader, peterh/liner, has no bracketed-paste support and is unmaintained (last release
2021), so it has been replaced with reeflective/readline.
The new reader persists history as JSON lines instead of one command per line. Existing history
files (~/.opa_history by default, or the path given to --history) are detected and migrated in
place the first time the REPL loads them, so history written by earlier versions of OPA is kept.
OPA's own multi-line buffering is unchanged, and readline's native multi-line editing is left
disabled to avoid changing REPL behavior.
Authored by @sspaink, reported by @aeneasr
--format flag for proto/JSON plan bundles to opa build (#8825) authored by @sspainkReadHeaderTimeout to 32s on all HTTP servers (#8877) authored by @RinZ27RoundTripper per Decision (#8884) authored by @paulo-raca--var-values cmd output (#7830) authored by @sspaink, reported by @charlieegan3future.keywords.not import in Rego v0 (#8953) authored by @johanfyllingx in [...] (#8918) reported and authored by @srenatusTermValueEqual performance regression (#8863) authored by @mchittenCogeneratedExprs return deterministic order (#8895) authored by @sspainkobject.* builtins (#8692) reported and authored by @anderseknert"a", "a" in {"a"} not returning true (#8747) authored by @anderseknertformat_int precision loss for integers larger than 64 bits (#8857) authored by @SynvoyaSliceStack/GroupStack, unify refStack/functionMocksStack/saveStack (#8886) authored by @srenatusruletrie.Children() call in Depth() (#8886) authored by @srenatusfunctionMocksStack on generic GroupStack[T] (#8886) authored by @srenatusin, bare refs; modernize rego (#8822) authored by @srenatus, reported by @tsandalltest.WithTempFS (#8908) authored by @anderseknertThis release includes a bug fix for a opa fmt regression introduced in v1.18.0.
This release includes a bug fix for a opa fmt regression introduced in v1.18.0.
The original fix for #8557 had the formatter enforce newlines in single-item collections (arrays, objects, sets) rather than merely honoring existing ones. As a result, running opa fmt on already-formatted policies could introduce a large number of unwanted changes. This patch release restores the intended behavior: only newlines already present in the source determine whether a single-item collection is formatted on one line or across multiple lines.
This release fixes a memory leak introduced in OPA v1.17.0. It is advised to update if you notice excess memory usage when running OPA server.
This release contains a mix of bugfixes and small features. Notably:
This release contains a mix of bugfixes and small features. Notably:
User-Agent header so it conforms to RFC 9110 (see below)GOMAXPROCS is restored and automatic GOMEMLIMIT is now supportedopa fmt correctness fixesopa test --coverage (ranges in report, inline rule head tracking, conjunction-expression coverage)OPA's outbound HTTP requests (bundle, discovery, decision log, status, http.send, AWS KMS/ECR)
previously sent User-Agent: Open Policy Agent/<version> (<os>, <arch>), which is not a valid
RFC 9110 User-Agent value because the product token cannot contain spaces. The header is now
Open-Policy-Agent/<version> (<os>, <arch>). Server-side log filters or WAF rules that
exact-match the old string will need to be updated.
Authored by @sspaink, reported by @SpecLad
file_rego_versions patterns with overlap (#8733) authored by @philipaconradwith on the closing-bracket line of multi-line expressions (#8804) authored by @anneheartrecord, reported by @burnsterast.Not nodes (#8731) authored by @johanfyllingast.Not expressions (#8717) authored by @johanfylling, reported by @anderseknertfuture.keywords.not negation inside every (#8781) authored by @johanfyllingplan/wasm bundle builds (#8732) authored by @philipaconradobject.get (#8729) authored by @anderseknertevery (#8816) authored by @johanfyllingdst.Compare(src) shortcut (#8739) authored by @srenatusgo-version-file with actions/setup-go (#8751) authored by @srenatusThis release uses the latest version of Go (1.26.4) to build OPA, fixing stdlib vulnerabilities in code that OPA's HTTP handler and crypto builtins us…
This release uses the latest version of Go (1.26.4) to build OPA, fixing stdlib vulnerabilities in code that OPA's HTTP handler and crypto builtins use:
It is otherwise the same code as v1.17.0.
Note that users building their own OPA binaries and images already control the Golang version, so this is not relevant for them.
This release contains a mix of new features, performance improvements, and bugfixes. Notably:
This release contains a mix of new features, performance improvements, and bugfixes. Notably:
future.keywords.not import that adds improved semantics to the not keyword.This OPA release introduces a new future.keywords.not import
that fixes a long-standing semantic issue with negation in Rego.
Without the import, the compiler expands a negated composite expression like
not f(g(input.x)) into a series of sub-expressions evaluated before the
not:
__local0__ = input.x
g(__local0__, __local1__)
not f(__local1__)
If any sub-expression fails — for example, input.x is undefined or g
produces an undefined result — the entire rule fails rather than the not succeeding.
This is unintuitive: the user's intent is "the condition does not hold," but
an undefined intermediate value causes a silent failure instead of the expected
not result.
With import future.keywords.not, composite-expression negation wraps the full compiler
expansion in an implicit body:
not { __local0__ = input.x; g(__local0__, __local1__); f(__local1__) }
Now, if any sub-expression is undefined or fails, the body is unsatisfiable
and the not expression succeeds; matching the intuition that "the condition does not hold."
NOTE:
Users are recommended to import
future.keywords.notwhenever thenotkeyword is used in a policy.
Authored by @johanfylling
Rule annotations now support a labels field. Labels from all successfully evaluated
rules are collected and included in each decision log entry as a top-level rule_labels
array. Each element is the merged label map for one successfully evaluated rule, with
inner-scope-wins precedence across the rule's annotation chain
(subpackages < package < document < rule). Merged maps are deduplicated
across rules so that identical label sets collapse to a single entry.
# METADATA
# scope: package
# labels:
# service: authz
# severity: info
package myapp
# METADATA
# labels:
# severity: low
# team: platform
allow if input.role == "admin"The resulting decision log entry will contain:
{"rule_labels": [{"service": "authz", "severity": "low", "team": "platform"}]}Note how severity: info from the package scope is overridden by severity: low from
the rule scope. Queries against rule_labels can now rely on each entry carrying the
full label context for a single rule, rather than one entry per contributing scope.
Both the runtime and the Go SDK now process metadata annotations by default.
Authored by @srenatus, reported by @tsandall
$ref in allOf in JSON schemas (#6523) authored by @deeglaze reported by @mosiac1json.verify_schema and json.match_schema built-in functions (#6089) authored by @sspaink reported by @ewout8index field in MakeNumberRefStmt IR statement (#6266) authored by @sspaink reported by @johanfyllingGenerateJSON function (#8690) authored by @anderseknertinmem.NewFromASTObject and add missing string case to ast.InternedValue (#8707) authored by @anderseknertgo install -> go install tool to control checksums (#8646) authored by @srenatusThis release updates the version of Go used to build the OPA binaries and images to 1.26.3; addressing a number of vulnerabilities .
This release updates the version of Go used to build the OPA binaries and images to 1.26.3;
addressing a number of vulnerabilities.
This is a patch release addressing a regression in the plugin manager that may cause the service to hang on shutdown ( #8590 ).
This is a patch release addressing a regression in the plugin manager that may cause the service to hang on shutdown (#8590).
This is a patch release addressing a regression (#8590) in the plugin manager that may cause the service to hang on shutdown.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
This release contains a mix of new features, performance improvements, and bugfixes. Notably:
This release contains a mix of new features, performance improvements, and bugfixes. Notably:
uri.parse and uri.is_valid built-in functionsNOTE:
In v1.15.x, OPA was dropping logs for bundle downloads,
print()calls and other plugin-originated logs. Users are advised to update, v1.16.0 fixes this bug in (#8544).
uri.parse and uri.is_valid built-in functions (#8263)Two new built-in functions have been added: uri.parse for parsing a given URI, and uri.is_valid for verifying the structure of a given URI.
Parses a URI and returns an object containing its components according to RFC 3986. Empty components are omitted.
package example
test_uri if {
uri.parse("https://example.com:8080/api?q=1#top") == {
"scheme": "https",
"hostname": "example.com",
"port": "8080",
"path": "/api",
"raw_path": "/api",
"raw_query": "q=1",
"fragment": "top",
}
}
Returns true if the input can be parsed as a URI, false otherwise.
package example
deny contains "invalid URI" if {
not uri.is_valid("http://[invalid")
}
Authored by @charlieegan3 reported by @anivar
Wrapping projects can now attach custom metadata to Data API requests and have evaluation produce response metadata.
Two distinct metadata paths are introduced:
Request metadata: parsed from extra top-level keys in the request body, made available to builtins via BuiltinContext.RequestMetadata. Logged in the decision log under Custom["request_metadata"].
Response metadata: a separate map (BuiltinContext.ResponseMetadata) that builtins can populate during evaluation. Only included in the API response and decision log if non-empty.
In vanilla OPA, no builtins write response metadata, so responses are unchanged. The request metadata map is only allocated when the request carries extra fields; the response map is one empty map per request.
To avoid conflicts with future OPA top-level keys, callers should use a namespaced key: {"input": {...}, "com.example.opa/md": {...}}.
Request with metadata:
curl -H 'Content-Type: application/json' \
-d '{"input": {"user": "alice"}, "com.example.opa/metadata": {"corp-id": "acme-42"}}' \
http://localhost:8181/v1/data/example/allow
Response (response metadata included if, for example, set by a custom builtin):
{
"decision_id": "04789f85-de5a-477b-8aa5-6d59d7742135",
"result": true,
"com.example.opa/response": {
"snapshot_version": "v3"
}
}
Decision log entry:
{
"custom": {
"request_metadata": {
"com.example.opa/metadata": {
"corp-id": "acme-42"
}
},
"response_metadata": {
"com.example.opa/response": {
"snapshot_version": "v3"
}
}
},
"decision_id": "04789f85-de5a-477b-8aa5-6d59d7742135",
"input": { "user": "alice" },
"msg": "Decision Log",
"path": "example/allow",
"result": true
}
Authored by @srenatus
--coverage (#8438) authored by @grosserwiths in expression (#8508) authored by @anderseknertevery body (#8558) authored by @johanfyllingopa fmt from formatting single attribute objects with comments (#7565) authored by @sspaink reported by @anderseknert*tls.Config (#8473) authored by @srenatus reported by @ashu2496- in front of a ref (#5014) authored by @mmzzuu reported by @philipaconradtime.parse_duration_ns built-in function (#2719) authored by @sspaink reported by @freeseachergraph.reachable_paths to return all reachable paths (#5871) authored by @davidmarne-wf reported by @ericjkaounits.parse_bytes built-in function to prevent timeout bypass (#8326) authored by @isaiahvita reported by @anderseknertcount and sum built-in functions (#8566) authored by @alliasgher reported by @srenatusnot undefined example (#8580) authored by @menma1234print() logging (#8567) authored by @srenatusNothing published for this version
This patch release fixes a backwards-incompatible change in the v1/logging.Logger interface that inadvertently made it into Release v1.15.0. When usin
This patch release fixes a backwards-incompatible change in the v1/logging.Logger interface that inadvertently made it into Release v1.15.0. When using OPA as Go module, and when providing custom Logger implementations, this change would break your build.
Users of the binaries or Docker images can ignore this, the code is otherwise the same as v1.15.0. Miscellaneous
logging: make WithContext() optional (authored by @srenatus)
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →