Patterns#
Production patterns for writing and rolling out CPEX policy. Each is expressed in APL and builds on the concepts in the earlier pages. The Tutorial builds most of these hands-on; this page is the condensed reference for authoring and rollout.
Layered enforcement#
Order effects cheapest-gate-first so expensive work only runs for requests that survive the early checks. Attribute gates, then a PDP call, then delegation (built up in tutorial modules 4, 5, and 6):
authorization:
pre_invocation:
- "require(team.engineering | team.security)" # cheap
- cedar:
action: 'Action::"read"'
resource:
type: Repo
id: ${args.repo_name}
- "delegate(github-oauth, target: github-api, permissions: [repo:read])" # expensive, lastA deny at any layer halts the rest, so you never mint a token for a request a later layer would reject.
Shadow rollout with audit mode#
Before a new policy blocks traffic, run it in audit mode to observe what it would do without enforcing. An audit-mode plugin records decisions but cannot block, so you can measure a policy’s deny rate against real traffic, then switch it to sequential once the rate is what you expect.
plugins:
- name: new-policy-check
kind: validator/pii-scan
mode: audit # observe only; flip to sequential to enforce
on_error: ignoreInput and output guardrails#
Validate and transform on the way in with args, redact on the way out with result. The two phases bracket the operation (redaction is tutorial module 3):
routes:
- tool: get_employee
args:
employee_id: "str | regex(\"^[0-9]{6}$\")" # reject malformed input
result:
ssn: "str | redact(!perm.view_ssn)" # redact output by permissionCross-request information flow#
Taint a session when it touches sensitive data, then gate later operations on the label. The control spans requests and the model cannot route around it (see Session Tainting and tutorial module 7):
routes:
- tool: get_compensation
authorization:
pre_invocation:
- "require(role.hr)"
- "taint(secret, session)"
- tool: send_email
authorization:
pre_invocation:
- "require(perm.email_send)"
- "security.labels contains \"secret\": deny('write-down blocked', 'session_tainted')"Least-privilege effects#
Declare the narrowest capabilities each plugin needs, and scope delegated tokens to the minimum. A scanner that reads content does not get identity; a downstream token gets only the scope the operation requires, verified after the exchange (deny if the grant is missing):
authorization:
pre_invocation:
- "delegate(workday-oauth, target: workday-api, permissions: [read_compensation])"
- "!(delegation.granted.permissions contains 'read_compensation'): deny" # fail closed if not grantedDefense in depth#
Combine the patterns: an attribute gate, a PDP relationship check, a PII scan on output, a taint, and an audit record, each a separate effect in one policy. No single layer is load-bearing alone; the operation has to pass all of them.