From f98a7488eb07845b7961cbb18215960b6c57298a Mon Sep 17 00:00:00 2001 From: CptSchnitz <12687466+CptSchnitz@users.noreply.github.com> Date: Mon, 16 Mar 2026 09:30:03 +0200 Subject: [PATCH 1/5] chore: progress --- helm/charts/opa/Chart.yaml | 4 ++ helm/charts/opa/config/opa.yaml | 14 +++++- helm/charts/opa/script/transform.lua | 63 +++++++++++++++++++++++++ helm/charts/opa/values.yaml | 70 ++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 helm/charts/opa/script/transform.lua diff --git a/helm/charts/opa/Chart.yaml b/helm/charts/opa/Chart.yaml index 2dafe71..eb9e027 100644 --- a/helm/charts/opa/Chart.yaml +++ b/helm/charts/opa/Chart.yaml @@ -8,3 +8,7 @@ dependencies: - name: mclabels version: 1.0.1 repository: oci://acrarolibotnonprod.azurecr.io/helm/infra + - name: fluent-bit + repository: oci://ghcr.io/fluent/helm-charts/fluent-bit + version: 0.56.0 + condition: fluent-bit.enabled diff --git a/helm/charts/opa/config/opa.yaml b/helm/charts/opa/config/opa.yaml index 256959a..a68d4e6 100644 --- a/helm/charts/opa/config/opa.yaml +++ b/helm/charts/opa/config/opa.yaml @@ -5,7 +5,14 @@ services: s3_signing: # Required for finding the envs for S3 environment_credentials: {} - +{{- if .Values.fluent-bit.enabled}} + fluent-bit: + enabled: {{ .Values.fluentBit.enabled }} + config: + inputs: + - name: tail + parameters: +{{- end }} bundles: authz: service: s3 @@ -21,8 +28,13 @@ status: decision_logs: console: {{ .Values.decisionLogs.console }} + {{- if .Values.fluent-bit.enabled }} + service: fluent-bit + {{- end }} reporting: buffer_size_limit_bytes: {{ .Values.decisionLogs.maxBufferSize }} + min_delay_seconds: {{ .Values.decisionLogs.minDelaySeconds }} + max_delay_seconds: {{ .Values.decisionLogs.maxDelaySeconds }} {{ if .Values.tracing.enabled }} distributed_tracing: diff --git a/helm/charts/opa/script/transform.lua b/helm/charts/opa/script/transform.lua new file mode 100644 index 0000000..640893a --- /dev/null +++ b/helm/charts/opa/script/transform.lua @@ -0,0 +1,63 @@ +function transform_opa_log(tag, timestamp, record) + local new_record = {} + -- 1. Input and Bundles + new_record["input"] = record["input"] + new_record["bundles"] = record["bundles"] + + -- 2. Trace & Span IDs + new_record["trace_id"] = record["trace_id"] + new_record["span_id"] = record["span_id"] + + -- 3. Extract Environment and Domain + if record["labels"] ~= nil then + new_record["env"] = record["labels"]["environment"] + end + + new_record["opa_domain"] = record["input"]["domain"] + + + new_record["token_location"] = "missing" + if record["input"]["headers"] ~= nil and record["input"]["headers"]["x-api-key"] ~= nil then + new_record["token_location"] = "header" + end + + if record["input"]["query"] ~= nil and record["input"]["query"]["token"] ~= nil then + if new_record["token_location"] == "header" then + new_record["token_location"] = "both" + else + new_record["token_location"] = "query" + end + end + + if record["input"]["headers"] ~= nil then + if record["input"]["headers"]["origin"] ~= nil then + new_record["origin"] = record["input"]["headers"]["origin"] + end + if record["input"]["headers"]["user-agent"] ~= nil then + new_record["user_agent"] = record["input"]["headers"]["user-agent"] + end + end + + -- 4. Requested By + new_record["requested_by"] = record["requested_by"] + + -- 5. Result splits + if record["result"] ~= nil then + -- Loki metadata requires strings, so we cast the boolean + new_record["allowed"] = tostring(record["result"]["allowed"]) + new_record["reason"] = record["result"]["reason"] + new_record["sub"] = record["result"]["sub"] + new_record["codes"] = record["result"]["codes"] + end + + -- 6. The original OPA timestamp string + new_record["opa_timestamp"] = record["timestamp"] + + -- 7. Total processing time + if record["metrics"] ~= nil then + new_record["total_time_ns"] = tostring(record["metrics"]["timer_server_handler_ns"]) + end + + -- We return the Fluent Bit ingestion timestamp as the official log time. + return 1, timestamp, new_record +end diff --git a/helm/charts/opa/values.yaml b/helm/charts/opa/values.yaml index 1fa9874..0981a62 100644 --- a/helm/charts/opa/values.yaml +++ b/helm/charts/opa/values.yaml @@ -135,3 +135,73 @@ ingress: # Add any label you want as `KEY: VALUE` labels: {} + +fluent-bit: + enabled: true + kind: Deployment + test-framework: + enabled: false + imagePullSecrets: + - name: my-registry-secret + serviceAccount: + create: false + rbac: + create: false + openshift: + enabled: true + service: + port: 9880 + resources: + limits: + cpu: 400m + memory: 256Mi + requests: + cpu: 100m + memory: 256Mi + autoscaling: + enabled: true + labels: + mapcolonies.io/environment: dev + mapcolonies.io/component: "infrastructure" + mapcolonies.io/part-of: "monitoring" + mapcolonies.io/owner: "infra" + podAnnotations: + prometheus.io/scrape: "true" + prometheus.io/port: "2020" + prometheus.io/path: "/api/v1/metrics/prometheus" + env: + - name: FLUENT_LOKI_HOST + value: "loki" + - name: FLUENT_LOKI_PORT + value: "3100" + luaScripts: + transform.lua: | + {{ readFile "script/transform.lua" | indent 6 }} + config: + inputs: | + [INPUT] + Name http + Listen 0.0.0.0 + Port 9880 + filter: | + [FILTER] + Name lua + Match * + script /fluent-bit/scripts/transform.lua + call transform_opa_log + outputs: | + [OUTPUT] + Name loki + Match * + Host ${FLUENT_LOKI_HOST} + Port ${FLUENT_LOKI_PORT} + + # LABELS: Domain added here for fast stream routing + Labels job=opa, environment=$env, opa_domain=$opa_domain + + # METADATA: Allowed moved here, along with other high-cardinality data + Structured_metadata trace_id=$trace_id, span_id=$span_id, requested_by=$requested_by, reason=$reason, subject=$sub, total_time_ns=$total_time_ns, allowed=$allowed, token_location=$token_location, origin=$origin, user_agent=$user_agent + + # CLEANUP: Strip these fields from the main JSON log body + Remove_Keys env, domain, allowed, trace_id, span_id, requested_by, reason, sub, total_time_ns, opa_domain, token_location, origin, user_agent + From cda00296878a744353c2f01efb23bcf6f94b652c Mon Sep 17 00:00:00 2001 From: Schnitz <12687466+CptSchnitz@users.noreply.github.com> Date: Thu, 19 Mar 2026 09:10:39 +0200 Subject: [PATCH 2/5] chore: done --- helm/Chart.lock | 14 +-- helm/charts/opa/Chart.lock | 7 +- helm/charts/opa/Chart.yaml | 3 +- helm/charts/opa/config/opa.yaml | 17 ++- helm/charts/opa/script/transform.lua | 63 ----------- helm/charts/opa/templates/deployment.yaml | 2 - helm/charts/opa/values.yaml | 129 +++++++++++++++++----- 7 files changed, 121 insertions(+), 114 deletions(-) delete mode 100644 helm/charts/opa/script/transform.lua diff --git a/helm/Chart.lock b/helm/Chart.lock index 4bbc240..869ef0b 100644 --- a/helm/Chart.lock +++ b/helm/Chart.lock @@ -1,18 +1,18 @@ dependencies: - name: opa repository: file://charts/opa - version: 1.10.0 + version: 1.12.0 - name: auth-cron repository: file://../packages/auth-cron/helm - version: 1.10.0 + version: 1.12.0 - name: auth-manager repository: file://../packages/auth-manager/helm - version: 1.10.0 + version: 1.12.0 - name: auth-ui repository: file://../packages/auth-ui/helm - version: 1.10.0 + version: 1.12.0 - name: token-kiosk repository: file://../packages/token-kiosk/helm - version: 1.10.0 -digest: sha256:164eb2c4310304fd4d51860fe117047c570e721db34f97747a7a958bef3a9c7a -generated: "2026-01-11T19:22:51.855858+02:00" + version: 1.12.0 +digest: sha256:3ae8431a5a9943c4d5cf1ec92cef60423db6eea085f2f82eabbb6818292da670 +generated: "2026-03-18T15:30:39.641484226+02:00" diff --git a/helm/charts/opa/Chart.lock b/helm/charts/opa/Chart.lock index a81c4cb..a4b431d 100644 --- a/helm/charts/opa/Chart.lock +++ b/helm/charts/opa/Chart.lock @@ -2,5 +2,8 @@ dependencies: - name: mclabels repository: oci://acrarolibotnonprod.azurecr.io/helm/infra version: 1.0.1 -digest: sha256:a97237cd8966ab9d4f8c0b8dda2ad110fbff5d485da868124fdce2a5dbbfa208 -generated: "2025-11-20T10:36:07.259160863+02:00" +- name: fluent-bit + repository: oci://ghcr.io/fluent/helm-charts + version: 0.56.0 +digest: sha256:cc01fd5ba8b22052738e6b6baec3816b5510a09837c44957ef9dca66212e3df8 +generated: "2026-03-17T09:10:00.789970582+02:00" diff --git a/helm/charts/opa/Chart.yaml b/helm/charts/opa/Chart.yaml index eb9e027..828a285 100644 --- a/helm/charts/opa/Chart.yaml +++ b/helm/charts/opa/Chart.yaml @@ -9,6 +9,7 @@ dependencies: version: 1.0.1 repository: oci://acrarolibotnonprod.azurecr.io/helm/infra - name: fluent-bit - repository: oci://ghcr.io/fluent/helm-charts/fluent-bit + repository: oci://ghcr.io/fluent/helm-charts version: 0.56.0 condition: fluent-bit.enabled + alias: fluentbit diff --git a/helm/charts/opa/config/opa.yaml b/helm/charts/opa/config/opa.yaml index a68d4e6..f35d0d6 100644 --- a/helm/charts/opa/config/opa.yaml +++ b/helm/charts/opa/config/opa.yaml @@ -5,13 +5,9 @@ services: s3_signing: # Required for finding the envs for S3 environment_credentials: {} -{{- if .Values.fluent-bit.enabled}} +{{- if .Values.fluentbit.enabled }} fluent-bit: - enabled: {{ .Values.fluentBit.enabled }} - config: - inputs: - - name: tail - parameters: + url: {{ .Values.fluentbit.url | default (printf "http://%s-fluentbit:9880" .Release.Name)}} {{- end }} bundles: authz: @@ -28,13 +24,13 @@ status: decision_logs: console: {{ .Values.decisionLogs.console }} - {{- if .Values.fluent-bit.enabled }} + {{- if .Values.fluentbit.enabled }} service: fluent-bit {{- end }} reporting: - buffer_size_limit_bytes: {{ .Values.decisionLogs.maxBufferSize }} - min_delay_seconds: {{ .Values.decisionLogs.minDelaySeconds }} - max_delay_seconds: {{ .Values.decisionLogs.maxDelaySeconds }} + buffer_size_limit_bytes: {{ .Values.decisionLogs.maxBufferSize | int }} + min_delay_seconds: {{ .Values.decisionLogs.minDelaySeconds | int }} + max_delay_seconds: {{ .Values.decisionLogs.maxDelaySeconds | int }} {{ if .Values.tracing.enabled }} distributed_tracing: @@ -52,6 +48,7 @@ storage: labels: + environment: {{ .Values.opaEnvironment | required "opaEnvironment is required" | quote }} {{- range $key, $value := .Values.labels }} {{ $key }}: {{ $value | quote }} {{- end }} diff --git a/helm/charts/opa/script/transform.lua b/helm/charts/opa/script/transform.lua deleted file mode 100644 index 640893a..0000000 --- a/helm/charts/opa/script/transform.lua +++ /dev/null @@ -1,63 +0,0 @@ -function transform_opa_log(tag, timestamp, record) - local new_record = {} - -- 1. Input and Bundles - new_record["input"] = record["input"] - new_record["bundles"] = record["bundles"] - - -- 2. Trace & Span IDs - new_record["trace_id"] = record["trace_id"] - new_record["span_id"] = record["span_id"] - - -- 3. Extract Environment and Domain - if record["labels"] ~= nil then - new_record["env"] = record["labels"]["environment"] - end - - new_record["opa_domain"] = record["input"]["domain"] - - - new_record["token_location"] = "missing" - if record["input"]["headers"] ~= nil and record["input"]["headers"]["x-api-key"] ~= nil then - new_record["token_location"] = "header" - end - - if record["input"]["query"] ~= nil and record["input"]["query"]["token"] ~= nil then - if new_record["token_location"] == "header" then - new_record["token_location"] = "both" - else - new_record["token_location"] = "query" - end - end - - if record["input"]["headers"] ~= nil then - if record["input"]["headers"]["origin"] ~= nil then - new_record["origin"] = record["input"]["headers"]["origin"] - end - if record["input"]["headers"]["user-agent"] ~= nil then - new_record["user_agent"] = record["input"]["headers"]["user-agent"] - end - end - - -- 4. Requested By - new_record["requested_by"] = record["requested_by"] - - -- 5. Result splits - if record["result"] ~= nil then - -- Loki metadata requires strings, so we cast the boolean - new_record["allowed"] = tostring(record["result"]["allowed"]) - new_record["reason"] = record["result"]["reason"] - new_record["sub"] = record["result"]["sub"] - new_record["codes"] = record["result"]["codes"] - end - - -- 6. The original OPA timestamp string - new_record["opa_timestamp"] = record["timestamp"] - - -- 7. Total processing time - if record["metrics"] ~= nil then - new_record["total_time_ns"] = tostring(record["metrics"]["timer_server_handler_ns"]) - end - - -- We return the Fluent Bit ingestion timestamp as the official log time. - return 1, timestamp, new_record -end diff --git a/helm/charts/opa/templates/deployment.yaml b/helm/charts/opa/templates/deployment.yaml index 998bcbd..d553203 100644 --- a/helm/charts/opa/templates/deployment.yaml +++ b/helm/charts/opa/templates/deployment.yaml @@ -36,9 +36,7 @@ spec: {{- end }} annotations: {{ include "mclabels.annotations" . | nindent 8 }} - {{- if .Values.resetOnConfigChange }} checksum/configmap: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} - {{- end }} {{- if .Values.additionalPodAnnotations }} {{- toYaml .Values.additionalPodAnnotations | nindent 8}} {{- end }} diff --git a/helm/charts/opa/values.yaml b/helm/charts/opa/values.yaml index 0981a62..d240eac 100644 --- a/helm/charts/opa/values.yaml +++ b/helm/charts/opa/values.yaml @@ -60,6 +60,8 @@ status: decisionLogs: console: true maxBufferSize: 5242880 # 5MB + min_delay_seconds: 5 + max_delay_seconds: 60 tracing: enabled: false @@ -136,10 +138,10 @@ ingress: # Add any label you want as `KEY: VALUE` labels: {} -fluent-bit: +fluentbit: enabled: true kind: Deployment - test-framework: + testFramework: enabled: false imagePullSecrets: - name: my-registry-secret @@ -149,8 +151,6 @@ fluent-bit: create: false openshift: enabled: true - service: - port: 9880 resources: limits: cpu: 400m @@ -169,39 +169,110 @@ fluent-bit: prometheus.io/scrape: "true" prometheus.io/port: "2020" prometheus.io/path: "/api/v1/metrics/prometheus" - env: + loki: + url: loki.namespace.svc.cluster.local + port: "3100" + envWithTpl: - name: FLUENT_LOKI_HOST - value: "loki" + value: "{{ .Values.loki.url }}" - name: FLUENT_LOKI_PORT - value: "3100" + value: "{{ .Values.loki.port }}" + extraPorts: + - name: input + port: 9880 + containerPort: 9880 + protocol: TCP luaScripts: transform.lua: | - {{ readFile "script/transform.lua" | indent 6 }} + function transform_opa_log(tag, timestamp, record) + local new_record = {} + -- 1. Input and Bundles + new_record["input"] = record["input"] + new_record["bundles"] = record["bundles"] + + -- 2. Trace & Span IDs + new_record["trace_id"] = record["trace_id"] + new_record["span_id"] = record["span_id"] + + -- 3. Extract Environment and Domain + if record["labels"] ~= nil then + new_record["env"] = record["labels"]["environment"] + end + + new_record["opa_domain"] = record["input"]["domain"] + + + new_record["token_location"] = "missing" + if record["input"]["headers"] ~= nil and record["input"]["headers"]["x-api-key"] ~= nil then + new_record["token_location"] = "header" + end + + if record["input"]["query"] ~= nil and record["input"]["query"]["token"] ~= nil then + if new_record["token_location"] == "header" then + new_record["token_location"] = "both" + else + new_record["token_location"] = "query" + end + end + + if record["input"]["headers"] ~= nil then + if record["input"]["headers"]["origin"] ~= nil then + new_record["origin"] = record["input"]["headers"]["origin"] + end + if record["input"]["headers"]["user-agent"] ~= nil then + new_record["user_agent"] = record["input"]["headers"]["user-agent"] + end + end + + -- 4. Requested By + new_record["requested_by"] = record["requested_by"] + + -- 5. Result splits + if record["result"] ~= nil then + -- Loki metadata requires strings, so we cast the boolean + new_record["allowed"] = tostring(record["result"]["allowed"]) + new_record["reason"] = record["result"]["reason"] + new_record["sub"] = record["result"]["sub"] + new_record["codes"] = record["result"]["codes"] + end + + -- 6. The original OPA timestamp string + new_record["opa_timestamp"] = record["timestamp"] + + -- 7. Total processing time + if record["metrics"] ~= nil then + new_record["total_time_ns"] = tostring(record["metrics"]["timer_server_handler_ns"]) + end + + -- We return the Fluent Bit ingestion timestamp as the official log time. + return 1, timestamp, new_record + end + config: inputs: | [INPUT] - Name http - Listen 0.0.0.0 - Port 9880 - filter: | + Name http + Listen 0.0.0.0 + Port 9880 + filters: | [FILTER] - Name lua - Match * - script /fluent-bit/scripts/transform.lua - call transform_opa_log + Name lua + Match * + script /fluent-bit/scripts/transform.lua + call transform_opa_log outputs: | [OUTPUT] - Name loki - Match * - Host ${FLUENT_LOKI_HOST} - Port ${FLUENT_LOKI_PORT} - - # LABELS: Domain added here for fast stream routing - Labels job=opa, environment=$env, opa_domain=$opa_domain - - # METADATA: Allowed moved here, along with other high-cardinality data - Structured_metadata trace_id=$trace_id, span_id=$span_id, requested_by=$requested_by, reason=$reason, subject=$sub, total_time_ns=$total_time_ns, allowed=$allowed, token_location=$token_location, origin=$origin, user_agent=$user_agent - - # CLEANUP: Strip these fields from the main JSON log body - Remove_Keys env, domain, allowed, trace_id, span_id, requested_by, reason, sub, total_time_ns, opa_domain, token_location, origin, user_agent + Name loki + Match * + Host ${FLUENT_LOKI_HOST} + Port ${FLUENT_LOKI_PORT} + + # LABELS: Domain added here for fast stream routing + Labels job=opa, environment=$env, opa_domain=$opa_domain + + # METADATA: Allowed moved here, along with other high-cardinality data + Structured_metadata trace_id=$trace_id, span_id=$span_id, requested_by=$requested_by, reason=$reason, subject=$sub, total_time_ns=$total_time_ns, allowed=$allowed, token_location=$token_location, origin=$origin, user_agent=$user_agent + + # CLEANUP: Strip these fields from the main JSON log body + Remove_Keys env, domain, allowed, trace_id, span_id, requested_by, reason, sub, total_time_ns, opa_domain, token_location, origin, user_agent From 5ba56c09377024f598f60fafefbacaefd76a7b73 Mon Sep 17 00:00:00 2001 From: Ofer <12687466+CptSchnitz@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:34:13 +0200 Subject: [PATCH 3/5] feat: update masking rules for token and x-api-key fields --- example/data/logs.rego | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/example/data/logs.rego b/example/data/logs.rego index 9752d25..c629d1a 100644 --- a/example/data/logs.rego +++ b/example/data/logs.rego @@ -1,9 +1,13 @@ package system.log # Mask the 'token' field in the query parameters -mask contains "/input/query/token" +mask contains {"op":"upsert","path":"/input/query/token", "value": "**redacted**"} if { + input.input.query.token +} # Mask the 'x-api-key' field in the headers parameters -mask contains "/input/headers/x-api-key" +mask contains {"op":"upsert","path":"/input/headers/x-api-key", "value": "**redacted**"} if { + input.input.headers["x-api-key"] +} drop if { input.result.allowed == true From 8735935eaf5af3863cf6e5c80ff9f0ef64dc9237 Mon Sep 17 00:00:00 2001 From: Ofer <12687466+CptSchnitz@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:34:50 +0200 Subject: [PATCH 4/5] feat: refactor deny messages to include reason and code --- example/data/policy.rego | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/example/data/policy.rego b/example/data/policy.rego index 2557aff..6546c69 100644 --- a/example/data/policy.rego +++ b/example/data/policy.rego @@ -23,6 +23,8 @@ tokens := [token | token := temp ] +default claims = {"payload": {}} + claims := {"payload": payload, "valid": valid, "kid": kid} if { token := tokens[_] [header, payload, _] := io.jwt.decode(token) @@ -38,29 +40,29 @@ userData := data.users[claims.payload.sub] if { claims.payload.sub != "c2b" } -deny contains "no token supplied in any of the possible locations" if { +deny contains {"reason":"no token supplied in any of the possible locations", "code": "TOKEN_MISSING"} if { count(tokens) == 0 } -deny contains "token environment mismatch" if { - claims.kid != data.keys.kid -} +# deny contains {"reason":"token environment mismatch", "code": "TOKEN_MISMATCH"} if { +# claims.kid != data.keys.kid +# } -deny contains "token not valid" if { +deny contains {"reason":"token not valid", "code": "TOKEN_INVALID"} if { not claims.valid count(tokens) > 0 } -deny contains "the token is valid, but the user is not found" if { +deny contains {"reason":"the token is valid, but the user is not found", "code": "USER_NOT_FOUND"} if { claims.valid not userData } -deny contains "domain missing" if { +deny contains {"reason":"domain missing", "code": "DOMAIN_MISSING"} if { not input.domain } -deny contains "domain check failed" if { +deny contains {"reason":"domain not allowed for this user", "code": "DOMAIN_INCORRECT"} if { every domain in userData.domains { domain != input.domain } } @@ -70,7 +72,7 @@ is_origin_invalid(originHeader, allowedOrigin) if { } -deny contains "origin check failed" if { +deny contains {"reason":"origin check failed", "code": "ORIGIN_CHECK_FAILED"} if { originHeader := object.get(headers, "origin", "A") every origin in userData.origins { is_origin_invalid(originHeader, origin) } @@ -89,17 +91,17 @@ need_user_agent := true if { } -deny contains "user-agent missing" if { +deny contains {"reason":"user-agent missing", "code": "USER_AGENT_MISSING"} if { not headers["user-agent"] need_user_agent } -deny contains "user-agent is not from allowed browsers" if { +deny contains {"reason":"user-agent is not from allowed browsers", "code": "USER_AGENT_NOT_ALLOWED"} if { not userData.allowNoBrowser not regex.match(".*(Gecko|AppleWebKit|Opera|Trident|Edge|Chrome)\\/\\d.*$", headers["user-agent"]) } -deny contains "c2b user only allowed from QGIS or ARCGIS" if { +deny contains {"reason":"c2b user only allowed from QGIS or ARCGIS", "code": "C2B_USER_AGENT_NOT_ALLOWED"} if { userAgent := lower(headers["user-agent"]) claims.payload.sub == "c2b" @@ -112,7 +114,12 @@ decision := {"allowed": true, "sub": claims.payload.sub, "kid": claims.kid} if { claims.payload.sub != null } -decision := {"allowed": false, "reason": reason} if { +decision := {"allowed": false, "reason": reason, "sub": sub, "codes": codes} if { count(deny) > 0 - reason := concat(", ", deny) + + reasons := [d.reason | some d in deny] + codes := [d.code | some d in deny] + + reason := concat(", ", reasons) + sub := object.get(claims.payload, "sub", "N/A") } From 1c21082e69d5b508c4928ddab93748b49b289e4b Mon Sep 17 00:00:00 2001 From: Ofer <12687466+CptSchnitz@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:39:49 +0200 Subject: [PATCH 5/5] feat: modify policy_test.rego to enhance error reporting Updated test to print result and check token reason. --- example/data/policy_test.rego | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/example/data/policy_test.rego b/example/data/policy_test.rego index 4c2f827..f5da4c0 100644 --- a/example/data/policy_test.rego +++ b/example/data/policy_test.rego @@ -86,7 +86,8 @@ test_deny_no_token if { with data.users as users not res.allowed - res.reason == "no token supplied in any of the possible locations" + print(res) + res.reason == "no token supplied in any of the possible locations" } test_deny_malformed_token if { @@ -306,16 +307,6 @@ test_allowed_decision_contains_sub if { res.sub == "avi" } -test_allowed_decision_contains_kid if { - token := generate_token(private_key_1, {"sub": "avi"}) - res := decision with input as {"domain":"avi", "headers": {"Origin": "https://avi.com", "X-Api-Key": token, "User-Agent": chrome_agent}} - with data.keys as public_key_1 - with data.users as users - - res.allowed - res.kid == "opa_test_key_1" -} - # ========================================================= # c2b (client-to-backend) tests # =========================================================