From b58c20311c4eb0b5e442171372c3d07b5f6332d1 Mon Sep 17 00:00:00 2001 From: Minseong Choi Date: Tue, 22 Sep 2026 13:54:31 +0900 Subject: [PATCH] test(bootstrap): pin the nano listen default to loopback nano_listen_is_loopback decides whether configure_nano_firewall opens the port, and hasJoined takes no token. A default that does not classify as loopback would make every fresh nano host a public auth relay. The harness now runs the classifier on four loopback binds and three routable ones, and feeds it the default resolve_nano_listen applies on a first install, with no operator value and no existing unit. Setting that default to 0.0.0.0:8081 or :8081, or counting 0.0.0.0 as loopback, now fails the harness. Test only. --- deploy/bootstrap_test.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/deploy/bootstrap_test.sh b/deploy/bootstrap_test.sh index ba932da..e363859 100644 --- a/deploy/bootstrap_test.sh +++ b/deploy/bootstrap_test.sh @@ -335,6 +335,23 @@ for v in 0.0.0.0:8081 '[::]:8081' :8081; do "$(run_summary "$v")" done +# Loopback is what keeps the firewall shut, and hasJoined takes no token: a default that +# does not classify as loopback turns every fresh nano host into a public auth relay. +run_loopback() { # listen + FELIS_NANO_LISTEN="$1" bash -c "$kblock"' + if nano_listen_is_loopback; then echo LOOPBACK; else echo ROUTABLE; fi' +} + +for v in 127.0.0.1:8081 127.0.0.5:8081 localhost:8081 '[::1]:8081'; do + expect "$v is loopback" LOOPBACK "$(run_loopback "$v")" +done +for v in 0.0.0.0:8081 10.0.0.5:8081 '[::]:8081'; do + expect "$v is not loopback" ROUTABLE "$(run_loopback "$v")" +done +ndefault="$(run_listen '' "$sdir/absent.service")" +ndefault="${ndefault#LISTEN: }" +expect "the default listen address (${ndefault:-empty}) is loopback" LOOPBACK "$(run_loopback "$ndefault")" + pblock="$(awk '/^prompt_install_mode\(\) \{/,/^}/' "$BS")" [ -n "$pblock" ] || { echo "FAIL: no prompt_install_mode found in $BS"; exit 1; } [ "$(printf '%s\n' "$pblock" | wc -l)" -lt 60 ] \