❗ We now parse rego metadata annotations by default.
Rule annotations now support a `labels` field. During policy eval,
labels from all successfully evaluated rules are collected and included
in each decision log entry as a top-level `rule_labels` array. Each
element preserves the label map from one evaluated rule. Exact
duplicates are omitted.
```rego
# METADATA
# labels:
# severity: low
# team: platform
allow if input.role == "admin"
```
The resulting decision log entry will contain:
```json
{"rule_labels": [{"severity": "low", "team": "platform"}]}
```
---------
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
Rules can now be annotated with a metadata `id` field. When any
metadata `id` annotations are present in the rego (scope: rule), the IDs
of successfully evaluated rules are included in decision log events.
Additionally, the Data API supports a `?id` query parameter to
include evaluated rule IDs directly in the response payload.
```rego
# METADATA
# id: allow-admin
allow if input.role == "admin"
```
Modules containing `id` annotations will have metadata parsing enabled
automatically.
Fixes#2089
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
The plugin registration step was missing before, so the code, while in
the tree, was not active and the plugin couldn't be used.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
External rule sources let wrapping projects inject rules at evaluation
time instead of compile time. The compiler marks external packages in
the rule tree but doesn't index them. When topdown hits an external
node, it calls Lookup to get rules, compiles them on the fly with a
scoped compiler, grafts the result into the tree, and caches it for the
duration of the evaluation.
Sources can be isolated (default, no access to surrounding policy) or
non-isolated (can reference static rules and other external sources).
The ExternalRuleIndexCloser interface handles cleanup after evaluation.
Precompiled rules can skip compiler stages via SkippedStages to avoid
redundant work.
This includes:
* hooks: add BundlePreActivate hook This one is handy when registering
external sources.
* topdown: catch `ir == nil` rule index result
This wouldn't ordinarily happen: the compiler is checking refs before.
But in our use case, the SP rules may be configured to be able to reach
into the surrounding Rego (non-isolated mode). If that happens, the IR
lookup may indeed end up as `nil, nil`.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
These had been bimodal, and thus not a good benchmark at all: running it
two times might give you two different inputs that mess up all
comparability.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
Bumps the dependencies group with 4 updates in the / directory:
[github.com/containerd/containerd/v2](https://github.com/containerd/containerd),
[github.com/huandu/go-sqlbuilder](https://github.com/huandu/go-sqlbuilder),
[github.com/lestrrat-go/jwx/v3](https://github.com/lestrrat-go/jwx) and
[golang.org/x/net](https://github.com/golang/net).
Bumps the dependencies group with 4 updates in the /e2e directory:
[github.com/docker/go-connections](https://github.com/docker/go-connections),
[github.com/lib/pq](https://github.com/lib/pq),
[github.com/testcontainers/testcontainers-go](https://github.com/testcontainers/testcontainers-go)
and [modernc.org/sqlite](https://gitlab.com/cznic/sqlite).
Updates `github.com/containerd/containerd/v2` from 2.2.2 to 2.2.3
Updates `github.com/huandu/go-sqlbuilder` from 1.40.0 to 1.40.2
Updates `github.com/lestrrat-go/jwx/v3` from 3.0.13 to 3.1.0
Updates `golang.org/x/net` from 0.52.0 to 0.53.0
Updates `golang.org/x/text` from 0.35.0 to 0.36.0
Updates `github.com/docker/go-connections` from 0.6.0 to 0.7.0
Updates `github.com/lib/pq` from 1.12.0 to 1.12.3
Updates `github.com/testcontainers/testcontainers-go` from 0.41.0 to 0.42.0
Updates `modernc.org/sqlite` from 1.47.0 to 1.49.1
---------
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Sebastian Spaink <sebastianspaink@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastian Spaink <sebastianspaink@gmail.com>
Wrapping projects can now attach custom metadata to Data API requests
and have evaluation produce response metadata.
Introduce two distinct metadata paths:
- Request (incoming) 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 (outgoing) metadata: a separate map (`BuiltinContext.ResponseMetadata`)
that builtins can populate during evaluation. Only included in the
API response and decision log (`Custom["response_metadata"]`)
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 outgoing 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": {...}}`.
```mermaid
flowchart LR
req["POST /v1/data\n{input, com.example.opa/md}"]
parse["readInputPostV1"]
eval["topdown eval"]
resp["API response"]
dl["decision log"]
req --> parse
parse -- "reqMetadata" --> eval
parse -- "reqMetadata" --> dl
eval -- "respMetadata\n(if non-empty)" --> resp
eval -- "respMetadata\n(if non-empty)" --> dl
eval -. "BuiltinContext\n.RequestMetadata\n.ResponseMetadata" .-> eval
```
---------
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
Expanding the Rego syntax to support not-bodies (not blocks?): `not {...}`
For a not block to successfully evaluate, its body must not successfully evaluate. If evaluation causes iteration, all evaluation paths must fail.
Fixes: #8402
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
Use location text of outer expression to calculate closing location of `every` body (the term itself doesn't capture the full text).
Fixes: #8558
Signed-off-by: Johan Fylling <johan.dev@fylling.se>
Timeouts passed via context are not honored because builtins that
parse exponents dont include context and will run with unrestricted
size on the exponents. Added an exponent limit checker based
on rough benchmakrking data of whats a reasonabile limit.
Fixes: #8326
Signed-off-by: Isaiah Vita <vita.isaiah@gmail.com>
Labeled as experimental as we'll want some time to adjust this
based on real editor integrations. Initial testing looks very
good though, and dramatically reduces the time taken to test
e.g. a package compared to the whole workspace and filtering
the result afterwards.
Fixes#6696
Signed-off-by: Anders Eknert <anders.eknert@apple.com>
* add a test to reproduce the issue and demonstrate that it is resolved
* adapt `parseTerm` to support parsing a `-` in front of a ref correctly
Fixes: #5014
Signed-off-by: Manuela Züger <manuela.zueger@ipt.ch>
The BufferedLogger introduced for logger plugins is created at startup
and passed to the `*plugins.Manager`. Plugins (bundle, discovery,
status, logs) cache `manager.Logger()` in a field at construction time.
After `Manager.Start()`, `ResolveBufferedLogger` flushes the buffer and
swaps the `Manager'`s logger to a `StandardLogger` — but the plugins
still hold the old `BufferedLogger`. Since bundle loading is async, the
"Bundle loaded and activated successfully" message (and similar) gets
written to the already-flushed buffer where nobody reads it.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
Abstract Unix sockets (paths prefixed with @) exist only in the
kernel socket namespace and have no filesystem representation.
Calling os.Chmod on them fails with "no such file or directory".
The --unix-socket-perm flag (added in v0.53.0 via PR #5888) defaults
to "755" and always triggers a chmod on the socket path after the
listener is created. This makes it impossible to use abstract Unix
sockets with OPA >= v0.53.0.
The fix adds a guard to skip chmod when the socket path starts with
"@", matching the existing guard that already skips os.Remove for
abstract sockets a few lines above.
Amp-Thread-ID: https://ampcode.com/threads/T-019d9906-2625-774e-8f1c-a0c288630be4
Signed-off-by: Ben Abderrazak <babderrazak@squareup.com>
Signed-off-by: Ben Apprederisse <bena@squareup.com>
Co-authored-by: Amp <amp@ampcode.com>
* topdown: add failing tests for graph.reachable_paths with shared ancestors
Adds a regression test (shared_ancestor) reproducing the bug reported in
#5871: given a graph where node 4 has edges to both 3 and 2, and 3 also
has an edge to 2, graph.reachable_paths from 5 drops the path [5,4,2,1].
Also corrects the expected result for the existing cycle_1022_3 test, which
was asserting the buggy output ([one,five,six] truncated) rather than the
correct complete path [one,five,six,seven,eight,three].
Signed-off-by: David Marne <david.marne@workiva.com>
* topdown: fix graph.reachable_paths dropping paths with shared ancestors
graph.reachable_paths had two bugs that caused paths to be silently dropped
when a node is reachable via multiple routes (diamond-shaped graphs).
Bug 1: the `reached` set was mutated and shared across sibling recursive
calls. After branch A finished traversal and added nodes to `reached`,
branch B would see those nodes as already visited and terminate early,
emitting a truncated path instead of continuing.
Fix: copy `reached` once per pathBuilder invocation and pass the copy to
all recursive calls. Each branch now has its own ancestor-only visited set.
Bug 2: ast.NewArray stores the slice it receives directly (elems: a)
without copying. When sibling calls appended to a shared backing array,
the in-place write by one sibling corrupted the already-committed path
term of a previous sibling.
Fix: pass append([]*ast.Term(nil), path...) to each recursive call,
giving each branch its own independent backing array.
Signed-off-by: David Marne <david.marne@workiva.com>
---------
Signed-off-by: David Marne <david.marne@workiva.com>
These currently fail, as laid out in #8461.
With this change, we'll return a controlled error, and don't let the
user run into an NPE or a cryptic error.
Fixes#8461.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
```rego
test_something if {
something
with input.foo as 1
with input.bar as 2
}
```
Would previously be formatted as:
```rego
test_something if {
something with input.foo as 1
with input.bar as 2
}
```
Now the formatter allows also the first `with` to be indented
as the rest if the first `with` is found below the line where
the expression begins.
Existing Rego files that have been formatted before should remain
the same when reformatted, and none of the existing formatter tests
have required changes. Only users who actively place the first `with`
in a group on a line below will now see that the formatter respects
their wish, and will indent it the same way as the following `with`s.
Signed-off-by: Anders Eknert <anders.eknert@apple.com>
Previously, initializing a new WASM resolver always used a background
context. This prevented callers from passing down an existing context
for timeouts, cancellation, or tracing.
This change introduces `NewWithContext` in `v1/resolver/wasm` which accepts
a context and propagates it to `Entrypoints()`. The existing `New`
function has been updated to wrap `NewWithContext` using a background
context to preserve backwards compatibility. `LoadWasmResolversFromStore`
has been updated to pass the provided context appropriately.
Signed-off-by: Dominik Schulz <dschulz@google.com>
* type checker: identify compatible type from reference
* Update unifiesObjectsStatic to allow static keys with dynamic properties to be optional, similar to unify1Object
Signed-off-by: Sebastian Spaink <sebastianspaink@gmail.com>
- The tokenTLSConfig is cloned from DefaultTLSConfig(c) (which
includes RootCAs) and then InsecureSkipVerify is set explicitly from
c.AllowInsecureTLS, since DefaultTLSConfig only sets it when the service
URL is https, but the token URL is always https regardless.
- New test configures a service with tls.ca_cert pointing to the token
server's CA cert, without allow_insecure_tls. This directly reproduces
the bug report — before the fix, this would fail with x509: certificate
signed by unknown authority. Also removes some duplication we had
before.
Fixes#8473.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
* distributedtracing: export Prometheus metrics via OTLP
Add support for pushing OPA's existing Prometheus metrics to an
OpenTelemetry collector via OTLP, eliminating the need for a dedicated
scraper sidecar. Uses the OTel Prometheus bridge to read from OPA's
prometheus.Registry and export through an OTLP metric exporter (gRPC
or HTTP), reusing the same address and TLS configuration as traces.
New config fields: distributed_tracing.metrics (bool, default false)
and distributed_tracing.metrics_export_interval_ms (int, default 60000).
Fixes#7591
Signed-off-by: Michael Munch <mm.munk@gmail.com>
* metricsexport: decouple metrics export into top-level config section
Extract metrics export from distributed_tracing into its own
metrics_export config section with independent type (otlp/grpc,
otlp/http), address, and TLS settings. This allows exporting
Prometheus metrics via OTLP without enabling tracing, and to a
different endpoint than traces.
- Extract shared TLS helpers into internal/tlsutil
- Add MetricsExport field to top-level Config
- Create internal/metricsexport package with Init, config parsing
- Remove metrics fields from distributedtracing
- Update runtime to call metricsexport.Init separately
- Move e2e tests to v1/test/e2e/metricsexport
- Add Metrics Export section to configuration docs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Michael Munch <mm.munk@gmail.com>
* ci: retrigger checks
Signed-off-by: Michael Munch <mm.munk@gmail.com>
* go.mod: upgrade dependencies downgraded during rebase
Modules like containerd, go-sqlbuilder, OpenTelemetry, and golang.org/x/*
were at older versions than main after a rebase. Upgrade them to match or
exceed main.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Michael Munch <mm.munk@gmail.com>
* Update internal/distributedtracing/distributedtracing_test.go
Signed-off-by: Michael Munch <mm.munk@gmail.com>
---------
Signed-off-by: Michael Munch <mm.munk@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Disabled by default. To enable, `not` future keyword must be present in capabilities and imported into Rego module.
Implements: #8391
Signed-off-by: Johan Fylling <johan.dev@fylling.se>