Redact before the call proceeds
Intent. The action is allowed, but a field is rewritten on the way through. This is the verdict that needs the most care: it is the one seams differ on.
Seam. Envoy ext_proc (body mutation) and inbound seams. Forward-auth cannot do this — it cannot rewrite a body, by protocol · Verdict. redact
How it is configured. Redaction is not a rule action. RuleAction admits four values — allow, deny, require_approval and transform — and a rule carries no field naming what to rewrite. A rule routes an action into shaping; the detector decides which leaf fields are shaped.
# policy.yaml — the rule selects the transform path. It matches the tool and,
# optionally, one structured condition. It does NOT name the field to redact:
# pkg/types Rule has id, priority, match and action, and nothing else.
rules:
- id: shape-support-payloads
priority: 20
match:
tool: "crm.case_update"
action: transform
What actually selects the field. Inline inspection walks the leaf fields of args on the canonical execute request — session_id, agent_id, namespace, tool, args. A detector fires against those fields, and a per-account override maps that detector, on a named seam, to an outcome.
# outcome override — detector_kind x seam -> decision.
# detector_kind: secret | sensitive_data | regulated_identifier | prompt_injection
# | encoded_payload | risky_tool_intent | unsafe_destination
# seam: gateway_execute | mcp_invocation | provider_bedrock | provider_azure
# | provider_gcp | sdk_wrapper | saas_native
detector_kind: regulated_identifier
seam: gateway_execute
decision: redact
Why this section does not show a Rego redact rule The Rego contract returns {"decision", "reason"}, and the decision is the verdict, not a set of rewritten fields. Nothing in the shipped Rego corpus returns redact, and a module cannot name the field to shape either. Writing one here would be inventing a form the policy engine does not read. Where a seam cannot shape at all, the capability is declared rather than assumed: redaction_supported is a per-seam flag, and forward-auth sets a shaping-required header instead of rewriting, because it cannot rewrite a proxied body by protocol.
Shaped arguments returned end-to-end are materialized for the AWS Bedrock inbound seam today. On other adapters, plan around allow, deny and pause.
Deny egress to an unapproved destination
Intent. The tool call is permitted in principle but its destination is not on the approved list.
Seam. Any · Verdict. deny
# policy.yaml — there is no `not in` operator, so a structured rule denies the
# attribute you can name rather than absence from a list.
rules:
- id: deny-external-transfers
priority: 1
match:
tool: "payments.wire_transfer"
condition:
field: "args.destination_type"
operator: "=="
value: "external"
action: deny
- id: deny-pii-export
priority: 2
match:
tool: "api.get"
condition:
field: "args.endpoint"
operator: "contains"
value: "/pii"
action: deny
# The approved-list form the YAML cannot express — Rego can negate a set.
package governor.decision
import future.keywords.if
import future.keywords.in
approved_destinations := {"erp.internal", "warehouse.internal", "s3://acme-reports"}
deny if {
input.action.args.destination
not input.action.args.destination in approved_destinations
}
deny_reason := sprintf("Destination %s is not on the approved list",
[input.action.args.destination]) if {
input.action.args.destination
not input.action.args.destination in approved_destinations
}
rule_id := "destination-not-approved" if {
input.action.args.destination
not input.action.args.destination in approved_destinations
}
Pairs with discovery: the approved list is only meaningful if you know what is actually running.