You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
token-exchange-aiac: put the refusal reason in the rejection, not only the message #1570
token-exchange-aiac answers two different refusals with the same 403 policy.forbidden:
audience_not_granted: Keycloak has a client for the destination, but the caller is not granted it.
target_disabled: the destination's client is disabled, for example a quarantined service.
The reason is recorded in the session event (pctx.Record(... Reason: reason ...)), but the rejection the caller sees carries no Details: deny() in core/plugins/tokenexchangeaiac/plugin.go returns pipeline.DenyStatus(status, code, msg). Only the human-readable message tells them apart ("the destination's client is disabled" vs "this workload is not granted the destination's audience").
rossoctl/aiac's system harness must tell them apart: its quarantine test (test_failed_tool_outbound_call_denied) counts a refusal as "blocked by the quarantine" only for target_disabled. It matches the message text, a copy of the cortex string, which breaks if the message is reworded. Raised in the review of rossoctl/aiac#242.
Task
Put the machine-stable reason in the rejection, for example Details: {"reason": "target_disabled"} (and audience_not_granted, exchange_failed, no_token, foreign_namespace), so it reaches the caller in the plain 403 body (details) and in error.data.details of the JSON-RPC frame.
Document the field in docs/token-exchange-aiac-plugin.md as part of the contract.
Acceptance criteria
A refusal of a disabled target carries details.reason == "target_disabled"; a refusal of an ungranted target carries details.reason == "audience_not_granted", in both rejection shapes.
The message text is no longer the only way to tell them apart.
Follow-up on the AIAC side: key target_disabled_refusal (k8s/authbridge-rejection.py) on the reason instead of the message.
Closing for now: this is specific to the Kubernetes / envoy-sidecar / SPIRE deployment path. Current prioritization is the laptop install; K8s and envoy-sidecar remain supported targets but are not priority. Reopen when that work resumes.
Activity
huang195 commentedon Oct 29, 2026
Closing for now: this is specific to the Kubernetes / envoy-sidecar / SPIRE deployment path. Current prioritization is the laptop install; K8s and envoy-sidecar remain supported targets but are not priority. Reopen when that work resumes.