docs(10): capture phase context
This commit is contained in:
@@ -0,0 +1,235 @@
|
|||||||
|
# Phase 10: Key-Material Hardening - Context
|
||||||
|
|
||||||
|
**Gathered:** 2026-08-01
|
||||||
|
**Status:** Ready for planning
|
||||||
|
|
||||||
|
<domain>
|
||||||
|
## Phase Boundary
|
||||||
|
|
||||||
|
Every path that creates, restores, or persists node key material proves the caller is
|
||||||
|
authorized and the material is per-node. Closes the three exploitable findings from
|
||||||
|
`docs/security/ENTROPY-SEED-AUDIT-2026-07-31.md`:
|
||||||
|
|
||||||
|
- An already-onboarded node must refuse to have its identity replaced (F-01, Critical).
|
||||||
|
- A node flashed from the fleet-shared rootfs must never share another node's host keys (F-03, High).
|
||||||
|
- The wallet spending key must not exist in cleartext outside the encrypted envelope (F-13, High).
|
||||||
|
|
||||||
|
**Not in scope:** the remaining audit findings F-04..F-12 (tracked as R-05..R-14 in
|
||||||
|
`docs/UNIFIED-TASK-TRACKER.md`), the PSBT air-gap *implementation*, and any change to
|
||||||
|
derivation paths, word counts, or the at-rest encryption envelope.
|
||||||
|
|
||||||
|
</domain>
|
||||||
|
|
||||||
|
<decisions>
|
||||||
|
## Implementation Decisions
|
||||||
|
|
||||||
|
### KEY-01 — Re-key policy (F-01, Critical)
|
||||||
|
|
||||||
|
- **D-01:** An already-onboarded node **hard refuses** `seed.restore` and `seed.generate`.
|
||||||
|
These endpoints are permanently closed once the node holds identity keys. No
|
||||||
|
authenticated-session variant, no physical-presence window — the pre-auth path carries no
|
||||||
|
authorization decision at all, which is what keeps its attack surface at zero.
|
||||||
|
— **Reversibility:** costly — the refusal becomes an observable API contract that the
|
||||||
|
onboarding UI, the companion app, and any restore tooling will be written against; loosening
|
||||||
|
it later is safe, but tightening a looser rule after release would break callers.
|
||||||
|
|
||||||
|
- **D-02:** The legitimate re-key path is the **existing authenticated `system.factory-reset`**
|
||||||
|
(`api/rpc/dispatcher.rs:469`, `system/handlers.rs:575`), after which the node is un-onboarded
|
||||||
|
and the normal onboarding restore flow works. Verified during discussion that both
|
||||||
|
`system.factory-reset` and `auth.resetOnboarding` are already authenticated — they are absent
|
||||||
|
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-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
|
||||||
|
F-01 names. Explicitly in the audit sweep: `seed.generate`, `seed.restore`,
|
||||||
|
`seed.save-encrypted`, `backup.restore-identity`, `auth.setup`, and `auth.onboardingComplete`.
|
||||||
|
Fixing `seed.restore` while `backup.restore-identity` reaches the same identity-overwrite
|
||||||
|
primitive would move the door, not close it. For endpoints that turn out not to mutate
|
||||||
|
(e.g. possibly `seed.verify`), record an explicit evidence-backed verdict rather than
|
||||||
|
changing behaviour.
|
||||||
|
|
||||||
|
### KEY-02 — First-boot secret regeneration (F-03, High)
|
||||||
|
|
||||||
|
- **D-05:** On failure, **retry with backoff, then fail closed** — refuse to bring the service
|
||||||
|
up and surface a loud console/screen error. Chosen over fail-immediately (a transient
|
||||||
|
first-boot condition would brick a new node with no self-recovery) and over boot-locked-with-
|
||||||
|
warning (a dismissable warning means running on shared keys). The current behaviour is the
|
||||||
|
opposite of all three: fail-open with the completion marker set even on failure
|
||||||
|
(`build-auto-installer-iso.sh:1647`, `:1659`, `:1663`).
|
||||||
|
|
||||||
|
- **D-06:** Scope is **fix the ISO builder AND remediate already-deployed nodes** — boot-time
|
||||||
|
detection plus one-time regeneration, reaching the fleet via OTA. Builder-only would stop the
|
||||||
|
exposure growing without ending it, on exactly the nodes that are already live.
|
||||||
|
— **Reversibility:** one-way — rotating SSH host keys on live nodes invalidates existing
|
||||||
|
`known_hosts` entries fleet-wide and changes host identity for any tooling pinned to it;
|
||||||
|
once rotated there is no going back to the old key. The plan must sequence this so remote
|
||||||
|
access is not lost mid-rotation, and this decision earns a checkpoint before the task that
|
||||||
|
implements it.
|
||||||
|
|
||||||
|
### KEY-03 — Wallet spending key (F-13, High)
|
||||||
|
|
||||||
|
- **D-07:** **Migrate existing wallets** to watch-only (`disable_private_keys=true`, xpub
|
||||||
|
imported with a `[fingerprint/derivation]` key origin), with **balance and UTXO-set parity
|
||||||
|
verified before and after**, keeping the old `wallet.dat` as a rollback. Matches the audit's
|
||||||
|
R-04 and CLAUDE.md's "migrations never destroy data" invariant. New-wallets-only was rejected
|
||||||
|
because it leaves the exposure precisely on nodes holding real funds.
|
||||||
|
— **Reversibility:** one-way — this rewrites a wallet that may hold user funds. Rollback
|
||||||
|
depends entirely on the retained `wallet.dat` and the parity proof; a migration that loses
|
||||||
|
UTXO visibility is a funds-visibility incident. Earns a checkpoint before execution.
|
||||||
|
|
||||||
|
- **D-08:** Default signing stays **daemon-side PSBT signing** using the seed already held in
|
||||||
|
the encrypted envelope, with the air-gapped/external-signer path from
|
||||||
|
`docs/security/PSBT-SIGNING-ARCHITECTURE.md` available as **opt-in**. Send UX is unchanged;
|
||||||
|
the win is that the spending key exists in exactly one place instead of two. Requiring an
|
||||||
|
external signer was rejected as a UX change needing hardware users may not have.
|
||||||
|
|
||||||
|
- **D-09:** The missing key-origin annotation is in scope, not a follow-up. Today's descriptors
|
||||||
|
(`bitcoin.rs:230-231`) carry none, which is why the current wallet could not be converted to
|
||||||
|
an external-signer setup even if the private key were removed — fixing the key without the
|
||||||
|
origin would leave D-08's opt-in path unreachable.
|
||||||
|
|
||||||
|
### Rollout
|
||||||
|
|
||||||
|
- **D-10:** The KEY-01 fix **rides the next scheduled OTA** rather than an emergency point
|
||||||
|
release. *Recorded consequence:* F-01 is remotely reachable on every live fleet node until
|
||||||
|
that OTA ships, so the exposure window is set by the OTA cadence, not by when 10-01 is
|
||||||
|
verified. Per CLAUDE.md the dev pair (archi-dev-box + x250-dev) is deployed and verified
|
||||||
|
before any OTA regardless.
|
||||||
|
|
||||||
|
- **D-11:** 10-01 (KEY-01) is still planned as **wave 1, empty `depends_on`, independently
|
||||||
|
shippable** — so the release decision stays a scheduling choice rather than a technical
|
||||||
|
constraint. If the OTA slips, 10-01 must remain cuttable on its own.
|
||||||
|
|
||||||
|
### Claude's Discretion
|
||||||
|
|
||||||
|
- Exact error code / JSON-RPC response shape for a refused call (must not leak whether the node
|
||||||
|
is onboarded to an unauthenticated caller beyond what `auth.isOnboardingComplete` already
|
||||||
|
discloses — that method is itself unauthenticated, so the information is not new).
|
||||||
|
- Rate-limit shape and thresholds, subject to the constraint in the traps below.
|
||||||
|
- Test organisation and file placement.
|
||||||
|
- Whether the shared gate is a middleware-layer check, a helper called by each handler, or both.
|
||||||
|
|
||||||
|
</decisions>
|
||||||
|
|
||||||
|
<canonical_refs>
|
||||||
|
## Canonical References
|
||||||
|
|
||||||
|
**Downstream agents MUST read these before planning or implementing.**
|
||||||
|
|
||||||
|
### The findings themselves (primary source — read first, in full)
|
||||||
|
- `docs/security/ENTROPY-SEED-AUDIT-2026-07-31.md` — the audit this phase exists to close.
|
||||||
|
F-01 at §166, F-03 at §267, F-13 at §528. Remediation register R-01..R-15 near §890.
|
||||||
|
On-node UNVERIFIED checklist C-3 §779, C-4 §792, C-6 §814. 103 file:line references.
|
||||||
|
- `docs/security/PSBT-SIGNING-ARCHITECTURE.md` — target architecture for KEY-03: watch-only
|
||||||
|
descriptors, `wsh(sortedmulti)`, air-gap transport, and the honest LND limits (channel,
|
||||||
|
revocation and HTLC keys cannot be air-gapped).
|
||||||
|
|
||||||
|
### Project invariants
|
||||||
|
- `CLAUDE.md` — rootless Podman only; secrets are manifest-declared; **migrations never
|
||||||
|
destroy data**; verify on a real node before any tag; commit+push every unit of work.
|
||||||
|
- `docs/UNIFIED-TASK-TRACKER.md` — carries R-01..R-15; the 9 items added by quick task
|
||||||
|
260731-upz are the out-of-scope remainder of this audit.
|
||||||
|
|
||||||
|
### Code that is the subject of the phase
|
||||||
|
- `core/archipelago/src/api/rpc/middleware.rs:5-40` — `UNAUTHENTICATED_METHODS`, the list D-04
|
||||||
|
sweeps.
|
||||||
|
- `core/archipelago/src/identity.rs:79-114` (`from_seed`, the unconditional overwrite) and
|
||||||
|
`:117` (`key_exists`, the guard that exists and is never called on this path).
|
||||||
|
- `core/archipelago/src/auth.rs:182-210` — `is_onboarding_complete` and its auto-heal drift logic.
|
||||||
|
- `core/archipelago/src/api/rpc/seed_rpc.rs:93-120` (generate, with the lock + TTL fast-path)
|
||||||
|
and `:226-265` (restore).
|
||||||
|
- `core/archipelago/src/api/rpc/bitcoin.rs:161-294` — `handle_bitcoin_init_wallet_from_seed`.
|
||||||
|
- `image-recipe/_archived/build-auto-installer-iso.sh:1647`,`:1659`,`:1663` — the fail-open
|
||||||
|
regeneration and its marker.
|
||||||
|
- `image-recipe/build-debian-iso.sh:40` — **proves `_archived/` is live**, not dead code.
|
||||||
|
|
||||||
|
</canonical_refs>
|
||||||
|
|
||||||
|
<code_context>
|
||||||
|
## Existing Code Insights
|
||||||
|
|
||||||
|
### Reusable Assets
|
||||||
|
- `NodeIdentity::key_exists` (`identity.rs:117`) — the guard D-03 needs, already written and
|
||||||
|
already correct; it is simply never called on the seed path.
|
||||||
|
- `system.factory-reset` (`system/handlers.rs:575`) and `auth.resetOnboarding` (`auth.rs:272`)
|
||||||
|
— both already authenticated; D-02's recovery path is existing behaviour, not new code.
|
||||||
|
- The wallet is already a **descriptor** wallet (`bitcoin.rs:207` passes `descriptors=true`),
|
||||||
|
which is the correct foundation for D-07 — the defect is which key goes into it, not the
|
||||||
|
wallet type.
|
||||||
|
- The xprv string is already zeroized on both the error path (`bitcoin.rs:222`) and the success
|
||||||
|
path (`:284`) — in-memory handling is careful and should be preserved by the migration.
|
||||||
|
|
||||||
|
### Established Patterns
|
||||||
|
- Pre-auth onboarding endpoints are an intentional design, not an oversight — the node has no
|
||||||
|
user account until `auth.setup` runs. Any fix must preserve first-boot onboarding on a fresh
|
||||||
|
node; this is the single biggest way to get KEY-01 wrong.
|
||||||
|
- `handle_seed_generate`'s `ONBOARDING_MNEMONIC` lock + `MNEMONIC_TTL` idempotent fast-path
|
||||||
|
(`seed_rpc.rs:93-120`) is **retry-storm protection, not authorization** — written because the
|
||||||
|
web client retries every 4s on slow first-boot hardware and aborts at 15s. A new rate limit
|
||||||
|
must not reintroduce the "error at the DID-creation screen" failure it was added to prevent.
|
||||||
|
|
||||||
|
### Integration Points
|
||||||
|
- The gate sits between `middleware.rs`'s dispatch decision and the `seed_rpc.rs` /
|
||||||
|
`backup` / `auth` handlers.
|
||||||
|
- KEY-02 spans the ISO builder (build host) and node boot (systemd), not the Rust daemon —
|
||||||
|
a different verification surface from KEY-01/KEY-03.
|
||||||
|
- KEY-03 touches the Bitcoin Core container's wallet, so it interacts with the app lifecycle,
|
||||||
|
not just the daemon.
|
||||||
|
|
||||||
|
</code_context>
|
||||||
|
|
||||||
|
<specifics>
|
||||||
|
## Specific Ideas
|
||||||
|
|
||||||
|
- **The regression test is the deliverable, not the patch.** For KEY-01 there must be a test
|
||||||
|
that fails against today's code: an already-onboarded node rejects `seed.restore` with
|
||||||
|
attacker-supplied words, and its `node_key` and `nostr_secret` are byte-identical afterwards.
|
||||||
|
This mirrors the standard the entropy fix in `8b51b7e2` was held to (a known-answer test that
|
||||||
|
could not exist before the change).
|
||||||
|
- `image-recipe/_archived/` must **not** be "tidied up" or relocated as part of KEY-02. It is
|
||||||
|
live — `build-debian-iso.sh:40` execs it — and the audit notes that treating it as dead would
|
||||||
|
have hidden F-03 entirely.
|
||||||
|
- Concurrent agents share this git tree and push to `main`: stage explicitly by path, never
|
||||||
|
`git add -A` / `git commit -a`.
|
||||||
|
|
||||||
|
</specifics>
|
||||||
|
|
||||||
|
<deferred>
|
||||||
|
## Deferred Ideas
|
||||||
|
|
||||||
|
- **F-04 (Medium)** — mnemonic crosses the RPC boundary and is held in memory 10 minutes over
|
||||||
|
plaintext-capable HTTP. Tracked as R-07, itself marked PHASE-sized by the audit. Its natural
|
||||||
|
home is a follow-up phase alongside the loopback/TLS confinement question, not here.
|
||||||
|
- **F-05 (Medium)** — `Argon2::default()` (19 MiB / t=2) contradicts ADR-005's stated 64 MB / 3
|
||||||
|
iterations. Needs either a versioned envelope migration or an ADR amendment (R-06).
|
||||||
|
- **F-06 (Medium)** — release master mnemonic passed via env var / stdout in the signing
|
||||||
|
ceremony (R-08). Deliberately scheduled separately: it *is* the signing ceremony.
|
||||||
|
- **F-07 (Medium)** — no `cargo audit` / `cargo deny` in CI; two `rand` majors coexist (R-05).
|
||||||
|
- **F-09 / F-10 / F-11 (Low / Informational)** — TOTP modulo bias (R-12), container
|
||||||
|
`generated_secrets` using `thread_rng()` (R-13, blocked on another agent's uncommitted work in
|
||||||
|
`container/secrets.rs`), and the `Math.random()` comment (R-14).
|
||||||
|
- **The archi-dev-box test node** (shapes A and B) —
|
||||||
|
`.planning/todos/pending/2026-08-01-archi-dev-box-as-fresh-test-node-without-iso.md`.
|
||||||
|
Sequenced after this phase; shape A is the natural harness for KEY-04, since a second
|
||||||
|
instance boots un-onboarded, which is exactly the state D-03's gate must distinguish.
|
||||||
|
|
||||||
|
### Reviewed Todos (not folded)
|
||||||
|
- *Fedimint gateway must not install with a pre-set password* — matched on `area: security`,
|
||||||
|
but already fixed by a concurrent agent in commit `42652547` (FED-07, Phase 1). Not folded.
|
||||||
|
- *Connected-nodes list scroll height*, *FIPS/Tor pills on cloud files* — matched only on
|
||||||
|
incidental keywords (`must`, `2026`, `fips`); both are UI work belonging to Phase 1's UIFIX
|
||||||
|
series. Not folded.
|
||||||
|
|
||||||
|
</deferred>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Phase: 10-key-material-hardening*
|
||||||
|
*Context gathered: 2026-08-01*
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
# Phase 10: Key-Material Hardening - Discussion Log
|
||||||
|
|
||||||
|
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||||
|
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
|
||||||
|
|
||||||
|
**Date:** 2026-08-01
|
||||||
|
**Phase:** 10-key-material-hardening
|
||||||
|
**Areas discussed:** Re-key policy for a live node, Gate signal, First-boot fail-closed behavior, Fleet scope, Wallet migration, Signing path, Rollout, 10-01 scope
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Re-key policy for a live node (KEY-01)
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Hard refuse; reset first | Endpoints permanently closed once the node holds identity keys; re-key via the authenticated `system.factory-reset`, then normal onboarding restore. No authorization logic on the pre-auth path at all. | ✓ |
|
||||||
|
| Allow with an authenticated session | Keep endpoints usable post-onboarding behind a session + password re-entry. Convenient for in-place recovery, but a session-fixation or CSRF bug becomes a node takeover. | |
|
||||||
|
| Allow only with physical presence | Local console / button-press window. Strongest guarantee, needs new plumbing, awkward for headless nodes reached over Tailscale. | |
|
||||||
|
|
||||||
|
**User's choice:** Hard refuse; reset first
|
||||||
|
**Notes:** Verified mid-discussion that `system.factory-reset` (`dispatcher.rs:469`) and `auth.resetOnboarding` (`auth.rs:272`) are both absent from `UNAUTHENTICATED_METHODS`, i.e. already authenticated. This made "reset first" a real existing path rather than something the phase would have to build, and confirmed it is not itself a gate bypass.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gate signal (KEY-01)
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Refuse if either says onboarded | Check both `key_exists` (on-disk key file) and `is_onboarding_complete` (JSON flag); refuse if either indicates onboarded. Fails safe when they disagree. | ✓ |
|
||||||
|
| Key file on disk only | Trust only `key_exists` — the artefact actually being protected, unflippable without filesystem access. | |
|
||||||
|
| Onboarding flag only | Trust only `is_onboarding_complete` — matches how the rest of the app reasons, but the flag is writable by `auth.resetOnboarding` and can drift. | |
|
||||||
|
|
||||||
|
**User's choice:** Refuse if either says onboarded
|
||||||
|
**Notes:** The drift case is real, not hypothetical — `auth.rs:196-207` already contains auto-heal logic that infers completion from `setup_complete` + `password_hash` precisely because the flag can be wrong.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## First-boot fail-closed behavior (KEY-02)
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Retry, then fail closed | Retry with backoff; on continued failure refuse to start and show a loud error. Survives transient causes without ever silently shipping fleet-shared keys. | ✓ |
|
||||||
|
| Fail closed immediately | First failure refuses to start. Absolutely safe; a transient condition bricks a brand-new node with no self-recovery. | |
|
||||||
|
| Boot locked, with a visible alert | Starts but refuses onboarding/network exposure until fixed. Most forgiving; risks a dismissed warning and a node running on shared keys. | |
|
||||||
|
|
||||||
|
**User's choice:** Retry, then fail closed
|
||||||
|
**Notes:** Current behaviour is the inverse of all three options — fail-open, with the completion marker written even when regeneration fails (`build-auto-installer-iso.sh:1647`, `:1659`, `:1663`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fleet scope (KEY-02)
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Fix builder + remediate existing | Fix the ISO builder for future flashes and add boot-time detection + one-time regeneration reaching existing nodes via OTA. | ✓ |
|
||||||
|
| Fix the ISO builder only | Future flashes get unique keys; deployed nodes keep what they have. | |
|
||||||
|
| Builder now, remediation as its own phase | Ship the builder fix here; scope live-node rotation separately since it can break `known_hosts` and Tailscale-based access. | |
|
||||||
|
|
||||||
|
**User's choice:** Fix builder + remediate existing
|
||||||
|
**Notes:** Chosen as the only option that ends the exposure rather than stopping it from growing. The `known_hosts` / remote-access risk raised in option 3 does not disappear with this choice — it was carried into CONTEXT.md as D-06's `one-way` reversibility rating with a required checkpoint, rather than being deferred.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wallet migration (KEY-03)
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Migrate with parity proof | Recreate watch-only (`disable_private_keys=true`, xpub + key origin), verify balance and UTXO-set parity before/after, retain old `wallet.dat` for rollback. | ✓ |
|
||||||
|
| New wallets only | Future initialisations are watch-only; existing nodes keep the private key until the user re-creates their wallet. | |
|
||||||
|
| Migrate, but user-confirmed per node | Same migration behind an explicit UI opt-in. | |
|
||||||
|
|
||||||
|
**User's choice:** Migrate with parity proof
|
||||||
|
**Notes:** Matches the audit's R-04 and CLAUDE.md's "migrations never destroy data". New-wallets-only was rejected because it leaves the exposure on exactly the nodes holding real funds.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Signing path (KEY-03)
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Daemon signs PSBTs, air-gap opt-in | Daemon signs with the seed it already holds in the encrypted envelope; send UX unchanged; the spending key exists in one place instead of two. External-signer path stays opt-in. | ✓ |
|
||||||
|
| Daemon signs, nothing else | Remove the duplicate copy, one hot signing path, defer all external-signer work. | |
|
||||||
|
| External signer required | Core goes watch-only, signing happens off-node. Strongest posture, changes how every user spends, needs hardware. | |
|
||||||
|
|
||||||
|
**User's choice:** Daemon signs PSBTs, air-gap opt-in
|
||||||
|
**Notes:** Because the opt-in path must actually be reachable, the missing `[fingerprint/derivation]` key-origin annotation on the current descriptors (`bitcoin.rs:230-231`) was pulled into scope as D-09 rather than left as a follow-up — without it no hardware signer can locate its key in a PSBT.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rollout
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| Emergency point release | Cut a release carrying 10-01 alone once verified on the dev pair. | |
|
||||||
|
| Dev pair now, decide after | Deploy and verify, then choose emergency vs scheduled after seeing the real diff. | |
|
||||||
|
| Ride the next scheduled OTA | Fold into the next planned release with the rest of Phase 10 and pending 1.7.119 work. | ✓ |
|
||||||
|
|
||||||
|
**User's choice:** Ride the next scheduled OTA
|
||||||
|
**Notes:** Claude recommended the emergency release; the user chose the scheduled OTA. Recorded in CONTEXT.md as D-10 with its consequence stated plainly — the exposure window for a Critical, remotely-reachable finding is now set by OTA cadence rather than by when the fix is verified. D-11 keeps 10-01 independently shippable so this stays a scheduling choice, not a technical constraint, if the timing changes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10-01 scope
|
||||||
|
|
||||||
|
| Option | Description | Selected |
|
||||||
|
|--------|-------------|----------|
|
||||||
|
| One gate over all identity-mutating endpoints | Sweep every `UNAUTHENTICATED_METHODS` entry that mutates identity or credentials behind the same gate with one shared test suite. | ✓ |
|
||||||
|
| Only seed.generate + seed.restore | Keep 10-01 minimal — exactly the endpoints F-01 names — others get their own plan. | |
|
||||||
|
| Gate the mutating ones, document the rest | Gate writers; record an evidence-backed verdict for read-only-ish endpoints. | |
|
||||||
|
|
||||||
|
**User's choice:** One gate over all identity-mutating endpoints
|
||||||
|
**Notes:** The "document the rest" behaviour from option 3 was folded into the chosen option for endpoints that turn out not to mutate — a verdict with evidence rather than a behaviour change.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Claude's Discretion
|
||||||
|
|
||||||
|
- Error code / JSON-RPC response shape for a refused call.
|
||||||
|
- Rate-limit shape and thresholds (constrained by the retry-storm trap).
|
||||||
|
- Test organisation and file placement.
|
||||||
|
- Whether the shared gate is middleware-layer, a per-handler helper, or both.
|
||||||
|
|
||||||
|
## Deferred Ideas
|
||||||
|
|
||||||
|
- F-04 mnemonic-over-RPC exposure (R-07) — PHASE-sized in its own right.
|
||||||
|
- F-05 Argon2 params vs ADR-005 (R-06) — needs a versioned envelope migration or an ADR amendment.
|
||||||
|
- F-06 ceremony mnemonic via env/stdout (R-08) — deliberately scheduled separately.
|
||||||
|
- F-07 no `cargo audit`/`cargo deny` in CI (R-05).
|
||||||
|
- F-09 / F-10 / F-11 low+informational items (R-12, R-13 — blocked on another agent's uncommitted work — and R-14).
|
||||||
|
- archi-dev-box as a fresh test node, shapes A and B — sequenced after this phase; shape A is the natural harness for KEY-04.
|
||||||
Reference in New Issue
Block a user