Skip to content

core.attestation

core.attestation

Attestation layer — the runtime proof layer (design-notes/attestation-layer.md).

Complements the STATIC proof layer (import-lint / FSM checks / typed firewalls, which prove what the code cannot do) with a RUNTIME record of what each agent actually did: signed (Step 3+), content-addressed, chained back to authored content. Step 2 is records-only — unsigned.

GATE_ACTIONS = frozenset({'gate_approve', 'gate_reject'}) module-attribute

AttestationKeyMissing

Bases: RuntimeError

Signing was enabled ([attestation] enabled = true) but no signing key is placed.

Fail-closed: rather than silently emit UNSIGNED attestations when the owner asked for signed ones, construction stops. Place the key (Keychain/Vault) before enabling — see the runbook.

Attestor

Bases: Protocol

emit(*, agent_role, action, input_hashes=(), output_hashes=(), derived_from_ids=None, vault_token_accessor='')

StoreAttestor dataclass

Builds, links, signs, and appends an attestation per agent action.

store instance-attribute

fingerprint = constitution_fingerprint class-attribute instance-attribute

clock = _utcnow class-attribute instance-attribute

signer = None class-attribute instance-attribute

emit(*, agent_role, action, input_hashes=(), output_hashes=(), derived_from_ids=None, vault_token_accessor='')

Ed25519Signer dataclass

A private key + a signer name ("supervisor" | "owner"). The key never leaves this object: callers hand it a payload and get a base64 signature back. (Code attests; the model — and any agent — only ever sees the signature, never the key. attestation-layer.md §4.)

name instance-attribute

from_seed(seed, name) classmethod

sign(payload)

public_b64()

Attestation dataclass

id instance-attribute

timestamp instance-attribute

agent_role instance-attribute

action instance-attribute

constitution_fingerprint instance-attribute

input_hashes instance-attribute

output_hashes instance-attribute

derived_from_ids instance-attribute

vault_token_accessor = '' class-attribute instance-attribute

signature = '' class-attribute instance-attribute

signer = '' class-attribute instance-attribute

signing_payload()

The exact bytes the id is SHA-256'd from and the signature (Step 3) signs.

create(*, timestamp, agent_role, action, constitution_fingerprint, input_hashes=(), output_hashes=(), derived_from_ids=(), vault_token_accessor='', signature='', signer='') classmethod

Build an attestation with its content-addressed id computed (never set by hand).

to_dict()

from_dict(d) classmethod

AttestationChain dataclass

The transitive closure of an attestation and the prior attestations it derived from.

root_id instance-attribute

attestations instance-attribute

complete instance-attribute

is_complete()

No broken links AND the root itself was found.

leaves()

Attestations with no parents — the bottom of the chain (e.g. ingest attestations, whose inputs are authored content digests).

leaf_input_hashes()

roles()

constitution_fingerprints()

verify_signatures(verify)

Step-3 hook: True iff verify(att) holds for every link. The caller supplies the verifier appropriate to the phase (unsigned records have no signature to check).

AttestationStore dataclass

path instance-attribute

append(att)

Insert one attestation. Append-only: an id already present is left untouched (INSERT OR IGNORE), never overwritten. Ids are content-addressed, so a collision is a re-emission of the identical record — a no-op, not a conflict.

get(att_id)

all()

by_role(role)

producers_of(hashes)

Ids of attestations whose output_hashes intersect hashes — the attestations that PRODUCED any of those outputs. This is the chain-linking lookup: an action consuming hash h derives from whatever attested producing h (attestation-layer.md §2).

chain_for(att_id)

Assemble the transitive closure following derived_from_ids. complete is False if any referenced parent (or the root) is absent — a broken link.

count()

close()

build_attestor(config=None)

Wire a StoreAttestor against the configured append-only attestation store.

Signing is owner-gated: only when [attestation] enabled = true is a supervisor signer attached, and only if the private seed is actually placed (else fail-closed, never silently unsigned). Default (enabled = false) is records-only — the Step-2 behavior.

generate_seed()

A fresh base64 Ed25519 private seed (32 bytes).

open_attestation_store(config=None)

build_verifier(config=None)

Wire a verifier from the configured public-key paths ([attestation]).

load_public_keys(supervisor_pub, owner_pub)

Load the committed public keys (non-secret) into a {signer: key} map. A missing file is simply absent from the map (verification of that signer then fails closed).

make_verifier(public_keys, *, require_owner_for=GATE_ACTIONS)

Return verify(att) -> bool over the given {signer_name: public_key} map.

attestor

The Attestor seam — agents emit attestations through this, not by touching store or crypto.

Keeping emission behind a small interface means the agents (dreamer, curator, vault watcher) never learn about signing keys or the store schema: they describe what they did (role, action, input/output hashes) and the attestor stamps the Constitution fingerprint + timestamp, links the chain, (later) signs, and appends. Step 3 adds the signing step INSIDE emit — the agents do not change. (Model advises; code attests — the agent never holds the key.)

AttestationKeyMissing

Bases: RuntimeError

Signing was enabled ([attestation] enabled = true) but no signing key is placed.

Fail-closed: rather than silently emit UNSIGNED attestations when the owner asked for signed ones, construction stops. Place the key (Keychain/Vault) before enabling — see the runbook.

Attestor

Bases: Protocol

emit(*, agent_role, action, input_hashes=(), output_hashes=(), derived_from_ids=None, vault_token_accessor='')

StoreAttestor dataclass

Builds, links, signs, and appends an attestation per agent action.

store instance-attribute
fingerprint = constitution_fingerprint class-attribute instance-attribute
clock = _utcnow class-attribute instance-attribute
signer = None class-attribute instance-attribute
emit(*, agent_role, action, input_hashes=(), output_hashes=(), derived_from_ids=None, vault_token_accessor='')

build_attestor(config=None)

Wire a StoreAttestor against the configured append-only attestation store.

Signing is owner-gated: only when [attestation] enabled = true is a supervisor signer attached, and only if the private seed is actually placed (else fail-closed, never silently unsigned). Default (enabled = false) is records-only — the Step-2 behavior.

crypto

Ed25519 signing primitives for attestations (attestation-layer.md §4).

Thin wrappers over cryptography's Ed25519. Keys are handled as base64 of the 32-byte raw seed (private) / 32-byte raw point (public) — compact, copy-pasteable into Keychain, no PEM ceremony. Signatures are base64 of the 64-byte raw signature.

cryptography is a crypto library, not a networking one — the import-lint network allowlist does not flag it, so it is permitted in the sealed core (it opens no socket).

Ed25519Signer dataclass

A private key + a signer name ("supervisor" | "owner"). The key never leaves this object: callers hand it a payload and get a base64 signature back. (Code attests; the model — and any agent — only ever sees the signature, never the key. attestation-layer.md §4.)

name instance-attribute
from_seed(seed, name) classmethod
sign(payload)
public_b64()

generate_seed()

A fresh base64 Ed25519 private seed (32 bytes).

seed_b64(priv)

public_b64(priv)

private_from_seed(seed)

public_from_b64(pub)

sign(priv, payload)

verify(pub, payload, signature_b64)

True iff signature_b64 is a valid Ed25519 signature of payload under pub. Any failure mode — bad signature, malformed base64, wrong length — returns False, never raises.

record

The attestation record — a content-addressed (eventually signed) claim about one action.

A Vault token already attests "role X was authorized for resource Y at time T"; this record is the analogue for the ACTION itself: "agent X performed action A on inputs I (by hash), producing outputs O (by hash), under Constitution F, derived from the prior attestations whose outputs it consumed." Chaining records by derived_from_ids gives every derived artifact a verifiable lineage back to authored content (design-notes/attestation-layer.md §0–2).

Step 2 builds the RECORDS only — signature/signer stay empty. The id and (later) the signature are both computed over signing_payload(), so the id is stable and the signature is verifiable independently of the id (attestation-layer.md §2, §8: "start without signatures").

Attestation dataclass

id instance-attribute
timestamp instance-attribute
agent_role instance-attribute
action instance-attribute
constitution_fingerprint instance-attribute
input_hashes instance-attribute
output_hashes instance-attribute
derived_from_ids instance-attribute
vault_token_accessor = '' class-attribute instance-attribute
signature = '' class-attribute instance-attribute
signer = '' class-attribute instance-attribute
signing_payload()

The exact bytes the id is SHA-256'd from and the signature (Step 3) signs.

create(*, timestamp, agent_role, action, constitution_fingerprint, input_hashes=(), output_hashes=(), derived_from_ids=(), vault_token_accessor='', signature='', signer='') classmethod

Build an attestation with its content-addressed id computed (never set by hand).

to_dict()
from_dict(d) classmethod

store

Append-only store for attestation records + chain assembly (attestation-layer.md §4–5).

APPEND-ONLY IS STRUCTURAL: this class exposes append and reads, and deliberately NO delete or update. There is no API to mutate or remove a record — the gate's purge-raw action appends a deletion attestation rather than erasing history (attestation-layer.md §4). That makes the audit trail tamper-evident-by-construction even before signatures land (Step 3).

Thread-safety mirrors the JobQueue fix (PROGRESS 2026-06-27): the vault watcher emits ingest attestations from a spawned thread, so the connection is opened check_same_thread=False and every method is guarded by a reentrant lock.

AttestationChain dataclass

The transitive closure of an attestation and the prior attestations it derived from.

root_id instance-attribute
attestations instance-attribute
complete instance-attribute
is_complete()

No broken links AND the root itself was found.

leaves()

Attestations with no parents — the bottom of the chain (e.g. ingest attestations, whose inputs are authored content digests).

leaf_input_hashes()
roles()
constitution_fingerprints()
verify_signatures(verify)

Step-3 hook: True iff verify(att) holds for every link. The caller supplies the verifier appropriate to the phase (unsigned records have no signature to check).

AttestationStore dataclass

path instance-attribute
append(att)

Insert one attestation. Append-only: an id already present is left untouched (INSERT OR IGNORE), never overwritten. Ids are content-addressed, so a collision is a re-emission of the identical record — a no-op, not a conflict.

get(att_id)
all()
by_role(role)
producers_of(hashes)

Ids of attestations whose output_hashes intersect hashes — the attestations that PRODUCED any of those outputs. This is the chain-linking lookup: an action consuming hash h derives from whatever attested producing h (attestation-layer.md §2).

chain_for(att_id)

Assemble the transitive closure following derived_from_ids. complete is False if any referenced parent (or the root) is absent — a broken link.

count()
close()

open_attestation_store(config=None)

verify

Attestation signature verification + the gate-action owner-key policy (attestation-layer.md §3).

make_verifier(public_keys) returns a verify(att) -> bool suitable for AttestationChain.verify_signatures(...). An attestation verifies iff: - it carries a non-empty signature and a known signer, - the signature is valid over att.signing_payload() under that signer's public key (so the id can stay stable while the signature is checked independently — §2), and - gate-decision attestations are signed by the OWNER key (§3): a gate_approve/gate_reject record signed by anything other than "owner" is rejected, making gate decisions non-repudiable. (Gate-attestation emission lands with the Phase-10 gate loop; this is the verification half, enforced now.)

GATE_ACTIONS = frozenset({'gate_approve', 'gate_reject'}) module-attribute

make_verifier(public_keys, *, require_owner_for=GATE_ACTIONS)

Return verify(att) -> bool over the given {signer_name: public_key} map.

load_public_keys(supervisor_pub, owner_pub)

Load the committed public keys (non-secret) into a {signer: key} map. A missing file is simply absent from the map (verification of that signer then fails closed).

build_verifier(config=None)

Wire a verifier from the configured public-key paths ([attestation]).