Problem
ADR 0016
makes the operator the trust root: a key is in
contextgraph_host::TrustStore because a person put it there. That is the
right primary tier and it is the only one that needs no organization.
It leaves a real gap. A provider a person installed but never handed a key for
serves evidence that reads as AttestationState::NoTrustedKey forever, even
though the same key has answered every query for a year. Trust-on-first-use
would record that continuity as a labelled second tier, strictly below a
configured key: pin the first key seen, and report loudly when it changes.
It is not implementable today, and the reason is a fact about the wire rather
than a judgement: a ProvenanceAttestation carries a key_id, an algorithm
and a signature, and no public key. Neither does handshake_ack
(contextgraph-types/src/capability.rs, ProviderInfo). There is nothing to
pin.
What would have to happen
- An additive wire field carrying a provider's public key(s) — most naturally
on handshake_ack beside ProviderInfo, since that is where a provider
already declares who it is. Optional, so no existing provider breaks.
Additive within contextgraph/1 per GOVERNANCE.md.
- Its own ADR, because it is a normative addition and because it introduces a
trust tier ADR 0016 deliberately did not adopt. That ADR must not let the
pinned tier be presented as equivalent to a configured one: TOFU proves
continuity, never identity, and an attacker present at first contact is
trusted forever.
TrustStore gains an origin on each key (configured vs pinned) and a
pinning path. Note that pinning mutates the store during a fan-out, which
takes &self today — either the pin happens outside the query path or the
store needs interior mutability.
AttestationState::Attested gains, or is joined by, the tier, so an audit
can distinguish "verified against a key a person checked" from "verified
against a key we happened to see first".
Files
contextgraph-host/src/trust.rs — TrustStore, TrustedKey, AttestationState
contextgraph-host/src/host.rs — Host::trust_key, query_one_isolated
contextgraph-types/src/capability.rs — ProviderInfo / handshake_ack
docs/adr/0016-attestation-trust-roots.md — the alternative, and why it was deferred
Definition of done
Problem
ADR 0016
makes the operator the trust root: a key is in
contextgraph_host::TrustStorebecause a person put it there. That is theright primary tier and it is the only one that needs no organization.
It leaves a real gap. A provider a person installed but never handed a key for
serves evidence that reads as
AttestationState::NoTrustedKeyforever, eventhough the same key has answered every query for a year. Trust-on-first-use
would record that continuity as a labelled second tier, strictly below a
configured key: pin the first key seen, and report loudly when it changes.
It is not implementable today, and the reason is a fact about the wire rather
than a judgement: a
ProvenanceAttestationcarries akey_id, analgorithmand a signature, and no public key. Neither does
handshake_ack(
contextgraph-types/src/capability.rs,ProviderInfo). There is nothing topin.
What would have to happen
on
handshake_ackbesideProviderInfo, since that is where a provideralready declares who it is. Optional, so no existing provider breaks.
Additive within
contextgraph/1perGOVERNANCE.md.trust tier ADR 0016 deliberately did not adopt. That ADR must not let the
pinned tier be presented as equivalent to a configured one: TOFU proves
continuity, never identity, and an attacker present at first contact is
trusted forever.
TrustStoregains an origin on each key (configured vs pinned) and apinning path. Note that pinning mutates the store during a fan-out, which
takes
&selftoday — either the pin happens outside the query path or thestore needs interior mutability.
AttestationState::Attestedgains, or is joined by, the tier, so an auditcan distinguish "verified against a key a person checked" from "verified
against a key we happened to see first".
Files
contextgraph-host/src/trust.rs—TrustStore,TrustedKey,AttestationStatecontextgraph-host/src/host.rs—Host::trust_key,query_one_isolatedcontextgraph-types/src/capability.rs—ProviderInfo/handshake_ackdocs/adr/0016-attestation-trust-roots.md— the alternative, and why it was deferredDefinition of done
that it proves continuity and not identity.
example, and
SPEC.mdsays a receiver MUST tolerate its absence.AttestationState, and a testproves a changed key under a pinned
key_idis reported loudly ratherthan silently re-pinned.
say so, so the option is closed rather than left hanging.