docs(hardening): tick §B/§C/§H items landed 2026-07-08 + two new findings

Secrets→podman-secrets verified on .228; release-path guards e77ccff0; test
creds/timeouts 380f4f19; mempool umbrella lifecycle fix 161a6e4d. New open
items: manifests hardcoding secrets in plain environment, orphan umbrella
container cleanup follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago 2026-07-08 19:36:27 -04:00
parent 161a6e4dbd
commit e706d446e7

View File

@ -107,13 +107,14 @@ end-to-end on real hardware.
No test installs the previous version, points it at a staged 1.8.0 manifest, applies,
and asserts health + rollback. This is the top release risk for an OTA release. A
two-VM (or two-node) harness is enough.
- [ ] 🟡 **Guard the frontend-build-no-op in the *actual* release path.** The
`ui-dist-version` grep guard (`tests/release/run.sh:82`) is behind `--with-build`, which
`scripts/create-release.sh:90` never passes → a stale frontend can ship with a valid
sha256. Call `run.sh --with-build --manifest` from create-release (or fold the grep in).
- [ ] 🟢 **publish-release-assets verifies size, not sha256** (`publish-release-assets.sh:97`).
Add a HEAD/GET sha256 compare so a size-correct/content-wrong mirror asset fails the
publish gate.
- [x] 🟡 **Guard the frontend-build-no-op in the *actual* release path.** DONE 2026-07-08
(`e77ccff0`): the grep guard is folded directly into `create-release.sh` right after its
own `npm run build` (post-version-bump, pre-packaging — calling `run.sh --with-build` at
stage 0 would have checked the pre-bump version). Verified both ways against the real
dist: passes on the current version, trips on a missing one.
- [x] 🟢 **publish-release-assets verifies size, not sha256.** DONE 2026-07-08 (`e77ccff0`):
the verify loop now downloads each published asset and compares sha256 (and size)
against the manifest. Verified live against the v1.7.99-alpha assets on the vps2 mirror.
---
@ -149,8 +150,11 @@ modules; production request/boot paths are essentially panic-free. The real risk
public; zmq 28332/28333 should get the same look — unauthenticated). ⚠ May break
external wallets pointed straight at nodeIP:8332 — needs a user call + on-node gate
re-run, so NOT changed drive-by from the dev box.
- [x] 🟡 **Move secret env out of plaintext channels → podman secrets.** DONE 2026-07-05
(code + unit tests; needs the on-node gate re-run before it counts as verified):
- [x] 🟡 **Move secret env out of plaintext channels → podman secrets.** DONE 2026-07-05,
**VERIFIED ON .228 2026-07-08**: recreate wave settled (only fedimint-gateway lagged —
restart-sensitive, converged via a controlled quadlet restart, healthy, 0 plaintext
password vars in inspect); btcpay inspect carries no secret values; 17 quadlet unit
files use `Secret=` lines. Original notes:
secret env no longer merges into `environment` — it would land in `podman inspect`
AND as plaintext `Environment=` lines in Quadlet unit files on disk (the worse leak).
New pipeline: `expand_and_partition_env` taints plain entries that interpolate
@ -185,6 +189,19 @@ modules; production request/boot paths are essentially panic-free. The real risk
runtime config.
- [ ] 🟢 **Apply the seccomp/apparmor profile**`security/src/container_policies.rs:71` is a
TODO; the profile is defined but never applied to podman.
- [ ] 🟡 **Manifests that hardcode secrets in plain `environment:` bypass the whole secret
pipeline** (found during the 2026-07-08 .228 leak check): indeedhub-api/-ffmpeg ship
`AES_MASTER_SECRET=0123456789abcdef…` and photoprism `PHOTOPRISM_ADMIN_PASSWORD=archipelago`
as literal plaintext in quadlet unit files; grafana's `GF_SECURITY_ADMIN_PASSWORD=$${…}`
reference never expands. Fix = declare them as `generated_secrets`/`secret_env` in the
manifests — which means catalog regen + re-sign + republish (catalog overlay supremacy).
- [x] 🟠 **Legacy `mempool` umbrella id destroys the split stack on stop→start (quadlet).**
FOUND by the first quadlet-mode gate run on .228 (2026-07-08), FIXED `161a6e4d`:
orchestrator start/stop/restart now alias `mempool` → the split members whenever the
umbrella manifest was dropped (same alias install already used); podman-5
`no such object` phrasing added to all 3 `is_missing_container_error` classifiers.
Follow-up (open): reconciler-side cleanup of an orphan umbrella `mempool` container
when the split stack owns the frontend, so the stale-tile state can't arise at all.
---
@ -312,10 +329,13 @@ media (latest artifact only one minor behind).
- [ ] 🟡 **Make the release gate run the full Rust suite** (or hard-require a green CI sha).
`tests/release/run.sh:101` runs only a 6-module slice because the full 1000-test suite
hangs PTYs on the dev box → 994 tests unverified at release time if CI is stale.
- [ ] 🟡 **Add `--max-time` to `node_rpc()`** (`tests/multinode/lib/multinode.bash`) — a slow
server-side RPC hangs the whole multinode suite with no feedback.
- [ ] 🟢 **De-hardcode creds/IPs in tests** (`tests/multinode/smoke.sh:32`,
`remote-lifecycle.sh:136`); snapshot/restore node baseline between destructive iterations
- [x] 🟡 **Add `--max-time` to `node_rpc()`.** DONE 2026-07-08 (`380f4f19`): login + rpc get
`--connect-timeout 10 --max-time 120` (override `MULTINODE_RPC_TIMEOUT`). Verified live:
.116 login/rpc OK; an unroutable node fails in 10s instead of hanging.
- [x] 🟢 **De-hardcode creds in tests.** DONE 2026-07-08 (`380f4f19`): multinode suites no
longer commit node passwords — `*_PW` env required, auto-loaded from git-ignored
`tests/multinode/.env` (`.env.example` documents the shape). Still open from this
bullet: snapshot/restore node baseline between destructive iterations
(teardown currently only clears `/tmp` session files).
---
@ -354,7 +374,8 @@ media (latest artifact only one minor behind).
6. **Before public GA only (NOT alpha/beta):** remove + rotate the Anthropic key (§F) —
intentionally left in for frictionless AI during alpha/beta.
*Last updated: 2026-07-02 PM (hardening session 1: §A anchor+catalog `1977bdef`, §A
manifest signature `51647b21`, §D origin checks `206d5fe8`, §C swallowed writes +
§I tombstone fix — this commit). Update this line + tick boxes with commit shas as
items land.*
*Last updated: 2026-07-08 PM (hardening session 3: §C secrets verified on .228,
§B release-path guards `e77ccff0`, §H test creds/timeouts `380f4f19`, mempool
umbrella lifecycle fix `161a6e4d` from the first quadlet-mode gate run; new
finding: manifests hardcoding secrets in plain `environment:`). Update this
line + tick boxes with commit shas as items land.*