Capability Leases
Bind a destructive workflow step to its lease, scope, validity window, and trusted signer, then verify the binding offline.
On this page
Two operators can let an agent take a destructive step in a shared workflow and later prove, offline, which authority allowed it. A capability lease is that authority’s signed statement: an issuer, a subject, a scope, an action class, and a validity window.
For a destructive step, a governance receipt binds the lease and the workflow to the hash of that step’s tool receipt body. A buyer’s verifier checks both records inside a proof package, beside the workflow evidence. Ordinary mediated calls take the runtime capability token and policy path.
A destructive step is valid only inside every window above it
Each record carries issued_at and expires_at, and each authority that signs one has a window of its own. Issuance nests the windows; verification tests them against one clock.
Issuance nests each window inside its authority
The lease sits inside its lease authority’s window. A destructive step’s governance receipt sits inside both the lease and the governance authority’s window. Issuance compares the windows in the profile and request; it reads no wall clock. Issuance.
The live interval is issued_at ≤ now < expires_at, so verification at the exact expiry value fails with LeaseExpiredOrUnknown. The pure verifiers take now_unix_ms from their caller and add no clock-skew allowance. Issuance compares the windows and authority status in the profile and request, without reading a wall clock, and refuses a receipt that would outlive its lease.
Buyer-core verifies at its configured verifier epoch. It checks each authority’s window at that epoch, each record’s issue time against its authority’s window, and each record’s own lifetime. For a destructive step it checks again that the receipt’s window sits inside the lease.
Two signed records and one preimage carry the authority
A lease authority signs the lease; a governance authority signs the receipt that authorizes a destructive step. The scope they cover is committed by digest.
- Capability lease,
chio.capability-lease.v1. The lease authority signs the lease id, issuer, subject, scope digest, action class, and issue and expiry times. - Governance receipt,
chio.governance-receipt.v1. The governance authority signs the receipt id, authorizing kernel, case kind, authorized lease, workflow, step hash, and issue and expiry times. - Lease scope binding. An unsigned preimage holding the workflow and tool scope. The signed lease commits to its digest.
pub struct GovernanceReceiptArtifact {
pub schema: String,
pub receipt_id: String,
pub authorizing_kernel: String,
pub case_kind: GovernanceReceiptCaseKind,
pub authorized_lease_id: String,
pub workflow_id: String,
pub step_sha256: String,
pub issued_at_unix_ms: u64,
pub expires_at_unix_ms: u64,
}Both signed records travel in SignedExportEnvelope<T>: the body, the signer key, and a signature over the canonical body JSON. The signature establishes integrity under the embedded key; authority pinning decides whether that key is trusted for its declared role.
Lease bodies use camelCase fields. Their action classes are scoped_observation, delegated_action, and narrow_destructive, compared against allowlists as named classes. The receipt’s case kind has one value, destructive_authorization. The Governance Ladder declares which action classes peers require, and listing charters and cases belong to Listing Disputes.
The scope digest binds the lease to the operation you mean
A digest means something only when the verifier rebuilds its preimage independently. The binding’s canonical preimage has thirteen fields, which answer four questions:
- Which workflow step? Lease id, workflow id, workflow grant id, and step index.
- Which execution target? Tool name, peer kernel id, action-class id, and tool-arguments hash.
- Whose authority? Subject, lease action class, and destructive flag.
- For how long? Issue and expiry timestamps in Unix milliseconds.
The schema field is validated and left out of the preimage. Buyer-core requires one binding per lease, resolves its workflow step, and compares its scope with the workflow receipt, the tool receipt, the class binding, and the lease body before it recomputes the digest. An edited binding therefore changes the digest and fails against the unchanged signed lease.
The pure lease helper sees only the digest string. Pass its optional expected digest from the scope you intend; with None, the helper skips that equality check and binds the lease to no particular operation.
One offline command issues a lease and its authorization together
The command reads an authority profile, an issuance request, and local signing seeds. One request selects a lease authority and a governance authority, and every step in it uses that pair.
chio federation authority issue \
--profile ./authority-profile.json \
--request ./issuance-request.json \
--signing-keys ./authority-signing-keys.json \
--out-dir ./issued-workflowThe output directory holds issuance-bundle.json, capability-leases.json, lease-scope-bindings.json, governance-receipts.json, and verification-context.json. Before signing, the command checks the inputs:
- Profile. Explicit authority keys, matching key ids, positive validity spans, status, and nonempty class and case allowlists. Runtime policy issuer keys stay separate from lease, governance, and revocation authority keys.
- Authorities. The selected authorities have Active status, and their configured seeds derive the profile’s public keys.
- Steps. A destructive step uses
narrow_destructiveand supplies the governance receipt fields; a non-destructive step omits them. Duplicate lease ids and step indices fail. The governance authority’s destructive-authorization allowlist is checked even when the request has no destructive step.
The buyer verifier pins the authority before it reads a signature
The buyer verifier resolves the lease issuer and the receipt’s authorizing kernel from its trusted authority bundle. It checks key revocation, authority windows, issue times, signer-key equality, and the class or case allowlist, then calls the pure helpers. That order ties a valid signature to an expected authority.
For a destructive step, buyer-core recomputes the step hash from the canonical tool receipt body, resolves the authorized lease and its scope binding, and calls the strict verifier with the package’s workflow id. The strict verifier compares the lease id, workflow id, and step hash. A presence check confirms only that a live, signed receipt exists, so it never replaces the binding check; the wrong-workflow case shows the difference.
Revocation here works on pinned authority-key fingerprints. A matching receipt verifies every time inside its window, so a workflow that needs one-time use enforces it in the admission system that executes the step.
Lease verification reference
Search for a verifier, an error, or a route.
Verification functions
| Function | Checks performed |
|---|---|
verify_ | Schema and shape, the embedded-key signature, validity at the supplied time, and the expected scope digest when one is passed. Trusted issuer, key revocation, and action-class authority come from the caller’s trust layer. |
verify_ | Receipt schema and shape, the embedded-key signature, lifetime, and equality with the expected lease id, workflow id, and step hash. It receives the receipt and the expected values, without the lease record. |
verify_ | For a destructive step: receipt presence, shape, lifetime, and signature, without the lease id, workflow id, or step hash comparison. For a non-destructive step it returns success immediately. |
A live receipt for the wrong workflow
A valid, live receipt authorizes workflow-alpha while the caller expects workflow-beta; the lease id and step hash match. The two receipt helpers disagree on this case:
- Destructive-step boundary check. Passes, because it checks the receipt’s presence and validity.
- Strict destructive authorization with
workflow-beta. Fails withWorkflowMismatch.
Verification errors
| Error | Meaning |
|---|---|
Unsupported | The record declares a different schema. |
InvalidArtifact | A required field, digest shape, or positive validity span is invalid. A malformed expected hash also produces this error. |
Invalid | The signature verifies as false under the embedded signer key. |
LeaseGovernance | The record’s issue time is later than the supplied verifier time. |
Lease | The pure helper reached expiry. The variant carries a lease id or a governance receipt id; the helper consults no registry for unknown ids. |
Scope | The supplied expected digest differs byte for byte. |
Governance | A destructive step has no governance receipt. |
LeaseMismatchWorkflowStep | The receipt binds a different lease, workflow, or step body. |
Crypto | The signature library returned an error instead of a verification result. |
The boundary helper checks expiry before its signature; the strict helpers check the signature first. Match on the returned error variant. Shape validation accepts uppercase hex while digest equality is byte-exact, so keep the canonical lowercase form that issuance writes.
Listing governance routes
Leases and destructive-step receipts come from the offline chio federation authority issue command. The trust control plane’s governance routes, under the prefix /v1/registry/governance/, serve listing charters and cases:
| POST route suffix | Operation |
|---|---|
charters/issue | Build and sign a listing- |
cases/issue | Validate the supplied listing and charter context, then build and sign a case for that governing operator. |
cases/evaluate | Evaluate caller-supplied records and return an unsigned result. |
These handlers require the service token and run on the node that receives the request, without leader forwarding. They return the record to the caller and keep no copy, so store the JSON. Capability-token issuance at /v1/capabilities/issue follows its own leader and authority admission path.
Both issue routes require an advertised operator URL and exactly one configured signing source, and they sign with the receiving node’s local keypair. When you compare records issued on different nodes, match the advertised operator and the intended signer; Authority & Rotation explains the key distinction. A case evaluation returns findings beside effective_state and blocks_admission; read all three, as Listing Disputes describes.
Source files
crates/trust/chio-governance/src/lease.rsandauthorization.rs: pure verification and the exact time boundaries.crates/trust/chio-federation-authority/src/lib.rs: issuance, scope construction, and window containment.crates/trust/chio-attest-buyer-core/src/report.rs: the rebuilt scope, authority pinning, and strict destructive-step verification.