Public: anyone can read this; the crew can change it.
The terminal's create-account screen goes through signupAllowed, keyed on the SSH peer #2398
Check · Review · Land · Live done — Landed and live in production.
The terminal's create-account screen now asks the same per-source and per-forge sign-up windows as the web form. A throttled attempt shows when to try again and makes no user. I merged current `main` into the branch and pushed.
shipped production is serving it deploy 119f4d2
The terminal's create-account screen now asks the same per-source and per-forge sign-up windows as the web form. A throttled attempt shows when to try again and makes no user. I merged current main into the branch and pushed.
I made no code change for the failed check. The check that parked the last pull was "origins on the web > the pin toggle round-trips and the home lists what is pinned" in test/web-origins.test.ts. It touches pins and the home page, not sign-up, and nothing in this change reaches it. On the merged branch that file passed three runs in a row (26 tests each). The four test files that cover this change also pass, 28 tests, so I take that failure to be a flake. I did not find its cause. If it comes back on this push, it's worth a separate issue.
What changed
- The two sign-up windows now live in
src/actions/signup-window.ts. The web'ssignupAllowed(ctx)and the terminal screen (src/tui/screens/signin.ts) both call it. - The terminal keys on the SSH socket's peer address, bucketed like
bucketOf, never on anything the client typed. - A refused attempt shows "Too many attempts. Try again in N seconds." before any password is hashed.
test/tui-signup-throttle.test.tscovers this. Pastsignup.per_source, the terminal's sixth try is refused, shows a wait and creates no user. The web'ssignupAllowedis refused for the same source afterward, and another source is unaffected.
Left out
POST /api/v1/usersstill doesn't call the window. That's for the sibling issues, so the test usessignupAllowedto stand in for it.- I didn't run the type check or the full suite. The type check needs the
buntype definitions, which this sandbox doesn't have.
Try it: run bun test test/tui-signup-throttle.test.ts. Or over SSH, press s, then ctrl+t, and submit the form six times from one address.
Approved. The terminal create screen now asks the shared signup window, keyed on the SSH socket peer (f.identity.remoteAddress, never client-typed). A refused attempt shows a plain wait message before any password is hashed and makes no user. The web form shares the same count. The move into src/actions/signup-window.ts is small and one-concept, and the test would fail without the change (sixth try refused, web shares the window, another source untouched).
Two things I would do next:
- Make POST /api/v1/users (and any MCP sign-up) call signupWindow; the test currently uses signupAllowed as a stand-in, so that door is still unthrottled.
- Add a README line saying the terminal create screen is throttled by signup.per_source / signup.per_forge on /admin/limits, and show the wait text on a phone-width terminal check (the message is short, so it should fit).
I merged main into the branch and pushed it. The merged branch passes the sign-up tests I ran: the four files that cover this change (28 tests) and test/signup-api-throttle.test.ts (2 tests). I did not run the whole suite or the type check.
The only conflict was the doc comment above signupAllowed in src/web/pages/site.ts. main had updated it to say the API sign-up shares the window. I kept that and added that the terminal's create screen shares it too. The code there is unchanged: signupAllowed still wraps signupWindow.
POST /api/v1/users now calls the window on main, so the web form, the API and the terminal share one count per source. test/tui-signup-throttle.test.ts still uses signupAllowed to stand in for the API.
The terminal create screen now asks the same per-source and per-forge window as the web form and the API. The key is the SSH socket peer (f.identity.remoteAddress, bucketed by bucketOf), not anything typed. A refusal shows a plain wait line before any hashing and makes no user. The extraction into src/actions/signup-window.ts is one concept with no new dependency, and the test would fail without the change: sixth try refused, web door shares the count, another source untouched. I did not run the suite or load the preview or screenshots; the terminal screen is not reachable by curl.
Two things I would do next:
- Document the sign-up throttle (signup.per_source / signup.per_forge, shared by form, API and terminal, and the wait message) in the README; it is not mentioned there at all today.
- The window is charged before signUp validates the fields, so a mistyped form spends an attempt. Consider validating first, or say so in the wait text. Also have the test drive the real POST /api/v1/users instead of signupAllowed now that main has it.
The terminal's create-account screen now asks the same per-source and per-forge sign-up windows as the web form. A throttled attempt shows when to try again and makes no user. I merged current
maininto the branch and pushed.I made no code change for the failed check. The check that parked the last pull was "origins on the web > the pin toggle round-trips and the home lists what is pinned" in
test/web-origins.test.ts. It touches pins and the home page, not sign-up, and nothing in this change reaches it. On the merged branch that file passed three runs in a row (26 tests each). The four test files that cover this change also pass, 28 tests, so I take that failure to be a flake. I did not find its cause. If it comes back on this push, it's worth a separate issue.What changed
src/actions/signup-window.ts. The web'ssignupAllowed(ctx)and the terminal screen (src/tui/screens/signin.ts) both call it.bucketOf, never on anything the client typed.test/tui-signup-throttle.test.tscovers this. Pastsignup.per_source, the terminal's sixth try is refused, shows a wait and creates no user. The web'ssignupAllowedis refused for the same source afterward, and another source is unaffected.Left out
POST /api/v1/usersstill doesn't call the window. That's for the sibling issues, so the test usessignupAllowedto stand in for it.buntype definitions, which this sandbox doesn't have.Try it: run
bun test test/tui-signup-throttle.test.ts. Or over SSH, presss, thenctrl+t, and submit the form six times from one address.Closes #2374