fix(deploy): the tunnel's door binds loopback only (P9a)

Review finding: `--http` parsed whatever address it was given and bound
it. The door is the plaintext MCP service with a static bearer token;
plan 3.9 and the P9a model put a TLS proxy or tunnel in front of a
loopback listener, and no decision authorises exposing the books
unencrypted. `--http 0.0.0.0:7411` would have done exactly that.

`local::tunnel_address` now accepts only a loopback address
(127.0.0.0/8 or ::1; `127.0.0.1:7411` stays the default) and refuses
anything else with a message naming loopback and why. `server` refuses
while parsing, before it takes the lock or binds a socket; `serve`
refuses before it starts a host, so nothing is left half-open. The
bind-failure behaviour for a loopback address is unchanged (said, not
fatal, 3.9), as is the unit's hardening.

The test `the_tunnel_door_binds_loopback_only` refuses 0.0.0.0, a public
sample address and [::] through `server`, checks no socket or host was
left behind, refuses through `serve`, then starts a loopback listener and
reaches `books.start` with the bearer.

No accounting code, report or figure changes.
This commit is contained in:
swaits committed 2026-10-27 09:35:36 -06:00
1 parent 47951e5734
commit c8541ea9fc
7 files changed
+156 -29

No files matched your search

+5 -2
View File
@@ -148,8 +148,11 @@ is not a command; if your machine has a persistent Secret Service, use it.)
## 6. TLS and the door
The server listens on 127.0.0.1:7411 for the tunnel, and on its own Unix
sockets for anything running as the same account. Put TLS in front of the
loopback port. Two ways that need no open inbound port:
sockets for anything running as the same account. **The TCP door is
loopback only, on purpose**: it is plaintext with a static bearer token,
so `--http` refuses `0.0.0.0`, a LAN address or `[::]` before it binds
anything; the TLS proxy or tunnel is what faces the network. Put TLS in
front of the loopback port. Two ways that need no open inbound port:
**Tailscale Funnel** (a tailnet name, TLS included):