Commit d527925
committed
chore(tooling): enumerate namespace-claiming wildcard mounts and require each to be classified (#4116)
A handler mounted on `<prefix>/*` claims an entire namespace, and Hono runs every
handler matching a path in registration order with the first Response winning. So
a TERMINAL wildcard — one that always answers, never yields — makes every other
route under that prefix reachable only when it happens to register first, and
plugin registration order is not a contract anyone declares or tests.
That shape has now cost four fixes, and every one was found by hand, after the
fact, by someone reading the code for an unrelated reason:
- #2567 — anonymous-deny on raw `/data` held only while REST registered first,
so a load-order change silently reopened anonymous data access.
- #4018 — the standalone `/discovery` sat behind the dispatcher's, so a third
publisher drifted unnoticed.
- #4088 / #4092 — AuthPlugin's `/api/v1/auth/*` swallowed plugin-hono-server's
`/auth/me/permissions`, the console's entire permission layer.
- cloud#923 — the same shape in AuthProxyPlugin, which cloud had ALREADY hit in
staging (its apps/*/server/index.ts record the Console 404ing on that path).
Nothing in CI noticed any of them, and nothing would notice the fifth. The driven
tests #4092 and cloud#923 shipped each pin ONE catch-all and cannot cover the next
wildcard someone mounts — a test only drives the routes that existed when it was
written. What never existed is the ENUMERATION.
This adds it, following check-route-envelope.mjs (#3843) including the part that
matters most: a site the scan finds but the ledger does not declare is an ERROR,
not a default. Three states — `yields` (verified from the AST, so an entry cannot
rot: delete the next() and it fails), `exempt` with a reason for a wildcard that
is supposed to own its namespace, `ratchet` naming the issue for one that is
terminal and should not be. No fourth state where nobody looked.
AST rather than regex because "does this call next()?" is a question about the
handler's parameter binding: a comment or string mentioning next(), or an inner
closure's own next, all fool a textual match in the direction that PASSES while
the defect ships, and the parameter is not always named `next`. Handlers passed by
identifier are resolved too — cloud#923 mounts its handler that way, and a scan
that only understood inline arrows would have called it terminal.
Found 13 namespace-claiming mounts where a manual grep had found 3, and with them
two real, previously untracked instances of the #4088 defect in
`packages/adapters/hono` (`${prefix}/auth/*`, `${prefix}/storage/*`) — ratcheted
under #4117. It also separates that file's deliberate `${prefix}/*` ownership
(ADR-0076 OQ#9) from the two that merely forgot to yield; in source they look
identical.
Verified both directions by hand: reverting #4092's fix fails with the terminal
diagnostic, and adding a new undeclared `${prefix}/reports/*` catch-all fails as
NOT DECLARED. Self-test covers 15 cases, including the three textual-match
failure modes and identifier handler resolution.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VZLsKypjrGhiLpio2uWKu1 parent c20b875 commit d527925
4 files changed
Lines changed: 538 additions & 0 deletions
File tree
- .changeset
- .github/workflows
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
123 | 123 | | |
124 | 124 | | |
125 | 125 | | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
126 | 139 | | |
127 | 140 | | |
128 | 141 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| 39 | + | |
39 | 40 | | |
40 | 41 | | |
41 | 42 | | |
| |||
0 commit comments