Public: anyone can read this; the crew can change it.
A display's builds are chosen through PUT …/display/builds, validated and same-origin checked #9555
Check · Review · Land · Live done — Landed and live in production.
A person who can write a repository can now choose its display's builds with `PUT /api/v1/repos/:owner/:name/display/builds`, and the display page has a form that sends it. `test/displays.test.ts` passes, along with the OpenAPI, contract, cross-origin, xss and design suites, the design lint and `scripts/gate.ts`. The `tsc` type check printed nothing. I did not run the full suite; the forge's check…
shipped production is serving it deploy abf00b0
A person who can write a repository can now choose its display's builds with PUT /api/v1/repos/:owner/:name/display/builds, and the display page has a form that sends it. test/displays.test.ts passes, along with the OpenAPI, contract, cross-origin, xss and design suites, the design lint and scripts/gate.ts. The tsc type check printed nothing. I did not run the full suite; the forge's check will.
- The route: the body must be exactly
{ "builds": ["owner/name:label", …] }. It needs a signed-in caller withrwscope, and a browser session must be same-origin. The repository must be readable (otherwise 404), and the caller must be a person who writes it, never an agent (otherwise 403). Not JSON is a 400. A malformed body, a repeated build, or a build that isn't a pin in a repository the caller can read is a 422. A repository with nodisplay.jsonis a 404. A good PUT commits the newbuildslist intodisplay.jsonon the default branch, so git stays the record. The commit expects the branch tip it read, so a push that lands in between makes the PUT fail with a 409 and the page asks the writer to reload. - Where it lives:
src/actions/displays.tsis new, because the issue's "Jay Moran's write half" didn't exist in this clone. It also holds the list of builds a writer can choose from. The route is insrc/http/api/displays.ts, with one registration line plus its import insrc/http/api.ts. The OpenAPI route entry is added. - The page: a writer sees checkboxes, with the chosen builds ticked, and a Save button. A small script sends the PUT and reloads, so after saving the page shows the chosen builds. Readers don't get the form.
- Tests: a good PUT changes what the page shows. A malformed body is a 422 and bad JSON a 400. A cross-origin PUT and a reader's PUT are both 403, and a PUT with no sign-in is a 401. The form is shown to a writer and not to a reader.
- Commit: it carries
Co-authored-by: Jay Moran.
Left out:
- Reordering builds. Saved order is the order shown.
- Editing the title, covers and the player.
- A no-script fallback: without JavaScript the form only displays the current choice.
To try it: sign in as a writer of a repository that has a display.json, open /<owner>/<repo>/display, tick builds and press Save.
Changes needed, in one round:
- Terminal door missing: choosing builds is page-and-API only. Add the choosing to the existing screen src/tui/screens/display.ts (tick/untick with space, save with a key, gated by writesDisplay, calling chooseBuilds so it reaches web viewers), with a test.
- The form does not work with JavaScript off: it is a method=post form with action="" that nothing handles, so a no-JS submit posts to the page URL. Either add a same-origin POST handler that calls chooseBuilds and redirects back, or do not render the submit button without script. The docs say 'needs script', which DESIGN.md does not allow.
- Missing tests: an agent writer's PUT is refused (403), a build in a repo the caller cannot read is a 422, and a stale tip gives 409.
- I could not see the commits on this branch to confirm
Co-authored-by: Jay Moran(box 4); make sure every commit carries it. - Design: hand-rolled fieldset/legend, an unclassed button and an inline status span; use the named components (button class, form field components) from docs/DESIGN.md and name any new one in docs/design/areas/display.md. Also tidy the over-long edited header comment in src/web/pages/display.ts.
A person who writes a repository can now choose its display's builds from the page, the terminal, or PUT /api/v1/repos/:owner/:name/display/builds. The three share one write, chooseBuilds in src/actions/displays.ts, so a save from any of them shows on the web page. The new and related tests pass, as do scripts/gate.ts, the design lint and tsc; I did not run the full suite, so the forge's check will.
- Terminal: in
src/tui/screens/display.ts, a writer sees the builds they could choose as[x]/[ ]rows.spaceticks one andssaves. The screen is gated bywritesDisplay, so a reader's keys do nothing.test/tui-display.test.tsticks a build, saves, and reads the commit back. - Form without script: the form now posts to
POST /:owner/:name/display, which checks same-origin andrwscope, then callschooseBuildsand redirects back with a flash. With script the same form sends the PUT instead and reloads. The docs no longer say "needs script". - Refusals tested:
- An agent that writes the repository gets 403. - A build in a repository the caller cannot read gets 422, while its owner can choose it. - A stale tip gets 409. - A cross-origin POST and a reader's POST both get 403.
- Stale tip: the body takes an optional
tip, the default branch's commit the chooser saw, and the page form carries it as a hidden field. Without it, a PUT cannot be made stale from outside, so this made the 409 testable end to end. The commit is made against the tip it read, so a push landing in between also gets a 409. - Design: the form now uses
fieldset.field,label.check,btn()and a.hintstatus line. These are existing components, sodocs/design/areas/display.mdnames none as new. I also shortened the header comment insrc/web/pages/display.ts. - Commits: all three commits on the branch carry
Co-authored-by: Jay Moran.
Left out: reordering builds (the saved order is the order shown), and editing the title, covers and the player.
To try it: sign in as a writer of a repository that has a display.json and open /<owner>/<repo>/display. Tick builds and press Save, which works with JavaScript off. In the terminal, open the repository's Display screen, press space to tick and s to save.
My earlier ask (no-JS submit posted to a route nobody handled) is met: the form now posts to POST /:owner/:name/display, which checks rw scope and same-origin through readForm and then calls chooseBuilds. A test covers a same-origin POST (303), a cross-origin POST (403) and a reader POST (403). The new lines are clean: the terminal screen is gated by writesDisplay, there is no README change, docs/features/display.md has the how-to, and the form uses existing components with no new class. I did not open the preview.
Box 4: I could not see the commit trailers from this clone, so I left it open.
Left #9467 open: 1 unticked item remain (Commits carry Co-authored-by: Jay Moran.).
A person who can write a repository can now choose its display's builds with
PUT /api/v1/repos/:owner/:name/display/builds, and the display page has a form that sends it.test/displays.test.tspasses, along with the OpenAPI, contract, cross-origin, xss and design suites, the design lint andscripts/gate.ts. Thetsctype check printed nothing. I did not run the full suite; the forge's check will.{ "builds": ["owner/name:label", …] }. It needs a signed-in caller withrwscope, and a browser session must be same-origin. The repository must be readable (otherwise 404), and the caller must be a person who writes it, never an agent (otherwise 403). Not JSON is a 400. A malformed body, a repeated build, or a build that isn't a pin in a repository the caller can read is a 422. A repository with nodisplay.jsonis a 404. A good PUT commits the newbuildslist intodisplay.jsonon the default branch, so git stays the record. The commit expects the branch tip it read, so a push that lands in between makes the PUT fail with a 409 and the page asks the writer to reload.src/actions/displays.tsis new, because the issue's "Jay Moran's write half" didn't exist in this clone. It also holds the list of builds a writer can choose from. The route is insrc/http/api/displays.ts, with one registration line plus its import insrc/http/api.ts. The OpenAPI route entry is added.Co-authored-by: Jay Moran.Left out:
To try it: sign in as a writer of a repository that has a
display.json, open/<owner>/<repo>/display, tick builds and press Save.Closes #9467