security: remove node credentials from tracked files (open-source Phase 1)
Demo images / Build & push demo images (push) Failing after 2m28s

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
<FLEET_PW> / <FLEET_PW_ALT> 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) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-07 09:59:10 -04:00
co-authored by Claude Opus 5
parent e3b98ed18f
commit 19082a44f0
12 changed files with 81 additions and 54 deletions
+11 -11
View File
@@ -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 `<FLEET_PW>` (**.88 = `<FLEET_PW_ALT>`**); UI/RPC .228/.198 =
`<FLEET_PW>`. 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 `<FLEET_PW_ALT>`) | ✅ 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@` + `<FLEET_PW>` rejected (`Permission denied (publickey,password)`); node creds unknown |
Deploy tooling (reusable): scratchpad `deploy-bin.sh <label> <local\|ssh\|ts> <host> <pw>` + `remote-apply.sh` (mv binary avoids ETXTBSY, atomic FE swap preserving `aiui`/APK/`claude-login.html`, chown 1000:1000, restart, sha+health verify). Frontend tarball = `tar -C web/dist/neode-ui -czf neode-ui.tgz .` (flat). Full sha `e0343137b99bf06642c45da67bb092e9a411190ff59eda8e5177c2a06b6f6e89`.
@@ -480,7 +480,7 @@ VALIDATION PROGRESS (sessions e→f):
**✅ 2026-06-25 — STRAY 13h GATE on .228 found + killed; mempool RESOLVED.** A `setsid` gate run from session-e was still churning .228 ~13h later (pathologically slow — only reached test 71/lnd; the 300s settle bump is the suspect). Killed its process group (note: `pkill -f bats` self-matches the ssh command's own argv → kill by numeric PID/PGID instead). After kill, `crash_recovery` (Fix A) auto-recovered the immich/indeedhub/netbird stacks — **good live exercise of Fix A**. **mempool fallout RESOLVED:** the gate churn left .228's podman **overlay storage corrupt** (mempool frontend crash-looped — container couldn't write `/etc/nginx`, same image serves fine on .116) → **fixed by rebooting .228** (clears overlay corruption; Fix A staggered-recovered all apps; mempool stable 200). **.198 is PRUNED** bitcoin → mempool requires archival (install correctly refused) → **cleanly uninstalled** the orphan mempool-db. All nodes now correct. LESSON: never leave the gate running unsupervised; reconsider the 300s settle before re-running.
Fleet on `e0343137` + FE `index-a75rd6Hy.js` on .116/.198/.228/.89/.88/.5/.120 (.15 still old). **`89d397bb` (netbird-delete) binary NOT yet deployed anywhere — verify on .228 then roll.** SSH/sudo pw UNIFORM `ThisIsWeb54321@` (**.88 = `ThisIsWeb54321!`**); **UI/RPC: .228=`ThisIsWeb54321@`, .198=`ThisIsWeb54321@`.** Reusable tooling in scratchpad: `deploy-bin.sh`/`remote-apply.sh` (binary+FE swap), `rpc.sh <host> <pw> <method> [params]` (auth.login→call). Gate harness at `~/lifecycle/lifecycle` on .228 — **CHECK it isn't already running/wedged before re-launching**.
Fleet on `e0343137` + FE `index-a75rd6Hy.js` on .116/.198/.228/.89/.88/.5/.120 (.15 still old). **`89d397bb` (netbird-delete) binary NOT yet deployed anywhere — verify on .228 then roll.** SSH/sudo pw UNIFORM `<FLEET_PW>` (**.88 = `<FLEET_PW_ALT>`**); **UI/RPC: .228=`<FLEET_PW>`, .198=`<FLEET_PW>`.** Reusable tooling in scratchpad: `deploy-bin.sh`/`remote-apply.sh` (binary+FE swap), `rpc.sh <host> <pw> <method> [params]` (auth.login→call). Gate harness at `~/lifecycle/lifecycle` on .228 — **CHECK it isn't already running/wedged before re-launching**.
---
@@ -518,14 +518,14 @@ probes (bitcoin-knots state, immich lan_address). All work is **committed + PUSH
| Node | Pw | Done | Notes |
|------|----|----|-------|
| .116 (local, http:80) | `ThisIsWeb54321@` | ✅ | dev node: bitcoin mid-IBD + http-only |
| .116 (local, http:80) | `<FLEET_PW>` | ✅ | dev node: bitcoin mid-IBD + http-only |
| .198 | `archipelago` | ✅ | resilience; user manual-testing here |
| .228 | `archipelago` | ✅ | canonical gate node (5×-green) |
| 100.82.34.38 (archipelago-1) | `archipelago` | ✅ | |
| 100.89.209.89 (archy-x250-pa) | `ThisIsWeb54321@` | ✅ | |
| 100.70.96.88 (archipelago node) | `ThisIsWeb54321!` | ✅ | note the `!` |
| 100.64.83.15 (archy-dev-pa) | ? | ⏳ | UP (tailscale ping ok) but `ThisIsWeb54321@` REJECTED — **need correct pw** |
| 100.66.157.120 (archy-x250-exp) | `ThisIsWeb54321@` | ⏭️ | DOWN — user said leave it |
| 100.89.209.89 (archy-x250-pa) | `<FLEET_PW>` | ✅ | |
| 100.70.96.88 (archipelago node) | `<FLEET_PW_ALT>` | ✅ | note the `!` |
| 100.64.83.15 (archy-dev-pa) | ? | ⏳ | UP (tailscale ping ok) but `<FLEET_PW>` REJECTED — **need correct pw** |
| 100.66.157.120 (archy-x250-exp) | `<FLEET_PW>` | ⏭️ | DOWN — user said leave it |
Deploy scripts saved in scratchpad: `deploy-node.sh` (full binary+FE, sha+health verify) and
`fe-only.sh` (FE-only, no archipelago restart). Reusable: `bash deploy-node.sh <host> <pw> <scheme> 127.0.0.1`.
@@ -883,7 +883,7 @@ stale `8081` target on .228 (repo code is correct at 18083 — re-check on other
indeedhub-minio indeedhub-relay indeedhub-api indeedhub-ffmpeg`; scp; `sudo tar xzf t.tgz
-C /opt/archipelago/apps`.
- **Nodes:** .228 = 192.168.1.228, SSH pw `archipelago`, RPC/UI pw `password123` (https).
.198 = 192.168.1.198, SSH pw `archipelago`, **RPC/UI pw `ThisIsWeb54321@`** (https). Both
.198 = 192.168.1.198, SSH pw `archipelago`, **RPC/UI pw `<FLEET_PW>`** (https). Both
have the 7-container indeedhub stack + secrets + named volumes pre-existing.
- **Trigger install via RPC:** `auth.login` (sets session+csrf cookies) → send the csrf
cookie value as `X-CSRF-Token` header → `package.install` with params
@@ -17,7 +17,7 @@ only those three.
## ⚠️ Outstanding user request for the deploy
- **Change .81's web-UI password to `ThisIsWeb54321@`** — the user forgot the
- **Change .81's web-UI password to `<FLEET_PW>`** — the user forgot the
current one. Node was unreachable from .116 during this session (flaky WiFi
AP, IP flapped .68↔.81). Do this during deploy (SSH works from the user's
machine; `archipelago`/`archipelago`).
+4 -4
View File
@@ -26,7 +26,7 @@ Updated: 2026-06-30
(`contact_id:1128152268`) now returns **`"encrypted":true`** — confirms the
`archy || peer_pkc_capable(contact_id)` TX fix is live, not just compiled.
- `.228`'s RPC password in memory (`password123`) was stale — user confirmed the correct
password is `ThisIsWeb54321@` (same as `.198`/`.116`, i.e. fully unified now). Re-verified via
password is `<FLEET_PW>` (same as `.198`/`.116`, i.e. fully unified now). Re-verified via
RPC: `mesh.peers` shows 3ccc `pkc_capable:true`, and `mesh.send` to 3ccc returns
`"encrypted":true`#17 confirmed live on `.228` too, not just `.198`.
@@ -94,7 +94,7 @@ has been asked for/owned by this session.
**`Mesh-CAkPgvLo.js`**, `archipelago` active on each:
`.116`, `.198`, `.228` (LAN, archipelago@ + `~/.ssh/archipelago-deploy`),
`100.72.136.5`, `100.89.209.89` (Tailscale, same key — installed this session;
SSH user `archipelago` / pw `ThisIsWeb54321@`; NOPASSWD sudo on all 5).
SSH user `archipelago` / pw `<FLEET_PW>`; NOPASSWD sudo on all 5).
**Shipped this session (commit `12e7990b` on `main`, pushed to gitea-vps2):**
-**#16 public-channel routing** — inbound Meshtastic text to `BROADCAST_NUM`
@@ -243,7 +243,7 @@ on-device (the caveat above).
### TEST RECIPE (works on each node)
- RPC helper used this session: a node-side `rpc.sh` that logs in (password
`ThisIsWeb54321@`), grabs the `csrf_token` cookie, echoes it as `X-CSRF-Token`, and POSTs to
`<FLEET_PW>`), grabs the `csrf_token` cookie, echoes it as `X-CSRF-Token`, and POSTs to
`http://127.0.0.1:5678/rpc/v1`. Recreate it or run archy's RPC directly. Methods:
`mesh.peers`, `mesh.status`, `mesh.messages`, `mesh.send {contact_id,message}`,
`mesh.broadcast`, `mesh.reboot-radio {seconds}`.
@@ -260,7 +260,7 @@ on-device (the caveat above).
build --release -p archipelago --bin archipelago`. (If `rust-lld: undefined hidden symbol`,
it's incremental cache — `CARGO_INCREMENTAL=0` fixes it.)
- SSH key `~/.ssh/archipelago-deploy` is authorized on `.116/.198/.228`. SSH/UI/RPC password
`ThisIsWeb54321@`. Per node: scp the binary, `sudo systemctl stop archipelago` →
`<FLEET_PW>`. Per node: scp the binary, `sudo systemctl stop archipelago` →
`kill -9 $(pgrep -x archipelago)` → `install -m0755` to `/usr/local/bin/archipelago` →
`systemctl start archipelago`. Verify by `sha256sum` match + `systemctl is-active`.
- **Current deployed sha on all 3 = `ba4aed590027690d`** (the reboot-enabled build).
+2 -2
View File
@@ -99,7 +99,7 @@ lock, so the managed service (held stopped) can't collide. When it has connected
to ~the prior tip (height ≥ ~955800) it's done; then:
```sh
# on .228 (SSH/sudo/UI pw all: ThisIsWeb54321@)
# on .228 (SSH/sudo/UI pw all: <FLEET_PW>)
podman stop -t 600 bitcoin-knots-reindex && podman rm bitcoin-knots-reindex
# start the managed service via RPC (sets desired=running, clears user_stopped):
# package.start {id: bitcoin-knots} (POST https://127.0.0.1/rpc/v1, CSRF: echo csrf_token cookie as X-CSRF-Token)
@@ -128,4 +128,4 @@ NO `Error initializing block database` and NO data loss:
Core 29.2** (exists). Revisit if a Knots 29.2 was meant.
- Reindex is unavoidable ONLY because .228's index was already corrupted by the pre-fix
crash loop; a normal switch on the fixed binary does NOT reindex.
- Creds for .228: SSH/sudo + UI/RPC all `ThisIsWeb54321@`.
- Creds for .228: SSH/sudo + UI/RPC all `<FLEET_PW>`.