diff --git a/docs/OPEN-SOURCE-READINESS-PLAN.md b/docs/OPEN-SOURCE-READINESS-PLAN.md index 378c0e7a..75e55f2d 100644 --- a/docs/OPEN-SOURCE-READINESS-PLAN.md +++ b/docs/OPEN-SOURCE-READINESS-PLAN.md @@ -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 ~428–429, 454–457, 483, 521–528, 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 0–2 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 1–2 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: A1–A6, B1–B2, 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.