docs(10-06): summary — Phase 10 complete, with the gate-effectiveness caveat
All five KEY-05 layers landed. Records the two things a reader would otherwise get wrong: - the 2 boot_reconciler test failures in the full-suite run are parallel-load flakes (4/4 pass in isolation), not regressions; - layer (b)'s clippy gate is LIVE but not yet EFFECTIVE, because 42 pre-existing warnings already fail the same -D warnings step. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a3283cffb4
commit
a850bb6cdd
+9
-9
@@ -5,15 +5,15 @@ milestone_name: milestone
|
||||
current_phase: 09
|
||||
current_phase_name: BotFights Platform Upgrade
|
||||
status: planning
|
||||
stopped_at: Phase 10 planned (5 plans, 2 waves) — ready to execute; F-01 verified but NOT yet fixed
|
||||
last_updated: "2026-08-02T10:15:10.221Z"
|
||||
last_activity: 2026-07-31
|
||||
last_activity_desc: Phase 02 complete, transitioned to Phase 09
|
||||
stopped_at: Phase 10 COMPLETE (10-01..10-06); OTA prep in progress — dev-pair deploy + macaroon rotation outstanding
|
||||
last_updated: "2026-08-02T21:30:00.000Z"
|
||||
last_activity: 2026-08-02
|
||||
last_activity_desc: 10-06 KEY-05 entropy enforcement shipped; LND macaroon rotation + Tor auto-onion fix
|
||||
progress:
|
||||
total_phases: 11
|
||||
completed_phases: 1
|
||||
total_plans: 44
|
||||
completed_plans: 27
|
||||
total_plans: 45
|
||||
completed_plans: 30
|
||||
percent: 9
|
||||
---
|
||||
|
||||
@@ -165,6 +165,6 @@ Decisions are logged in PROJECT.md (10 locked ADRs in the `<decisions>` block +
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-08-02T10:15:10.179Z
|
||||
Stopped at: Phase 10 planned (5 plans, 2 waves) — ready to execute; F-01 verified but NOT yet fixed
|
||||
Resume file: .planning/phases/10-key-material-hardening/10-01-PLAN.md
|
||||
Last session: 2026-08-02T21:30:00.000Z
|
||||
Stopped at: Phase 10 complete; OTA prep — dev-pair deploy + macaroon rotation outstanding
|
||||
Resume file: .planning/phases/10-key-material-hardening/10-06-SUMMARY.md
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
phase: 10-key-material-hardening
|
||||
plan: 06
|
||||
subsystem: entropy
|
||||
tags: [security, key-material, entropy, rng, KEY-05, F-10a, F-07, R-05, R-09, R-13]
|
||||
status: complete
|
||||
requires:
|
||||
- "docs/security/ENTROPY-SEED-AUDIT-2026-07-31.md F-10a (the deliberately-unclassified raw match table), F-07, F-02, F-09"
|
||||
- "10-01 (F-01 onboarding gate) and 10-05 (F-13 Core wallet deletion) committed first"
|
||||
provides:
|
||||
- "crate::entropy — sealed KeyGenRng allowlist, degenerate-entropy predicate, CSPRNG-readiness ledger"
|
||||
- "core/clippy.toml — crate-wide compile-time ban on rand::random / rand::thread_rng"
|
||||
- "core/deny.toml — change-detecting rand duplicate-major rule, grandfathered 2026-08-02"
|
||||
- "docs/security/KEY-05-ENTROPY-ENFORCEMENT.md — per-site classification + observed gate evidence"
|
||||
affects:
|
||||
- "core/archipelago/src/entropy.rs (new)"
|
||||
- "core/archipelago/src/seed.rs"
|
||||
- "core/archipelago/src/session.rs"
|
||||
- "core/archipelago/src/storage_crypto.rs"
|
||||
- "core/archipelago/src/credentials/store.rs"
|
||||
- "core/archipelago/src/wallet/bdhke.rs"
|
||||
- "core/archipelago/src/mesh/x3dh.rs"
|
||||
- "core/archipelago/src/container/secrets.rs"
|
||||
- "core/archipelago/src/totp.rs"
|
||||
- "17 further call-site files (see the commit)"
|
||||
tech-stack:
|
||||
added:
|
||||
- "cargo-deny 0.20.2 (pinned; installed from crates.io in CI)"
|
||||
patterns:
|
||||
- "Sealed trait as an allowlist: supertrait in a private module, so no other module can add a member"
|
||||
- "Hardcoded pre-migration ciphertext vectors from an INDEPENDENT implementation, because a same-process round trip proves self-consistency rather than compatibility"
|
||||
- "Degenerate-entropy predicate restricted to shapes with closed-form false-positive bounds — no heuristics, no entropy estimators"
|
||||
- "Gates proven by observation (inject -> observe failure -> revert -> observe pass), never by assumption"
|
||||
key-files:
|
||||
created:
|
||||
- "core/archipelago/src/entropy.rs"
|
||||
- "core/clippy.toml"
|
||||
- "core/deny.toml"
|
||||
modified:
|
||||
- "docs/security/KEY-05-ENTROPY-ENFORCEMENT.md"
|
||||
- ".github/workflows/ci.yml"
|
||||
- "23 source files under core/archipelago/src (see commit 09a1f762)"
|
||||
decisions:
|
||||
- "cargo-deny wired as bans-only; advisories deliberately NOT enabled (human checkpoint, Task 5) — F-07's advisory half stays OPEN"
|
||||
- "cargo-deny installed from crates.io at a pinned 0.20.2 rather than via EmbarkStudios/cargo-deny-action, because that action exposes no version-pinning input and an unpinned supply-chain checker reproduces the very failure shape this plan removes"
|
||||
- "generate_mnemonic_with switched from generate_in_with to from_entropy so the draw is inspectable at the seam; equivalence held by the pre-existing known-answer test"
|
||||
- "The blinding factor in bdhke.rs is deliberately NOT routed through the guard — intercepting it would mean reimplementing secp256k1 rejection sampling, a larger correctness risk than the guard buys"
|
||||
- "totp.rs migrated SOURCE only; the % charset.len() reduction and 32-char charset untouched (R-12 stays deferred, bias is presently zero)"
|
||||
- "session token minting aborts rather than returns on a degenerate draw, because the callers live in files this plan does not own and widening them to Result is an API change out of scope"
|
||||
metrics:
|
||||
duration: "resumed session; migration pre-existing uncommitted, gates + evidence completed 2026-08-02"
|
||||
completed: 2026-08-02
|
||||
tasks_completed: 6
|
||||
tasks_total: 6
|
||||
---
|
||||
|
||||
# 10-06 — KEY-05 entropy enforcement
|
||||
|
||||
## What shipped
|
||||
|
||||
Five layers, all landed:
|
||||
|
||||
| Layer | What | Where |
|
||||
|---|---|---|
|
||||
| (a) | Every production key/nonce/token draw names `rand::rngs::OsRng` at its own call site; the mnemonic seam is bound to a **sealed** `KeyGenRng` allowlist | `entropy.rs`, 23 source files |
|
||||
| (b) | Crate-wide compile-time ban on `rand::random` / `rand::thread_rng` | `core/clippy.toml` |
|
||||
| (c) | `rand` duplicate-major rule that is change-detecting, grandfathered | `core/deny.toml`, CI step |
|
||||
| (d) | Degenerate-entropy predicate refusing all-zero / all-identical / ±1-counter draws | `entropy::draw_key_bytes` |
|
||||
| (e) | Durable kernel-CSPRNG readiness record at master-seed generation (R-09) | `entropy::record_csprng_readiness` |
|
||||
|
||||
`impl rand::CryptoRng` count in the crate is now **zero** — the false marker promise at the old
|
||||
`seed.rs:656` is retired, as the roadmap required.
|
||||
|
||||
## Why this was worth doing when nothing was broken
|
||||
|
||||
Nothing in F-10a's table is broken today: on the pinned `rand 0.8.5` both banned entry points
|
||||
resolve to a ChaCha12 CSPRNG seeded from `getrandom(2)`. What they lacked was a *stated* backend —
|
||||
fixed by dependency and build configuration rather than by the calling code, with no compile error
|
||||
if it changed. That is the structural shape ("T1") behind the 2026-07-30 COLDCARD entropy defect,
|
||||
and here the blast radius included Cashu blinded-key-exchange values, X3DH prekey material, session
|
||||
bearer tokens and a ChaCha20-Poly1305 nonce.
|
||||
|
||||
## Evidence
|
||||
|
||||
- `cargo test -p archipelago`: **1068 passed, 2 failed**. Both failures are
|
||||
`container::boot_reconciler` timing tests in a file this plan never touches; **re-run in
|
||||
isolation they pass 4/4 in 0.84s**, so they are full-suite parallel-load flakes, not regressions.
|
||||
- Format compatibility proven with **hardcoded pre-migration ciphertext vectors** produced by an
|
||||
independent RFC 8439 implementation — a same-process seal/open round trip would have passed even
|
||||
if the envelope had changed.
|
||||
- Both gates observed working (inject → fail → revert → pass for clippy; remove grandfather →
|
||||
exit 2 → restore → exit 0 for cargo-deny). Full transcripts in the evidence doc.
|
||||
|
||||
## Open, and deliberately so
|
||||
|
||||
1. **⚠️ Layer (b)'s gate is live but not yet EFFECTIVE.** The tree carries **42 pre-existing clippy
|
||||
warnings** unrelated to KEY-05 (unused imports, dead code, ~39 style lints). Under the CI step's
|
||||
`-D warnings` every one is already an error, so that step cannot pass today for reasons that
|
||||
predate this plan. The ban is correctly configured and proven to fire, but until a dedicated
|
||||
lint-clearing pass lands, a new banned RNG call is one error among many rather than the
|
||||
distinctive build-stopper the design intends. **Recommended next follow-up.**
|
||||
2. **F-07's advisory half stays OPEN** (bans-only policy).
|
||||
3. **`core/models` is outside the enforcement graph** — not a workspace member, so no
|
||||
`disallowed-methods` entry can reach its two matches. Stated limitation, not an omission.
|
||||
4. **F-09/R-12 and F-11/R-14 remain deferred.**
|
||||
5. **Sealing does not prevent an edit to `entropy.rs` itself** — it raises the act from an invisible
|
||||
default to a reviewable change to the one file whose purpose is this guarantee. That is the
|
||||
honest claim; "impossible" would not be.
|
||||
|
||||
Nothing already generated is suspect: the previous source was, and remains, `getrandom(2)`-backed.
|
||||
This plan removes a *future* failure mode and implies no re-generation of existing key material.
|
||||
Reference in New Issue
Block a user