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

Boards, step 6c: a security source and the Security starting board #2474

Merged opened this

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

Merged

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

opened this

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"):

  • signins reads the session table and exposes user_id and the created, expires and last-seen times.
  • tokens reads the token table and exposes id, user_id, scope, and the created, last-used and expires times.
  • adminActions reads event rows whose actor is an admin and exposes id, kind, repo_id, actor_id and created_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

Closes #2460

commented

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"):

  • signins reads the session table and exposes user_id and the created, expires and last-seen times.
  • tokens reads the token table and exposes id, user_id, scope, and the created, last-used and expires times.
  • adminActions reads event rows whose actor is an admin and exposes id, kind, repo_id, actor_id and created_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

Approved

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.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs