Add --host flag to ty serve - #699
Merged
Merged
Conversation
ty serve hardcoded ":port", listening on every interface — including whatever untrusted network the machine happens to be on. The board can create and execute tasks, so that reachability matters. --host sets the bind address, so the board can be pinned to a tailnet address (ty serve --host 100.x.y.z) or to loopback. An empty host keeps today's ":port" behaviour exactly, so the Tauri sidecar and ty-chrome (both localhost) are unaffected. Invalid hosts fail fast with a clear message instead of a confusing net.Listen error, and IPv6 literals are bracketed via net.JoinHostPort. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VyWdPGetDrC7KeZXeg2jWd
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
ty serveboundfmt.Sprintf(":%d", port)— every interface, including whatever untrusted network the laptop is on. The board can create and execute tasks (spawning agents with the user's credentials), so that reachability is a real exposure. There was also no way to bind a specific address, which is what tailnet-only access needs (tailscale serveis not workable on macOS — the sandboxed App Store client fails to proxy to localhost services).What changed
ty serve --host <addr>sets the bind address; listen address becomeshost:port.Empty/unset
--hostproduces:portexactly as before — no behaviour change for anyone.Host validation up front: an IP literal (with optional IPv6 zone) or an RFC 1123 hostname. Anything else (
http://127.0.0.1,127.0.0.1:8080,bad_host) fails withinvalid host "...": not a valid IP address or hostnameinstead of a confusingnet.Listenerror. Port range is checked too.IPv6 literals are bracketed via
net.JoinHostPort(::1→[::1]:8080); an already-bracketed[::1]is accepted and not double-bracketed.Startup prints the bind address, and flags the all-interfaces case explicitly:
web.Server.Startalready logs the resolvedln.Addr()on top of that.Address construction lives in
serveListenAddr(cmd/task/serve_addr.go) so it is testable without binding a socket.Recommendation on the default (not changed here)
I recommend flipping the default to
127.0.0.1in a follow-up, but did not do it in this PR.Reasoning for the flip:
desktop/src-tauri/src/supervisor.rs:168) spawnsty serve --port <port>and health-checks/connects over localhost.extensions/ty-chromehardcodeshttp://127.0.0.1:8080/http://localhost:8080(sw.js:5,91-92,sidepanel.html:30).Reasoning for holding off in this PR:
--host 0.0.0.0exists there is a clean migration path for anyone who wants the old behaviour back.Tests
cmd/task/serve_addr_test.go: empty host →:port; whitespace-only host →:port; IPv4; a Tailscale IP with a custom port; hostname; IPv6 literal bracketing; pre-bracketed IPv6;::; IPv6 with a zone; plus an invalid-input table (scheme, embedded port, path, space, underscore, leading dash, port 0, port 70000).All pass;
go build ./...,go vet ./cmd/task/andgofmtare clean.Out of scope
No TLS, no auth, no tailscale integration — bind address only.
🤖 Generated with Claude Code
https://claude.ai/code/session_01VyWdPGetDrC7KeZXeg2jWd