docs(open-source): move Phase 0 rotation to a pre-publish gate

Sequencing change per user decision: credential rotation/revocation runs
last, immediately before Phase 6, instead of first. Safe under fresh-history
publish — the scrub commits never become public — but recorded as a HARD
blocking gate on Phase 6, with an explicit rotation sign-off added as a
numbered pre-publish step so "scrubbed" cannot be mistaken for "rotated".

Also corrects the plan against what execution actually found:
- the fleet password was in 8 tracked files, not 7 (3 in .planning/)
- both Gitea tokens are already dead (401); only the `ai` password is live
- the Framework node's SSH password was rotated out-of-band and is unrecorded,
  which would block it from receiving the fleet rotation
- .planning/ is 199 tracked files of internal agent state — added to Phase 2
  as the largest un-triaged internal block still in the tree

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-07 10:00:32 -04:00
co-authored by Claude Opus 5
parent 19082a44f0
commit 39eb6b0553
+41 -7
View File
@@ -98,17 +98,40 @@ Still required before public publish:
---
## Phase 0 — Credential rotation (immediate, independent of the repo)
## Phase 0 — Credential rotation (DEFERRED to the pre-publish gate, 2026-08-07)
> **Sequencing decision (user, 2026-08-07):** rotation/revocation moved from first to
> last. This is safe *only* because the publish is fresh-history — the scrub commits
> never become public, so scrubbing before rotating leaks nothing to outsiders.
>
> **Hard gate: Phase 6 MUST NOT run until every item below is done.** The export is the
> point where a missed literal becomes public and a live key becomes an incident.
> Everything here is still live as of this writing. Phase 6 step 3 now includes an
> explicit rotation sign-off.
Treat all of these as already compromised; rotate even though we're doing fresh-history:
- **Anthropic API key #1**: `image-recipe/_archived/build-auto-installer-iso.sh:2837` (the "intentional alpha" ISO key). Revoke + reissue; move the live key OUT of source into a build-time secret/env (`ISO_ANTHROPIC_API_KEY`), keep the alpha-baking behavior if desired but never the literal in git.
- **Anthropic API key #2**: `scripts/setup-aiui-server.sh:28` — a *different* live key, not covered by the documented alpha exception. Revoke; parameterize the script.
- **The shared node SSH/sudo/UI password** (two variants) — in 7 tracked files + 24+ commits. Rotate fleet-wide (user task).
- **Gitea `ai` account password + 2 Gitea tokens** — embedded in `.git/config` remote URLs (not tracked, but leaks in any directory copy/tarball). Rotate; switch remotes to credential-helper storage instead of URL-embedded creds.
- **The shared node SSH/sudo/UI password** (two variants) — was in **8** tracked files (see
Phase 1 status) + 24+ commits. Now scrubbed from the tree; still live on the fleet.
Rotate fleet-wide (user task).
- **Gitea `ai` account password + 2 Gitea tokens** — embedded in `.git/config` remote URLs
(not tracked, but leaks in any directory copy/tarball). **Verified 2026-08-07: both tokens
are already dead** — `localhost:3000` and `146.59.87.168:3000` both return 401. Only the
`ai` password on `source.archipelago-foundation.org` is live. Rotate it; switch remotes to
credential-helper storage instead of URL-embedded creds.
- **Framework node SSH** — its password was rotated out-of-band and is not recorded anywhere;
key auth is also rejected. Whoever holds it should capture it before the fleet rotation, or
that node becomes unreachable for the rotation itself.
## Phase 1 — Secrets & sanitization of tracked files
**Status 2026-08-07: items 1, 2 and 4 DONE** (`e3b98ed1`, `19082a44`). The password was in
**8 files, not 7** — the reworked audit found three in `.planning/` that this list missed.
`scripts/audit-secrets.sh` is 5/5 green and canary-tested. Items 3 (infra identifiers) and
5 (`.gitignore`) remain.
1. Strip the password/credential lines from the 7 files:
`docs/PRODUCTION-MASTER-PLAN.md` (lines ~428429, 454457, 483, 521528, 886 — the fleet cred table),
`docs/archive/SESSION-1.8.0-OTA-PROGRESS.md`, `docs/archive/HANDOVER-2026-07-02-iso-feedback.md`,
@@ -130,6 +153,11 @@ Treat all of these as already compromised; rotate even though we're doing fresh-
## Phase 2 — Repo restructure: deletions, binaries, layout
Delete (each its own commit):
- **`.planning/` — 199 tracked files, not in the original plan.** GSD phase/session material
(RESUME notes, phase SUMMARYs, `.continue-here.md`); three of them held the fleet password.
Same class as `loop/` and `.agents/`: internal agent working state, not product. Decide
delete-vs-`docs/history/` explicitly — it is the largest un-triaged block of internal
material still tracked.
- `loop/` (AI overnight harness w/ node SSH lines), `.agents/`, `.codex`, `.githooks/pre-push`
(the hook that re-commits the 27 MB APK — root cause of the 5.5 GB history).
- `indeedhub/` submodule + `.gitmodules` entry (points at private HTTP Gitea, breaks `--recursive`
@@ -263,14 +291,18 @@ PodmanClient API extension + call-site migration; god-module splits (`install.rs
2. Build the public tree: `git archive`-style export of HEAD (never copy `.git/` — it holds
credentialed remotes) → new repo, single initial commit ("Initial public release, vX.Y.Z"),
optionally preserving CHANGELOG.md as the human-readable history.
3. Pre-publish gate on the export: `scripts/audit-secrets.sh` (fixed version) clean; grep-zero for
3. **Rotation sign-off (blocking):** confirm every Phase 0 item is rotated/revoked — both
Anthropic keys dead, fleet SSH password changed fleet-wide, Gitea `ai` password rotated,
remotes moved off URL-embedded creds. Do not proceed on "it's scrubbed" — scrubbed and
rotated are different things, and only rotation covers the private history.
4. Pre-publish gate on the export: `scripts/audit-secrets.sh` (fixed version) clean; grep-zero for
`sk-ant-`, rotated-password strings, `146.59.87.168`, tailnet `100.` IPs, `192.168.1.`,
internal hostnames; `du -sh .git` sanity (< ~100 MB); fresh `git clone` + `cd core && cargo build`
+ `cd neode-ui && npm ci && npm run build` on a clean machine/container; one app image pull
from the public domain.
4. Publish to GitHub; enable issue templates (already present in `.github/`); file the deferred-work
5. Publish to GitHub; enable issue templates (already present in `.github/`); file the deferred-work
issues (from Phase 5's issue list) as the initial public issue set — honest and gives contributors entry points.
5. Internal repo remains the private full-history remote; decide sync direction post-launch
6. Internal repo remains the private full-history remote; decide sync direction post-launch
(recommend: public repo becomes canonical, private keeps only ops/infra notes).
## Verification (end-to-end)
@@ -282,7 +314,9 @@ PodmanClient API extension + call-site migration; god-module splits (`install.rs
## Sequencing / cut-line
Order: 0 → 1 → 2 → (3 ∥ 4) → 5 (A→E) → 6. Phases 02 are non-negotiable security; Phase 3 is the
Order (revised 2026-08-07): 1 → 2 → (3 ∥ 4) → 5 (A→E) → **0** 6. Phase 0 rotation now sits
immediately before publish as a blocking gate rather than first; see the Phase 0 banner for why
that is safe under fresh-history. Phases 12 are non-negotiable security; Phase 3 is the
functional blocker; Phase 4 is the developer-experience payload; Phase 5 can be cut after any
commit (minimum viable: A1A6, B1B2, unused_io_amount fix); Phase 6 last. If the timeline
compresses, Tier-2 dead_code and Phase E move to public issues — everything else holds.