map: keep the request namespace through renamed destructuring - #128
Merged
Conversation
|
Correctly preserves request namespace through renamed destructuring. 🎯 Quality: 85% Excellent · 📦 Size: Oversized — strongly consider breaking this down 🛡️ Standards: no pre-flight fit check ran for this change — wire 📈 This month: Your 59th PR — above team average · Averaging Good |
Contributor
Author
|
/review |
daniloradovic
approved these changes
Aug 13, 2026
Found while splitting extract.ts. The request namespace decides an input's runtime
coordinate, but it was recorded as a SET of local names and then compared against the
literal strings 'query'/'params'. With a renamed destructuring the local is the alias, so
the comparison failed and the namespace was silently discarded:
({ query }) => query.doc -> get.doc (correct)
({ query: q }) => q.doc -> post.doc (WRONG: never matches a query-string attack)
({ params: p }) => p.id -> post.id (WORSE: a coordinate for a route param)
The second case is the dangerous one: route params are not exposed by the runtime resolver at
all, which is exactly why runtimeCoordinate returns null for them — and aliasing bypassed that
guard, handing a rule compiler an address the engine can never resolve. This is the same
failure class as attributing a sink by name: a coordinate that looks plausible and quietly
does nothing.
`sourceNames` is now a Map from local name to the namespace it was bound from, so an alias
resolves to its true source. An aliased request-body read (`const b = await req.json()`) also
keeps its precise source (json-body / form-body) instead of collapsing to a generic body.
Covered for all five shapes plus the candidate consequence: the aliased route param yields no
coordinate and therefore no candidate, while the four addressable ones still compile.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
patchstackdave
force-pushed
the
fix/map-aliased-request-namespace
branch
from
August 13, 2026 14:25
e9d0404 to
8af63b5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found while splitting
extract.ts— reported there, fixed here, because that PR's contract was zero behaviour change. Now rebased ontomain; this branch contains only the fix.The bug
The request namespace decides an input's runtime coordinate. It was recorded as a
Setof local names and then compared against the literal strings'query'/'params'— so with a renamed destructuring the local is the alias, the comparison fails, and the namespace is silently discarded:The third line is the serious one. Route params aren't exposed by the runtime resolver at all — that's precisely why
runtimeCoordinatereturnsnullfor them. Aliasing bypassed that guard and would hand a rule compiler an address the engine can never resolve. Same failure class as attributing a sink by name: a coordinate that looks plausible and quietly does nothing.The fix
sourceNamesbecomes aMapfrom local name → the namespace it was bound from, so an alias resolves to its true source. An aliased request-body read (const b = await req.json()) now also keeps its precise source (json-body/form-body) instead of collapsing to a genericbody.Verified
({ query })get.docget.doc({ query: q })post.docget.doc({ params: p })post.idnull(+ no candidate)({ body: b })post.filepost.file({ query: q }) → const { doc } = qpost.docget.docPlus the consequence that matters: the aliased route param produces no candidate, while the four addressable inputs still compile candidates. 851 tests (80 files), typecheck clean.