From 2781bd5a6c7694543bff5f469efa4cd1fa1e3e6a Mon Sep 17 00:00:00 2001 From: archipelago Date: Sat, 1 Aug 2026 07:07:06 -0400 Subject: [PATCH] =?UTF-8?q?docs(10):=20correct=20D-03's=20gate=20signal=20?= =?UTF-8?q?=E2=80=94=20key=5Fexists=20is=20true=20on=20every=20booted=20no?= =?UTF-8?q?de?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit D-03 named NodeIdentity::key_exists as one of the two gate signals. Server::new (server.rs:63-72) calls load_or_create on both branches, and load_or_create (identity.rs:48-51) generates and writes a random temporary node key when none exists — so key_exists is true on any node that has booted once, onboarded or not. A gate keyed on it would refuse seed.generate on a fresh node and brick onboarding fleet-wide. The flaw came from the audit's own suggested remediation (§214-221) and was repeated in the planning brief; the planner caught it against the code. D-03's intent (two signals, OR-ed, fail safe on drift) is unchanged. Corrected signal set: is_setup() / is_onboarding_complete() / seed_exists(), pinned by a test rather than a comment. Co-Authored-By: Claude Opus 5 (1M context) --- .../10-key-material-hardening/10-CONTEXT.md | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/.planning/phases/10-key-material-hardening/10-CONTEXT.md b/.planning/phases/10-key-material-hardening/10-CONTEXT.md index 0bdec32b..65e1048e 100644 --- a/.planning/phases/10-key-material-hardening/10-CONTEXT.md +++ b/.planning/phases/10-key-material-hardening/10-CONTEXT.md @@ -40,11 +40,26 @@ derivation paths, word counts, or the at-rest encryption envelope. from `UNAUTHENTICATED_METHODS` — so this path does not need to be built, and it is not itself a bypass. -- **D-03:** The gate **refuses if *either* signal says onboarded** — the on-disk key file - (`NodeIdentity::key_exists`, `identity.rs:117`) **or** the onboarding flag - (`AuthManager::is_onboarding_complete`, `auth.rs:182`). Fails safe when the two disagree, - which is a real state: `auth.rs:196-207` already carries auto-heal logic for exactly that - drift. Do not pick one signal and trust it alone. +- **D-03:** The gate **refuses if *either* signal says onboarded** — never one signal trusted + alone. Fails safe when signals disagree, which is a real state: `auth.rs:196-207` already + carries auto-heal logic for exactly that drift. + +- **D-03a (mechanism correction, 2026-08-01 — intent of D-03 unchanged):** D-03 originally named + `NodeIdentity::key_exists` (`identity.rs:117`) as one of the two signals. **That signal is + unusable and would have bricked onboarding on every fresh node.** `Server::new` + (`server.rs:63-72`) calls `NodeIdentity::load_or_create` on *both* branches of its + fresh-vs-existing check, and `load_or_create` (`identity.rs:48-51`) generates and writes a + random temporary node key when none exists. So `key_exists` is `true` on every node that has + booted even once, onboarded or not — a gate keyed on it refuses `seed.generate` on a node that + has never been onboarded. + + This flaw was inherited from the audit's own suggested remediation + (`ENTROPY-SEED-AUDIT-2026-07-31.md:214-221`) and repeated in the planning brief; the planner + caught it against the code. The corrected signal set is `is_setup()` / + `is_onboarding_complete()` / `seed_exists()` — all false on a fresh node and during the seed + steps, all true afterwards. `key_exists` and `fips_key_exists` are rejected with recorded + verdicts, and the correction is pinned by a test + (`allows_on_fresh_temp_dir_even_though_node_key_exists`), not a comment. - **D-04:** 10-01 covers **every method in `UNAUTHENTICATED_METHODS` that can mutate identity or credentials**, behind the same gate and one shared test suite — not just the two endpoints