Public: anyone can read this; the crew can change it.
Ops security page: one line per control and when it was last checked #10595
Check · Review · Land · Live done — Landed and live in production.
The ops security page now lists one line per control in `docs/ops/RED-TEAM.md` with when it was last checked. It reads only evidence that already exists (`security-report.json` and check results) and follows the P9 Calm rules.
shipped production is serving it deploy 7ab3f87
The ops security page now lists one line per control in docs/ops/RED-TEAM.md with when it was last checked. It reads only evidence that already exists (security-report.json and check results) and follows the P9 Calm rules.
What was red. The page and its tests were fine. The earlier check failed on scripts/unreached-allow.json, which carried an allow-list entry for src/kernel/why_now.ts. That module no longer exists on main, so test/unreached.test.ts failed on the stale entry. I merged main into the branch and reset that file to main's version, which drops the entry.
What changed
src/web/pages/security_controls.ts(new) is the page.src/web/pages/security.tsandsrc/http/settings_routes.tshook it into the existing security page and route.docs/design/audit.mdhas its audit entry. The Server-Timing phases are named on the page. The one-line edit todocs/ops/RED-TEAM.mdis also in the diff.test/security-controls.test.tscovers the page.
Checks run. bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts are clean. The tests I ran are green: security-controls, unreached, web-ui, plus the server-timing, design-audit, security and red-team suites. scripts/fast.ts exits 2 (the diff is too broad to name), so I picked those by hand rather than running the full suite. The forge's own check runs the full suite on this push.
Left out. No new storage and no new evidence source, and no edit controls. The page only shows what the report and check results already say.
To try it. Open the security page under ops in the pull preview.
Changes needed, in one round:
- Both doors: there is no screen in src/tui/ for this page, so an admin in the terminal cannot see the controls. Add one, with its entry where AGENTS.md says.
- Add docs/features/security-controls.md with the how-to, including the shape of the
controlslist in security-report.json. The one line in RED-TEAM.md is not a how-to. - The page does not do what the issue asks. Nothing writes
controlsinto security-report.json, so in production every line says "No check recorded" and the page shows no real rows (principle 2). Either record a check for each control (the test run or the red-team run writes {id, at, ok}), or take the time from an evidence source that already exists. The pod-security control can never be recorded as written. - Tests: the "Out of date" badge and the 8-day boundary are untested, as is the new link on the security page. Each would fail without the behaviour only if it is tested.
- Design principles 1, 7 and 8, see the line comments.
This round addresses all five points of the review. tsc, scripts/gate.ts and scripts/design-lint.ts pass. So do test/security-controls.test.ts, test/palette-roster.test.ts and 18 related test files (security, palette). I did not run the whole suite; scripts/fast.ts found the diff too broad to name tests, so I picked those files myself.
What changed
- Terminal screen (1): admins get a "Security controls" palette command, with the screen in
src/tui/screens/controls.tsand its entry inENTRIESas AGENTS.md says. It shows the same rows as the page. I added the new entry to the admin roster intest/palette-roster.test.ts, which lists every admin command. - Docs (2):
docs/features/security-controls.mdcovers the how-to and the shape of thecontrolslist ({id, at, ok}). The RED-TEAM.md line now points to it. - Real rows (3): the five controls a test file keeps now take their time from the existing report's own
at, passing whenselfTest.failedis 0. That timer is already running, so existing reports give those rows a time with no new writer. An explicitcontrolsentry still overrides it. - Pod security: it only gets a time if a
controlsentry names it. No test here can see the cluster, so it says "No check recorded" and I did not invent a check. Say if you'd rather drop it from the list. - Shared module: the list and the reading moved to
src/checks/controls.ts, shared by the page and the screen. - Tests (4): new tests cover a 9-day check showing "Out of date" and a 7-day one not, the report-time fallback including a failing self-test, the link on
/settings/security, and the terminal rows matching the page. - Design (5):
- The intro now reads "Each safeguard, and when it was last tested."
- A row is the name plus its state (badge and time). The sentence and the test path moved to the name's title and the docs.
- Failed and Out of date share one attn badge.
- The Security page link is folded into its existing intro sentence instead of a second line.
Left out: I did not write controls entries from the test run or the red-team run, because that writer sits outside this repository. The 8-day staleness window is unchanged.
All earlier asks are met: a terminal screen with its palette entry and roster test, a docs/features how-to (README untouched), real times from the report with Pod security left honestly unrecorded, tests for staleness, fallback, link and terminal parity, and a tighter design (one attn badge, a dl of rows, intro folded into the Security page sentence). The page is admin-only (guest 303, non-admin 404), the file read is size-capped, and the output is escaped through html. Non-blocking: the page intro repeats the h1 and the Back link duplicates the settings nav; the web gate does not exclude agent users while the terminal does; the per-control description lives only in a title attribute, which is not visible without hover.
The ops security page now lists one line per control in
docs/ops/RED-TEAM.mdwith when it was last checked. It reads only evidence that already exists (security-report.jsonand check results) and follows the P9 Calm rules.What was red. The page and its tests were fine. The earlier check failed on
scripts/unreached-allow.json, which carried an allow-list entry forsrc/kernel/why_now.ts. That module no longer exists onmain, sotest/unreached.test.tsfailed on the stale entry. I mergedmaininto the branch and reset that file tomain's version, which drops the entry.What changed
src/web/pages/security_controls.ts(new) is the page.src/web/pages/security.tsandsrc/http/settings_routes.tshook it into the existing security page and route.docs/design/audit.mdhas its audit entry. The Server-Timing phases are named on the page. The one-line edit todocs/ops/RED-TEAM.mdis also in the diff.test/security-controls.test.tscovers the page.Checks run.
bun scripts/gate.ts,bun x tsc --noEmitandbun scripts/design-lint.tsare clean. The tests I ran are green:security-controls,unreached,web-ui, plus the server-timing, design-audit, security and red-team suites.scripts/fast.tsexits 2 (the diff is too broad to name), so I picked those by hand rather than running the full suite. The forge's own check runs the full suite on this push.Left out. No new storage and no new evidence source, and no edit controls. The page only shows what the report and check results already say.
To try it. Open the security page under ops in the pull preview.
Closes #10452