From b2c75928405b307eee2e56122f47d357221383f8 Mon Sep 17 00:00:00 2001 From: archipelago Date: Fri, 7 Aug 2026 10:53:25 -0400 Subject: [PATCH] security: parameterize node addresses; drop dead APP_URLS config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keeps the dev and test tooling an outside contributor would want, and takes our node addresses out of it. Scripts that silently defaulted to one of our nodes now require an explicit host and exit 2 without one: smoke-test.sh, trust-archipelago-cert.sh, dev-container-test.sh (which also derives its RPC and health URLs from the SSH target instead of a second hardcoded copy), and image-recipe/dev-branding.sh. A default that points at a machine the user does not own is worse than no default: it fails confusingly, or reaches a stranger's device. Usage examples, mock data and test fixtures move to the RFC 5737 documentation range (192.0.2.0/24). CGNAT test values stay inside 100.64.0.0/10 so the range-check semantics they exercise still hold, and 192.168.1.0/.1/.254 are left alone — those are gateway logic and UI placeholders, not our addresses. Playwright and the perf spec defaulted their baseURL to one of our nodes; they now default to localhost:8100, the local dev server. Removed neode-ui APP_URLS entirely. It is dead code — exported, never imported — and it pinned fedimint's *prod* launch URL to 192.168.1.228:8175. Had anything consumed it, every user's node would have tried to reach an address that on their LAN is either nothing or someone else's machine. Deleting beats sanitizing dead config. Verified: frontend 868/868 vitest across 108 files; archipelago-container 75/75; mesh tests 9/9; audit-secrets 5/5. Zero node addresses and zero node names remain in tracked files. Co-Authored-By: Claude Opus 5 (1M context) --- Android/rust/archy-fips-core/src/mesh.rs | 4 +- core/archipelago/src/api/rpc/fips.rs | 2 +- core/archipelago/src/api/rpc/middleware.rs | 4 +- .../src/api/rpc/package/pine_ha.rs | 2 +- core/archipelago/src/config.rs | 4 +- core/archipelago/src/fips/anchors.rs | 2 +- core/archipelago/src/host_ip.rs | 8 +-- core/archipelago/src/transport/mod.rs | 4 +- core/container/src/manifest.rs | 6 +- docker/bitcoin-ui/index.html | 2 +- docker/fips-ui/index.html | 4 +- .../.gitea-workflows/build-iso-dev.yml | 2 +- image-recipe/_archived/BUILD-ISO-STATUS.md | 8 +-- .../_archived/build-auto-installer-iso.sh | 6 +- image-recipe/_archived/build-unbundled-iso.sh | 4 +- image-recipe/dev-branding.sh | 2 +- neode-ui/e2e/perf/surface-perf.spec.ts | 2 +- neode-ui/mock-backend.js | 18 ++--- neode-ui/playwright.config.ts | 2 +- .../src/stores/__tests__/appLauncher.test.ts | 68 +++++++++---------- neode-ui/src/utils/dummyApps.ts | 2 +- neode-ui/src/views/AppRegistries.vue | 2 +- neode-ui/src/views/ContainerApps.vue | 2 +- .../__tests__/AppSessionMobileNewTab.test.ts | 2 +- .../__tests__/ServerNetworkRefresh.test.ts | 8 +-- .../src/views/appDetails/appDetailsData.ts | 33 --------- .../appSession/__tests__/appOrigin.test.ts | 4 +- .../__tests__/appSessionConfig.test.ts | 22 +++--- .../views/apps/__tests__/AppIconGrid.test.ts | 4 +- .../fleet/__tests__/useFleetData.test.ts | 6 +- neode-ui/vite.config.ts | 2 +- scripts/app-catalog-image-smoke-test.py | 2 +- scripts/app-surface-smoke-test.sh | 2 +- scripts/bitcoin-stack-lifecycle-test.sh | 6 +- scripts/create-release.sh | 2 +- scripts/dev-container-test.sh | 11 ++- scripts/dev-start.sh | 2 +- scripts/install-tui-demo.sh | 4 +- scripts/resilience/README.md | 10 +-- scripts/resilience/lib.sh | 2 +- scripts/resilience/resilience.sh | 2 +- scripts/smoke-test.sh | 6 +- scripts/trust-archipelago-cert.sh | 10 ++- tests/multinode/.env.example | 4 +- tests/multinode/lib/multinode.bash | 4 +- tests/multinode/meshtastic.sh | 8 +-- tests/multinode/repro-federation-sync.sh | 4 +- tests/multinode/smoke.sh | 6 +- tests/production-quality/lnd-cors-test.sh | 2 +- 49 files changed, 154 insertions(+), 174 deletions(-) diff --git a/Android/rust/archy-fips-core/src/mesh.rs b/Android/rust/archy-fips-core/src/mesh.rs index ed33db90..6f1a9e37 100644 --- a/Android/rust/archy-fips-core/src/mesh.rs +++ b/Android/rust/archy-fips-core/src/mesh.rs @@ -258,8 +258,8 @@ mod tests { "npub": "npub1abc", "alias": "My Archipelago", "addresses": [ - {"transport": "udp", "addr": "192.168.1.228:2121", "priority": 10}, - {"transport": "tcp", "addr": "192.168.1.228:8443", "priority": 20} + {"transport": "udp", "addr": "192.0.2.10:2121", "priority": 10}, + {"transport": "tcp", "addr": "192.0.2.10:8443", "priority": 20} ] }]"#, ) diff --git a/core/archipelago/src/api/rpc/fips.rs b/core/archipelago/src/api/rpc/fips.rs index 391759b7..7b2fbed5 100644 --- a/core/archipelago/src/api/rpc/fips.rs +++ b/core/archipelago/src/api/rpc/fips.rs @@ -219,7 +219,7 @@ impl RpcHandler { anyhow::bail!("npub must be bech32 (npub1...)"); } if !anchor.address.contains(':') { - anyhow::bail!("address must be host:port (e.g. 192.168.1.116:8668)"); + anyhow::bail!("address must be host:port (e.g. 192.0.2.12:8668)"); } let list = fips::anchors::add(&self.config.data_dir, anchor.clone()).await?; // Push just the newly-added anchor into the running daemon so diff --git a/core/archipelago/src/api/rpc/middleware.rs b/core/archipelago/src/api/rpc/middleware.rs index 3e0c8367..1fafef61 100644 --- a/core/archipelago/src/api/rpc/middleware.rs +++ b/core/archipelago/src/api/rpc/middleware.rs @@ -317,10 +317,10 @@ mod client_ip_tests { #[test] fn loopback_connection_trusts_forwarded_header() { // nginx on loopback forwards the real client IP — use it. - let parts = parts_with(Some("127.0.0.1:44412"), Some("192.168.1.50")); + let parts = parts_with(Some("127.0.0.1:44412"), Some("192.0.2.50")); assert_eq!( extract_client_ip(&parts), - "192.168.1.50".parse::().unwrap() + "192.0.2.50".parse::().unwrap() ); } diff --git a/core/archipelago/src/api/rpc/package/pine_ha.rs b/core/archipelago/src/api/rpc/package/pine_ha.rs index ae774fc8..6ed13805 100644 --- a/core/archipelago/src/api/rpc/package/pine_ha.rs +++ b/core/archipelago/src/api/rpc/package/pine_ha.rs @@ -725,7 +725,7 @@ async fn seed_assist_pipeline(storage: &std::path::Path, claude_entity: Option<& /// HA's zeroconf discovery stores a satellite as a fixed LAN IP. DHCP /// renumbering — or the whole node moving to a different network — strands /// the entry and the speaker silently drops (a test node 2026-07-23: entry -/// pinned to 192.168.1.241 while the LAN had become 192.168.63.0/24). HA +/// pinned to 192.0.2.16 while the LAN had become 192.168.63.0/24). HA /// never re-resolves on its own. This keeper probes each satellite entry and, /// when one stops answering, sweeps the node's local /24s for the same /// Wyoming port and rewrites the entry to the address that answers. diff --git a/core/archipelago/src/config.rs b/core/archipelago/src/config.rs index c011b9e4..a270541e 100644 --- a/core/archipelago/src/config.rs +++ b/core/archipelago/src/config.rs @@ -411,7 +411,7 @@ mod tests { bind_host = "127.0.0.1" bind_port = 9999 log_level = "debug" - host_ip = "192.168.1.100" + host_ip = "192.0.2.100" dev_mode = true container_runtime = "Podman" port_offset = 20000 @@ -425,7 +425,7 @@ mod tests { assert_eq!(config.bind_host, "127.0.0.1"); assert_eq!(config.bind_port, 9999); assert_eq!(config.log_level, "debug"); - assert_eq!(config.host_ip, "192.168.1.100"); + assert_eq!(config.host_ip, "192.0.2.100"); assert!(config.dev_mode); assert_eq!(config.port_offset, 20000); assert!(!config.nostr_discovery_enabled); diff --git a/core/archipelago/src/fips/anchors.rs b/core/archipelago/src/fips/anchors.rs index 077021d7..fa702ffe 100644 --- a/core/archipelago/src/fips/anchors.rs +++ b/core/archipelago/src/fips/anchors.rs @@ -123,7 +123,7 @@ pub fn default_public_anchors() -> Vec { pub struct SeedAnchor { /// Bech32 `npub1...` of the anchor's FIPS identity. pub npub: String, - /// Directly-dialable transport address, e.g. `192.168.1.116:8668`. + /// Directly-dialable transport address, e.g. `192.0.2.12:8668`. pub address: String, /// Transport to use — almost always `"udp"`. #[serde(default = "default_transport")] diff --git a/core/archipelago/src/host_ip.rs b/core/archipelago/src/host_ip.rs index ee1ffdd4..538ab33d 100644 --- a/core/archipelago/src/host_ip.rs +++ b/core/archipelago/src/host_ip.rs @@ -110,8 +110,8 @@ mod tests { #[test] fn route_src_wins() { - let route = "default via 192.168.1.254 dev wlp3s0 proto dhcp src 192.168.1.116 metric 600"; - assert_eq!(parse_route_src(route).as_deref(), Some("192.168.1.116")); + let route = "default via 192.168.1.254 dev wlp3s0 proto dhcp src 192.0.2.12 metric 600"; + assert_eq!(parse_route_src(route).as_deref(), Some("192.0.2.12")); } #[test] @@ -123,8 +123,8 @@ mod tests { #[test] fn addr_inet_strips_prefix() { - let out = "3: wlp3s0 inet 192.168.1.65/24 brd 192.168.1.255 scope global dynamic noprefixroute wlp3s0\\ valid_lft 85328sec preferred_lft 85328sec"; - assert_eq!(parse_addr_inet(out).as_deref(), Some("192.168.1.65")); + let out = "3: wlp3s0 inet 192.0.2.17/24 brd 192.0.2.255 scope global dynamic noprefixroute wlp3s0\\ valid_lft 85328sec preferred_lft 85328sec"; + assert_eq!(parse_addr_inet(out).as_deref(), Some("192.0.2.17")); } #[test] diff --git a/core/archipelago/src/transport/mod.rs b/core/archipelago/src/transport/mod.rs index 2b700fe0..6d535d4c 100644 --- a/core/archipelago/src/transport/mod.rs +++ b/core/archipelago/src/transport/mod.rs @@ -522,7 +522,7 @@ mod tests { trust_level: None, source: None, mesh_contact_id: Some(42), - lan_address: Some("192.168.1.100:5678".to_string()), + lan_address: Some("192.0.2.100:5678".to_string()), fips_npub: None, onion_address: Some("abc123.onion".to_string()), last_mesh: None, @@ -536,7 +536,7 @@ mod tests { ); assert_eq!( peer.address_for(TransportKind::Lan), - Some("192.168.1.100:5678".to_string()) + Some("192.0.2.100:5678".to_string()) ); assert_eq!( peer.address_for(TransportKind::Tor), diff --git a/core/container/src/manifest.rs b/core/container/src/manifest.rs index 20b6ffe7..bc3c9d36 100644 --- a/core/container/src/manifest.rs +++ b/core/container/src/manifest.rs @@ -1379,7 +1379,7 @@ impl HostFacts { #[cfg(test)] pub fn sample() -> Self { Self { - host_ip: "192.168.1.116".to_string(), + host_ip: "192.0.2.12".to_string(), host_mdns: "test-node.local".to_string(), disk_gb: 2000, bitcoin_host: "bitcoin-knots".to_string(), @@ -2305,7 +2305,7 @@ app: secret_env_hash: None, }; let facts = HostFacts { - host_ip: "192.168.1.116".to_string(), + host_ip: "192.0.2.12".to_string(), host_mdns: "test-node.local".to_string(), disk_gb: 2000, bitcoin_host: "bitcoin-core".to_string(), @@ -2313,7 +2313,7 @@ app: let out = c.resolve_derived_env(&facts); assert_eq!(out[0], "FM_API_URL=ws://test-node.local:8174"); - assert_eq!(out[1], "INFO=192.168.1.116-2000"); + assert_eq!(out[1], "INFO=192.0.2.12-2000"); assert_eq!(out[2], "CORE_RPC_HOST=bitcoin-core"); } diff --git a/docker/bitcoin-ui/index.html b/docker/bitcoin-ui/index.html index ce7e2809..a479acaa 100644 --- a/docker/bitcoin-ui/index.html +++ b/docker/bitcoin-ui/index.html @@ -999,7 +999,7 @@
- +
diff --git a/docker/fips-ui/index.html b/docker/fips-ui/index.html index 3c7752ba..83651210 100644 --- a/docker/fips-ui/index.html +++ b/docker/fips-ui/index.html @@ -153,7 +153,7 @@
-
+
@@ -396,7 +396,7 @@ const transport = document.getElementById('aTransport').value; const label = document.getElementById('aLabel').value.trim(); if (!npub.startsWith('npub1')) { notice('anchorNotice', 'error', 'npub must start with npub1…'); return; } - if (!address.includes(':')) { notice('anchorNotice', 'error', 'Address must be host:port (e.g. 192.168.1.116:8668).'); return; } + if (!address.includes(':')) { notice('anchorNotice', 'error', 'Address must be host:port (e.g. 192.0.2.12:8668).'); return; } busy(btn, true, 'Adding…'); notice('anchorNotice', '', ''); try { diff --git a/image-recipe/_archived/.gitea-workflows/build-iso-dev.yml b/image-recipe/_archived/.gitea-workflows/build-iso-dev.yml index a05c7cd8..bc63a62f 100644 --- a/image-recipe/_archived/.gitea-workflows/build-iso-dev.yml +++ b/image-recipe/_archived/.gitea-workflows/build-iso-dev.yml @@ -243,7 +243,7 @@ jobs: # Build download base URL (FileBrowser serves from /Builds/) HOST=$(hostname -I 2>/dev/null | awk '{print $1}') - BASE_URL="http://${HOST:-192.168.1.228}:8083/Builds/releases/v${VERSION}" + BASE_URL="http://${HOST:-192.0.2.10}:8083/Builds/releases/v${VERSION}" # Generate manifest JSON python3 -c " diff --git a/image-recipe/_archived/BUILD-ISO-STATUS.md b/image-recipe/_archived/BUILD-ISO-STATUS.md index d90b3007..cd4fda97 100644 --- a/image-recipe/_archived/BUILD-ISO-STATUS.md +++ b/image-recipe/_archived/BUILD-ISO-STATUS.md @@ -18,7 +18,7 @@ The script will automatically: ```bash # From your Mac (captures from remote dev server): cd image-recipe -DEV_SERVER=archipelago@192.168.1.228 sudo bash build-auto-installer-iso.sh +DEV_SERVER=archipelago@192.0.2.10 sudo bash build-auto-installer-iso.sh # From the dev server itself: cd ~/archy/image-recipe @@ -40,7 +40,7 @@ BUILD_FROM_SOURCE=1 sudo bash build-auto-installer-iso.sh ```bash # Instead of building on the server, build from your Mac: cd ~/Projects/archy/image-recipe -DEV_SERVER=archipelago@192.168.1.228 sudo bash build-auto-installer-iso.sh +DEV_SERVER=archipelago@192.0.2.10 sudo bash build-auto-installer-iso.sh ``` ### Issue: Podman registry not configured @@ -49,7 +49,7 @@ DEV_SERVER=archipelago@192.168.1.228 sudo bash build-auto-installer-iso.sh **Fix**: ```bash -ssh archipelago@192.168.1.228 +ssh archipelago@192.0.2.10 sudo tee -a /etc/containers/registries.conf </dev/null) fi if [ -n "$BOOTSTRAP_RPC_PASS" ]; then - DEV_IP="${DEV_SERVER:-192.168.1.228}" + DEV_IP="${DEV_SERVER:-192.0.2.10}" cat > "$ARCH_DIR/bootstrap.conf" < { return res.json({ result: { interfaces: [ - { name: 'eth0', type: 'ethernet', state: 'up', mac: 'a8:a1:59:3c:f2:10', ipv4: ['192.168.1.228/24'] }, - { name: 'wlan0', type: 'wifi', state: 'up', mac: 'dc:a6:32:12:ab:cd', ipv4: ['192.168.1.230/24'] }, + { name: 'eth0', type: 'ethernet', state: 'up', mac: 'a8:a1:59:3c:f2:10', ipv4: ['192.0.2.10/24'] }, + { name: 'wlan0', type: 'wifi', state: 'up', mac: 'dc:a6:32:12:ab:cd', ipv4: ['192.0.2.14/24'] }, { name: 'lo', type: 'loopback', state: 'up', mac: '00:00:00:00:00:00', ipv4: ['127.0.0.1/8'] }, { name: 'podman0', type: 'bridge', state: 'up', mac: '2e:f4:8a:11:22:33', ipv4: ['10.89.0.1/16'] }, { name: 'tailscale0', type: 'tunnel', state: 'up', mac: '', ipv4: ['100.82.97.63/32'] }, @@ -3075,10 +3075,10 @@ app.post('/rpc/v1', (req, res) => { return res.json({ result: { nodes: [ - { did: 'did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2ReMkBe4bR6XBIDNq9', onion: 'disc1abc2def3ghi4jkl5mno6pqr7stu8vwx9yz.onion', pubkey: 'disc1pub', node_address: '192.168.1.50' }, - { did: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH', onion: 'disc2xyz9wvu8tsr7qpo6nml5kji4hgf3edc2ba.onion', pubkey: 'disc2pub', node_address: '192.168.1.51' }, - { did: 'did:key:z6MkfV2sQpXm4d8YtR1nWc7uHb3eKj9gLa5xPzD6oTiN8rEw', onion: 'disc3mn04pq15rs26tu37vw48xy59za60bc71de.onion', pubkey: 'disc3pub', node_address: '192.168.1.72' }, - { did: 'did:key:z6MkrJ8pWx2yNc5vT9qLb4eHu7dKf1gMa3sPzE6oXiQ8nRvw', onion: 'disc4fg82hi93jk04lm15no26pq37rs48tu59vw.onion', pubkey: 'disc4pub', node_address: '100.72.19.44' }, + { did: 'did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2ReMkBe4bR6XBIDNq9', onion: 'disc1abc2def3ghi4jkl5mno6pqr7stu8vwx9yz.onion', pubkey: 'disc1pub', node_address: '192.0.2.50' }, + { did: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH', onion: 'disc2xyz9wvu8tsr7qpo6nml5kji4hgf3edc2ba.onion', pubkey: 'disc2pub', node_address: '192.0.2.51' }, + { did: 'did:key:z6MkfV2sQpXm4d8YtR1nWc7uHb3eKj9gLa5xPzD6oTiN8rEw', onion: 'disc3mn04pq15rs26tu37vw48xy59za60bc71de.onion', pubkey: 'disc3pub', node_address: '192.0.2.72' }, + { did: 'did:key:z6MkrJ8pWx2yNc5vT9qLb4eHu7dKf1gMa3sPzE6oXiQ8nRvw', onion: 'disc4fg82hi93jk04lm15no26pq37rs48tu59vw.onion', pubkey: 'disc4pub', node_address: '100.64.0.6' }, { did: 'did:key:z6MkhT4wQn8xPc2vL6sRb9eYu3dJf7gKa1mNzD5oWiE8tXvq', onion: 'disc5xy60za71bc82de93fg04hi15jk26lm37no.onion', pubkey: 'disc5pub', node_address: '100.101.7.23' }, ], }, @@ -3604,7 +3604,7 @@ app.post('/rpc/v1', (req, res) => { name: 'archy-198', trust_level: 'trusted', mesh_contact_id: 1, - lan_address: '192.168.1.198:5678', + lan_address: '192.0.2.11:5678', onion_address: 'peer1abc2def3ghi4jkl5mno6pqr7stu8vwx9yz.onion', preferred_transport: 'lan', available_transports: ['mesh', 'lan', 'tor'], @@ -3640,7 +3640,7 @@ app.post('/rpc/v1', (req, res) => { name: 'office-node', trust_level: 'trusted', mesh_contact_id: null, - lan_address: '192.168.1.42:5678', + lan_address: '192.0.2.42:5678', onion_address: 'peer4mno6pqr7stu8vwx9yzabc2def3ghi4jkl5.onion', preferred_transport: 'lan', available_transports: ['lan', 'tor'], @@ -4438,7 +4438,7 @@ app.post('/rpc/v1', (req, res) => { ssid: 'CasaDelSol-5G', assoc_ssid: 'CasaDelSol-5G', encryption: 'psk2', - ip: '192.168.1.187', + ip: '192.0.2.15', internet: true, radio0_disabled: false, sta_iface: 'wifinet1', diff --git a/neode-ui/playwright.config.ts b/neode-ui/playwright.config.ts index 10bd34bf..dc416849 100644 --- a/neode-ui/playwright.config.ts +++ b/neode-ui/playwright.config.ts @@ -8,7 +8,7 @@ export default defineConfig({ timeout: 10_000, }, use: { - baseURL: process.env.ARCHY_BASE_URL ?? 'http://192.168.1.228', + baseURL: process.env.ARCHY_BASE_URL ?? 'http://localhost:8100', viewport: { width: 1440, height: 900 }, screenshot: 'only-on-failure', trace: 'off', diff --git a/neode-ui/src/stores/__tests__/appLauncher.test.ts b/neode-ui/src/stores/__tests__/appLauncher.test.ts index 1e26c8b3..dcc76dac 100644 --- a/neode-ui/src/stores/__tests__/appLauncher.test.ts +++ b/neode-ui/src/stores/__tests__/appLauncher.test.ts @@ -25,7 +25,7 @@ describe('useAppLauncherStore', () => { vi.clearAllMocks() // Default to HTTP to avoid proxy rewriting Object.defineProperty(window, 'location', { - value: { origin: 'http://192.168.1.228', protocol: 'http:', hostname: '192.168.1.228' }, + value: { origin: 'http://192.0.2.10', protocol: 'http:', hostname: '192.0.2.10' }, writable: true, configurable: true, }) @@ -71,8 +71,8 @@ describe('useAppLauncherStore', () => { it('open() never falls through to the iframe overlay', () => { const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:9999', title: 'Unknown app' }) - expect(openInApp).toHaveBeenCalledWith('http://192.168.1.228:9999') + store.open({ url: 'http://192.0.2.10:9999', title: 'Unknown app' }) + expect(openInApp).toHaveBeenCalledWith('http://192.0.2.10:9999') expect(store.isOpen).toBe(false) }) }) @@ -81,7 +81,7 @@ describe('useAppLauncherStore', () => { const store = useAppLauncherStore() // Port 8083 maps to /app/filebrowser/ — should route to session - store.open({ url: 'http://192.168.1.228:8083', title: 'FileBrowser' }) + store.open({ url: 'http://192.0.2.10:8083', title: 'FileBrowser' }) // Default panel mode: sets panelAppId, doesn't open overlay expect(store.isOpen).toBe(false) @@ -128,12 +128,12 @@ describe('useAppLauncherStore', () => { it('routes BTCPay (port 23000) to full-page session', () => { const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:23000', title: 'BTCPay' }) + store.open({ url: 'http://192.0.2.10:23000', title: 'BTCPay' }) expect(store.isOpen).toBe(false) expect(store.panelAppId).toBe(null) expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.228:23000', + 'http://192.0.2.10:23000', '_blank', 'noopener,noreferrer', ) @@ -142,12 +142,12 @@ describe('useAppLauncherStore', () => { it('normalizes old Nginx Proxy Manager port 81 to 8081', () => { const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:81', title: 'Nginx Proxy Manager' }) + store.open({ url: 'http://192.0.2.10:81', title: 'Nginx Proxy Manager' }) expect(store.isOpen).toBe(false) expect(store.panelAppId).toBe(null) expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.228:8081', + 'http://192.0.2.10:8081', '_blank', 'noopener,noreferrer', ) @@ -161,7 +161,7 @@ describe('useAppLauncherStore', () => { }) const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:8081', title: 'Nginx Proxy Manager' }) + store.open({ url: 'http://192.0.2.10:8081', title: 'Nginx Proxy Manager' }) // Tab-only app on mobile-web: open directly in a new browser tab (the // companion would use the in-app WebView). No session, no route push, no @@ -170,7 +170,7 @@ describe('useAppLauncherStore', () => { expect(store.panelAppId).toBe(null) expect(mockPush).not.toHaveBeenCalled() expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.228:8081', + 'http://192.0.2.10:8081', '_blank', 'noopener,noreferrer', ) @@ -179,10 +179,10 @@ describe('useAppLauncherStore', () => { it('opens Nginx Proxy Manager in new tab using title hint when URL is path-only', () => { const store = useAppLauncherStore() - store.open({ url: 'https://192.168.1.228/app/nginx-proxy-manager/', title: 'Nginx Proxy Manager' }) + store.open({ url: 'https://192.0.2.10/app/nginx-proxy-manager/', title: 'Nginx Proxy Manager' }) expect(mockWindowOpen).toHaveBeenCalledWith( - 'https://192.168.1.228/app/nginx-proxy-manager/', + 'https://192.0.2.10/app/nginx-proxy-manager/', '_blank', 'noopener,noreferrer', ) @@ -192,10 +192,10 @@ describe('useAppLauncherStore', () => { it('normalizes legacy Nginx Proxy Manager ports to 8081', () => { const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:8181', title: 'Nginx Proxy Manager' }) + store.open({ url: 'http://192.0.2.10:8181', title: 'Nginx Proxy Manager' }) expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.228:8081', + 'http://192.0.2.10:8081', '_blank', 'noopener,noreferrer', ) @@ -204,10 +204,10 @@ describe('useAppLauncherStore', () => { it('normalizes legacy Uptime Kuma port 3001 to 3002', () => { const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:3001', title: 'Uptime Kuma' }) + store.open({ url: 'http://192.0.2.10:3001', title: 'Uptime Kuma' }) expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.228:3002', + 'http://192.0.2.10:3002', '_blank', 'noopener,noreferrer', ) @@ -218,10 +218,10 @@ describe('useAppLauncherStore', () => { it('opens Uptime Kuma in new tab using title hint when URL is path-only', () => { const store = useAppLauncherStore() - store.open({ url: 'https://192.168.1.228/app/uptime-kuma/', title: 'Uptime Kuma' }) + store.open({ url: 'https://192.0.2.10/app/uptime-kuma/', title: 'Uptime Kuma' }) expect(mockWindowOpen).toHaveBeenCalledWith( - 'https://192.168.1.228/app/uptime-kuma/', + 'https://192.0.2.10/app/uptime-kuma/', '_blank', 'noopener,noreferrer', ) @@ -231,12 +231,12 @@ describe('useAppLauncherStore', () => { it('routes Home Assistant (port 8123) to full-page session', () => { const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:8123', title: 'Home Assistant' }) + store.open({ url: 'http://192.0.2.10:8123', title: 'Home Assistant' }) expect(store.isOpen).toBe(false) expect(store.panelAppId).toBe(null) expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.228:8123', + 'http://192.0.2.10:8123', '_blank', 'noopener,noreferrer', ) @@ -245,12 +245,12 @@ describe('useAppLauncherStore', () => { it('routes Grafana (port 3000) to full-page session', () => { const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:3000', title: 'Grafana' }) + store.open({ url: 'http://192.0.2.10:3000', title: 'Grafana' }) expect(store.isOpen).toBe(false) expect(store.panelAppId).toBe(null) expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.228:3000', + 'http://192.0.2.10:3000', '_blank', 'noopener,noreferrer', ) @@ -259,12 +259,12 @@ describe('useAppLauncherStore', () => { it('opens Gitea path URL in new tab', () => { const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228/app/gitea/', title: 'Gitea' }) + store.open({ url: 'http://192.0.2.10/app/gitea/', title: 'Gitea' }) expect(store.isOpen).toBe(false) expect(store.panelAppId).toBe(null) expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.228/app/gitea/', + 'http://192.0.2.10/app/gitea/', '_blank', 'noopener,noreferrer', ) @@ -273,7 +273,7 @@ describe('useAppLauncherStore', () => { it('does not map raw port 3001 to gitea session', () => { const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:3001', title: 'Unknown 3001' }) + store.open({ url: 'http://192.0.2.10:3001', title: 'Unknown 3001' }) expect(store.panelAppId).toBe(null) expect(store.isOpen).toBe(true) @@ -283,11 +283,11 @@ describe('useAppLauncherStore', () => { const store = useAppLauncherStore() // Use an unresolvable URL so it doesn't route to session - store.open({ url: 'http://192.168.1.228:9999', title: 'Unknown', openInNewTab: true }) + store.open({ url: 'http://192.0.2.10:9999', title: 'Unknown', openInNewTab: true }) expect(store.isOpen).toBe(false) expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.228:9999', + 'http://192.0.2.10:9999', '_blank', 'noopener,noreferrer', ) @@ -327,13 +327,13 @@ describe('useAppLauncherStore', () => { it('routes HTTPS same-host apps via session view', () => { Object.defineProperty(window, 'location', { - value: { origin: 'https://192.168.1.228', protocol: 'https:', hostname: '192.168.1.228' }, + value: { origin: 'https://192.0.2.10', protocol: 'https:', hostname: '192.0.2.10' }, writable: true, configurable: true, }) const store = useAppLauncherStore() - store.open({ url: 'http://192.168.1.228:8083', title: 'FileBrowser' }) + store.open({ url: 'http://192.0.2.10:8083', title: 'FileBrowser' }) // Known port — routes to session (panel mode by default) expect(store.isOpen).toBe(false) @@ -344,17 +344,17 @@ describe('useAppLauncherStore', () => { const store = useAppLauncherStore() // Unresolvable URL — falls through to iframe overlay - store.open({ url: 'http://192.168.1.228:9999', title: 'Custom App' }) + store.open({ url: 'http://192.0.2.10:9999', title: 'Custom App' }) expect(store.isOpen).toBe(true) - expect(store.url).toBe('http://192.168.1.228:9999') + expect(store.url).toBe('http://192.0.2.10:9999') expect(store.title).toBe('Custom App') expect(mockWindowOpen).not.toHaveBeenCalled() }) it('opens unknown different-host URL in iframe overlay', () => { Object.defineProperty(window, 'location', { - value: { origin: 'https://192.168.1.228', protocol: 'https:', hostname: '192.168.1.228' }, + value: { origin: 'https://192.0.2.10', protocol: 'https:', hostname: '192.0.2.10' }, writable: true, configurable: true, }) @@ -370,7 +370,7 @@ describe('useAppLauncherStore', () => { it('close resets state', () => { const store = useAppLauncherStore() // Use unknown URL to trigger iframe overlay - store.open({ url: 'http://192.168.1.228:9999', title: 'Custom' }) + store.open({ url: 'http://192.0.2.10:9999', title: 'Custom' }) store.close() @@ -385,7 +385,7 @@ describe('useAppLauncherStore', () => { const mockButton = { focus: vi.fn() } as unknown as HTMLElement Object.defineProperty(document, 'activeElement', { value: mockButton, configurable: true }) - store.open({ url: 'http://192.168.1.228:9999', title: 'Custom' }) + store.open({ url: 'http://192.0.2.10:9999', title: 'Custom' }) store.close() expect(store.isOpen).toBe(false) diff --git a/neode-ui/src/utils/dummyApps.ts b/neode-ui/src/utils/dummyApps.ts index a2e9b013..34f9e464 100644 --- a/neode-ui/src/utils/dummyApps.ts +++ b/neode-ui/src/utils/dummyApps.ts @@ -144,7 +144,7 @@ export const dummyApps: Record = { 'interface-addresses': { main: { 'tor-address': 'lorabell.onion', - 'lan-address': 'http://192.168.1.166' + 'lan-address': 'http://192.0.2.13' } }, status: ServiceStatus.Running diff --git a/neode-ui/src/views/AppRegistries.vue b/neode-ui/src/views/AppRegistries.vue index 1236a392..976e5d98 100644 --- a/neode-ui/src/views/AppRegistries.vue +++ b/neode-ui/src/views/AppRegistries.vue @@ -129,7 +129,7 @@

The URL should be of the form host[:port]/namespace — for example ghcr.io/myorg or - 192.168.1.50:3000/apps. Registries are + 192.0.2.10:3000/apps. Registries are added to the end of the list; use "Make primary" to reorder.

diff --git a/neode-ui/src/views/ContainerApps.vue b/neode-ui/src/views/ContainerApps.vue index dd675190..9d5ee67d 100644 --- a/neode-ui/src/views/ContainerApps.vue +++ b/neode-ui/src/views/ContainerApps.vue @@ -368,7 +368,7 @@ const backendPort = 5678 function getLaunchUrl(app: BundledApp): string { // Prefer lan_address from backend (for apps with custom UIs) if (app.lan_address) { - // Replace localhost so Launch works when browsing from another machine (e.g. 192.168.1.228) + // Replace localhost so Launch works when browsing from another machine (e.g. a LAN address) let url = app.lan_address.replace(/localhost/i, currentHost.value) // LND UI (and other app UIs) need backend URL for live data (logs, getinfo proxy) if (app.id === 'lnd') { diff --git a/neode-ui/src/views/__tests__/AppSessionMobileNewTab.test.ts b/neode-ui/src/views/__tests__/AppSessionMobileNewTab.test.ts index dd64361b..531a2e57 100644 --- a/neode-ui/src/views/__tests__/AppSessionMobileNewTab.test.ts +++ b/neode-ui/src/views/__tests__/AppSessionMobileNewTab.test.ts @@ -56,7 +56,7 @@ describe('AppSession mobile new-tab apps', () => { configurable: true, }) Object.defineProperty(window, 'location', { - value: { hostname: '192.168.1.228' }, + value: { hostname: '192.0.2.10' }, writable: true, configurable: true, }) diff --git a/neode-ui/src/views/__tests__/ServerNetworkRefresh.test.ts b/neode-ui/src/views/__tests__/ServerNetworkRefresh.test.ts index 6f00e44a..7fa543eb 100644 --- a/neode-ui/src/views/__tests__/ServerNetworkRefresh.test.ts +++ b/neode-ui/src/views/__tests__/ServerNetworkRefresh.test.ts @@ -103,7 +103,7 @@ describe('Server network refresh states', () => { vi.mocked(rpcClient.call).mockImplementation((request: { method: string }) => { if (request.method === 'network.list-interfaces') { return Promise.resolve({ - interfaces: [{ name: 'eth0', type: 'ethernet', state: 'up', mac: '00:11:22:33:44:55', ipv4: ['192.168.1.10'] }], + interfaces: [{ name: 'eth0', type: 'ethernet', state: 'up', mac: '00:11:22:33:44:55', ipv4: ['192.0.2.10'] }], }) } if (request.method === 'network.diagnostics') { @@ -131,7 +131,7 @@ describe('Server network refresh states', () => { await flushPromises() expect(wrapper.text()).toContain('eth0') - expect(wrapper.text()).toContain('192.168.1.10') + expect(wrapper.text()).toContain('192.0.2.10') const pendingInterfaces = deferred<{ interfaces: [] }>() vi.mocked(rpcClient.call).mockImplementation((request: { method: string }) => { @@ -143,7 +143,7 @@ describe('Server network refresh states', () => { await wrapper.vm.$nextTick() expect(wrapper.text()).toContain('eth0') - expect(wrapper.text()).toContain('192.168.1.10') + expect(wrapper.text()).toContain('192.0.2.10') expect(wrapper.text()).toContain('Refreshing interfaces...') pendingInterfaces.reject(new Error('offline')) @@ -151,7 +151,7 @@ describe('Server network refresh states', () => { await flushPromises() expect(wrapper.text()).toContain('eth0') - expect(wrapper.text()).toContain('192.168.1.10') + expect(wrapper.text()).toContain('192.0.2.10') }) it('keeps Tor services visible while refresh is pending or fails', async () => { diff --git a/neode-ui/src/views/appDetails/appDetailsData.ts b/neode-ui/src/views/appDetails/appDetailsData.ts index e3af6854..bbd16f56 100644 --- a/neode-ui/src/views/appDetails/appDetailsData.ts +++ b/neode-ui/src/views/appDetails/appDetailsData.ts @@ -52,39 +52,6 @@ export function resolvePackageKey(routeId: string): string { /** Apps that depend on Bitcoin being synced */ export const BITCOIN_DEPENDENT_APPS = ['lnd', 'electrumx', 'electrs', 'mempool-electrs', 'btcpay-server', 'btcpayserver'] -/** App launch URLs for dev and prod environments */ -export const APP_URLS: Record = { - 'lorabell': { dev: 'http://192.168.1.166', prod: 'http://192.168.1.166' }, - 'atob': { dev: 'http://localhost:8102', prod: 'https://app.atobitcoin.io' }, - 'k484': { dev: 'http://localhost:8103', prod: 'http://localhost:8103' }, - 'bitcoin': { dev: 'http://localhost:8332', prod: 'http://localhost:8332' }, - 'btcpay-server': { dev: 'http://localhost:23000', prod: 'http://localhost:23000' }, - 'homeassistant': { dev: 'http://localhost:8123', prod: 'http://localhost:8123' }, - 'grafana': { dev: 'http://localhost:3000', prod: 'http://localhost:3000' }, - 'endurain': { dev: 'http://localhost:8080', prod: 'http://localhost:8080' }, - 'fedimint': { dev: 'http://localhost:8175', prod: 'http://192.168.1.228:8175' }, - 'fedimint-gateway': { dev: 'http://localhost:8176', prod: 'http://192.168.1.228:8176' }, - 'morphos-server': { dev: 'http://localhost:8081', prod: 'http://localhost:8081' }, - 'lightning-stack': { dev: 'http://localhost:9735', prod: 'http://localhost:9735' }, - 'mempool': { dev: 'http://localhost:4080', prod: 'http://localhost:4080' }, - 'ollama': { dev: 'http://localhost:11434', prod: 'http://localhost:11434' }, - 'searxng': { dev: 'http://localhost:8888', prod: 'http://localhost:8888' }, - 'nextcloud': { dev: 'http://localhost:8085', prod: 'http://localhost:8085' }, - 'vaultwarden': { dev: 'http://localhost:8082', prod: 'http://localhost:8082' }, - 'jellyfin': { dev: 'http://localhost:8096', prod: 'http://localhost:8096' }, - 'photoprism': { dev: 'http://localhost:2342', prod: 'http://localhost:2342' }, - 'immich': { dev: 'http://localhost:2283', prod: 'http://localhost:2283' }, - 'filebrowser': { dev: 'http://localhost:8083', prod: 'http://localhost:8083' }, - 'nginx-proxy-manager': { dev: 'http://localhost:8081', prod: 'http://localhost:8081' }, - 'gitea': { dev: 'http://localhost:3001', prod: 'http://localhost:3001' }, - 'portainer': { dev: 'http://localhost:9000', prod: 'http://localhost:9000' }, - 'uptime-kuma': { dev: 'http://localhost:3002', prod: 'http://localhost:3002' }, - 'tailscale': { dev: 'http://localhost:8240', prod: 'http://localhost:8240' }, - 'lnd': { dev: 'http://localhost:18083', prod: 'http://localhost:18083' }, - 'bitcoin-knots': { dev: 'http://localhost:8334', prod: 'http://localhost:8334' }, - 'botfights': { dev: 'http://localhost:9100', prod: 'http://localhost:9100' }, -} - /** V3 onion addresses are 56+ chars + .onion. Placeholders like "btcpay.onion" are not real. */ export function isRealOnionAddress(addr: string | undefined): boolean { return !!(addr && addr.endsWith('.onion') && addr.length >= 60 && addr.length <= 70) diff --git a/neode-ui/src/views/appSession/__tests__/appOrigin.test.ts b/neode-ui/src/views/appSession/__tests__/appOrigin.test.ts index c2546bd0..7086aaec 100644 --- a/neode-ui/src/views/appSession/__tests__/appOrigin.test.ts +++ b/neode-ui/src/views/appSession/__tests__/appOrigin.test.ts @@ -27,8 +27,8 @@ describe('appOrigin', () => { }) it('keeps the hostname the user actually typed, not a fixed name', () => { - setLocation('https:', '100.69.68.39') - expect(appOrigin(3000)).toBe('https://100.69.68.39:3000') + setLocation('https:', '100.64.0.5') + expect(appOrigin(3000)).toBe('https://100.64.0.5:3000') }) }) diff --git a/neode-ui/src/views/appSession/__tests__/appSessionConfig.test.ts b/neode-ui/src/views/appSession/__tests__/appSessionConfig.test.ts index d9c51de1..54ceb5e1 100644 --- a/neode-ui/src/views/appSession/__tests__/appSessionConfig.test.ts +++ b/neode-ui/src/views/appSession/__tests__/appSessionConfig.test.ts @@ -16,19 +16,19 @@ describe('appSessionConfig', () => { it('resolves direct app ports against the current browser host', () => { Object.defineProperty(window, 'location', { - value: { hostname: '192.168.1.228' }, + value: { hostname: '192.0.2.10' }, writable: true, configurable: true, }) - expect(resolveAppUrl('mempool')).toBe('http://192.168.1.228:4080') - expect(resolveAppUrl('indeedhub')).toBe('http://192.168.1.228:7778') - expect(resolveAppUrl('botfights')).toBe('http://192.168.1.228:9100') + expect(resolveAppUrl('mempool')).toBe('http://192.0.2.10:4080') + expect(resolveAppUrl('indeedhub')).toBe('http://192.0.2.10:7778') + expect(resolveAppUrl('botfights')).toBe('http://192.0.2.10:9100') }) it('uses manifest-generated launch ports for apps outside the manual override list', () => { Object.defineProperty(window, 'location', { - value: { hostname: '192.168.1.228' }, + value: { hostname: '192.0.2.10' }, writable: true, configurable: true, }) @@ -36,12 +36,12 @@ describe('appSessionConfig', () => { // did-wallet's manifest publishes host port 8088 (apps/did-wallet/ // manifest.yml) — assert against the manifest-generated value, which is // exactly what this test exists to protect. - expect(resolveAppUrl('did-wallet')).toBe('http://192.168.1.228:8088') + expect(resolveAppUrl('did-wallet')).toBe('http://192.0.2.10:8088') }) it('does not treat service-only tcp ports as web launch surfaces', () => { Object.defineProperty(window, 'location', { - value: { hostname: '192.168.1.228' }, + value: { hostname: '192.0.2.10' }, writable: true, configurable: true, }) @@ -51,21 +51,21 @@ describe('appSessionConfig', () => { it('keeps NetBird on the unified dashboard proxy port', () => { Object.defineProperty(window, 'location', { - value: { hostname: '192.168.1.228' }, + value: { hostname: '192.0.2.10' }, writable: true, configurable: true, }) - expect(resolveAppUrl('netbird', undefined, 'http://localhost:8086')).toBe('http://192.168.1.228:8087') + expect(resolveAppUrl('netbird', undefined, 'http://localhost:8086')).toBe('http://192.0.2.10:8087') }) it('uses backend runtime URLs for apps with dynamic launch surfaces', () => { Object.defineProperty(window, 'location', { - value: { hostname: '192.168.1.228' }, + value: { hostname: '192.0.2.10' }, writable: true, configurable: true, }) - expect(resolveAppUrl('filebrowser', undefined, 'http://localhost:18083')).toBe('http://192.168.1.228:18083') + expect(resolveAppUrl('filebrowser', undefined, 'http://localhost:18083')).toBe('http://192.0.2.10:18083') }) }) diff --git a/neode-ui/src/views/apps/__tests__/AppIconGrid.test.ts b/neode-ui/src/views/apps/__tests__/AppIconGrid.test.ts index 5322944b..11ffcea9 100644 --- a/neode-ui/src/views/apps/__tests__/AppIconGrid.test.ts +++ b/neode-ui/src/views/apps/__tests__/AppIconGrid.test.ts @@ -52,7 +52,7 @@ describe('AppIconGrid', () => { configurable: true, }) Object.defineProperty(window, 'location', { - value: { hostname: '192.168.1.198' }, + value: { hostname: '192.0.2.11' }, writable: true, configurable: true, }) @@ -112,7 +112,7 @@ describe('AppIconGrid', () => { await flushPromises() expect(mockWindowOpen).toHaveBeenCalledWith( - 'http://192.168.1.198:3001', + 'http://192.0.2.11:3001', '_blank', 'noopener,noreferrer', ) diff --git a/neode-ui/src/views/fleet/__tests__/useFleetData.test.ts b/neode-ui/src/views/fleet/__tests__/useFleetData.test.ts index 75d8a9d1..52a6c4b0 100644 --- a/neode-ui/src/views/fleet/__tests__/useFleetData.test.ts +++ b/neode-ui/src/views/fleet/__tests__/useFleetData.test.ts @@ -91,19 +91,19 @@ describe('fleet data helpers', () => { node_id: 'abcdef123456', node_name: 'Kitchen Node', hostname: 'kitchen-node', - server_url: 'https://192.168.1.20', + server_url: 'https://192.0.2.20', }) const hostOnly = normalizeFleetNode({ node_id: '123456abcdef', hostname: 'workshop-node', - server_url: 'https://192.168.1.21', + server_url: 'https://192.0.2.21', }) const idOnly = normalizeFleetNode({ node_id: 'feedfacecafebeef' }) expect(fleetNodeDisplayName(named)).toBe('Kitchen Node') expect(fleetNodeSubtitle(named)).toBe('kitchen-node') expect(fleetNodeDisplayName(hostOnly)).toBe('workshop-node') - expect(fleetNodeSubtitle(hostOnly)).toBe('https://192.168.1.21') + expect(fleetNodeSubtitle(hostOnly)).toBe('https://192.0.2.21') expect(fleetNodeDisplayName(idOnly)).toBe('feedface') expect(fleetNodeSubtitle(idOnly)).toBe('feedfacecafebeef') }) diff --git a/neode-ui/vite.config.ts b/neode-ui/vite.config.ts index e8a8f0dc..afea9723 100644 --- a/neode-ui/vite.config.ts +++ b/neode-ui/vite.config.ts @@ -117,7 +117,7 @@ export default defineConfig({ } }, server: { - host: true, // listen on 0.0.0.0 so the dev UI is reachable over the LAN (e.g. http://192.168.1.116:8100) + host: true, // listen on 0.0.0.0 so the dev UI is reachable over the LAN (e.g. http://192.0.2.12:8100) port: 8100, proxy: { '/rpc/v1': { diff --git a/scripts/app-catalog-image-smoke-test.py b/scripts/app-catalog-image-smoke-test.py index b6ab7e80..7e3e71be 100755 --- a/scripts/app-catalog-image-smoke-test.py +++ b/scripts/app-catalog-image-smoke-test.py @@ -13,7 +13,7 @@ Checks: Usage: scripts/app-catalog-image-smoke-test.py \ - --target archipelago@192.168.1.198 \ + --target archipelago@192.0.2.11 \ --ssh-key /home/archipelago/.ssh/id_ed25519 """ diff --git a/scripts/app-surface-smoke-test.sh b/scripts/app-surface-smoke-test.sh index a014a021..096b1cd6 100755 --- a/scripts/app-surface-smoke-test.sh +++ b/scripts/app-surface-smoke-test.sh @@ -7,7 +7,7 @@ # the common "container is running but UI disappeared" failure mode. # # Usage: -# scripts/app-surface-smoke-test.sh --target archipelago@192.168.1.228 --ssh-key /path/key +# scripts/app-surface-smoke-test.sh --target archipelago@192.0.2.10 --ssh-key /path/key set -euo pipefail diff --git a/scripts/bitcoin-stack-lifecycle-test.sh b/scripts/bitcoin-stack-lifecycle-test.sh index 34cae1f4..ac361c49 100755 --- a/scripts/bitcoin-stack-lifecycle-test.sh +++ b/scripts/bitcoin-stack-lifecycle-test.sh @@ -10,8 +10,8 @@ # installed nodes, but it will briefly interrupt Bitcoin/ElectrumX service. # # Usage: -# scripts/bitcoin-stack-lifecycle-test.sh --target archipelago@192.168.1.228 -# scripts/bitcoin-stack-lifecycle-test.sh --target archipelago@192.168.1.116 --cycles 5 +# scripts/bitcoin-stack-lifecycle-test.sh --target archipelago@192.0.2.10 +# scripts/bitcoin-stack-lifecycle-test.sh --target archipelago@192.0.2.12 --cycles 5 set -euo pipefail @@ -50,7 +50,7 @@ while [ "$#" -gt 0 ]; do done if [ -z "$TARGET" ]; then - echo "--target is required, for example archipelago@192.168.1.228" >&2 + echo "--target is required, for example archipelago@192.0.2.10" >&2 exit 2 fi diff --git a/scripts/create-release.sh b/scripts/create-release.sh index 2f2308ad..9739b148 100755 --- a/scripts/create-release.sh +++ b/scripts/create-release.sh @@ -128,7 +128,7 @@ if $DRY_RUN; then echo "" echo "After this script, you would:" echo " - Push: git push && git push --tags" - echo " - Build ISOs on server: ssh archipelago@192.168.1.228" + echo " - Build ISOs on server: ssh archipelago@192.0.2.10" exit 0 fi diff --git a/scripts/dev-container-test.sh b/scripts/dev-container-test.sh index 7973e0a1..939e26af 100755 --- a/scripts/dev-container-test.sh +++ b/scripts/dev-container-test.sh @@ -16,10 +16,15 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}" -SSH_HOST="${ARCHIPELAGO_SSH_HOST:-archipelago@192.168.1.228}" +SSH_HOST="${ARCHIPELAGO_SSH_HOST:-}" +if [ -z "$SSH_HOST" ]; then + echo "ARCHIPELAGO_SSH_HOST must be set, e.g. archipelago@" >&2 + exit 2 +fi +HOST_ONLY="${SSH_HOST#*@}" SSH_OPTS="-o StrictHostKeyChecking=no -o ServerAliveInterval=15 -i $SSH_KEY" REMOTE_DIR="/home/archipelago/archy" -RPC_URL="http://192.168.1.228/rpc/v1" +RPC_URL="http://${HOST_ONLY}/rpc/v1" COOKIE="" ONCE=false [ "$1" = "--once" ] && ONCE=true @@ -66,7 +71,7 @@ login() { wait_for_health() { local timeout=${1:-30} for i in $(seq 1 "$timeout"); do - if curl -sf "http://192.168.1.228/health" >/dev/null 2>&1; then + if curl -sf "http://${HOST_ONLY}/health" >/dev/null 2>&1; then return 0 fi sleep 1 diff --git a/scripts/dev-start.sh b/scripts/dev-start.sh index e87b4c48..911e3279 100755 --- a/scripts/dev-start.sh +++ b/scripts/dev-start.sh @@ -82,7 +82,7 @@ case $choice in echo " a) Preview GRUB background only (instant):" echo " python3 image-recipe/branding/generate-grub-background.py /tmp/grub-bg.png && open /tmp/grub-bg.png" echo "" - echo " b) Download an ISO from FileBrowser (http://192.168.1.228:8083)" + echo " b) Download an ISO from FileBrowser (http://192.0.2.10:8083)" echo " then drop it on your Desktop and re-run this option." echo "" echo " Files you can edit:" diff --git a/scripts/install-tui-demo.sh b/scripts/install-tui-demo.sh index d3e2cf19..79168699 100755 --- a/scripts/install-tui-demo.sh +++ b/scripts/install-tui-demo.sh @@ -576,12 +576,12 @@ screen_complete() { # URL in orange goto $row 1 - p " ${ORANGE}http://192.168.1.198${NC}" + p " ${ORANGE}http://192.0.2.11${NC}" row=$((row + 2)) # Credentials — white, NOT orange (user request) goto $row 1 - p " ${WHITE}SSH ssh archipelago@192.168.1.198${NC}" + p " ${WHITE}SSH ssh archipelago@192.0.2.11${NC}" row=$((row + 1)) goto $row 1 p " ${WHITE}Password archipelago${NC}" diff --git a/scripts/resilience/README.md b/scripts/resilience/README.md index 102efedb..9c6e20ce 100644 --- a/scripts/resilience/README.md +++ b/scripts/resilience/README.md @@ -28,23 +28,23 @@ will never catch. This harness is the gate. Against the .228 test node: - scripts/resilience/resilience.sh archipelago@192.168.1.228 + scripts/resilience/resilience.sh archipelago@192.0.2.10 Or non-interactive (CI): RESILIENCE_SSH_PASS=… RESILIENCE_UI_PASS=… \ - scripts/resilience/resilience.sh archipelago@192.168.1.228 + scripts/resilience/resilience.sh archipelago@192.0.2.10 Filters: # Smoke test (3 apps, no reboot, ~15min) - scripts/resilience/resilience.sh archipelago@192.168.1.228 smoke + scripts/resilience/resilience.sh archipelago@192.0.2.10 smoke # Single app - scripts/resilience/resilience.sh archipelago@192.168.1.228 bitcoin-knots + scripts/resilience/resilience.sh archipelago@192.0.2.10 bitcoin-knots # Subset - scripts/resilience/resilience.sh archipelago@192.168.1.228 bitcoin-knots,lnd + scripts/resilience/resilience.sh archipelago@192.0.2.10 bitcoin-knots,lnd Without a filter, the harness sweeps **every** app in the catalog (~24 apps × 7 per-app transitions + 2 batch transitions) and runs the diff --git a/scripts/resilience/lib.sh b/scripts/resilience/lib.sh index 89d2ec26..7fe22d5a 100755 --- a/scripts/resilience/lib.sh +++ b/scripts/resilience/lib.sh @@ -3,7 +3,7 @@ # Sourced by resilience.sh — do not invoke directly. # Required env (set by resilience.sh before sourcing): -# TARGET — ssh target, e.g. archipelago@192.168.1.228 +# TARGET — ssh target, e.g. archipelago@192.0.2.10 # RPC_URL — http://:5678/rpc/v1 # COOKIE_JAR — path for curl cookie store # SSH_PASS — sshpass password diff --git a/scripts/resilience/resilience.sh b/scripts/resilience/resilience.sh index 0bdcc024..4643456d 100755 --- a/scripts/resilience/resilience.sh +++ b/scripts/resilience/resilience.sh @@ -8,7 +8,7 @@ # remains in the expected state at every step. # # Usage: -# scripts/resilience/resilience.sh archipelago@192.168.1.228 [filter] +# scripts/resilience/resilience.sh archipelago@192.0.2.10 [filter] # # `filter` is a comma-separated list of app IDs (or "smoke" for the curated # fast subset). Default: every app in app-catalog/catalog.json. diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index b54a3074..acf75af8 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -5,7 +5,11 @@ set -euo pipefail -HOST="${1:-192.168.1.198}" +HOST="${1:-${ARCHY_HOST:-}}" +if [ -z "$HOST" ]; then + echo "usage: $0 (or set ARCHY_HOST)" >&2 + exit 2 +fi PASS=0 FAIL=0 FAILURES="" diff --git a/scripts/trust-archipelago-cert.sh b/scripts/trust-archipelago-cert.sh index 55120f2b..75afc0d1 100755 --- a/scripts/trust-archipelago-cert.sh +++ b/scripts/trust-archipelago-cert.sh @@ -1,17 +1,21 @@ #!/bin/bash # # Trust the Archipelago server's self-signed certificate on macOS. -# Run this to eliminate "Not secure" when accessing https://192.168.1.228 +# Run this to eliminate "Not secure" when accessing https:// # # Usage: ./scripts/trust-archipelago-cert.sh [host] -# Default host: 192.168.1.228 +# Host is required: pass it as $1 or set ARCHY_HOST # # Requires: SSH access to archipelago@host (uses deploy-config.sh password) # set -e -HOST="${1:-192.168.1.228}" +HOST="${1:-${ARCHY_HOST:-}}" +if [ -z "$HOST" ]; then + echo "usage: $0 (or set ARCHY_HOST)" >&2 + exit 2 +fi CERT_FILE="/tmp/archipelago-${HOST}.crt" KEYCHAIN="${HOME}/Library/Keychains/login.keychain-db" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" diff --git a/tests/multinode/.env.example b/tests/multinode/.env.example index 5baca825..129e1cf7 100644 --- a/tests/multinode/.env.example +++ b/tests/multinode/.env.example @@ -3,8 +3,8 @@ # NEVER commit real node passwords. # smoke.sh / repro-federation-sync.sh -A_PW=changeme # node A (default URL http://192.168.1.116) -B_PW=changeme # node B (default URL https://192.168.1.228) +A_PW=changeme # node A (default URL http://192.0.2.12) +B_PW=changeme # node B (default URL https://192.0.2.10) #C_URL=https://x.x.x.x # optional third node #C_PW=changeme diff --git a/tests/multinode/lib/multinode.bash b/tests/multinode/lib/multinode.bash index 84023802..3ed10942 100755 --- a/tests/multinode/lib/multinode.bash +++ b/tests/multinode/lib/multinode.bash @@ -11,8 +11,8 @@ # # Usage: # source tests/multinode/lib/multinode.bash -# node_register A https://192.168.1.228 "$A_PW" -# node_register B http://192.168.1.116 "$B_PW" +# node_register A https://192.0.2.10 "$A_PW" +# node_register B http://192.0.2.12 "$B_PW" # node_login A; node_login B # node_rpc A node.tor-address # node_result B federation.list-nodes diff --git a/tests/multinode/meshtastic.sh b/tests/multinode/meshtastic.sh index 75609b96..d6713ad1 100755 --- a/tests/multinode/meshtastic.sh +++ b/tests/multinode/meshtastic.sh @@ -33,8 +33,8 @@ # # Usage: # tests/multinode/meshtastic.sh -# MA_URL=http://192.168.1.116 MB_URL=https://192.168.1.228 \ -# MC_URL=https://192.168.1.198 tests/multinode/meshtastic.sh +# MA_URL=http://192.0.2.12 MB_URL=https://192.0.2.10 \ +# MC_URL=https://192.0.2.11 tests/multinode/meshtastic.sh # # Requires: curl, jq. Exit code = number of failed assertions (0 = all green). @@ -44,8 +44,8 @@ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$HERE/lib/multinode.bash" # ── node registration ────────────────────────────────────────────────────── -MA_URL="${MA_URL:-http://192.168.1.116}"; MA_PW="${MA_PW:?MA_PW required — export it or set tests/multinode/.env (see .env.example)}" -MB_URL="${MB_URL:-https://192.168.1.228}"; MB_PW="${MB_PW:?MB_PW required — export it or set tests/multinode/.env (see .env.example)}" +MA_URL="${MA_URL:-http://192.0.2.12}"; MA_PW="${MA_PW:?MA_PW required — export it or set tests/multinode/.env (see .env.example)}" +MB_URL="${MB_URL:-https://192.0.2.10}"; MB_PW="${MB_PW:?MB_PW required — export it or set tests/multinode/.env (see .env.example)}" MC_URL="${MC_URL:-}"; MC_PW="${MC_PW:-}" PROP_WAIT="${PROP_WAIT:-45}" MB_NAME="${MB_NAME:-}" diff --git a/tests/multinode/repro-federation-sync.sh b/tests/multinode/repro-federation-sync.sh index 7de94bff..a50a3c6c 100755 --- a/tests/multinode/repro-federation-sync.sh +++ b/tests/multinode/repro-federation-sync.sh @@ -18,8 +18,8 @@ set -uo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$HERE/lib/multinode.bash" -A_URL="${A_URL:-http://192.168.1.116}"; A_PW="${A_PW:?A_PW required — export it or set tests/multinode/.env (see .env.example)}" -B_URL="${B_URL:-https://192.168.1.228}"; B_PW="${B_PW:?B_PW required — export it or set tests/multinode/.env (see .env.example)}" +A_URL="${A_URL:-http://192.0.2.12}"; A_PW="${A_PW:?A_PW required — export it or set tests/multinode/.env (see .env.example)}" +B_URL="${B_URL:-https://192.0.2.10}"; B_PW="${B_PW:?B_PW required — export it or set tests/multinode/.env (see .env.example)}" bar() { printf '\n=== %s ===\n' "$*"; } diff --git a/tests/multinode/smoke.sh b/tests/multinode/smoke.sh index 1cbbe71b..bb2c1cd1 100644 --- a/tests/multinode/smoke.sh +++ b/tests/multinode/smoke.sh @@ -21,13 +21,13 @@ # # Usage: # tests/multinode/smoke.sh -# A_URL=http://192.168.1.116 B_URL=https://192.168.1.228 tests/multinode/smoke.sh +# A_URL=http://192.0.2.12 B_URL=https://192.0.2.10 tests/multinode/smoke.sh set -uo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$HERE/lib/multinode.bash" -A_URL="${A_URL:-http://192.168.1.116}"; A_PW="${A_PW:?A_PW required — export it or set tests/multinode/.env (see .env.example)}" -B_URL="${B_URL:-https://192.168.1.228}"; B_PW="${B_PW:?B_PW required — export it or set tests/multinode/.env (see .env.example)}" +A_URL="${A_URL:-http://192.0.2.12}"; A_PW="${A_PW:?A_PW required — export it or set tests/multinode/.env (see .env.example)}" +B_URL="${B_URL:-https://192.0.2.10}"; B_PW="${B_PW:?B_PW required — export it or set tests/multinode/.env (see .env.example)}" C_URL="${C_URL:-}"; C_PW="${C_PW:-}" # ── tiny assertion framework ────────────────────────────────────────────── diff --git a/tests/production-quality/lnd-cors-test.sh b/tests/production-quality/lnd-cors-test.sh index 950e872c..1ad0c9cb 100755 --- a/tests/production-quality/lnd-cors-test.sh +++ b/tests/production-quality/lnd-cors-test.sh @@ -5,7 +5,7 @@ # Bug B5: /lnd-connect-info duplicated ACAO on some nodes; /proxy/lnd/v1/* 401 # carries no ACAO fleet-wide. Browser blocks both. # -# Usage: ./lnd-cors-test.sh (e.g. 192.168.1.116 or 100.102.169.103) +# Usage: ./lnd-cors-test.sh (e.g. 192.0.2.12 or 100.64.0.7) # Exit 0 = all assertions pass. set -uo pipefail