audit the whole app for stupid cases of missing functionality or basic things like this (like the stats panel at the top that i requested).
What is wrong: every error outside a form is a bare plain-text page, with no page frame, no navigation bar and no link back. The audit reached them by opening a webhook that had just been deleted, a target ID that does not exist, and a mistyped path. Each shows only "404 page not found".
"404 page not found" comes from http.NotFound throughout internal/handlers.
"Bad request", "Forbidden" and "Internal server error" come from http.Error and serverError in internal/handlers/handlers.go.
"Forbidden - invalid CSRF token" comes from internal/middleware/csrf.go. A form left open in a tab long enough can hit it.
"The server is busy verifying credentials. Please try again." comes from internal/handlers/profile.go.
Validation errors on forms are not part of this issue. They belong on the form itself (#381 and #370).
Definition of done:
Every admin page route answers 400, 403, 404 and 500 with a rendered page in the normal layout. The page gives a one-line plain explanation and links back to the webhook list, or to sign-in when nobody is signed in. Status codes are unchanged.
The receiver at the inbound entrypoint URL, the healthcheck and /metrics keep their plain responses.
The pages show no more internal detail than the text does today.
Tests: a missing webhook, a missing target, an unknown path and a bad CSRF token each render the page, with the right status and the link back.
PRIORITY: from the owner's audit request of 1 October (#377), in the tier of #367 to #376.
Model: opus-5-5
Owner's request, https://git.eeqj.de/sneak/webhooker/issues/377 (chat, 2026-10-01):
> audit the whole app for stupid cases of missing functionality or basic things like this (like the stats panel at the top that i requested).
What is wrong: every error outside a form is a bare plain-text page, with no page frame, no navigation bar and no link back. The audit reached them by opening a webhook that had just been deleted, a target ID that does not exist, and a mistyped path. Each shows only "404 page not found".
- "404 page not found" comes from `http.NotFound` throughout `internal/handlers`.
- "Bad request", "Forbidden" and "Internal server error" come from `http.Error` and `serverError` in `internal/handlers/handlers.go`.
- "Forbidden - invalid CSRF token" comes from `internal/middleware/csrf.go`. A form left open in a tab long enough can hit it.
- "The server is busy verifying credentials. Please try again." comes from `internal/handlers/profile.go`.
Validation errors on forms are not part of this issue. They belong on the form itself (https://git.eeqj.de/sneak/webhooker/issues/381 and https://git.eeqj.de/sneak/webhooker/issues/370).
Definition of done:
- Every admin page route answers 400, 403, 404 and 500 with a rendered page in the normal layout. The page gives a one-line plain explanation and links back to the webhook list, or to sign-in when nobody is signed in. Status codes are unchanged.
- The receiver at the inbound entrypoint URL, the healthcheck and `/metrics` keep their plain responses.
- The pages show no more internal detail than the text does today.
- Tests: a missing webhook, a missing target, an unknown path and a bad CSRF token each render the page, with the right status and the link back.
PRIORITY: from the owner's audit request of 1 October (https://git.eeqj.de/sneak/webhooker/issues/377), in the tier of https://git.eeqj.de/sneak/webhooker/issues/367 to https://git.eeqj.de/sneak/webhooker/issues/376.
Model: opus-5-5
clawbot
self-assigned this 2026-10-01 22:06:18 +02:00
Plan. The issue body is the brief. One error template in the normal layout, and one helper in internal/handlers that renders it with a status code and a fixed one-line explanation; every http.NotFound, http.Error and serverError on an admin page route goes through it, as does the CSRF failure in the middleware and the router's not-found handler for unknown paths. The page links back to the webhook list, or to sign-in when nobody is signed in. The receiver, the healthcheck and /metrics keep their plain responses. No more internal detail than today. It rebases onto #378's paths if that lands first.
Model: opus-5-5
Plan. The issue body is the brief. One error template in the normal layout, and one helper in `internal/handlers` that renders it with a status code and a fixed one-line explanation; every `http.NotFound`, `http.Error` and `serverError` on an admin page route goes through it, as does the CSRF failure in the middleware and the router's not-found handler for unknown paths. The page links back to the webhook list, or to sign-in when nobody is signed in. The receiver, the healthcheck and `/metrics` keep their plain responses. No more internal detail than today. It rebases onto https://git.eeqj.de/sneak/webhooker/pulls/378's paths if that lands first.
Model: opus-5-5
Built in #408. Every 400, 403, 404 and 500 on an admin page, unknown paths and a refused form token included, now answers with an error page in the normal layout: one fixed line for the status and a link back to the webhook list, or to sign-in when nobody is signed in. Status codes are unchanged; the receiver, the healthcheck and /metrics stay plain. If the error page itself cannot render, the answer is the same status in plain text.
Judgement call: on the page for an unknown path outside every route group the navbar leaves out Logout, because no form token is issued there and a logout without one is refused.
Judgement call: the line is fixed per status, so a refused form token and another user's profile share the 403 line; the profile page's busy answer (503) uses the page too.
Not changed: form validation messages (#381, #370), the 413 and 429 answers from the middleware, and the 500 written after a panic stay plain text.
Model: opus-5-5
Built in https://git.eeqj.de/sneak/webhooker/pulls/408. Every 400, 403, 404 and 500 on an admin page, unknown paths and a refused form token included, now answers with an error page in the normal layout: one fixed line for the status and a link back to the webhook list, or to sign-in when nobody is signed in. Status codes are unchanged; the receiver, the healthcheck and `/metrics` stay plain. If the error page itself cannot render, the answer is the same status in plain text.
- Judgement call: on the page for an unknown path outside every route group the navbar leaves out Logout, because no form token is issued there and a logout without one is refused.
- Judgement call: the line is fixed per status, so a refused form token and another user's profile share the 403 line; the profile page's busy answer (503) uses the page too.
- Not changed: form validation messages (https://git.eeqj.de/sneak/webhooker/issues/381, https://git.eeqj.de/sneak/webhooker/issues/370), the 413 and 429 answers from the middleware, and the 500 written after a panic stay plain text.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Owner's request, #377 (chat, 2026-10-01):
What is wrong: every error outside a form is a bare plain-text page, with no page frame, no navigation bar and no link back. The audit reached them by opening a webhook that had just been deleted, a target ID that does not exist, and a mistyped path. Each shows only "404 page not found".
http.NotFoundthroughoutinternal/handlers.http.ErrorandserverErrorininternal/handlers/handlers.go.internal/middleware/csrf.go. A form left open in a tab long enough can hit it.internal/handlers/profile.go.Validation errors on forms are not part of this issue. They belong on the form itself (#381 and #370).
Definition of done:
/metricskeep their plain responses.PRIORITY: from the owner's audit request of 1 October (#377), in the tier of #367 to #376.
Model: opus-5-5
Plan. The issue body is the brief. One error template in the normal layout, and one helper in
internal/handlersthat renders it with a status code and a fixed one-line explanation; everyhttp.NotFound,http.ErrorandserverErroron an admin page route goes through it, as does the CSRF failure in the middleware and the router's not-found handler for unknown paths. The page links back to the webhook list, or to sign-in when nobody is signed in. The receiver, the healthcheck and/metricskeep their plain responses. No more internal detail than today. It rebases onto #378's paths if that lands first.Model: opus-5-5
Built in #408. Every 400, 403, 404 and 500 on an admin page, unknown paths and a refused form token included, now answers with an error page in the normal layout: one fixed line for the status and a link back to the webhook list, or to sign-in when nobody is signed in. Status codes are unchanged; the receiver, the healthcheck and
/metricsstay plain. If the error page itself cannot render, the answer is the same status in plain text.Model: opus-5-5