❗ 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>
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>
* e2e/cli: add test for debug `print()` logging
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
* ci: add *.txtar to "golang_change_suffixes"
This is so that e2e/cli testscript definitions cause CI runs.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
---------
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>