Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .changeset/wildcard-fallthrough-guard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
---

chore(tooling): enumerate namespace-claiming wildcard mounts and require each to be classified (#4116)

Release-nothing: adds `scripts/check-wildcard-fallthrough.mjs` plus its CI step.
No package code changes.

A handler mounted on `<prefix>/*` claims an entire namespace, and Hono runs
handlers matching a path in registration order with the first Response winning.
So a TERMINAL wildcard — one that always answers and never yields — makes every
other route under that prefix reachable only when it happens to register first.
That shape has cost four fixes (#2567, #4018, #4088/#4092, cloud#923) and every
one was found by hand, after the fact, by someone reading the code for an
unrelated reason.

The two driven tests #4092 and cloud#923 shipped each pin one catch-all, and are
structurally unable to cover the next wildcard someone mounts. What never existed
is the enumeration. This scan is it: three states (`yields`, verified from the AST
so the entry cannot rot; `exempt` with a reason; `ratchet` naming the issue), and
a mount the scan finds but the ledger does not declare is an error, never a
default — the same shape as `check-route-envelope.mjs` (#3843).

It found 13 namespace-claiming mounts where a manual grep had found 3, including
two real, previously untracked instances of the #4088 defect in
`packages/adapters/hono` (`${prefix}/auth/*` and `${prefix}/storage/*`), now
ratcheted under #4117.
13 changes: 13 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ jobs:
- name: Error-code casing guard
run: pnpm check:error-code-casing

# Namespace-wildcard fall-through guard (#4116). A handler mounted on
# `<prefix>/*` claims the whole namespace, and Hono's first-registered
# handler that answers wins — so a TERMINAL wildcard makes every other
# route under that prefix reachable only by registration luck. That shape
# has now cost four fixes (#2567, #4018, #4088/#4092, cloud#923) and every
# one was found by hand, never by CI. Per-plugin tests cannot cover the
# next one; what was missing is the ENUMERATION. Three states — yields
# (verified from the AST, so it cannot rot) / exempt-with-reason / ratchet
# — and an undeclared mount is an error, never a default. Runs its own
# --self-test first.
- name: Wildcard fall-through guard
run: pnpm check:wildcard-fallthrough

# Release-notes drift guard: the platform is one version-locked train, so
# every released @objectstack/spec major must have a curated, navigable
# release page at content/docs/releases/v<major>.mdx. Catches the gap that
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"check:authz-resolver": "node scripts/check-single-authz-resolver.mjs",
"check:route-envelope": "node scripts/check-route-envelope.mjs --self-test && node scripts/check-route-envelope.mjs",
"check:error-code-casing": "node scripts/check-error-code-casing.mjs --self-test && node scripts/check-error-code-casing.mjs",
"check:wildcard-fallthrough": "node scripts/check-wildcard-fallthrough.mjs --self-test && node scripts/check-wildcard-fallthrough.mjs",
"check:console-sha": "node scripts/check-console-sha.mjs",
"check:release-notes": "node scripts/check-release-notes.mjs",
"check:node-version": "node scripts/check-node-version.mjs"
Expand Down
Loading
Loading