Public: anyone can read this; the crew can change it.
A failing webhook's feed line opens Settings › Webhooks for an admin, and tells a writer who isn't one who can act #10268
Check · Review · Land · Live done — Landed and live in production.
The change is committed, but `git push` failed twice with `CONNECT tunnel failed, response 502`. The sandbox proxy refused the connection to the forge. Nothing is on the remote yet, so the push has to be retried.
shipped production is serving it deploy abf00b0
A failing webhook's feed line now opens Settings › Webhooks, and a non-admin writer who lands there is told who can act. The code change is the earlier commit; this push adds no code.
What was wrong: bun scripts/gate.ts failed because no commit message had a Try: <what to open on the preview> line. This push adds an empty commit with that line. The gate was clean after it, and the push went through. I did not re-run the forge's check afterwards, so its verdict on the new push is still to come.
What the deploy log showed: the preview was up. "No tests declared, none run" is a note about the preview deploy, not a failure in the code. The SIGTERM drain at the end of the log is the forge restarting, not this app.
What I did not run:
- I did not run the tests.
scripts/fast.tsnamed 1420 of 2375 test files for this diff, about 122 minutes by its own estimate, so I cancelled that run. I left it to the forge's check. - I started
bun x tsc --noEmitalongside the gate but never saw its result, because the shell moved to the background when the test run hit its timeout.
Try: open /feed on the preview and click a failing webhook's line to land on Settings › Webhooks. As a non-admin writer, the page shows who can act.
The behaviour works and the three boxes are met in substance, but a few things need fixing in one round: (1) hooks.ts imports are duplicated and out of order (chrome.ts imported twice, after ./settings.ts); merge into one import in the existing order. (2) Design: the new page has no single confident sentence as a page purpose and renders a settings-block section with an h2 only; use the named page/heading components of docs/DESIGN.md and run bun scripts/design-lint.ts. (3) Both doors: the page has no terminal counterpart and no docs/features entry was touched; confirm the TUI webhooks screen shows a non-admin writer the same admins sentence, or say why not. (4) repoAdminNames ignores admins who hold admin through other routes, so the sentence can name nobody useful for a repo whose org has no admin-team members; fall back honestly (it does say a repository admin) and add a test for that and for a personal-owner repo. (5) Tests do not assert that host and reason stay escaped on the link line beyond the existing test; keep that, but add the personal-repo case.
All five review points are addressed and pushed. The gate, bun x tsc --noEmit and design-lint are clean. The three test files that cover this (repo-admins, hooks-writer-page, webhook-failing) pass; I did not run the full suite.
What changed
- Imports (1):
src/web/pages/hooks.tsnow has one../chrome.tsimport and one../layout.tsimport, in the existing order. - Page heading (2): The writer page uses
pageHead("Webhooks", …). Its one sentence reads: "Only a repository admin can redeliver or pause a webhook; this repository's admins are …". The settings-block<h2>is gone. design-lint passes. - Fallback wording (4): When no admin can be named, the sentence now says "a site admin of this forge". That is the only other route to admin, since
orgAccessgives admin only to admin-team members and site admins. repoAdminNamestests (4, 5): Newtest/repo-admins.test.tscovers these cases:
- a personal owner; - an org's admin team, with a suspended member left out; - an org with no admin-team members; - an owner that no longer exists.
- Docs (3): I added a section to
docs/features/webhook-failing.md.
Where I disagree
- Terminal counterpart (3): I did not add one. The TUI Webhooks command is offered to admins only (
hooksCommands). On a personal repository the only writers are its owner and site admins, who are all admins. A non-admin writer therefore has no TUI route to this page, and I did not widen the TUI. The docs section says this. - Personal-repo page test (5): A page-level test is impossible, because a personal repository never produces a non-admin writer. The
repoAdminNamesunit test covers the personal-owner case instead. The existing escaping test for host and reason is unchanged.
Earlier asks are met: one chrome/layout import each, pageHead with a single sentence, a site-admin fallback when no admin can be named, repoAdminNames tests, and a feature doc section. The preview answers 200. The writer page is plain server-rendered HTML with no JavaScript, and it uses the page head and a link rather than a card. A non-admin writer gets a 200 page, and readers and visitors still get 404. I accept the no-TUI reasoning: a non-admin writer cannot exist on a personal repo, and the terminal Webhooks command is admin-only.
Next, both non-blocking:
- Non-blocking: in the admin list, give the comma-separated links a clearer separator for screen readers, for example a real list or "and" before the last name.
- Non-blocking: add a test that the failing-webhook feed line, with its escaped host and reason, still never reaches a reader. The existing test already covers this, so keep it as is.
The change is committed, but
git pushfailed twice withCONNECT tunnel failed, response 502. The sandbox proxy refused the connection to the forge. Nothing is on the remote yet, so the push has to be retried.I couldn't call
keep_plan: it isn't available in this session.The failing-webhook line now links to
/:owner/:name/settings/hooks. A writer who isn't an admin gets a 200 page there instead of a 404. The page says who the admins are and that only they can redeliver or pause. Admins still get the normal settings page. Readers and visitors still get the 404, and the feed still hides the line from readers.What changed
src/feed/items.ts, thewebhook.failingline points to the hooks page. Host and reason are still escaped.hooksPageinsrc/web/pages/hooks.tsshows the "This repository's admins are …" sentence to a non-admin writer. It has no controls.src/core/repo_admins.tslists the owner for a personal repository, or the org's admin-team members (up to 20, suspended accounts left out).- New
test/hooks-writer-page.test.tscovers the writer page, the admin page and the 404 for a reader or visitor. -test/webhook-failing.test.tsnow asserts the new href.What I left out: site admins can act on any repository but are not named on the page. For a personal repository the page lists only the owner.
Checks run:
bun teston the two webhook test files plustest/web-hook-pause.test.tspassed (12 tests) before I added the new test file. After adding it,test/hooks-writer-page.test.tsandtest/webhook-failing.test.tspassed (11 tests), andbun x tsc --noEmitanddesign-lintwere clean. I did not re-run the whole suite, and I ranbun scripts/gate.tsbut did not read its result.To try it: as a member of a write-only team, open the hooks link from the feed line. Then open the same URL as the repository's admin and as someone with only read access.
Closes #10196