From d7c49a3fb860ec885ea8b19eece95870602737c1 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Wed, 21 Oct 2026 10:53:43 -0700 Subject: [PATCH] Audit of fab6ce5 --- README.md | 2 +- cmd/byre/serve.go | 2 +- docs/operations.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f2c1d04..9a3331d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ A server and macOS app for running many coding agents (Claude Code, Codex and An ## Requirements -macOS and a [Tailscale](https://tailscale.com) tailnet with MagicDNS and HTTPS certificates turned on. byre and the app each join it as their own node, so no Mac needs the Tailscale app. Identity comes from Tailscale: byre serves only the tailnet's users, as its node identifies them. +macOS and a [Tailscale](https://tailscale.com) tailnet with MagicDNS and HTTPS certificates turned on. byre and the app each join it as their own node, so no Mac needs the Tailscale app. Remote access uses Tailscale identity: byre serves the tailnet's users, as its node identifies them. Local scripts use a bearer token to check server status and run commands on connected Macs (see [docs/operations.md](docs/operations.md#tailnet)). The Mac that runs the server needs `git` and at least one agent CLI: Claude Code (`claude`), Codex (`codex`) or Antigravity (`agy`, for Gemini models; `brew install --cask antigravity-cli`, signed in once by running `agy`). Browser tools also need Node.js (agents' Playwright tools run through `npx`) and Google Chrome (`brew install git node --cask google-chrome`). diff --git a/cmd/byre/serve.go b/cmd/byre/serve.go index 38d3bfc..6aaeee9 100644 --- a/cmd/byre/serve.go +++ b/cmd/byre/serve.go @@ -37,7 +37,7 @@ func serveCmd(args []string) { flags := flag.NewFlagSet("serve", flag.ExitOnError) dataDir := flags.String("data", filepath.Join(configDir, "byre"), "directory holding byre's database, worktrees, leads and blobs") - listenAddr := flags.String("listen", defaultListen, "loopback address serving GET /api/tailnet") + listenAddr := flags.String("listen", defaultListen, "loopback address for server status and client commands") ports := flags.Int("ports", store.DefaultPortFirst, "first port of the tasks' port blocks") hostname := flags.String("ts-hostname", "byre-"+macSlug(), "hostname of byre's tailnet node") flags.Parse(args) diff --git a/docs/operations.md b/docs/operations.md index 0dd6586..4c813c5 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -20,11 +20,11 @@ The service always runs from the app: `/Applications/Byre.app/Contents/Helpers/b ## Tailnet -byre runs its own tailnet node with `tsnet`; it doesn't use the Tailscale app. The API is served only there, at the root of the node's `ts.net` name on 443, not under a path: the API uses absolute paths and the app takes an origin with no path. There is no way to call the API other than as a tailnet user; a tagged node gets 403. +byre runs its own tailnet node with `tsnet`; it doesn't use the Tailscale app. The app connects at the root of the node's `ts.net` name on 443, not under a path: the API uses absolute paths and the app takes an origin with no path. Tailnet access requires a user identity; a tagged node gets 403. Local scripts can also check server status and run client commands through the authenticated loopback address. Tailscale identifies the connecting Mac, including requests from a web page opened there; network identity alone doesn't establish the user's intent. Cross-origin browser requests must not be allowed to change state through that identity. Native app and CLI access remains intentional. -The local status endpoint requires the bearer credential in `/loopback-token`, regenerated on service startup. Loopback is reachable by other OS accounts, so it cannot protect the node’s sign-in URL by itself. +Loopback access requires the bearer credential in `/loopback-token`, regenerated on service startup. It grants both server status (including the node's sign-in URL) and command execution on connected client Macs. Keep it private: loopback is reachable by other OS accounts, so the address alone provides no protection. A new node needs signing in: `curl -H "Authorization: Bearer $(cat "$HOME/Library/Application Support/byre/loopback-token")" /api/tailnet` (`byre check` prints the loopback address) shows `NeedsLogin` and the `auth_url`, and the app on the same Mac shows it as **Sign in to Tailscale**. The tailnet must have MagicDNS and HTTPS certificates turned on (the DNS page of Tailscale's admin console); without certificates byre logs `tailnet has no https certificates` and serves only the loopback address until it is restarted.