276 lines
18 KiB
Markdown
276 lines
18 KiB
Markdown
---
|
|
phase: 01-federation-mesh-hardening
|
|
plan: 09
|
|
type: execute
|
|
wave: 5
|
|
depends_on: ["01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08"]
|
|
files_modified:
|
|
- .planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md
|
|
- core/archipelago/src/federation/storage.rs
|
|
- core/archipelago/src/federation/sync.rs
|
|
- core/archipelago/src/api/rpc/federation/handlers.rs
|
|
- core/archipelago/src/fips/dial.rs
|
|
- core/archipelago/src/mesh/mod.rs
|
|
- core/archipelago/src/api/rpc/mesh/typed_messages.rs
|
|
autonomous: true
|
|
requirements: [FED-03, FED-01]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "A findings document exists listing every issue the structured review of the federation/fleet area and the mesh area produced, with file and line citations"
|
|
- "Every finding carries exactly one disposition — fixed, or deferred with a written reason — and no finding is left without one (FED-03 ordering edge)"
|
|
- "Every reviewed area appears in the document, including areas where the review produced no findings, recorded as reviewed with none rather than omitted (FED-03 empty edge)"
|
|
- "Every federation and mesh claim in the codebase concerns document is re-verified against current code and git history before being filed as a finding or dismissed, with the evidence cited (FED-03 adjacency edge)"
|
|
- "Every finding marked fixed cites the commit and the test or command that demonstrates the fix"
|
|
- "The known-fixed claims are recorded as already-fixed with their commit, not re-fixed"
|
|
prohibitions:
|
|
- statement: "A finding MUST NOT be closed as fixed without evidence a reader can re-run — a disposition of fixed always cites a commit and a verifying command or test name, never an assertion alone"
|
|
category: transparency
|
|
- statement: "A finding MUST NOT be dropped silently — an item judged out of scope is recorded as deferred with the reason and the phase or requirement that owns it, never deleted from the list"
|
|
category: transparency
|
|
artifacts:
|
|
- path: .planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md
|
|
provides: "The FED-03 structured review output with per-finding dispositions"
|
|
min_lines: 60
|
|
key_links:
|
|
- from: .planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md
|
|
to: .planning/codebase/CONCERNS.md
|
|
via: "each federation/mesh concern is re-verified and cross-referenced by its finding id"
|
|
pattern: "CONCERNS"
|
|
---
|
|
|
|
<objective>
|
|
Run the structured code review FED-03 requires over the federation/fleet area and the mesh area, and
|
|
close it out: every finding fixed or explicitly deferred with a reason.
|
|
|
|
Purpose: FED-03. RESEARCH.md Pitfall 2 is the governing constraint — `.planning/codebase/CONCERNS.md`
|
|
is NOT current truth for this phase. At least two of its federation claims were already fixed on main
|
|
before this phase started (the tombstone-write-swallowed claim was fixed in `01cbec27`; the
|
|
peer-joined DID path does verify an ed25519 signature). Re-fixing an already-fixed bug wastes the
|
|
review and risks reverting working code, so every claim gets a fresh code read plus a git-history
|
|
check before it is filed or dismissed.
|
|
Output: `01-REVIEW-FINDINGS.md` with a disposition on every finding, the small findings fixed inline,
|
|
and the phase's code deployed to the dev pair so plan 01-10's verification has something to test.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@$HOME/.claude/gsd-core/workflows/execute-plan.md
|
|
@$HOME/.claude/gsd-core/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/STATE.md
|
|
@.planning/codebase/CONCERNS.md
|
|
@.planning/codebase/ARCHITECTURE.md
|
|
@.planning/phases/01-federation-mesh-hardening/01-RESEARCH.md
|
|
@.planning/phases/01-federation-mesh-hardening/01-01-SUMMARY.md
|
|
@.planning/phases/01-federation-mesh-hardening/01-05-SUMMARY.md
|
|
@.planning/phases/01-federation-mesh-hardening/01-07-SUMMARY.md
|
|
</context>
|
|
|
|
## Artifacts this phase produces
|
|
|
|
Created or changed by **this plan**:
|
|
|
|
| Symbol | Kind | File |
|
|
|---|---|---|
|
|
| `01-REVIEW-FINDINGS.md` | new findings document with per-finding dispositions | `.planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md` |
|
|
| finding-dependent fixes | code changes in the reviewed areas | files listed in `files_modified` |
|
|
| dev-pair deployment | the phase build running on archi-dev-box and x250-dev, sha256-verified | (no repo file) |
|
|
|
|
<tasks>
|
|
|
|
<task type="tracer">
|
|
<name>Task 1: End-to-end — one finding from discovery to closed disposition</name>
|
|
<files>.planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md</files>
|
|
<read_first>
|
|
- `.planning/codebase/CONCERNS.md` — the federation and mesh entries: the node-removal tombstone
|
|
gap (cited at `federation/storage.rs:180-197`), the incomplete federation DID validation, the
|
|
unbounded harness curl (cited as a multinode test-harness issue), the node-list dedup scaling
|
|
note, and the mesh radio configuration boot race.
|
|
- `.planning/phases/01-federation-mesh-hardening/01-RESEARCH.md` — the "Common Pitfalls" section
|
|
(especially Pitfall 2's instruction to `git log -p` each cited range before acting) and the
|
|
"Assumptions Log" rows A1, A2, and A5. A5 in particular is explicitly NOT independently
|
|
re-verified and must be re-checked here.
|
|
- The SUMMARYs from plans 01-01, 01-05, and 01-07 — what has already been fixed in this phase,
|
|
so those items are recorded as fixed-by-this-phase rather than re-opened.
|
|
</read_first>
|
|
<action>
|
|
Create `01-REVIEW-FINDINGS.md` with a table whose columns are: finding id (`F-01`, `F-02`, …),
|
|
area (federation store / federation sync / federation RPC / FIPS-transport dial / mesh core /
|
|
mesh RPC surface), severity, the file and line citation, the evidence (what was read and what
|
|
`git log -p` or `git blame` showed), the disposition (`fixed` / `already-fixed` / `deferred`), and
|
|
for `fixed` the commit plus the verifying command or test name, or for `deferred` the reason and
|
|
the owning phase or requirement.
|
|
|
|
Then take exactly one finding all the way through in this task, to prove the pipeline: re-verify
|
|
the codebase-concerns claim about incomplete federation DID validation — specifically the part
|
|
RESEARCH.md flags as un-re-verified, whether anything checks proof of ownership of a DID on first
|
|
contact, as opposed to the peer-joined path which does verify a signature. Read the add-node and
|
|
peer-joined paths in the federation RPC handlers and run `git log -p` on them. File the finding
|
|
with its evidence, then either fix it (if the fix is contained and does not touch federation trust
|
|
or join cryptography beyond what correctness requires — CONTEXT.md's scope fence) or defer it with
|
|
a written reason naming what a fix would touch and why that belongs elsewhere.
|
|
|
|
Record the two claims RESEARCH.md already verified as fixed with their commits, as `already-fixed`
|
|
rows, so a future reader does not re-open them.
|
|
</action>
|
|
<verify>
|
|
<automated>test -f .planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md && grep -Eq '^\| *F-01' .planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md && cd core && cargo test -p archipelago federation</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- `01-REVIEW-FINDINGS.md` exists with a header row and at least one `F-NN` row.
|
|
- The first finding's row has a non-empty evidence cell naming the command that produced it and a non-empty disposition cell.
|
|
- Rows exist recording both already-fixed claims with their commit hashes.
|
|
- `cd core && cargo test -p archipelago federation` exits 0 (if the first finding was fixed here, its test is included).
|
|
- The SUMMARY quotes the `git log -p` output excerpt that decided the first finding.
|
|
</acceptance_criteria>
|
|
<done>The findings document exists and one finding has travelled the full path from claim to evidence to disposition.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Complete the review across both areas and disposition every finding</name>
|
|
<files>.planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md, core/archipelago/src/federation/storage.rs, core/archipelago/src/federation/sync.rs, core/archipelago/src/api/rpc/federation/handlers.rs, core/archipelago/src/fips/dial.rs, core/archipelago/src/mesh/mod.rs, core/archipelago/src/api/rpc/mesh/typed_messages.rs</files>
|
|
<read_first>
|
|
- `core/archipelago/src/federation/` — `storage.rs`, `sync.rs`, `types.rs`, `invites.rs`, `mod.rs`
|
|
as left by plans 01-01, 01-05, and 01-06.
|
|
- `core/archipelago/src/api/rpc/federation/handlers.rs` — the full RPC surface, including the
|
|
peer-joined, peer-did-changed, and peer-address-changed signature-verification paths.
|
|
- `core/archipelago/src/fips/dial.rs` and the transport dial/fallback path — the FIPS-to-Tor
|
|
fast-fail behaviour FED-03 names as in scope.
|
|
- `core/archipelago/src/mesh/mod.rs` — `purge_federation_peer`, `upsert_federation_peer`,
|
|
`seed_federation_peers_into_mesh`; and `core/archipelago/src/api/rpc/mesh/typed_messages.rs`
|
|
as left by plans 01-04 and 01-07.
|
|
- `.planning/codebase/CONCERNS.md` — every remaining federation and mesh entry.
|
|
- `.planning/phases/01-federation-mesh-hardening/01-02-SUMMARY.md` — the mock-parity residual
|
|
class that plan flagged as a candidate finding for this review.
|
|
- `.planning/phases/01-federation-mesh-hardening/01-CONTEXT.md` — the scope fence: do not touch
|
|
federation trust or join cryptography beyond what removal and sync correctness require, and no
|
|
data-destroying migrations.
|
|
</read_first>
|
|
<action>
|
|
Review each area in turn and add its findings to the document. For each codebase-concerns claim,
|
|
do the fresh read plus `git log -p` on the cited range BEFORE filing or dismissing it, and put
|
|
that evidence in the row — a finding that merely restates a concerns bullet without fresh
|
|
evidence is not admissible.
|
|
|
|
Areas to cover, each of which must appear in the document even when it produced no findings —
|
|
record those as reviewed with none rather than omitting them: federation store, federation sync,
|
|
federation RPC surface, FIPS and transport dial, mesh core, mesh RPC surface.
|
|
|
|
Required specific checks, each of which becomes a row:
|
|
- The mock-parity residual class flagged in the plan 01-02 SUMMARY (a mock case that exists but
|
|
returns a differently-shaped success object than the daemon).
|
|
- Whether the paid-tick grep from plan 01-03 still finds exactly the two surfaces it found at
|
|
planning time, or whether a third has appeared.
|
|
- The unbounded-curl concern: confirm it belongs to the multinode test harness and defer it to
|
|
the phase that owns that requirement, with that phase named in the reason.
|
|
- The node-list dedup scaling note: disposition it with the peer counts this fleet actually runs.
|
|
- The mesh radio configuration boot race: confirm against current code and defer if it needs real
|
|
LoRa hardware, naming that as the reason.
|
|
|
|
Fix findings that are contained — a bounded change inside the reviewed area with a test — and
|
|
commit each as its own focused commit per CLAUDE.md. Defer anything that would breach the
|
|
CONTEXT.md scope fence, require hardware this session lacks, or belong to another phase, and write
|
|
the reason and the owner in the row. Every row ends with exactly one disposition.
|
|
|
|
Finish with a short summary section stating the counts: findings filed, fixed, already-fixed, and
|
|
deferred; and a line stating that the counts sum to the number of rows.
|
|
</action>
|
|
<verify>
|
|
<automated>cd core && cargo test -p archipelago && cd ../neode-ui && npx vitest run && node scripts/mock-rpc-parity.mjs</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- `cd core && cargo test -p archipelago` exits 0.
|
|
- `cd neode-ui && npx vitest run` exits 0 and `node scripts/mock-rpc-parity.mjs` exits 0.
|
|
- Every row in `01-REVIEW-FINDINGS.md` has a non-empty disposition cell — verify by counting rows and counting non-empty disposition cells and asserting the two numbers match; record both numbers in the SUMMARY.
|
|
- All six named areas appear in the document.
|
|
- The summary section's counts sum to the row count.
|
|
- Every `fixed` row cites a commit hash and a verifying command or test name.
|
|
- Every `deferred` row has a non-empty reason and names an owning phase or requirement.
|
|
</acceptance_criteria>
|
|
<done>Both areas are reviewed, every finding has exactly one evidenced disposition, and the contained fixes are committed.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 3: Build and deploy the phase to the dev pair, sha256-verified</name>
|
|
<precondition>archi-dev-box and x250-dev are reachable over the fleet network — confirm with a bounded connectivity probe to each before starting; if either is unreachable, halt rather than deploying to a partial pair.</precondition>
|
|
<files>.planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md</files>
|
|
<read_first>
|
|
- `scripts/deploy-to-target.sh` — the established deploy path and the environment variable it
|
|
takes for the target. Read it fully before running it; do not hand-roll a deploy.
|
|
- `CLAUDE.md` — the build instructions (cargo from `core/`; frontend build outputs to
|
|
`web/dist/neode-ui/`; grep the built bundle for new strings because the build can silently
|
|
no-op) and the deploy discipline (dev pair before any OTA).
|
|
- The project memory note on deploying via service restart while containers are running — confirm
|
|
what the deploy script does about restarts before running it, and record the answer.
|
|
</read_first>
|
|
<action>
|
|
Build the backend from `core/` and the frontend from `neode-ui/`, then grep the built frontend
|
|
bundle for a string introduced by this phase to prove the build is not stale.
|
|
|
|
Deploy to archi-dev-box and then to x250-dev using the established deploy script, one at a time.
|
|
After each, verify the deployed binary's sha256 matches the locally built artifact, and record
|
|
both hashes. After each deploy, check that the node's app containers are still running and record
|
|
the result — a deploy that takes containers down is a finding, not a success.
|
|
|
|
Add a short deployment section to `01-REVIEW-FINDINGS.md` recording: the built artifact hashes,
|
|
the two target hostnames, the per-target sha256 match, the container-survival result, and the
|
|
frontend bundle grep result.
|
|
|
|
Do not deploy to any other fleet node, do not cut a release, and do not publish an OTA — this
|
|
phase ends at the dev pair plus the verification in plan 01-10.
|
|
</action>
|
|
<verify>
|
|
<automated>grep -Eq 'sha256' .planning/phases/01-federation-mesh-hardening/01-REVIEW-FINDINGS.md</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- `cd core && cargo build --release -p archipelago` exits 0 and `cd neode-ui && npm run build` exits 0.
|
|
- The built frontend bundle contains a string introduced by this phase — assert with a grep over `web/dist/neode-ui/assets/` for the badge ring class name added in plan 01-03.
|
|
- The deployment section records two target hostnames, two sha256 pairs that match, and a container-survival result per target.
|
|
- No release tag was created and no OTA manifest was published — confirmed by `git tag --points-at HEAD` producing no output, recorded in the SUMMARY.
|
|
</acceptance_criteria>
|
|
<done>The phase's code is running on both dev-pair nodes, provably the artifact that was built, with containers intact.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<threat_model>
|
|
## Trust Boundaries
|
|
|
|
| Boundary | Description |
|
|
|----------|-------------|
|
|
| developer workstation → fleet node (deploy) | A built binary crosses onto a live node over SSH |
|
|
| review process → codebase | A fix applied during review changes federation trust-adjacent code |
|
|
|
|
## STRIDE Threat Register
|
|
|
|
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
|
|-----------|----------|-----------|----------|-------------|-----------------|
|
|
| T-01-37 | Tampering | a deployed binary differing from the one built and tested | high | mitigate | Per-target sha256 comparison against the local artifact, both hashes recorded (Task 3) |
|
|
| T-01-38 | Denial of Service | a deploy restarting the service and killing running app containers | high | mitigate | The established deploy script is read before use and container survival is checked and recorded per target; a container loss is filed as a finding |
|
|
| T-01-39 | Elevation of Privilege | a review fix loosening federation trust or join verification | high | mitigate | CONTEXT.md's scope fence is a required read; findings needing trust-code changes are deferred with the reason rather than patched here; the full test suite gates each fix |
|
|
| T-01-40 | Repudiation | a finding quietly dropped so a known issue leaves no trace | medium | mitigate | The row-count-equals-disposition-count check and the summing counts section make an omission detectable; the prohibitions above state the rule |
|
|
| T-01-41 | Information Disclosure | deploy credentials or node passwords committed while recording deployment evidence | high | mitigate | The deployment section records hostnames and hashes only; per CLAUDE.md, never commit secrets. Stage by explicit path and review the diff before committing |
|
|
</threat_model>
|
|
|
|
<verification>
|
|
- `cd core && cargo test -p archipelago` — green.
|
|
- `cd neode-ui && npx vitest run && node scripts/mock-rpc-parity.mjs && npm run build` — green.
|
|
- `01-REVIEW-FINDINGS.md` row count equals its disposition count, and the summary counts sum to it.
|
|
- Both dev-pair nodes report a matching sha256 and surviving containers.
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- A findings document covers six named areas, including those with no findings.
|
|
- Every finding has exactly one evidenced disposition; fixed rows cite commit and test, deferred rows cite reason and owner.
|
|
- Every codebase-concerns federation/mesh claim was re-verified against current code and git history before being filed or dismissed.
|
|
- The phase is deployed to the dev pair, sha256-verified, with containers intact and no release cut.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
Create `.planning/phases/01-federation-mesh-hardening/01-09-SUMMARY.md` when done.
|
|
Stage by explicit path, commit each fix separately, and `git push gitea-ai main`.
|
|
</output>
|