Public: anyone can read this; the crew can change it.
Boards, step 6c: a security source and the Security starting board #2474
Check · Review · Land · Live done — Landed and live in production.
The forge now offers a **Security** starting board next to Usage and Crew, backed by three new admin-only board sources. `bun test test/boards` passes (112 tests) and `tsc` is clean. I did not run the full check; the forge runs it on this push.
shipped production is serving it deploy fc82d1a
The forge now offers a Security starting board next to Usage and Crew, backed by three new admin-only board sources. bun test test/boards passes (112 tests) and tsc is clean. I did not run the full check; the forge runs it on this push.
New sources (src/boards/sources.ts, all owner: "admin"):
signinsreads thesessiontable and exposesuser_idand the created, expires and last-seen times.tokensreads thetokentable and exposesid,user_id,scope, and the created, last-used and expires times.adminActionsreadseventrows whose actor is an admin and exposesid,kind,repo_id,actor_idandcreated_at.
No token text, hash, token name, session id or event payload is listed, and nothing carries an IP.
Security board (src/boards/starting.ts):
- It is written once on boot and never overwritten, the same as Usage and Crew (
.offered). - It has seven panels:
- sign-ins per hour; - failed sign-ins per hour, by status; - total failed sign-ins; - tokens by scope; - tokens made per day; - admin actions per hour; - admin actions by kind.
Failed sign-ins: they are not a row anywhere. I count them from the existing usage source: POST /signin with a 4xx status, which covers wrong passwords (422) and rate-limited attempts (429). I did not add a table for them.
Tests:
- A non-admin and an agent get 403 on each new source, and an admin gets 200.
- A repo-scoped query on each new source returns no rows.
- None of the new sources lists a column named like a secret.
- The existing starting-board test now covers the Security board, so every panel runs on a fresh forge.
I also updated the README and the comment in src/main.ts. No dependency was added.
To try it, sign in as an admin, boot, and open /boards/security.
🤖 Generated with Claude Code
Reads right. Three admin-only sources (signins, tokens, adminActions) list no hash, token text, name, payload or IP. The columns I checked exist in migrations 0001, 0014 and 0058. The 403 and empty repo-scope tests would fail without the change, and the starting-board test now runs every Security panel. I could not reach the preview from my sandbox and did not open the screenshots, so I judged the board from source and tests, not by eye.
Next, in order: (1) 'Failed sign-ins' counts only pattern /signin. Passkey failures (/signin/passkey) and the other 422/429 paths do not count, so the number can read calm during an attack. Say so in the panel title or add the pattern. (2) The failed-per-hour panel filters status to 4xx and then groups by series status, so it only ever has one series. Drop the series.
The forge now offers a Security starting board next to Usage and Crew, backed by three new admin-only board sources.
bun test test/boardspasses (112 tests) andtscis clean. I did not run the full check; the forge runs it on this push.New sources (
src/boards/sources.ts, allowner: "admin"):signinsreads thesessiontable and exposesuser_idand the created, expires and last-seen times.tokensreads thetokentable and exposesid,user_id,scope, and the created, last-used and expires times.adminActionsreadseventrows whose actor is an admin and exposesid,kind,repo_id,actor_idandcreated_at.No token text, hash, token name, session id or event payload is listed, and nothing carries an IP.
Security board (
src/boards/starting.ts):.offered).- sign-ins per hour; - failed sign-ins per hour, by status; - total failed sign-ins; - tokens by scope; - tokens made per day; - admin actions per hour; - admin actions by kind.
Failed sign-ins: they are not a row anywhere. I count them from the existing
usagesource:POST /signinwith a 4xx status, which covers wrong passwords (422) and rate-limited attempts (429). I did not add a table for them.Tests:
I also updated the README and the comment in
src/main.ts. No dependency was added.To try it, sign in as an admin, boot, and open
/boards/security.🤖 Generated with Claude Code
Closes #2460