mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 11:49:28 +00:00
fix(ranker): scope a region to the file that defines its handler (M1b 12.4)
A route-registration module registers handlers that other modules define. app/routes/index.js requires seven handler modules and defines none, yet regions there were scoped to handleContributionsUpdate and its siblings. The graph rightly held no such method, so every question in those regions was unresolvable: 138 across six families on that one repository. The entry record still names the handler. The authorization question is which middleware guards which handler, and that is cross-file by nature. It now also records whether the file defines what it names, and a region built from an entry that does not is scoped to the file instead of to a method the file lacks. The handler's own module still gets its function-scoped region, so nothing is lost. My first attempt changed the mapper to stop naming cross-file handlers at all. An existing control caught it by asserting that a multi-line registration names the handler its middleware guards, which is exactly the attribution the authorization family needs. The evidence was against me and the fix belonged one layer up, in region construction. 1,407 tests passed, nine skipped. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5
parent
ca2c3a8b5f
commit
573b764bbb
@@ -74,6 +74,15 @@ class EntryPointRecord:
|
||||
conditions: list[str]
|
||||
provenance: str
|
||||
rationale: str
|
||||
# Does the file this record belongs to actually DEFINE the handler it names?
|
||||
#
|
||||
# A route-registration module registers handlers that live elsewhere: NodeGoat's `index.js`
|
||||
# requires seven handler modules and defines none. The record still names the handler, because
|
||||
# the authorization question is about which middleware guards which handler and that is
|
||||
# inherently cross-file. But a REGION scoped to a function its file does not hold is a question
|
||||
# the graph cannot answer, and 138 questions across six families were unresolvable for exactly
|
||||
# that reason on one repository. The region builder uses this to scope such an entry to the file.
|
||||
defines_handler: bool = True
|
||||
# Did the access level come from a DECLARATION, or from the absence of one?
|
||||
#
|
||||
# The distinction decides whether "public" can be trusted. An OpenAPI operation with no `security` block
|
||||
@@ -424,18 +433,20 @@ def _js_entry_points(target: FileTarget, text: str) -> list[EntryPointRecord]:
|
||||
handler, middleware = _js_registration(stripped, bounds)
|
||||
access, evidence = _js_route_access(middleware, stripped)
|
||||
start, end = bounds.get(handler or "", (number, number))
|
||||
named = handler or _js_handler_name(stripped)
|
||||
records.append(
|
||||
_entry(
|
||||
target,
|
||||
start,
|
||||
end,
|
||||
handler or _js_handler_name(stripped),
|
||||
named,
|
||||
"http_handler",
|
||||
"route",
|
||||
access,
|
||||
"http_request",
|
||||
evidence,
|
||||
_line_conditions(stripped),
|
||||
defines_handler=bool(named) and named in bounds,
|
||||
)
|
||||
)
|
||||
if "process.argv" in stripped:
|
||||
@@ -762,6 +773,7 @@ def _entry(
|
||||
access_evidence: list[str],
|
||||
conditions: list[str],
|
||||
access_declared: bool = False,
|
||||
defines_handler: bool = True,
|
||||
) -> EntryPointRecord:
|
||||
return EntryPointRecord(
|
||||
path=target.path,
|
||||
@@ -773,6 +785,7 @@ def _entry(
|
||||
access_level=access_level,
|
||||
trust_boundary=trust_boundary,
|
||||
access_evidence=access_evidence,
|
||||
defines_handler=defines_handler,
|
||||
conditions=conditions,
|
||||
provenance=f"entrypoint:{kind}:{access_level}",
|
||||
rationale=f"{kind} surface classified as {access_level} at {trust_boundary}",
|
||||
|
||||
@@ -99,6 +99,13 @@ def regions_for(entries: Sequence[object], targets: Sequence[object], *, shipped
|
||||
if not families:
|
||||
continue
|
||||
function = getattr(entry, "function_name", None) or None
|
||||
if function is not None and not getattr(entry, "defines_handler", True):
|
||||
# The entry names a handler this file registers but does not define, which is what a
|
||||
# route-registration module does. Scoping a region to it asks the graph about a method
|
||||
# the file does not hold, and every question in that region is then unresolvable. The
|
||||
# handler's own module gets its own regions, so the route is scoped to the file here and
|
||||
# the record keeps the name for the authorization question, which is cross-file by nature.
|
||||
function = None
|
||||
module_body = function in _MODULE_MARKERS
|
||||
if module_body:
|
||||
# A module body is not a handler, whatever the mapper called it, so it is offered the families a
|
||||
|
||||
Reference in New Issue
Block a user