Repository navigation
feat(cli): serve --bind to choose the listen address (default unchanged: 0.0.0.0) - #537
Conversation
…into modules main.rs and serve/mod.rs sit just under the 1000-line readability ratchet; the --bind option would push both over it. Move the flag/env resolvers to serve/options.rs and the Observe UI spawn to serve/observe_ui.rs. No behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed: 0.0.0.0) `temper serve` always bound 0.0.0.0, so a single-user server reached through an SSH tunnel or a local proxy had to be fenced off with firewall rules. --bind <ip> picks the address; TEMPER_BIND_ADDR selects it when the flag is not given, with the same precedence the storage and actor-runtime options use. Only 0.0.0.0 and 127.0.0.1 are accepted: Temper's own components (the Observe UI proxy, WASM host self-calls, the blob endpoint, the Discord transport) reach the API at http://127.0.0.1:{port}, so any other address would bind a server those callers cannot reach; a host name is refused rather than resolved. The Observe UI port probe and dev server and the auto-started local sandbox follow the chosen address, so --bind 127.0.0.1 leaves no listener on 0.0.0.0. Opt-in and backward compatible: without the flag or the variable nothing changes, and the startup line still names the address that was bound. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Valid finding — fixed in 101840e. The mechanics (detached child, discarded errors, unconditional "auto-started") predate this PR, but The fix probes the sandbox port with a connect before spawning — a bind probe misses the case on macOS, where
After a clean spawn the child is checked for an immediate exit before "auto-started" is printed, the handle is kept, and the child is killed when the server returns. ( Reproduction: SIGKILL a default serve → sandbox lingers on |
feat(cli): serve --bind to choose the listen address (port of nerdsane#537)
temper servealways bound0.0.0.0, so a single-user server reached through an SSH tunnel or a local proxy had to be fenced off with firewall rules. This adds an opt-in loopback-only mode:temper serve --bind <ip>: the address to bind. Default0.0.0.0, so nothing changes for anyone who does not pass it.TEMPER_BIND_ADDR: selects the address when the flag is not given, in the same precedence the storage and actor-runtime options use (flag wins over env; a set-but-invalid value aborts startup).0.0.0.0and127.0.0.1are accepted. Temper's own components — the Observe UI proxy, WASM host self-calls, the blob endpoint, the Discord transport — reach the API athttp://127.0.0.1:{port}, so any other address (::1, an interface IP, a host name) would bind a server those callers cannot reach. They are refused with a clear error; the list can widen later if those callers ever follow the bind address.--bind 127.0.0.1leaves no listener on0.0.0.0: the Observe UI port probe and dev server (next dev -H <bind>) and the auto-started local sandbox (local_sandbox.py --host <bind>, an unauthenticated shell-exec helper that previously always bound all interfaces) follow the same address. Both are passed only when the bind is non-default, so existing setups and older sandbox scripts are untouched.A preparatory refactor commit moves the serve option resolvers to
serve/options.rsand the Observe UI spawn toserve/observe_ui.rs:main.rs(990 lines) andserve/mod.rs(997) sit just under the 1000-line readability ratchet (PROD_FILES_GT1000baseline is exactly the current count), and the feature would have pushed both files over it.Verification
Unit tests (
cargo test -p temper-cli --bin temper, 101 passed): the resolver (default, env, trimming, blank env, explicit flag, flag-beats-env, rejected values includinglocalhost,::1, other IPs) and the clap parse of--bindand its default.cargo fmt --check,cargo clippy -p temper-cli --all-targets -- -D warnings, andscripts/readability-ratchet.sh checkall clean.On the built binary (listeners read with
lsof; "LAN IP" is the same machine's non-loopback address):--bind 127.0.0.1127.0.0.1:3399127.0.0.1:3409*:3399*:3409TEMPER_BIND_ADDR=127.0.0.1127.0.0.1:3399127.0.0.1:3409--bind 0.0.0.0+ env127.0.0.1*:3399*:3409With observe enabled and
--bind 127.0.0.1, the spawned dev server runsnext dev -H 127.0.0.1and listens on127.0.0.1:3400only; without the flag it still binds all interfaces, as before.Rejected values exit 1 before binding anything:
Context: we run Temper per person on a workspace behind an SSH tunnel; a security review asked for the listener to be loopback-only rather than relying on an iptables rule.
🤖 Generated with Claude Code
Fix sandbox restart behavior before merging so loopback-only mode does not silently leave the shell helper exposed.
Fix with agent prompt
Summary
Adds
--bindandTEMPER_BIND_ADDRwhile preserving the all-interface default.Reviews (1) · Last reviewed commit: "feat(cli): serve --bind to choose the li..." · Reviewed by Greptile