feat: add --host to bind the desk beyond loopback for remote review - #63
Merged
Conversation
The desk has always bound 127.0.0.1 only. Remote-dev setups (agent + desk on a server, reviewer's browser on a laptop) needed a wrapper or proxy to reach it. Add a --host <addr> flag (GALLEY_HOST env fallback) that binds both listen sites (preferred port + the EADDRINUSE random fallback) to the given address. Default stays 127.0.0.1 — zero behavior change unless opted in. Composes with the #51 origin lock rather than defeating it: a non-loopback bind EXTENDS the trusted authorities with the machine hostname, the bound address (for a specific bind), and any GALLEY_ALLOWED_HOSTS (comma-separated, for names the hostname/address don't cover, e.g. a tailnet MagicDNS FQDN). A loopback bind widens nothing — a foreign Host (and DNS-rebinding) still 403s. Two URLs now diverge: the printed/opened browser URL is hostname-based when bound non-loopback, while the desk-lock URL stays loopback-reachable so the same-machine agent subcommands (await/comment/reload/status/stop) are unaffected. A specific non-loopback bind (unreachable over loopback) uses that exact address for both. IPv6 literals are bracket-wrapped. Binding beyond loopback prints a security warning — the desk API is unauthenticated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
What
Adds a
--host <addr>flag (withGALLEY_HOSTenv fallback) that binds the desk HTTP server to a given address, for remote-dev workflows — desk + agent on a tailnet-only server, reviewer's browser on another device — without a wrapper or proxy. The absolute default stays127.0.0.1(loopback-only): zero behavior change unless opted in.How it composes with #51 (the origin lock)
The #51 Host/Origin guard is extended, never defeated:
127.0.0.1/localhost/[::1]) — a foreignHostand DNS-rebinding still403.os.hostname(), the bound address (for a specific bind), and anyGALLEY_ALLOWED_HOSTS(comma-separated) to the trusted set. SoHost: devbox:41010passes on a host nameddevbox, whileHost: evil.example:41010still403s.GALLEY_ALLOWED_HOSTScovers names the hostname/address don't — e.g. a tailnet MagicDNS FQDN, which differs from the short hostname.The derivation lives in a pure, exported
resolveBinding(host, hostname, allowedHostsEnv)so the URL/authority logic is unit-tested without binding exotic addresses.Two URLs
http://devbox:41010/).await/comment/reload/status/stop): stays loopback-reachable (127.0.0.1) for loopback/wildcard binds, so the agent side is unaffected. A specific non-loopback bind — unreachable over loopback — uses that exact address for both. IPv6 literals are bracket-wrapped.Binding beyond loopback prints a security warning: the desk API is unauthenticated (runs the configured editor command, mutates the git index, reads any repo file), so it should be exposed only on a fully trusted network.
Docs
README gets a "Reviewing on a remote machine" section with the honest security warning; the
--host/GALLEY_HOST/GALLEY_ALLOWED_HOSTSflags are in--help, andsrc/spec.tsnotes the lock URL stays loopback-reachable (per the CLAUDE.md rule to update the spec on flag changes).Tests
resolveBinding: loopback default (widens nothing, both URLs loopback), wildcard (hostname browser URL + loopback lock), specific IP + specific name, IPv6 bracketing,GALLEY_ALLOWED_HOSTSmerge.403s the machine hostname (guards the "no widening" property);--host 0.0.0.0accepts the hostname authority and loopback while a foreign Host still403s;GALLEY_ALLOWED_HOSTSmembers pass and non-members403.All repo checks green locally:
pnpm check,pnpm lint,pnpm test(209),pnpm build,pnpm smoke,pnpm perf-smoke.🤖 Generated with Claude Code