Repository navigation
Conversation
… or fly cloud/Dockerfile builds one container that is the owner's dev box: the repos, the tmux server where every supervisor and worker runs, and the hub. cloud/gateway.mjs (node, no dependencies) is its only public listener: the box is claimed with a passkey from a link in the first boot's log, and afterwards only a registered passkey gets in. The hub is the box's home page, with a Terminal tab first (ttyd on the box's tmux server); each dashboard keeps an origin of its own on a subdomain (4321.box.example.com), so nothing a dashboard runs can reach the terminal or the box's passkeys. Requests reach the kit as a local browser's would, and the kit's loopback origins in its headers are mapped to the public ones, so devteam.mjs is unchanged. The gateway runs as its own user, so no agent can read or write its state. hub.html: on a box (box.json answers), instance URLs come from the gateway and the Terminal tab is first; a 401 reloads the page to sign in. On a laptop nothing changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eview's other findings The hub and the terminal are bytes the box's user (every agent) can change: the hub page is read from a checkout, and its port and ttyd's can be taken. So signing in and passkeys move to auth.<box>, which serves only the gateway's own pages; a passkey made anywhere else is refused, and adding one takes a sign-in in the last five minutes. With a SameSite=None cookie, a read another site's page makes is refused, but for what a sandboxed review page or artifact loads. Also: a response cut off upstream ends the browser's, and a browser that leaves stops the kit's work; nothing behind the gateway sets a cookie for the box's names, and every session cookie sent is tried; state that can't be read never reads as a new box; a link reclaim printed survives a restart; login challenges are pooled apart; the terminal's upgrade forwards its first bytes and can't leak a ttyd connection; origin-form request lines only; RSA under 2048 bits, duplicate CBOR keys and trailing attestation bytes refused. Image: gw's uid pinned, its state chowned on boot, a stop closes the tmux server before the gateway, and the hub links to Passkeys on a box. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Fable's review dev's login shells read files any agent can write, so dev's side started first could take the public port and stand in for the gateway. The gateway now starts first and dev's side only once /healthz answers (checked in the container with a listener planted in .profile: it can't bind). Also: the Render notes name every DNS record a wildcard needs and the real claim link; the onrender.com address is refused with the name to open; reclaim says it needs root; mise and Claude Code are pinned; an artifact's cross-site loads are limited to subresource kinds; the README says a repo's kit must be at this release to serve the box's hub; a test for the https cookie and HSTS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ifact may load its own Worker; pins noted Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Member
Author
|
Review (upstream loop, adversarial): CHANGES. One blocker. The WebAuthn implementation holds up. Blocker
Should-fix
Nits
Checked and fine
Method: a scratch worktree, |
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
An owner can run their whole devteam setup as one container on Render (or fly.io, or any Docker host with a disk). It holds the repos, the tmux server where every supervisor and worker runs, and the hub, reached at a URL of the owner's.
cloud/Dockerfilebuilds the box: Node 22, git, tmux, gh, ttyd 1.7.7 (checksum-pinned), mise and Claude Code. Its header has the Render and fly steps.cloud/gateway.mjsis the box's only public listener (Node, no dependencies).box.example.comserves the hub, with a new Terminal tab first (ttyd on the box's tmux server).<port>.box.example.comserves each dashboard, so each keeps an origin of its own, as on a laptop.auth.box.example.comserves sign-in and passkeys, and only the gateway's own pages.hub.html: when a gateway answersbox.json, instance URLs come from it and the Terminal tab and a Passkeys link appear. On a laptop nothing changes.cloud/sits outsidedocs/devteam/, so adopting projects never copy it.Why
The owner wants their dev box in the cloud, reachable from any browser, claimed and opened with a passkey, with a terminal for the supervisors and logins.
Security model
dev. The hub page is read from a checkout, and its port and ttyd's can be rebound bydev, so the box's own name is treated as agent-controlled.auth., which serves only the gateway's bytes.gwuser, and its state is in/data/gateway(mode 0700). Agents can't read it or kill the gateway (both checked in the container).SameSite=None; Secure; HttpOnly; Domain=<box>. Sandboxed review pages and artifacts have opaque origins, so a Lax cookie wouldn't go with their loads. Instead, the gateway refuses any cross-site, non-navigation read except what a sandboxed page loads: the kit's two helpers,/api/fileimages, and artifact files.devteam-reclaim, run as root in a shell on the box (Render Shell,fly ssh console), is how a lost passkey is recovered.Verification
node --test test/gateway.test.mjs: 5 tests covering:next; Host and port variants; absolute-form request lines; cross-site reads.reclaim, a restart keeping the reclaim link, and corrupt state.devteam.mjs dashboardbehind the gateway: hub CSP mapping, an owner POST passing the kit's own same-origin check, a review page, header and cookie scrubbing, and the WebSocket.devteam-ui.jsand a committed image with the cookie;auth.and back.Not in this PR
Migration
None. Projects adopting the kit get no new files. The hub change only runs when a gateway answers
box.json.🤖 Generated with Claude Code