From 19082a44f0ee207ce13c95ba037d5e96f589e117 Mon Sep 17 00:00:00 2001 From: archipelago Date: Fri, 7 Aug 2026 09:59:10 -0400 Subject: [PATCH] security: remove node credentials from tracked files (open-source Phase 1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scrubs the fleet SSH/UI password from every tracked file (22 occurrences) and removes inline credentials from the code paths that used them. Docs and trackers keep the surrounding context — these are published under docs/history/ per the open-source plan — with the literals replaced by / so the "two variants exist" detail survives without the values. Three of the eight files were in .planning/ and were NOT in the plan's enumerated list; the reworked audit-secrets.sh found them. Code changes: - neode-ui/test-openwrt.mjs: node URL and password come from ARCHY_NODE_URL / ARCHY_NODE_PW; the SSH target derives from the URL instead of a hardcoded tailnet IP; exits 2 when unset. - scripts/run-post-install-tests.sh: drops the built-in "testpass123!" default and adds --password-stdin; refuses to run unauthenticated instead of silently trying a known password. --phase1-only still needs no password. - .gitea/workflows/post-install-tests.yml: sshpass with an inline literal replaced by key auth (NODE_SSH_KEY secret); password comes from the NODE_UI_PASSWORD secret and is piped over stdin rather than argv, so it stays out of the node's process list and the job log. Default target IP removed. scripts/audit-secrets.sh now reports 5/5 pass, 0 fail. Note: rotation of the exposed credentials is deliberately deferred to the pre-publish gate and is NOT done by this commit — these values are still live. See Phase 0. Co-Authored-By: Claude Opus 5 (1M context) --- .gitea/workflows/post-install-tests.yml | 55 +++++++++++-------- .planning/.continue-here.md | 2 +- .planning/RESUME-2026-08-05-appgate-fixes.md | 2 +- .../09-07-SUMMARY.md | 4 +- docs/PRODUCTION-MASTER-PLAN.md | 22 ++++---- .../HANDOVER-2026-07-02-iso-feedback.md | 2 +- docs/archive/SESSION-1.8.0-OTA-PROGRESS.md | 8 +-- docs/bitcoin-version-bulletproof-rollout.md | 4 +- neode-ui/test-openwrt.mjs | 16 ++++-- scripts/run-post-install-tests.sh | 14 ++++- tests/multinode/meshtastic.sh | 2 +- tests/production-quality/TRACKER.md | 4 +- 12 files changed, 81 insertions(+), 54 deletions(-) diff --git a/.gitea/workflows/post-install-tests.yml b/.gitea/workflows/post-install-tests.yml index 7c5c4c86..91c53ffc 100644 --- a/.gitea/workflows/post-install-tests.yml +++ b/.gitea/workflows/post-install-tests.yml @@ -4,13 +4,11 @@ on: workflow_dispatch: inputs: target: - description: 'Target node IP (e.g. 192.168.1.198)' + description: 'Target node IP or hostname' required: true - default: '192.168.1.198' password: - description: 'Node password (or "auto" for fresh install)' + description: 'Node UI password (leave blank to use the NODE_UI_PASSWORD secret)' required: false - default: 'auto' jobs: post-install-tests: @@ -22,33 +20,46 @@ jobs: with: fetch-depth: 1 - - name: Run post-install tests on target + - name: Install SSH key + env: + SSH_KEY: ${{ secrets.NODE_SSH_KEY }} run: | - TARGET="${{ github.event.inputs.target }}" - PASSWORD="${{ github.event.inputs.password }}" - if [ "$PASSWORD" = "auto" ]; then - PASSWORD="testpass123!" + if [ -z "$SSH_KEY" ]; then + echo "ERROR: repository secret NODE_SSH_KEY is not configured." + echo "Post-install tests authenticate by key; password auth is not supported." + exit 1 fi + mkdir -p ~/.ssh && chmod 700 ~/.ssh + printf '%s\n' "$SSH_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + + - name: Run post-install tests on target + env: + TARGET: ${{ github.event.inputs.target }} + NODE_PASSWORD: ${{ github.event.inputs.password }} + NODE_UI_PASSWORD: ${{ secrets.NODE_UI_PASSWORD }} + SSH_USER: ${{ vars.NODE_SSH_USER }} + run: | + PASSWORD="${NODE_PASSWORD:-$NODE_UI_PASSWORD}" + if [ -z "$PASSWORD" ]; then + echo "ERROR: no node password supplied (input or NODE_UI_PASSWORD secret)." + exit 1 + fi + USER_NAME="${SSH_USER:-archipelago}" echo "══════════════════════════════════════════" echo "Running post-install tests on $TARGET" echo "══════════════════════════════════════════" - # Copy test script to target and run - sshpass -p 'archipelago' scp -o StrictHostKeyChecking=no \ + scp -o StrictHostKeyChecking=accept-new \ scripts/run-post-install-tests.sh \ - archipelago@${TARGET}:/tmp/run-post-install-tests.sh 2>/dev/null || \ - scp -o StrictHostKeyChecking=no \ - scripts/run-post-install-tests.sh \ - archipelago@${TARGET}:/tmp/run-post-install-tests.sh + "${USER_NAME}@${TARGET}:/tmp/run-post-install-tests.sh" - # Run tests (with sudo for service checks) - sshpass -p 'archipelago' ssh -o StrictHostKeyChecking=no \ - archipelago@${TARGET} \ - "sudo bash /tmp/run-post-install-tests.sh '$PASSWORD'" 2>/dev/null || \ - ssh -o StrictHostKeyChecking=no \ - archipelago@${TARGET} \ - "sudo bash /tmp/run-post-install-tests.sh '$PASSWORD'" + # Password is passed over stdin, never as an argv the node's process + # list (or this job's log) would expose. + printf '%s' "$PASSWORD" | ssh -o StrictHostKeyChecking=accept-new \ + "${USER_NAME}@${TARGET}" \ + "sudo bash /tmp/run-post-install-tests.sh --password-stdin" frontend-tests: runs-on: ubuntu-latest diff --git a/.planning/.continue-here.md b/.planning/.continue-here.md index 0f76dce7..014f2a14 100644 --- a/.planning/.continue-here.md +++ b/.planning/.continue-here.md @@ -74,7 +74,7 @@ Nothing blocking the demo. One loose end, likely moot: - **ANTI-PATTERN (from earlier this session, already corrected): never run `archipelago --version` on a fleet node** — it starts the full daemon rather than printing a version string (deployed binaries predate the flag). Use source-reading instead of the binary for investigation. ## Infrastructure State -- **archi-dev-box** (local node): `archipelago` daemon healthy, RPC on `127.0.0.1:5678` (session cookie in `/tmp/archy-dev-cookies.txt`, likely stale by the time this is read — re-login with `auth.login` / password `ThisIsWeb54321@`). `botfights` container healthy on `1.2.11`. +- **archi-dev-box** (local node): `archipelago` daemon healthy, RPC on `127.0.0.1:5678` (session cookie in `/tmp/archy-dev-cookies.txt`, likely stale by the time this is read — re-login with `auth.login` / password ``). `botfights` container healthy on `1.2.11`. - **x250-beta** (`archy-x250-beta.tail08d8f2.ts.net`, tailnet IP rotates — resolve by MagicDNS name): reachable via plain `ssh archipelago@archy-x250-beta.tail08d8f2.ts.net` this session (no password prompt hit — key-based or cached). RPC session cookie in `/tmp/archy-cookies.txt` **on that remote node**, likely stale — re-login same way. `botfights` container healthy on `1.2.11`. - Both nodes' local `/tmp` filled up mid-session (a 12G tmpfs, hit 0MB free once) — if you hit `ENOSPC` from the harness itself (not the actual command), check `df -h /tmp` and clean up stray large files (this session's culprit: two OTA release assets, ~260MB, downloaded to `/tmp` on the **local** machine as a relay step for an unrelated node update earlier in the session). - Canonical arena: `https://botfights.archipelago-foundation.org` — both demo nodes proxy to this via `ARENA_UPSTREAM_URL`, confirmed serving identical bot/fight data on both. diff --git a/.planning/RESUME-2026-08-05-appgate-fixes.md b/.planning/RESUME-2026-08-05-appgate-fixes.md index 250900e9..743227c4 100644 --- a/.planning/RESUME-2026-08-05-appgate-fixes.md +++ b/.planning/RESUME-2026-08-05-appgate-fixes.md @@ -69,7 +69,7 @@ reject — they silently keep their old cached copy. **Always verify ## Fleet -SSH: `sshpass -p 'ThisIsWeb54321!' ssh archipelago@` (note the `!`; `@` +SSH: `sshpass -p '' ssh archipelago@` (note the `!`; `@` is older and still works on some). RPC/node password differs per node — the `!` one failed RPC login on `.38`. diff --git a/.planning/phases/09-botfights-platform-upgrade/09-07-SUMMARY.md b/.planning/phases/09-botfights-platform-upgrade/09-07-SUMMARY.md index fec3a26a..8bb23538 100644 --- a/.planning/phases/09-botfights-platform-upgrade/09-07-SUMMARY.md +++ b/.planning/phases/09-botfights-platform-upgrade/09-07-SUMMARY.md @@ -27,7 +27,7 @@ key-files: key-decisions: - "Used the real RPC path (package.check-updates then package.update, id=botfights) rather than any hand-placed container edit — matches what the UI's per-app Update button drives and what CLAUDE.md/D-04 requires (T-09-34 mitigation)." - - "Local RPC auth: ARCHY_HOST=127.0.0.1 ARCHY_SCHEME=http, password ThisIsWeb54321@ (the second candidate, password123, failed with 'Password Incorrect') — confirmed via tests/lifecycle/lib/rpc.bash's rpc_login." + - "Local RPC auth: ARCHY_HOST=127.0.0.1 ARCHY_SCHEME=http, password (the second candidate, password123, failed with 'Password Incorrect') — confirmed via tests/lifecycle/lib/rpc.bash's rpc_login." - "x250-dev (100.72.136.6, Tailscale) was unreachable this session (SSH connect timeout) — dev-pair rule recorded as satisfied on archi-dev-box only, with an explicit follow-up note in the demo checklist to repeat Task 1 there if it comes back online before the demo." - "Task 2 and Task 3 are gate=\"blocking\" checkpoint:human-verify tasks requiring a real browser NIP-07 extension and a real cloud agent — neither is automatable (09-RESEARCH.md Pitfall 5: no window.nostr mock exists anywhere in the test suite). Per this run's explicit instruction, execution stopped here rather than simulating or skipping these checks; the demo-rehearsal checklist below is the structured hand-off for a human/relay to complete them." @@ -118,7 +118,7 @@ status: awaiting-human-verification ## Accomplishments - Confirmed the archipelago service was already active on archi-dev-box (running since 20:45 the previous evening) — no service start needed, contrary to the plan's precondition note that it "was inactive at planning time." -- Logged into the local RPC (`http://127.0.0.1/rpc/v1`) using `tests/lifecycle/lib/rpc.bash`'s `rpc_login`, with `ThisIsWeb54321@` (the working candidate — `password123` failed with `Password Incorrect`). +- Logged into the local RPC (`http://127.0.0.1/rpc/v1`) using `tests/lifecycle/lib/rpc.bash`'s `rpc_login`, with `` (the working candidate — `password123` failed with `Password Incorrect`). - Triggered `package.check-updates`: the local `/var/lib/archipelago/app-catalog.json` cache (previously stuck at 1.1.0, dated 2026-07-23) refreshed to 1.2.1, `manifests_reloaded: 55`, and `journalctl` recorded the release-root signature verification log line (`did:key:z6MkkidEnEpo6qHMCNSZoNKWtvQvxq3whnaME9wGgEFhq7ur`). - Triggered `package.update {id: botfights}`: the orchestrator's normal upgrade path stopped, pulled, and recreated the container — no manual container edit, no manifest disk edit. Reached `146.59.87.168:3000/lfg2025/botfights:1.2.1` / `running` / `healthy` within ~40s. - Verified every acceptance criterion in the plan: image tag, `ARENA_UPSTREAM_URL` present, `JWT_SECRET` delivered as a podman secret (`--secret ...,type=env,target=JWT_SECRET`, masked in `podman inspect`, backed by a 0600/64-hex-char file at `/var/lib/archipelago/secrets/botfights-jwt-secret`) with **no plaintext `JWT_SECRET=`** anywhere in the container env, local `/api/bots` matching the arena's fighter set exactly (104 default + 15 classic, both sides), the unified prompt serving with the arena hostname substituted, and the local database byte-identical before/after (`367144960` bytes / mtime `1782916151` — same numbers 09-04-SUMMARY recorded, confirming zero data loss across three plans' worth of work on this same file). diff --git a/docs/PRODUCTION-MASTER-PLAN.md b/docs/PRODUCTION-MASTER-PLAN.md index 39bc6a2c..cde97ca0 100644 --- a/docs/PRODUCTION-MASTER-PLAN.md +++ b/docs/PRODUCTION-MASTER-PLAN.md @@ -425,8 +425,8 @@ fresh machine (`cd core && CARGO_INCREMENTAL=0 cargo build --release -p archipel - **nostr-rs-relay** stuck "Stopping" + ~2s create-loop on .228 (from session g). **NEXT:** finish .88/.5/.120 roll → push main to gitea-vps2 → Phase-3 quadlet / Workstream F / -multinode. SSH/sudo pw `ThisIsWeb54321@` (**.88 = `ThisIsWeb54321!`**); UI/RPC .228/.198 = -`ThisIsWeb54321@`. Reusable tooling in scratchpad: `deploy-bin.sh`/`remote-apply.sh` (EXPECT_SHA +multinode. SSH/sudo pw `` (**.88 = ``**); UI/RPC .228/.198 = +``. Reusable tooling in scratchpad: `deploy-bin.sh`/`remote-apply.sh` (EXPECT_SHA = `040df5ce…`), `rpc.sh`. --- @@ -451,10 +451,10 @@ multinode. SSH/sudo pw `ThisIsWeb54321@` (**.88 = `ThisIsWeb54321!`**); UI/RPC . | .116 (local) | ✅ binary + fresh FE; 36 containers survived restart; UI 200; `index-a75rd6Hy.js` live | | .198 (LAN) | ✅ binary + fresh FE; 38 containers up; UI 200 | | .89 (100.89.209.89) | ✅ binary + fresh FE; service active | -| .88 (100.70.96.88, pw `ThisIsWeb54321!`) | ✅ binary + fresh FE; service active | +| .88 (100.70.96.88, pw ``) | ✅ binary + fresh FE; service active | | .5 (100.72.136.5) | ⏳ attempted — see resume note (cellular x250) | | .120 (100.66.157.120) | ⏳ attempted — see resume note (cellular x250) | -| .15 (100.64.83.15, archy-dev-pa) | ❌ SKIPPED — `archipelago@` + `ThisIsWeb54321@` rejected (`Permission denied (publickey,password)`); node creds unknown | +| .15 (100.64.83.15, archy-dev-pa) | ❌ SKIPPED — `archipelago@` + `` rejected (`Permission denied (publickey,password)`); node creds unknown | Deploy tooling (reusable): scratchpad `deploy-bin.sh