Files
hq/04-ISSUES/070-an-operator-cannot-deliver-a-pair-credential/00-report.md
T
jschoubben 418261213c
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the change's judges the pull requests after it merges; it…
mesh/delivery superseded: a newer head of the same pull request
Remove the decision records and research efforts, which the knowledge base now holds whole (issue 426)
ADR 0290 rule 9: once the import is checked record by record, hq keeps no copy.
The records and efforts are removed; every link or path to them reads "ADR NNNN" or
"research NNN"; a design's decisions: lists "ADR NNNN". 02-DECISIONS keeps a pointer
README with the reading order's six topics, which the knowledge base reads through the
records module; 01-RESEARCH keeps a pointer README. The checks drop the rules that
judged records (the knowledge base holds each at propose; checks/README.md says where)
and refuse a record written here again. Playbooks 01 and 02 and the skills write and
read records with the knowledge base's verbs.
2026-10-11 12:56:09 +02:00

2.8 KiB

opened
opened
2026-09-20

An operator cannot deliver a pair credential, so the vault's third species has no entry

Symptom, as observed

ADR 0085 names three species of secret and gives the vault two: a module's own secret, which the mesh mints, and an operator-delivered secret — a credential for something outside the mesh, which only a person can supply. The design (24) says the vault "takes custody of one an operator delivered".

Under 0085 a secret from the vault is a pair credential between the consumer and the vault. The controller has one command that takes a value from a person — secret accept — and it writes only a module's own secret: one node, one module, one name, sealed to that node's key alone. There is no command that accepts a value into a pair: sealed to the consumer's node and to the vault's node, recorded as accepted so a later push does not replace it with a minted one.

The primitive exists. The sealing package's Accept takes a value and two keys, and the licence adapters already use it to carry an operator's token to both ends of a licence. Nothing exposes it for an ordinary provision.

So today an operator-delivered secret can be held in only one of two wrong ways: as an own secret (un-audited, un-rotatable — the gap 0085 opened to close), or not at all.

Why it matters beyond this instance

  • The vault is one third short of its decision until this exists, and the third that is missing is the one with a real leak history — external keys are the secrets that end up in transcripts and env files.
  • The made/accepted distinction is only recorded for own secrets. A pair credential has no origin column, so even once a value can be accepted into a pair, rotate would mint over it — generating "32 random bytes where a working credential was", the exact fault secret accept was written to prevent for own secrets. Rotating an accepted pair credential must refuse, or must ask for the replacement value, and neither is designed.
  • The consumer's login is derived, and an external service did not derive it. An accepted external key has no as the far side knows; a pair credential assumes both ends agree on one. For the vault this is harmless (the vault creates nothing under that login), but the model leaks through in what the consumer is told.

Open questions

  • Is this secret accept <consumer-node> <module> secret --from … growing a provider end, or a new verb on the pair?
  • Does an accepted pair credential refuse rotate, or does rotate become "accept a new value and deliver it" for that pair?
  • Should the origin (made / accepted) become a fact of every pair credential, so the vault's ledger can show which of its secrets a person supplied?