Guardrails policy
CRUD over the per-workspace guardrail policy that the gateway consults on every chat completion. A policy is a structured DSLPolicy document — input/output rules, redaction patterns, blocked-prompt lists — that load_policy_from_dict validates at upsert time. Hot-reload: the next chat completion sees the new policy without a process restart.
The router lives at packages/guardrails/policy_routes.py. The registry is PolicyRegistry (packages/guardrails/policy_repo.py).
Endpoints
| Method | Path | Auth | Summary |
|---|---|---|---|
| GET | /admin/guardrails/policy | Bearer | Read the workspace policy; 404 when unset. |
| PUT | /admin/guardrails/policy | Bearer | Replace the workspace policy atomically. |
| DELETE | /admin/guardrails/policy | Bearer | Drop the workspace policy; 204 on success. |
GET /admin/guardrails/policy
Returns the JSON-encoded DSLPolicy for the caller's workspace. Returns 404 with "no guardrail policy registered for this workspace" when no override is set — the gateway falls through to the default no-op policy in that case.
curl -H "Authorization: Bearer $BIGWAVE_ADMIN_TOKEN" \
http://localhost:8000/admin/guardrails/policyPUT /admin/guardrails/policy
Accepts the raw DSLPolicy document as the JSON request body. Validation runs at load time — a malformed document returns 400 with the underlying parser error in detail.
Example body (illustrative — fields driven by the in-tree DSL grammar):
{
"version": 1,
"workspace_id": "default",
"input": [
{"rule": "block_if_matches", "pattern": "(?i)credit card"}
],
"output": [
{"rule": "redact", "pattern": "\\b\\d{16}\\b", "replacement": "[REDACTED]"}
]
}Returns {"status": "ok", "workspace_id": "default"} on success.
curl -X PUT -H "Authorization: Bearer $BIGWAVE_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d @policy.json \
http://localhost:8000/admin/guardrails/policyDELETE /admin/guardrails/policy
Drops the override. Returns 204 No Content. Subsequent chat completions fall through to the default no-op policy until a new PUT arrives.
Operator notes
- Workspace fence. All three routes scope to the bearer principal's workspace; you cannot read or replace another tenant's policy through this surface. See workspace fence.
- Atomic replace.
PUTis full-replace — there is no patch / partial-update. Pull the current document, edit, re-upload. - Hot-reload. Policy registry reads happen on every chat call; there is no cache that needs invalidation. A successful
PUTtakes effect on the very next request. - Blocked vs redacted. Blocked requests appear in
/admin/inferencewithstatus="blocked"and contribute zero cost; redacted responses are surfaced asstatus="succeeded"with the post-redaction body. See/admin/inferenceand/admin/cost. 503causes.app.state.guardrail_policy_registryis wired in lifespan; routes return503with"guardrail policy registry not initialised"when the lifespan did not complete.- Audit.
PUTandDELETEemit audit rows when anAuditLogRepositoryis wired. See Audit.