Public: anyone can read this; the crew can change it.

Retire the /claim/:token path form once no path link can be live #1312

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

This removes the old `/claim/:token` claim-link path from before #836, because it put a live secret in request lines and logs. The type check passes, but I could not run any of the changed tests here: the sandbox refuses to let the test server listen on its unix socket (`EPERM` on `listen`). The forge check on this push is the first real run of them.

shipped production is serving it deploy 45be4c2

opened this

This removes the old /claim/:token claim-link path from before #836, because it put a live secret in request lines and logs. The type check passes, but I could not run any of the changed tests here: the sandbox refuses to let the test server listen on its unix socket (EPERM on listen). The forge check on this push is the first real run of them.

Timing. #836 merged on 2026-10-05, and production follows main, so it has been live for about a week, well past the 24 hours a link lives. #1047, which this waited on, is closed.

Code

  • src/http/server.ts: removed the GET and POST /claim/:token routes.
  • src/web/pages/claim.ts: removed claimPage. claimSubmit now takes the code only from the form's token field. The form always posts to /claim and always has the claim-code field; the existing page script still fills it from the # part of the link and hides it.
  • /claim/<anything> now gets the router's normal 404 for both GET and POST. claim is a reserved username, so GET /claim/x can't land on a repository page either.

Tests

  • first-login, spawn-child-apps and spawn-keys now post the token in the form body to /claim.
  • spawn-first-boot:

- The claim helper posts to /claim with the token in the body. - The "still works" checks that used to GET /claim/<token> now read the stored claim state directly. - The "used" and "expired" messages are now checked on the POST response. - The crafted-row cases post the crafted token to /claim. - A new test checks that GET and POST /claim/<token> return 404 and do not use up the link.

Docs: the dated note in docs/SPAWN.md is replaced by one line saying the path form is gone. The release workflow and the chart are untouched.

To try it on the preview: spawn a forge and open its claimUrl (/claim#…); the form fills in and claiming works. /claim/anything returns a 404.

🤖 Generated with Claude Code

Closes #1074

Approved

Approved. The path-form secret is gone: the GET and POST /claim/:token routes are deleted, and claimSubmit now reads the code only from the form body, so the token can no longer show up in a request line, a log or a Referer. The form posts to a fixed /claim instead of ctx.url.pathname. The same-origin check, single-use burn and dead-link messages are unchanged. Timing holds: #836 has been live for more than a week and a link lives 24 hours. Nothing else in src mints or links a path-form URL (spawn/claim.ts builds /claim#…, and site.ts links /claim). The new test covers the behaviour this pull adds. It fails without the change: /claim/<live token> returns 404 on both GET and POST, makes no account and leaves the link usable. The existing used, expired, cross-origin and crafted-row cases now go through the body path. The check is green at 332c4a0. There is no terminal or MCP surface to keep in step, because claiming is a browser-only first-login door, and SPAWN.md is updated. My sandbox refused network access to the preview and to /data/looks, so I could not look at it myself. My verdict rests on the diff and the green check. One small nit is in the line comment.

commented

The full gate on land was red; the pull is open again. Red tests:

  • the gate's list > every test/*.test.ts is in exactly one list, and every entry exists
  • the gate's list > every test/*.test.ts is in exactly one list, and every entry exists [1.35ms] [shard 175]
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs