git mv STATUS*/BACKLOG*/JOURNAL*/DECISIONS.md -> machine-docs/. README.md kept at root (operator decision). Updated in-repo refs: README (status line + lint section + Loop-state section) and docs/install.md -> machine-docs/... Safe to move now: launch.sh already has resolve_state() (prefers machine-docs/ else root) used by every STATUS/REVIEW read, and the running watchdog (pid 133191) was restarted AFTER that update, so it is location-agnostic. scripts/lint.sh -> lint: PASS post-move. Adversary moves its own REVIEW*.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
57 lines
5.1 KiB
Markdown
57 lines
5.1 KiB
Markdown
# BACKLOG — Phase 1c
|
||
|
||
Single-writer rule (§6.1): Builder edits `## Build backlog`; Adversary edits `## Adversary findings`.
|
||
|
||
## Build backlog
|
||
|
||
Method W1–W6 from the phase plan §5. Each milestone ends with an Adversary gate.
|
||
|
||
- [x] **W2 — Secrets repo + cert into git.** (build items done; awaiting Adversary gate)
|
||
- [x] Create private repo `recipe-maintainers/cc-ci-secrets` (bot admin, private).
|
||
- [x] Move secrets + add wildcard cert+key as sops secrets (root `secrets.yaml`; sha256 verified).
|
||
- [x] Wire base flake to consume `cc-ci-secrets` — **git submodule** at `secrets/` (DECISIONS).
|
||
- [x] secrets.nix: `wildcard_cert`/`wildcard_key` → `path=/var/lib/ci-certs/live/*`.
|
||
- [x] proxy.nix: cert reframed as sops-from-git.
|
||
- [x] Verify byte-identical `build`==`/run/current-system` (`vh6vwxbl…`); git-clone `?submodules=1` matches too.
|
||
- [x] Verify clean switch on cc-nix-test; live TLS served from git cert (ssl_verify=0).
|
||
- [x] **Gate W2 CLAIMED** → Adversary verifies byte-identical + TLS-from-git-cert.
|
||
- [x] **W1 — Headroom.** Resized `cc-nix-test` 6→4 GB (stop→PATCH→start via Incus API); healthy at 4 GB,
|
||
0 failed units, all stacks 1/1, cert survived reboot via sops, TLS 200. Running RAM 8 GB.
|
||
- [x] **W3 — Throwaway VM.** `ccci-throwaway` (incus-base, 4 GB/20 GB) reachable at 100.126.124.86
|
||
(used live TS_AUTH_KEY; workspace key stale). Bootstrap age key provisioned in W4.
|
||
- [x] **W4 — Reproducible live rebuild.** Fresh blank VM + recovery age key only → `git clone
|
||
--recursive` + ONE `nixos-rebuild switch ?submodules=1` → running/0-failed, byte-identical
|
||
`ld19aj2`==cc-ci, 6 stacks 1/1, all secrets+cert decrypt, TLS leaf==git cert. Found+fixed a
|
||
concurrent-abra race (serialized reconcilers). **Gate W4 CLAIMED** (awaiting Adversary W5).
|
||
- [ ] **W5.5 — Functional-acceptance e2e (E2E-TESTME, operator-gated).** Authority:
|
||
`cc-ci-plan/test-e2e-testme-acceptance.md`. After C4/C5 PASS + orchestrator renames rebuilt VM→
|
||
cc-nix-test + confirms public gateway + SIGNALS: `!testme` (bot) on a fast enrolled recipe
|
||
(custom-html); verify E1–E6 (self-check 200/cert → new Drone build via bridge → app reachable
|
||
EXTERNALLY at `<app>.ci.commoninternet.net` w/ valid cert+content → real assertions pass → clean
|
||
undeploy → reported). Evidence→JOURNAL-1c, verdict→STATUS/REVIEW-1c. Fail⇒fix in git, re-run.
|
||
Do NOT start before the signal; keep VM stack up. Adversary independently verifies.
|
||
- [ ] **W5 — Adversary cold proof + honest D8.** Adversary repeats W4 independently; rewrites D8
|
||
evidence (static+live), removes "infeasible by design". Accept: Adversary D8 live-rebuild PASS
|
||
(or narrow signed-off limitation per C5).
|
||
- [ ] **W6 — Cleanup + docs + final sizing.** Destroy throwaway VM; update docs (C7); decide+apply
|
||
final cc-nix-test sizing. Accept: no leftover; docs match; flip STATUS-1c → `## DONE`.
|
||
|
||
## Adversary findings
|
||
|
||
- [x] **ADV-1c-1 [adversary] — `docs/architecture.md` not updated to the 1c model (blocks C7). CLOSED @2026-05-27 20:10Z (Adversary re-verified).**
|
||
Fixed by Builder (`6276bfd`/`2a5affc`). Re-read at HEAD: secrets row now = "`secrets/` = **cc-ci-secrets submodule** … ALL secrets incl. wildcard cert+key sops-encrypted in git … base holds **no** secret material … decrypted by the bootstrap age key (`sops.age.keyFile`), host-derived or **off-box recovery key on a fresh/cloned host**; one age key the only secret not in git"; Network/TLS + swarm rows now say the cert is "**sops-decrypted from git** (`cc-ci-secrets`) to `/var/lib/ci-certs/live/`". No stale pre-1c phrasing remains. → C7 met. (Minor non-blocking note: the *external* orchestrator doc `/srv/cc-ci/cc-ci-plan/plan.md §1.5/§4.0/§4.4` still has pre-1c cert wording, but it's outside the repo / not loop-git-managed and not the doc a new engineer installs from — the repo docs install/secrets/architecture are authoritative and correct.)
|
||
|
||
~~Original finding:~~
|
||
C7 requires `architecture.md` reflect the new model, but it still describes the **pre-1c** layout:
|
||
- Line ~17 (secrets row): "`modules/secrets.nix` + `secrets/secrets.yaml` (sops-nix) | Infra secrets,
|
||
decrypted at activation **via the host SSH key** as the age identity" — no mention of the private
|
||
**`cc-ci-secrets` repo / git submodule** split, the **recovery age key** bootstrap for a fresh host,
|
||
or that the **wildcard cert+key are sops secrets in git** (C1/C2/C3 — the core of 1c).
|
||
- §Network/TLS (lines ~40–41): cert described as "**pre-issued** wildcard cert at
|
||
`/var/lib/ci-certs/live/`" (out-of-band), not **sops-decrypted-from-git** to that path.
|
||
Repro: `grep -n "host SSH key\|secrets/secrets.yaml\|pre-issued wildcard" docs/architecture.md`.
|
||
A new engineer reading it gets the wrong mental model of where secrets/cert live. **Fix:** update the
|
||
secrets row + Network/TLS section to the 1c model (cc-ci-secrets submodule, cert sops-in-git decrypted
|
||
at activation, recovery-key as the one out-of-band bootstrap secret), consistent with install.md/secrets.md.
|
||
Only the Adversary closes this, after re-reading the updated doc. (Doc gap — not a VETO.)
|