Repository navigation
Mandate 0.7.0
Wave 5a: Mandate moves onto ESS 0.59.0, and the shared agent authority evaluator arrives. Two
stories, each attacked by an adversary pass. Minor, because the signing key's window move is a
Rust API break.
Added
- Agent authority evaluator.
mandate_authz::agent::evaluate_agent_authoritydecides what
an agent may do, acting for itself or for a subject under a delegation: the permitted set is
exactly the intersection of the request, both validated proofs' authority, the delegation's
scope and every applicable current capability ceiling, and never exceeds any of them; it
expires at the earliest of the inputs, compared as instants. Expired, revoked or mismatched
delegations, a disabled or retired actor, a mismatched organization, absent evidence and a
delegation chain deny, and an approval requirement answersallowed = falsewith its
challenge. The records arrive throughmandate_authz::agent::AgentAuthorityReadas the new
mandate_authz::delegationprojections ofAgent,AgentCapabilityCeilingand
Delegation. A reusable library function: no token issuance, route or storage
(story:agent-authority-kernel). - One current ceiling per key. Ceilings are keyed by
(agent_id, organization_id), absent
organization being the platform key; the current one is the latest stillRecorded, a ceiling
recorded for another organization does not apply, and two current ceilings on one key deny.
ExchangeCredential's declared denial gains the clause "two current capability ceilings share
one agent and organization-or-platform key", with the authored scenario
exchange-ceiling-conflict(201 scenarios; it is refused before dispatch, attributed to
story:declared-writers).
Changed
- Breaking. A signing key's validity instants move into one record,
mandate_types::SigningKeyWindow(mandate.core.SigningKeyWindow), carried aswindow:
mandate_token::projection::SigningKey,CredentialEvent::SigningKeyRegisteredand
mandate_sts::keys::RegisterSigningKeyholdwindowwhere they heldnot_beforeand
expires_at. The entity invariant readswindow.not_before < window.expires_at. Rust API only:
no HTTP route and no stored event changes (story:ess-repin-0-59). - ESS moves from 0.26.0 to 0.59.0: the
ess-conformance,ess-primitivesandess-domain
crates, the CLI the gate requires and CI installs, andgenerated/, regenerated under it
(story:ess-repin-0-59). - The conformance suite is synthesized under 0.59.0: 166 → 200 scenarios,
cargo xtask conform
40 passed / 78 failed / 0 error / 82 unsupported / 0 skipped. The 34 newwrong-state
scenarios start from an empty state: 19 name commands no crate realizes and restate the owner
injections.jsonnames, and the 15 the handlers refuse asdeniedact on an identity no record
carries; ESS reads that aswrong-stateunless the command declares anunknown_instance:
outcome, so they are attributed tostory:unknown-instance-refusals. FourResourceServer
scenarios whose synthesizedallowed_exchange_sourcesnames a resource server that does not
exist are attributed tostory:ess-synthesizer-prerequisites. Every non-passed scenario names
a live story. - The conformance target decides an armed
mandate.federationcommand over the standing readers
first: 0.59.0 compiles an authoreddeniedinto aconfigure_external_outcome, and a refusal
the input already decides is now the handler's own answer, recordedinput-decided, rather
than a fault placed ahead of it (federation-audience-mismatch,federation-ambiguous-tenant,
federation-configured-method-on-explicit-link). - The
mandate.delegationrecords the evaluator reads (Agent,AgentCapabilityCeiling,
Delegation) are implemented; the delegation commands, their events and
mandate.delegation.Deniedmove tostory:agent-security, deferred on
decision-blocker:identity-uniqueness. cargo denyadmits RUSTSEC-2024-0449 (unsafe-libyaml, unmaintained, not a vulnerability),
reached only throughserde_yamlin the ESS crates; the ignore leaves when ESS drops
serde_yaml.
Fixed
- An authorization request answered
server_errorwhen a clock second passed during it: the
code's expiry was read from a second clock read and landed one second past the ceiling the STS
admits (ExpiryUnbounded). The code's expiry, and a login's session expiry, are now derived
from the request's one instant.