raxit
security.yaml reference

Rules & effects

How rules and effects are expressed in security.yaml.

Every entry under rules: matches a resource (a tool or endpoint) and says what happens when an agent calls it. rules: is required and must have at least one entry — security.yaml: at least one rule is required otherwise.

effect — a strict 3-value enum

rules:
  - effect: allow
    resource: search_docs
  - effect: review
    resource: stripe/refund
  - effect: block
    resource: stripe/payouts

effect accepts exactly three values: allow, review, block. There is no fourth effect: modify — modification is a separate field (below). Anything else fails to load:

security.yaml: rules[1].effect "foo" is unsupported; use allow, review, or block

What each one resolves to at decision time:

effect:DecisionTypeWhat the caller sees
allowpermitALLOWthe tool runs
reviewdeferDEFERsuspended, routed to human approval (defer.policy)
blockdenyDENYthe tool never runs (deny.default_or_forbid)

review resolves to a plain defer (core.TypeDefer, reason defer.policy) by default. Add a when: condition to a review rule and it resolves instead to a step-up-typed defer (core.TypeStepUp, reason defer.step_up): "a step-up rule requires explicit human approval for this call; approve via: raxit approvals approve <token>." See Permit / defer / deny / modify / step-up for the full resolution chain.

resource (required)

- effect: allow
  resource: read_file

Exact-match only against a Cedar entity — no glob support on the rule's own resource field. (Globs do exist elsewhere in the schema — egress, credentials.resources, warrants.templates[].tool, classify — just not here.) Empty fails: security.yaml: rules[0].resource is required.

resourceType (optional)

- effect: allow
  resource: api.internal.example.com
  resourceType: endpoint

"tool" (default) or "endpoint" — selects which Cedar entity type the resource targets. Anything else: security.yaml: rules[0].resourceType "x" is unsupported; use tool or endpoint.

when (optional) — single-comparison condition

- effect: block
  resource: send_email
  when: recipient_count > 50

A single <field> <op> <value> comparison only — no boolean combinators (no and/or). op is one of < <= > >= == !=; field may contain letters, digits, _, .; value parses as an integer first, else a string. Combines with validate: (below) using AND when both are present on the same rule.

denyWhenTainted (optional) — lethal-trifecta sugar

- effect: block
  resource: post_to_webhook
  denyWhenTainted: [PII, SECRET]

Only legal on effect: block rules — security.yaml: rules[0].denyWhenTainted requires effect: block otherwise. The rule fires only when the session's taint set carries any of the listed labels. The closed vocabulary is 7 labels: PII, SECRET, FINANCIAL, CREDENTIAL, PHI, PROMPT_INJECTION, COST_ANOMALY. See Taint & the lethal trifecta for how a session accumulates these labels across calls.

You don't have to hand-write these: raxit init --taint-denial-posture strict generates one co-located denyWhenTainted rule per discovered egress-capable tool automatically. See taint_denial: for the document-level posture record this pairs with, and raxit init for exactly what gets generated.

modify — arg transform (mutually exclusive with effect)

- resource: send_email
  modify:
    redact: [body, subject]

A rule carries either effect: or modify:, never both — security.yaml: rules[0] has both effect "allow" and a modify block; they are mutually exclusive. modify: is a single-op map: { <op>: [<arg-path>, ...] }.

The op set is redact, hash, dropnot truncate. truncate is explicitly rejected with a load-bearing error, not silently ignored:

security.yaml: rules[0].modify: truncate is not yet supported via security.yaml — it needs a
max length the current shape cannot express, and a no-max truncate would silently forward the
original args; use redact, hash, or drop

A different truncate action does exist, but only under postcondition.rules[].action (a separate output-scanning subsystem, see Advanced) — don't conflate the two.

At decision time a modify: rule resolves to permit with TypeModify and reason modify.policy if the transform parses; if it doesn't, it fails closed to deny.modify_error rather than forwarding the original, untransformed arguments.

validate — parameter-validation guard

- effect: allow
  resource: send_email
  validate:
    field: recipient
    allowlist: ["*@internal.example.com"]

Exactly one of like (regex-ish), allowlist, or blocklist must be set, plus a required field. Semantically a guard, not a denial of its own: a non-matching arg means the rule simply does not fire, and the call falls through to whatever rule (or the default) matches next — it never itself denies.

Duplicate rules

Two rules with the same computed effect (allow/review/block/modify), the same resource, the same when, and the same validate signature are a load error: security.yaml: duplicate allow rule for "calc". Rules for the same resource with different when/validate are not duplicates.

Reference: every field

FieldRequiredNotes
effectyes, unless modify: is setallow | review | block
resourceyesexact match, no glob
resourceTypenotool (default) | endpoint
whennosingle comparison, no and/or
denyWhenTaintednoonly with effect: block; 7-label vocabulary
modifyno, mutually exclusive with effectredact | hash | drop
validatenoexactly one of like/allowlist/blocklist

On this page