/** * ⟨q-79ee2086⟩ Where the bus listens. * * ⛔ ITS OWN MODULE BECAUSE `server.ts` RUNS ON IMPORT. `main()` is invoked at the bottom of that * file, so importing it to reach a helper starts a real server and never returns — a test that did * so would hang rather than fail, which is worse. These two predicates decide who can reach the bus, * so they must be reachable by a test without standing one up. */ /** * `AGENT_COORD_BIND` as a comma-separated LIST. * * ⛔ A LIST RATHER THAN `0.0.0.0`, and the difference is the whole point. `0.0.0.0` binds every * interface this host has now AND every one it gains later — a VPN coming up silently widens the * listener with nothing in any log. A list states exactly which doors are open, is reviewable on * disk, and cannot grow behind the operator's back. * * Empty or unset is `127.0.0.1`, the safe default. Duplicates collapse — the same address twice * would otherwise be a self-inflicted `EADDRINUSE` at startup, read as a real conflict. Order of * first appearance is preserved so the startup log matches what the operator wrote. */ export function parseBindList(raw: string | undefined): string[] { const parts = String(raw ?? "") .split(",") .map((s) => s.trim()) .filter((s) => s.length > 0); if (parts.length === 0) return ["127.0.0.1"]; return [...new Set(parts)]; } /** * Loopback exactly — the set that needs no per-agent token and no out-of-band-security assertion, * because nothing off this host can reach it. * * ⚠ AN EXACT MATCH, never a prefix or a regex. `127.0.0.1` is loopback; `127.0.0.10` and * `localhost.attacker.net` are not, and a gate satisfiable by a lookalike string is not a gate. */ export function isLoopbackAddr(addr: string): boolean { return addr === "127.0.0.1" || addr === "localhost" || addr === "::1"; }