Archipelago — open-source initial import
This commit is contained in:
@@ -0,0 +1,370 @@
|
||||
---
|
||||
phase: 10-key-material-hardening
|
||||
plan: 05
|
||||
subsystem: bitcoin-signing
|
||||
tags: [security, key-material, psbt, lnd, bitcoin-core, F-13, KEY-03]
|
||||
status: complete
|
||||
requires:
|
||||
- "10-CONTEXT.md D-07b (delete, do not migrate) and D-07c (deferred BDK cold vault)"
|
||||
- "docs/security/ENTROPY-SEED-AUDIT-2026-07-31.md F-13 / R-04"
|
||||
provides:
|
||||
- "No daemon code path writes the BIP-84 account private key into Bitcoin Core"
|
||||
- "psbt_key_origin_report + the key_origin field on lnd.create-psbt"
|
||||
- "docs/security/KEY-03-SIGNING-POSTURE.md — the evidence-backed signing-posture record"
|
||||
affects:
|
||||
- "core/archipelago/src/api/rpc/bitcoin.rs"
|
||||
- "core/archipelago/src/api/rpc/dispatcher.rs"
|
||||
- "core/archipelago/src/api/rpc/lnd/wallet.rs"
|
||||
- "core/archipelago/src/seed.rs"
|
||||
- "docs/security/PSBT-SIGNING-ARCHITECTURE.md"
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Best-effort inspection that degrades to null, never to an error, on a funds path"
|
||||
- "Programmatically-built PSBT test fixtures instead of pasted opaque base64"
|
||||
- "Tombstone comments that deliberately omit the deleted symbol name so grep-based regression checks stay durable"
|
||||
key-files:
|
||||
created:
|
||||
- "docs/security/KEY-03-SIGNING-POSTURE.md"
|
||||
modified:
|
||||
- "core/archipelago/src/api/rpc/bitcoin.rs"
|
||||
- "core/archipelago/src/api/rpc/dispatcher.rs"
|
||||
- "core/archipelago/src/api/rpc/lnd/wallet.rs"
|
||||
- "core/archipelago/src/seed.rs"
|
||||
- "docs/security/PSBT-SIGNING-ARCHITECTURE.md"
|
||||
decisions:
|
||||
- "F-13 closed by deleting the Core wallet path outright rather than rewriting it watch-only (D-07b)"
|
||||
- "derive_bitcoin_xprv retained with #[allow(dead_code)] and a stated D-07c reason rather than deleted as cruft"
|
||||
- "Verdict recorded: no fleet node is provisioned watch-only, so an external signer cannot meaningfully sign a default node's PSBT today"
|
||||
- "Census conclusion scoped to examined nodes only — not generalised to the fleet while 6 nodes are unreachable"
|
||||
metrics:
|
||||
duration: "~3h15m (dominated by cargo target-dir contention with three concurrent agents)"
|
||||
completed: 2026-08-02
|
||||
tasks_completed: 3
|
||||
tasks_total: 3
|
||||
---
|
||||
|
||||
# Phase 10 Plan 05: Key-Material Hardening (KEY-03) Summary
|
||||
|
||||
Deleted the uncalled Bitcoin Core wallet handler that imported the BIP-84 account **xprv** into
|
||||
`wallet.dat` (F-13), and made LND's PSBT round trip report the BIP-32 key-origin data an external
|
||||
signer needs — with an honest, evidence-backed record of what that round trip does and does not
|
||||
deliver.
|
||||
|
||||
**Status: 3 of 3 tasks complete.** Task 3's blocking `checkpoint:human-verify` was satisfied by
|
||||
operator-run verification (the plan is `autonomous: false`; the checkpoint was not self-approved —
|
||||
execution stopped, the operator ran the census, and the result was recorded).
|
||||
|
||||
## Commits
|
||||
|
||||
| # | SHA | Task | Message |
|
||||
|---|---|---|---|
|
||||
| 1 | `96229268` | Task 1 (tracer) | `fix(10-05): delete the Bitcoin Core wallet path that duplicated the spending key (F-13, D-07b)` |
|
||||
| 2 | `26299874` | Task 2 | `feat(10-05): report BIP-32 key origin on lnd.create-psbt, and record the honest signing posture (D-07b/D-09)` |
|
||||
| 3 | `0d513a0e` | Task 3 | `docs(10-05): record the Core-wallet fleet census — 4 nodes clear, 6 unchecked (D-07b)` |
|
||||
|
||||
Not pushed, not tagged, not deployed, per the execution brief. The SUMMARY itself is deliberately
|
||||
uncommitted.
|
||||
|
||||
## Task 1 — Core wallet path deleted
|
||||
|
||||
### No-caller search output (re-established, not inherited)
|
||||
|
||||
```
|
||||
$ grep -rn 'bitcoin\.init-wallet-from-seed' core/ neode-ui/src scripts/ web/ apps/ tests/ docs/
|
||||
core/archipelago/src/api/rpc/dispatcher.rs:122: "bitcoin.init-wallet-from-seed" => {
|
||||
|
||||
$ grep -rn 'handle_bitcoin_init_wallet_from_seed' core/ neode-ui/src scripts/ web/ apps/ tests/ docs/
|
||||
core/archipelago/src/api/rpc/bitcoin.rs:161: pub(super) async fn handle_bitcoin_init_wallet_from_seed(
|
||||
core/archipelago/src/api/rpc/dispatcher.rs:123: self.handle_bitcoin_init_wallet_from_seed(params).await
|
||||
docs/UNIFIED-TASK-TRACKER.md:208: §8 Phase 1). `handle_bitcoin_init_wallet_from_seed` passes
|
||||
docs/security/ENTROPY-SEED-AUDIT-2026-07-31.md:607:(`handle_bitcoin_init_wallet_from_seed`):
|
||||
docs/security/PSBT-SIGNING-ARCHITECTURE.md:147: `handle_bitcoin_init_wallet_from_seed`, `core/archipelago/src/api/rpc/bitcoin.rs:161-294`).
|
||||
```
|
||||
|
||||
Exactly the expected result: one occurrence of the method name (its own dispatcher registration),
|
||||
two of the symbol in code (definition + dispatch call). The three remaining symbol hits are prose
|
||||
in documentation, not callers. **No third caller — the deletion's premise held**, so no checkpoint
|
||||
was raised.
|
||||
|
||||
Also re-verified independently:
|
||||
|
||||
- **Across all of `neode-ui/src`, every `bitcoin.*` RPC call is read-only status**: `bitcoin.getinfo`
|
||||
(14 sites), `bitcoin.prune-status` (3), `bitcoin.onion` (1). Zero `bitcoin.*` wallet operations.
|
||||
- **The endpoint is absent from `UNAUTHENTICATED_METHODS`** (`middleware.rs:5-40`) and additionally
|
||||
called `verify_password` (`bitcoin.rs:176-179`) — authenticated *and* password-gated, so F-13
|
||||
was key-at-rest duplication, never a remotely reachable endpoint.
|
||||
|
||||
### What changed
|
||||
|
||||
- Deleted `handle_bitcoin_init_wallet_from_seed` (`bitcoin.rs:161-295`) and the
|
||||
`"bitcoin.init-wallet-from-seed"` dispatch arm (`dispatcher.rs:122-124`).
|
||||
- Removed the now-unused `use zeroize::Zeroize;` from `bitcoin.rs`.
|
||||
- `seed::derive_bitcoin_xprv` retained with `#[allow(dead_code)]` and a doc line naming **D-07c**
|
||||
as the reason (deferred BDK cold vault), so the next reader does not remove it as cruft.
|
||||
- Created `docs/security/KEY-03-SIGNING-POSTURE.md`.
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
| Criterion | Result |
|
||||
|---|---|
|
||||
| `cargo build -p archipelago` succeeds | **PASS** (1m47s, 3 pre-existing warnings, none in this plan's files) |
|
||||
| `grep -rn 'handle_bitcoin_init_wallet_from_seed' core/ --include=*.rs` → no matches | **PASS** (see deviation 1) |
|
||||
| `grep -n 'init-wallet-from-seed' dispatcher.rs` → only the `lnd.` arm | **PASS** — `145: "lnd.init-wallet-from-seed"` only |
|
||||
| `cargo test -p archipelago seed::` still passes | **PASS** — 25 passed, 0 failed, incl. `test_bitcoin_xprv_deterministic` and `test_full_derivation_from_known_mnemonic` |
|
||||
| Doc exists, cites D-07b and D-07c, carries the search output | **PASS** — 397 lines; 6× D-07b, 4× D-07c |
|
||||
| `cargo clippy -p archipelago -- -D warnings` clean | **PARTIAL** — see deviation 2 |
|
||||
|
||||
## Task 2 — LND PSBT key-origin reporting
|
||||
|
||||
### What was added
|
||||
|
||||
`core/archipelago/src/api/rpc/lnd/wallet.rs`:
|
||||
|
||||
| Symbol | Line | Kind |
|
||||
|---|---|---|
|
||||
| `PsbtKeyOriginReport` | `:1169` | struct `{ input_count, inputs_with_key_origin, all_inputs_have_key_origin }` |
|
||||
| `psbt_key_origin_report` | `:1186` | `fn(&str) -> Result<PsbtKeyOriginReport>` |
|
||||
| call site + warn | `:705` | best-effort, degrades to `null` |
|
||||
| response field | `:737` | `"key_origin": { … } \| null` |
|
||||
|
||||
An input counts as carrying key origin when either `bip32_derivation` or `tap_key_origins` is
|
||||
non-empty. A zero-input PSBT reports `all_inputs_have_key_origin: false` rather than vacuous truth,
|
||||
since an inputless PSBT cannot be signed and "yes, a signer has everything it needs" would be
|
||||
actively misleading.
|
||||
|
||||
### Tests (new, 3 passing)
|
||||
|
||||
```
|
||||
running 3 tests
|
||||
test api::rpc::lnd::wallet::tests::psbt_with_derivations_reports_key_origin ... ok
|
||||
test api::rpc::lnd::wallet::tests::psbt_without_derivations_reports_no_key_origin ... ok
|
||||
test api::rpc::lnd::wallet::tests::malformed_psbt_is_an_error_not_a_panic ... ok
|
||||
|
||||
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 1014 filtered out; finished in 0.00s
|
||||
```
|
||||
|
||||
Fixtures are built programmatically with the `bitcoin` crate (`Psbt::from_unsigned_tx` over a
|
||||
one-input `Transaction`, then a `(Fingerprint, DerivationPath)` inserted on input 0) rather than
|
||||
pasted as opaque base64, so the tests explain themselves.
|
||||
|
||||
### Round-trip coverage map (recorded in the doc)
|
||||
|
||||
| # | Step | `file:line` | Tested? |
|
||||
|---|---|---|---|
|
||||
| 1 | Fund — `lnd.create-psbt` → `/v2/wallet/psbt/fund` | `lnd/wallet.rs:605`, `dispatcher.rs:136` | **No** |
|
||||
| 1a | Inspect — key origin | `lnd/wallet.rs:1186`, `:1169`, `:705`, `:737` | **Yes** (3 tests) |
|
||||
| 2 | Export — base64 to UI | `rpc-client.ts:407-423`, `Web5SendReceiveModals.vue:308` | **Partial** (`rpc-client.test.ts:319-323` asserts the method name only) |
|
||||
| 3 | Sign offline | not in this repo | N/A |
|
||||
| 4 | Import — paste signed PSBT | `Web5SendReceiveModals.vue:102`, `:419-424` | **No** |
|
||||
| 5 | Finalize — `/v2/wallet/psbt/finalize` | `lnd/wallet.rs:743`, `dispatcher.rs:137` | **No** |
|
||||
| 6 | Broadcast — `/v2/wallet/tx` | `lnd/wallet.rs:795` | **No** |
|
||||
| — | Rate limits 5/300s | `rate_limit.rs:68-69` | **No** |
|
||||
|
||||
**One of six steps has automated coverage.** There is also **no air-gap transport** — no animated
|
||||
QR, no `.psbt` file exchange; export/import is copy-paste of base64 in a textarea. Nothing has
|
||||
been verified against real signing hardware. The doc states all of this plainly rather than
|
||||
describing an untested path as verified.
|
||||
|
||||
### The watch-only verdict (the question that decides whether this is an air gap)
|
||||
|
||||
**Verdict: NO — on a default Archipelago node an externally-held signer cannot meaningfully sign
|
||||
a PSBT from `lnd.create-psbt`, because LND holds the private keys for every input it selects.**
|
||||
|
||||
Evidence:
|
||||
|
||||
1. The PSBT is funded from **LND's own wallet** — `/v2/wallet/psbt/fund` (`lnd/wallet.rs:672`)
|
||||
selects LND's UTXOs.
|
||||
2. **LND's wallet on every node is a full key-holding wallet, created locally.**
|
||||
`container::lnd::ensure_wallet_initialized` (`container/lnd.rs:86`) → `init_wallet_via_rest`
|
||||
POSTs `/v1/initwallet` with a `cipher_seed_mnemonic` (`container/lnd.rs:504-516`) and persists
|
||||
the aezeed backup (`:523-525`).
|
||||
3. **The generated `lnd.conf` carries no `remotesigner.*` block** — `container/lnd.rs:64-79` writes
|
||||
`bitcoin.node=bitcoind` plus bitcoind RPC settings and nothing else.
|
||||
4. **Nothing in the repo provisions watch-only LND.** A search of `apps/`, `scripts/`,
|
||||
`core/archipelago/src` and `image-recipe/` for `remotesigner`, `createwatchonly` and
|
||||
`nochainbackend` returns **zero matches**.
|
||||
|
||||
So what ships today is the PSBT **transport**, complete and rate-limited, **not air-gapped
|
||||
custody**. The gap between here and D-08's opt-in path is **provisioning, not plumbing**
|
||||
(PSBT-SIGNING-ARCHITECTURE §8 Phase 6, out of scope for Phase 10).
|
||||
|
||||
### Honesty statement (its own subsection in the doc)
|
||||
|
||||
Lightning channel, revocation and HTLC keys are **not air-gappable at all** — they must sign in
|
||||
real time to answer counterparty commitments; a routing node cannot tolerate human-in-the-loop
|
||||
signing. LND remote signing **relocates** them to a hardened host; it does **not** cool them. No
|
||||
wording in either document implies otherwise.
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
| Criterion | Result |
|
||||
|---|---|
|
||||
| ≥3 new tests including the with/without pair | **PASS** — 3 passed |
|
||||
| `cargo clippy -p archipelago` clean for this plan's files | **PASS** — zero diagnostics in `bitcoin.rs`, `dispatcher.rs`, `seed.rs`, `lnd/wallet.rs` |
|
||||
| `git diff core/archipelago/Cargo.toml` empty | **PASS** — no dependency added |
|
||||
| `grep -c 'key_origin' lnd/wallet.rs` ≥ 4 | **PASS** — 26 |
|
||||
| `handle_lnd_create_raw_tx` unchanged | **PASS** — diff hunks at `+701`, `+737`, `+1161`, `+1211`; `create_raw_tx` starts at `:825` and `finalize_psbt` spans `:743-823`, so no hunk falls inside either |
|
||||
| PSBT-SIGNING-ARCHITECTURE diff confined to the banner; §5.4 byte-identical | **PASS** — single hunk `@@ -2,0 +3,28 @@`; `diff` of §5.4 against HEAD reports IDENTICAL |
|
||||
|
||||
## Task 3 — Fleet census: **RUN 2026-08-02, no escalation**
|
||||
|
||||
`type="checkpoint:human-verify" gate="blocking"`, plan `autonomous: false`. Execution stopped at
|
||||
the checkpoint; the operator ran the read-only procedure across the Tailscale fleet and supplied
|
||||
the results, which are recorded in `docs/security/KEY-03-SIGNING-POSTURE.md` § *Fleet census*.
|
||||
|
||||
### Examined — 4 nodes, all CLEAR
|
||||
|
||||
| Node | Tailscale IP | Container | `listwalletdir` | `archipelago` wallet? | Default wallet |
|
||||
|---|---|---|---|---|---|
|
||||
| archi-dev-box | `100.69.68.39` | `bitcoin-knots` | 2× `gatewayd-*`, `""` | **No** | `blank: true`, keypool 0, txcount 0, balance 0 |
|
||||
| shorty-s (`.228`) | `100.64.204.114` | `bitcoin-knots` | 1× `gatewayd-*`, `""` | **No** | same |
|
||||
| archy-x250-beta | `100.72.136.5` | `bitcoin-core` | 1× `gatewayd-*`, `""` | **No** | same |
|
||||
| archy-x250-pa | `100.89.209.89` | `bitcoin-core` | 1× `gatewayd-*`, `""` | **No** | same |
|
||||
|
||||
`listwallets` → `[""]` on every node. The only named wallets are Fedimint `gatewayd-*`. The one
|
||||
loaded (unnamed, default) wallet does report `private_keys_enabled: true`, but also `blank: true`,
|
||||
`keypoolsize: 0`, `txcount: 0`, `balance: 0.00000000`, `descriptors: true` — Core's own statement
|
||||
that **no key was ever imported into it and no transaction ever touched it.**
|
||||
|
||||
**The result holds across two container vintages** (`bitcoin-knots` ×2, `bitcoin-core` ×2), so it
|
||||
is a property of the fleet rather than four copies of one image behaving identically.
|
||||
|
||||
**No key material appeared in any output; `listdescriptors true` was never run.**
|
||||
|
||||
Supporting history: `git log -S "init-wallet-from-seed"` scoped to `dispatcher.rs` and
|
||||
`neode-ui/src` returns exactly one commit — `19dcfd4f`, the commit that **added** it. No frontend
|
||||
wrapper was ever written.
|
||||
|
||||
### Not examined — 6 nodes, recorded with reasons
|
||||
|
||||
| Node | Tailscale IP | Why |
|
||||
|---|---|---|
|
||||
| framework-pt | `100.65.115.109` | `Permission denied (publickey,password)` — SSH password rotated, not held |
|
||||
| archipelago-1 | `100.82.34.38` | `Permission denied (publickey,password)` |
|
||||
| archipelago | `100.70.96.88` | `Permission denied (publickey,password)` |
|
||||
| archy-dev-pa | `100.64.83.15` | `Permission denied (publickey,password)` |
|
||||
| archipelago-5 | `100.114.134.21` | Timed out during SSH banner exchange |
|
||||
| archy-x250-dev | `100.113.100.55` | Offline — Tailscale last seen 2 days prior |
|
||||
|
||||
Password auth was **deliberately not attempted** on any of these: several fleet nodes lock PAM
|
||||
quickly on a wrong password, and locking out an in-use production node is a worse outcome than an
|
||||
incomplete census.
|
||||
|
||||
### Conclusion, at the strength the evidence supports
|
||||
|
||||
> **No examined node holds a wallet created by the deleted handler, and no examined node holds any
|
||||
> wallet with keys or funds.**
|
||||
|
||||
Deliberately **not** generalised to "the fleet is clear" while six nodes are unknown — an
|
||||
unexamined node is unknown, not safe. F-13 is closed **by deletion** regardless: the code that
|
||||
could create such a wallet is gone from every future build. The census adds that no such wallet
|
||||
was found anywhere anyone could look. **Nothing to escalate; the stop-on-finding rule stands** for
|
||||
the remaining nodes.
|
||||
|
||||
### Standing item
|
||||
|
||||
The six unchecked nodes are homed in **`docs/UNIFIED-TASK-TRACKER.md`** as *"Finish the
|
||||
Core-wallet fleet census — 6 nodes unchecked"*, not only in the security doc, so it is visible to
|
||||
someone who is not already reading one. Flagged there as a natural fold-in for **KEY-04's on-node
|
||||
work** (which needs node access anyway) but tracked independently so it does not vanish if KEY-04
|
||||
is re-scoped. That file's stale R-04/F-13 entry — which still described the deleted handler and a
|
||||
watch-only migration as pending work — was corrected to done-by-deletion in the same commit.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### 1. [Rule 2 — preserved a durable regression check] Tombstone comments reworded to omit the deleted symbol name
|
||||
|
||||
**Found during:** Task 1 acceptance verification.
|
||||
**Issue:** I first wrote tombstone comments in `bitcoin.rs`, `dispatcher.rs` and `seed.rs` that
|
||||
named `handle_bitcoin_init_wallet_from_seed` / `bitcoin.init-wallet-from-seed` verbatim. That
|
||||
broke two acceptance criteria (`grep … → no matches`) — and, more importantly, it would have
|
||||
**permanently defeated the greps as a regression check**: any future reintroduction of the symbol
|
||||
would be masked by the comment that warns against reintroducing it.
|
||||
**Fix:** Reworded all three to describe the deleted thing ("the Bitcoin Core wallet-init handler
|
||||
that used to live here") and point at `docs/security/KEY-03-SIGNING-POSTURE.md`, which carries the
|
||||
full symbol name. Guidance preserved, greps clean, regression check durable.
|
||||
**Commit:** `96229268`
|
||||
|
||||
### 2. [Out of scope — pre-existing] `cargo clippy -- -D warnings` fails in `archipelago-openwrt`
|
||||
|
||||
**Found during:** Task 1 verification.
|
||||
**Issue:** `cargo clippy -p archipelago -- -D warnings` fails with 4 lint errors — 2×
|
||||
`consider using sort_by_key`, 1× `str::trim` before `str::split_whitespace`, 1× `creates an owned
|
||||
instance just for comparison` — **all in `archipelago-openwrt`**, a crate this plan does not touch.
|
||||
**Assessment:** Pre-existing and out of scope under the scope boundary rule. Neither of my commits
|
||||
touches that crate (`git log 96229268^..HEAD -- core/archipelago-openwrt` → 0 commits), and my
|
||||
crate is not a dependency of it, so the failure is independent of this work by construction.
|
||||
**Action:** Not fixed. `cargo clippy -p archipelago --message-format=short` reports **zero
|
||||
diagnostics** in this plan's four files, which is the criterion that speaks to this work.
|
||||
**Recommend:** a separate cleanup task for `archipelago-openwrt`'s lints so `-D warnings` can be
|
||||
used as a gate again.
|
||||
|
||||
### 3. [Process — atomicity preserved] SUMMARY not committed, and the doc split across commits
|
||||
|
||||
`docs/security/KEY-03-SIGNING-POSTURE.md` is a single file carrying all three tasks' content. To
|
||||
keep the commits genuinely atomic, it was staged truncated to its Task 1 sections for commit
|
||||
`96229268`, restored in full for `26299874`, and extended with the census for `0d513a0e`.
|
||||
`.planning/phases/10-key-material-hardening/10-05-SUMMARY.md` is left uncommitted per the
|
||||
execution brief.
|
||||
|
||||
### 4. [Rule 2 — corrected a record this change invalidated] Updated `docs/UNIFIED-TASK-TRACKER.md`
|
||||
|
||||
**Found during:** Task 3 write-up.
|
||||
**Issue:** the tracker's R-04/F-13 entry still described `handle_bitcoin_init_wallet_from_seed`,
|
||||
its `disable_private_keys = false` and a watch-only migration with balance/UTXO parity as pending
|
||||
work — all of which now describe code that does not exist. A stale open item pointing at deleted
|
||||
line numbers actively misleads the next reader.
|
||||
**Fix:** marked it done-by-deletion with a pointer to `KEY-03-SIGNING-POSTURE.md`, and added the
|
||||
six unchecked census nodes as a new standing item.
|
||||
**Scope note:** `docs/UNIFIED-TASK-TRACKER.md` is not in the plan's `files_modified`. It was
|
||||
verified clean (`git status --porcelain`) before editing, and staged by path.
|
||||
**Commit:** `0d513a0e`
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None. No placeholder values, mock data or unwired components were introduced.
|
||||
|
||||
Two *absences* are documented rather than stubbed, because they are honest statements of scope
|
||||
rather than placeholders: there is no air-gap transport (QR / file exchange) and no automated
|
||||
coverage for round-trip steps 1, 4, 5 and 6. Both are recorded in
|
||||
`docs/security/KEY-03-SIGNING-POSTURE.md` as untested/unimplemented, and neither is presented as
|
||||
working.
|
||||
|
||||
## Threat Flags
|
||||
|
||||
None. No new network endpoint, auth path, file-access pattern or schema change at a trust boundary
|
||||
was introduced. The plan's threat register is addressed as follows:
|
||||
|
||||
| Threat | Disposition |
|
||||
|---|---|
|
||||
| T-10-41 (xprv in `wallet.dat`) | **Mitigated** — the only code path that wrote it is deleted; census found no pre-existing wallet on 4 examined nodes, 6 remain unknown and are tracked |
|
||||
| T-10-42 (census prints a private key) | **Mitigated** — `listdescriptors true` banned by name in the doc and never run; only read-only RPCs used; no key material appeared in any output. Password auth was not attempted on locked-out nodes, so the census also avoided locking a production node out |
|
||||
| T-10-43 (automated migration rewrites a funded wallet) | **Mitigated** — no migration built, none run; stop-on-finding rule recorded and never triggered |
|
||||
| T-10-44 (opaque signer refusal) | **Mitigated** — `key_origin` on the response plus a `warn!` names the condition before the user reaches the device |
|
||||
| T-10-45 (docs claim custody they don't deliver) | **Mitigated** — watch-only verdict recorded with 4 evidence points; Lightning-keys subsection added; PSBT-SIGNING-ARCHITECTURE banner records Phase 1 superseded |
|
||||
| T-10-46 (inspection breaks a send) | **Mitigated** — best-effort, degrades to `null`; finalize and `create_raw_tx` untouched, asserted by diff scope |
|
||||
| T-10-47 (RPC surface change) | **Accepted** — no-caller search re-run, not inherited |
|
||||
| T-10-SC (dependency install) | **Accepted** — no dependency added; `Cargo.toml` diff empty |
|
||||
|
||||
## Notes for the next agent
|
||||
|
||||
- **The tree is shared with three other agents.** All staging was explicit by path;
|
||||
`.planning/STATE.md` (another agent's uncommitted edit) was never staged. `cargo` runs contended
|
||||
heavily (load average 25-30, one test build took 34 minutes); one intermediate test build failed
|
||||
with 16 errors in `federation/*` from another agent's mid-edit state, which resolved on its own.
|
||||
- **`STATE.md` / `ROADMAP.md` / `REQUIREMENTS.md` were deliberately not updated.** Another agent
|
||||
holds an uncommitted edit to `STATE.md` throughout, and the execution brief scoped this run to
|
||||
commits only. KEY-03's requirement should be marked complete by whoever reconciles phase state,
|
||||
noting that the census's six unchecked nodes are tracked separately and are not a blocker on
|
||||
KEY-03 itself (F-13 is closed by deletion, which is build-wide and does not depend on the
|
||||
census).
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- Files verified present: `docs/security/KEY-03-SIGNING-POSTURE.md`,
|
||||
`docs/security/PSBT-SIGNING-ARCHITECTURE.md`, `docs/UNIFIED-TASK-TRACKER.md`,
|
||||
`core/archipelago/src/api/rpc/lnd/wallet.rs`, this SUMMARY.
|
||||
- Commits verified in git: `96229268`, `26299874`, `0d513a0e`.
|
||||
- No file belonging to this plan is left uncommitted (the SUMMARY is uncommitted deliberately,
|
||||
per the execution brief).
|
||||
Reference in New Issue
Block a user