enforcement
Module: enforcement
Section titled “Module: enforcement”Contents
Section titled “Contents”Modules
capability_map- Capability token selection map.capability_validation- Stage 1 — Capability Validation.cedar_evaluator- Concrete Cedar policy evaluator for Sidecar Stage 2.constraint_enforcement- Stage 2 — Constraint Enforcement Engine (CEE).decision- Enforcement decision types.error- Internal enforcement errors.registry- Canonical Action Class Registry v0.1.revocation- Revocation cache: bloom filter + LRU store.session_state- Per-session runtime state for Stage 2 quantitative constraint enforcement.
Module: capability_map
Section titled “Module: capability_map”Capability token selection map.
Holds pre-provisioned capability tokens issued by the Authority at pre-flight and selects the best match for each intercepted request based on action class and resource scope (ADR-002).
Tokens are indexed by action class at construction time so that per-request lookups avoid a full linear scan. The agent knows nothing about Firma — the sidecar selects the correct token internally after intent normalization.
Module: capability_validation
Section titled “Module: capability_validation”Stage 1 — Capability Validation.
First enforcement phase. Selects the best-matching capability token and validates it:
- Capability token selection — selects the best-matching pre-provisioned
token from the
CapabilityMapby action class and resource scope (ADR-002). The agent knows nothing about Firma; the sidecar selects the correct token internally. - Token validation — parse PASETO v4, verify Ed25519 signature, check expiry (with configurable clock skew tolerance), and check revocation via bloom filter + LRU cache.
All operations are fully local — the Authority is never contacted on the hot path. Target latency: < 1 ms p95.
Security properties
Section titled “Security properties”Stage 1 prevents forged, tampered, expired, or revoked capabilities from entering the execution path:
- Token forgery — cryptographic signature verification rejects tokens not signed by a trusted Authority.
- Token tampering — any modification to scope, budget, expiry, agent ID, or resource scope invalidates the signature.
- Expired credential reuse — expiry check rejects tokens whose TTL has elapsed.
- Revoked token reuse — bloom filter + LRU cache check rejects tokens that have been explicitly invalidated.
Module: cedar_evaluator
Section titled “Module: cedar_evaluator”Concrete Cedar policy evaluator for Sidecar Stage 2.
Implements [PolicyEvaluation] by evaluating a compiled Cedar policy set
against the context produced by
[ConstraintEnforcer::build_context][super::constraint_enforcement::ConstraintEnforcer].
Evaluation is fully local — no network calls. [CedarPolicyEvaluator] is
constructed from a [PolicyBundle] received from the Authority and tracks
freshness against the bundle TTL.
Entity UID conventions (must match Authority’s service.rs)
Section titled “Entity UID conventions (must match Authority’s service.rs)”| Cedar role | Format |
|---|---|
principal | Firma::Agent::"<agent_id>" |
action | Firma::Action::"<action_class>" |
resource | Firma::Resource::"<resource_uri>" |
Module: constraint_enforcement
Section titled “Module: constraint_enforcement”Stage 2 — Constraint Enforcement Engine (CEE).
Second enforcement phase. The semantic layer where Cedar policies and
quantitative constraints are evaluated. Operates on a previously normalized
ExecutionEnvelope produced by Stage 1 — it must not infer the canonical
action class from raw transport-specific input.
Steps:
- Scope check — verifies that the requested
action_classis within the token’s allowedaction_set. Wildcard"*"permits all actions. - Policy bundle freshness — if the bundle TTL has expired without a successful refresh, the Sidecar enters fail-closed mode and denies all new requests.
- Context build — assembles the Cedar request context from envelope fields, claims, and runtime signals (budget consumed, risk score).
- Cedar eval — evaluates against the current policy bundle. Deterministic: same context + same bundle = same decision. Fully local, no external calls.
Target latency: < 200 µs p95.
Security properties
Section titled “Security properties”Stage 2 prevents valid capabilities from being misused for out-of-policy, over-budget, or contextually disallowed actions:
- Privilege escalation within token — a valid token does not imply all calls are allowed; Cedar eval checks the specific call against policy.
- Scope misuse at runtime — a valid capability for action class X cannot be used for action class Y.
- Budget overrun / quota abuse — pre-computed
budget_remainingattribute checked against threshold. - Non-deterministic authorization — same context + same bundle always produces the same decision.
Module: decision
Section titled “Module: decision”Enforcement decision types.
Every enforce() call produces exactly one [EnforcementDecision]:
ALLOW or DENY. ALLOW carries the verified claims and normalized envelope
for downstream use (credential injection, connector dispatch, audit).
DENY carries a structured reason, the originating stage, and a detail
message for audit and agent error reporting.
ABORT is an asynchronous in-flight kill signal emitted by the Authority
via WatchAborts, not produced by the enforcement pipeline itself.
Module: error
Section titled “Module: error”Internal enforcement errors.
Every variant maps to a [DenyReason] via [EnforcementError::into_deny].
This is the fail-closed boundary: errors become DENY decisions.
These types are never exposed to external callers.
Module: registry
Section titled “Module: registry”Canonical Action Class Registry v0.1.
Contains the 15 canonical action classes defined by FEP v0.1 §2.3.5.
Every intent.action_class field in an ExecutionEnvelope MUST be one
of these identifiers. Unknown protected actions that cannot be
deterministically mapped to a registry entry fail closed with
DENY: UNCLASSIFIED_INTENT (FEP [I-N1]).
Identifiers follow the naming rules in FEP §2.3.2: lowercase ASCII,
dot-separated, describing semantic meaning only. Transport, provider,
and connector names MUST NOT appear in identifiers. See
docs/markdown/firma_action_class_registry.md for the implementation
notes and default mapping strategy.
The same canonical class is produced regardless of whether the underlying action arrives as a native tool call, a CLI invocation, an HTTP request, or an MCP call. Policies and HITL conditions bind to the canonical action class, not to transport-specific names.
Module: revocation
Section titled “Module: revocation”Revocation cache: bloom filter + LRU store.
Implements [firma_core::RevocationStore] for the sidecar. See
docs/tasks/006-revocation-cache.md.
Behavior
Section titled “Behavior”is_revoked: bloom-miss ->Ok(false)fast path. Bloom-hit -> LRU lookup. LRU-hit ->Ok(true). LRU-miss on bloom-positive (either a bloom false positive or an evicted LRU entry) ->Ok(true), to honor the spec’s “REVOKED is terminal” invariant.add_revocation: bloom insert + LRU insert. Idempotent.- V1 never returns
Err; the trait’sResultis kept for forward compatibility.
Module: session_state
Section titled “Module: session_state”Per-session runtime state for Stage 2 quantitative constraint enforcement.
V1 stores three signals per SessionId: action count (monotonic
counter incremented on every admitted request), budget_consumed
(cumulative, placeholder 0.0 in V1), risk_score (placeholder 0.0 in
V1). Storage is in-memory with LRU eviction — V1 runs single-process.
Eviction resets an evicted session’s counters on next access. Since
Cedar policies in V1 are monotone (action_count > N denies as count
grows), eviction can only move a denying session back toward allowing
— acceptable for V1 scope. Document when this is upgraded to a
persistent or cluster-shared store.