No description
  • NCL 57.8%
  • Rust 40.2%
  • Nickel 2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
claude-bot 4920dbb08d
feat(verify): the Attestation contract and a verifier that cannot sign
Delivers wo-mandatum-attestation-contract-v2. schemas/attestation.ncl closes
the record over subject_digest, scope and proof{scheme, signature, key_id};
an attestation without a scheme does not export. mandatum-verify checks a
minisign proof over the canonical payload (domain line, subject digest,
sorted scope) with public material only, derives the key id from the key,
and refuses closed every scheme it cannot evaluate.

witness-post accepted all five runtime contracts and every refutation bit;
the receipt is signed by the principal.
2026-09-22 23:21:54 +01:00
.governance feat(verify): the Attestation contract and a verifier that cannot sign 2026-09-22 23:21:54 +01:00
crates/mandatum-verify feat(verify): the Attestation contract and a verifier that cannot sign 2026-09-22 23:21:54 +01:00
examples feat(verify): the Attestation contract and a verifier that cannot sign 2026-09-22 23:21:54 +01:00
schemas feat(verify): the Attestation contract and a verifier that cannot sign 2026-09-22 23:21:54 +01:00
.gitignore chore: initialize mandatum member 2026-09-22 21:48:15 +01:00
Cargo.lock feat(verify): the Attestation contract and a verifier that cannot sign 2026-09-22 23:21:54 +01:00
Cargo.toml feat(verify): the Attestation contract and a verifier that cannot sign 2026-09-22 23:21:54 +01:00
README.md docs: describe mandatum — contract, mechanisms, principles, open questions 2026-09-22 22:04:50 +01:00

mandatum

A signature grants a declared reach. mandatum produces that grant and checks it.

An agent — usually an AI agent — works under a Work Order. A person signs the scope the agent may act within. mandatum is the mechanism behind that signature: how it is produced without the agent ever holding a key, how anyone verifies it with public material only, and how a verifier decides whether the signer's roles cover what the scope asks for.

It is a member of the stratumiops constellation (an Addon of code), and it is consumed by contract: ontoref, provisioning, vapora and rustelo depend on the shape of what it produces, not on its implementation.

The contract

Attestation = subject_digest + scope + proof { scheme }

verify(Attestation) → { principal?, roles, ial, aal, isolation }
  • subject_digest — the digest of the Work Order being granted.
  • scope — the paths and aspects the grant covers.
  • proof — a signature, or any other proof, tagged with the scheme that produced it. Verification dispatches on the tag and fails closed on a scheme it cannot evaluate.
  • principal is optional. A verifier receives the attributes its decision reads, not necessarily who the signer is.

Three mechanisms, one responsibility each

  • custody answers who holds the key, and whether a person was present when it signed. It knows nothing about what is signed, or why.
  • verify answers whether a proof is valid for its subject and scope, using public material only. It knows nothing about private keys or roles.
  • authorize answers whether the signer's roles cover every path of the scope — Cedar policies evaluated over a Nickel model. It knows nothing about how the proof was produced.

verify and authorize touch public material only, so they may run anywhere: a daemon, a plugin, a CI job, the agent's own session. sign is packaged apart; where it may be installed is declared, never assumed.

Identity, roles, assignments

  • A key identifies a person — one authenticator per person, not one per area.
  • A role grants attributions: which surfaces and which aspects it governs.
  • An assignment binds persons to roles, and changes without touching any key.

A person with five responsibilities signs with one key; the verifier derives the roles. While one person holds every role the separation between roles is declarative; it becomes cryptographic when a second person holds a key.

Principles

  • Only a person signs. An agent never signs — not with a person's key, not with its own.
  • Keys stay out of the agent's reach, by mechanism, not by instruction. The agent reads public keys only.
  • Nothing grants itself. No actor widens its own authorization under any pretext.
  • The agent leaves a trace, not a signature. The trace authorizes nothing.
  • A signature authorizes a declared scope. Changing the scope is signing again.
  • Outside the scope, stop and ask the role that governs that surface — a matter of roles, not hierarchy.
  • Declared, never imposed. No mechanism is required. The floor is a software ed25519 key anyone can generate; hardware authenticators raise the assurance level. The attestation states what was used — scheme, assurance, whether the signing environment was shared with an agent — and the consumer's policy decides whether it is enough.
  • Exposure is declared per audience. What a signed artefact carries travels with it through every channel and cannot be withdrawn; which field reaches which audience is decided at issuance.

What mandatum is not

  • Not a secrets store. sops, age and a vault's key-value engine decide who reads values; mandatum decides who granted what.
  • Not identity or sessions. That is stratum-ui's auth; mandatum complements it with authorization and attestation.
  • Not a runtime dependency of its consumers. ontoref verifies Work Orders without it.

Open

Recorded as open, not decided:

  • The default proof scheme (SSHSIG over ed25519 is a candidate; minisign is in use today).
  • How exposure per field and audience is expressed in the contract, and which unlinkable schemes (per-context keys, anonymous credentials, group signatures with a declared opener) enter as schemes.
  • Whether code's ncl-load is the edge that loads the Nickel model.

Status

No code yet. What exists is this description and the member declaration in the stratumiops constellation. Work on it proceeds through signed Work Orders.