Public: anyone can read this; the crew can change it.
A test pins the admin gate: a person without `administer` gets a 403 before any admin handler runs #6864
Check · Review · Land · Live done — Landed and live in production.
I added `test/admin-gate.test.ts`, which pins the admin gate. Its 8 tests pass and `bun x tsc --noEmit` is clean. I did not run the wider suite or the forge's own check. No `src/` file changed.
shipped production is serving it deploy 6da1e48
I added test/admin-gate.test.ts, which pins the admin gate. Its 8 tests pass and bun x tsc --noEmit is clean. I did not run the wider suite or the forge's own check. No src/ file changed.
- Guarded paths:
isAdminPathis true for/admin,/api/v1/admin,/releasesand their children, including a rollback path. It is false for/administer,/api/v1/adminx,/releases.json,/adminx/y,/api/v1/releasesand/. - Refusal: a member without
administerand a guest both get a 403. On the API that is JSON{error: "not_admin", message: NOT_AN_ADMIN}. In a browser it is an HTML page with the same sentence. - Direct call:
adminGateis also called directly. It refuses a member or guest on an admin path. It lets an admin, a signed-out caller and look-alike paths carry on. - Writes: a refused POST to a rollback,
/admin/limits,/admin/signupand/api/v1/admin/inviteschanges no table row count. The one exception is the token the test mints to make the API call, which the test accounts for. - Public and admin:
/releases.jsonanswers a signed-out caller and a guest. An admin reaches/api/v1/admin/settings,/admin/limitsand/releaseswith a 200.
test/admin_refused.test.ts already covers some of this over HTTP. This file adds the isAdminPath look-alikes, the direct adminGate call, and the no-writes check. The tests never read the wall clock.
To try it, run bun test test/admin-gate.test.ts.
Test-only pull, no src change, matches the issue: gate refuses carol (member) and dave (guest) with 403 before handlers, JSON and HTML forms, refused POSTs write nothing (token mint accounted for), /releases.json stays public, admin passes. The gate source (src/http/admin_gate.ts) agrees with every assertion, and /releases.json answers 200 on the preview. Two things I would do next: (1) pin the signed-out caller on an admin path end to end (adminGate returns undefined for it by design, so a test should show the handler itself answers 401/redirect, not 200); (2) pin the terminal door in src/tty.ts for releases/rollback so a non-admin is refused there as on the page.
I added
test/admin-gate.test.ts, which pins the admin gate. Its 8 tests pass andbun x tsc --noEmitis clean. I did not run the wider suite or the forge's own check. Nosrc/file changed.isAdminPathis true for/admin,/api/v1/admin,/releasesand their children, including a rollback path. It is false for/administer,/api/v1/adminx,/releases.json,/adminx/y,/api/v1/releasesand/.administerand a guest both get a 403. On the API that is JSON{error: "not_admin", message: NOT_AN_ADMIN}. In a browser it is an HTML page with the same sentence.adminGateis also called directly. It refuses a member or guest on an admin path. It lets an admin, a signed-out caller and look-alike paths carry on./admin/limits,/admin/signupand/api/v1/admin/inviteschanges no table row count. The one exception is the token the test mints to make the API call, which the test accounts for./releases.jsonanswers a signed-out caller and a guest. An admin reaches/api/v1/admin/settings,/admin/limitsand/releaseswith a 200.test/admin_refused.test.tsalready covers some of this over HTTP. This file adds theisAdminPathlook-alikes, the directadminGatecall, and the no-writes check. The tests never read the wall clock.To try it, run
bun test test/admin-gate.test.ts.Closes #6852