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>
58 lines
2.3 KiB
JavaScript
58 lines
2.3 KiB
JavaScript
import { chromium } from './node_modules/playwright/index.mjs';
|
|
|
|
// Node under test + credentials come from the environment; never commit literals.
|
|
// ARCHY_NODE_URL=https://<node> ARCHY_NODE_PW=… node test-openwrt.mjs
|
|
const BASE = process.env.ARCHY_NODE_URL || 'https://127.0.0.1';
|
|
const PASS = process.env.ARCHY_NODE_PW;
|
|
const DIR = process.env.ARCHY_OUT_DIR || '/tmp/openwrt-test';
|
|
|
|
if (!PASS) {
|
|
console.error('ERROR: ARCHY_NODE_PW must be set in the environment.');
|
|
process.exit(2);
|
|
}
|
|
|
|
// Find the OpenWrt router IP from the Tailscale/LAN
|
|
const { execSync } = await import('child_process');
|
|
let routerIp = '192.168.1.1';
|
|
try {
|
|
const sshTarget = process.env.ARCHY_NODE_SSH || `archipelago@${new URL(BASE).hostname}`;
|
|
const route = execSync(`ssh ${sshTarget} 'ip route | grep default'`, { encoding: 'utf8' }).trim();
|
|
const match = route.match(/default via ([\d.]+)/);
|
|
if (match) routerIp = match[1];
|
|
} catch {}
|
|
console.log('Detected router IP:', routerIp);
|
|
|
|
const browser = await chromium.launch({ headless: true });
|
|
const ctx = await browser.newContext({ ignoreHTTPSErrors: true });
|
|
const page = await ctx.newPage();
|
|
|
|
// Login
|
|
await page.goto(`${BASE}/login`, { waitUntil: 'networkidle', timeout: 20000 });
|
|
await page.fill('input[type="password"]', PASS);
|
|
await page.keyboard.press('Enter');
|
|
await page.waitForURL(/dashboard/, { timeout: 20000 });
|
|
|
|
// Server page
|
|
await page.goto(`${BASE}/dashboard/server`, { waitUntil: 'networkidle', timeout: 20000 });
|
|
await page.screenshot({ path: `${DIR}/01-server.png` });
|
|
|
|
// Click OpenWrt Gateway
|
|
await page.getByText('OpenWrt Gateway').click();
|
|
await page.waitForURL(/openwrt/, { timeout: 10000 });
|
|
await page.waitForTimeout(2000);
|
|
await page.screenshot({ path: `${DIR}/02-connect-form.png` });
|
|
console.log('Connect form visible');
|
|
|
|
// Fill in the connect form
|
|
await page.fill('input[placeholder="192.168.1.1"]', routerIp);
|
|
await page.screenshot({ path: `${DIR}/03-form-filled.png` });
|
|
await page.getByRole('button', { name: 'Connect' }).click();
|
|
|
|
// Wait for SSH connection + UCI read (can take up to 30s)
|
|
console.log('Connecting to router, waiting for data...');
|
|
await page.waitForTimeout(15000);
|
|
await page.screenshot({ path: `${DIR}/04-result.png` });
|
|
console.log('Result page text:\n', (await page.innerText('body')).replace(/\s+/g, ' ').substring(0, 800));
|
|
|
|
await browser.close();
|