mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
docs(contributor-scan): 5.12 -- the ranker knows one framework, everything else is "unknown"
The rank SCALE is generic: `_ACCESS_RANK` maps abstract access levels to
numbers and knows no framework. The EVIDENCE feeding it does not --
`_wordpress_hook_access` holds the literals `wp_ajax_nopriv_` and `wp_ajax_`,
`_rest_route_access` holds `__return_true`. One framework, written in Python.
The consequence is not "slightly worse elsewhere", it is no ordering at all.
Anything unrecognised falls to review-required = 0.30 and ties break
alphabetically by path. That is where CVE-2023-23488's region sits -- position
~1036 of 4,463, below every REST handler -- so a 500-region budget never
reaches it. On a Laravel or Django codebase EVERY region lands in that tier:
thousands of regions ordered by filename.
Three layers, and the model is only the third:
* facts, not code -- an [[access]] fact declares hook patterns and their
access level, the way [[dispatch]] already replaced hardcoded
add_action/apply_filters today;
* generic features needing no framework knowledge -- modelled sinks in the
file, a modelled source present, call-graph distance to the nearest sink,
shipped, an unsanitized path to any sink. This is what would move
CVE-2023-23488's region on its own, and it should exist BEFORE any model,
or the model's contribution cannot be measured against anything;
* the LLM for the residue the first two cannot separate.
Ranking is a safe place for a model because it cannot manufacture a finding:
it decides what is looked at, never what is reported. The arbiters still
decide, the gates stay byte-identical, and a misrank costs recall -- now
visibly, since regions_truncated reports 500 of 4,463.
Records the constraints that must be settled before spending model budget:
batched over a prefilter (4,463 calls a scan is not a CI tool),
leave-one-repository-out (this project already has the train-on-test scar),
a recorded ranking so baselines diff, and honest degradation with no model.
A model proposing FACTS for an unknown framework is a different, slower loop
needing human approval -- ranking at runtime is not policy, a fact table is.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
co-authored by
Claude Opus 5
parent
4a1e06b75b
commit
7308570ba6
@@ -40,7 +40,12 @@ BEGIN = "---OUSAST-CPG-BEGIN---"
|
||||
END = "---OUSAST-CPG-END---"
|
||||
|
||||
BUILD_TIMEOUT_SECONDS = 900 # a large tree takes minutes; the go/no-go records what it actually cost
|
||||
# A slice's questions answer in seconds; a repository's do not. Measured on a 637-file WordPress plugin:
|
||||
# 13 dominance requests answer in 50s (most of it loading the graph) and 2,500 taint requests exceed 300s.
|
||||
# The constant was chosen when a "scan" meant an excerpt, and a repository scan is not a slower slice -- it
|
||||
# is a different order of question, so the ceiling is configurable rather than a number to keep raising.
|
||||
QUERY_TIMEOUT_SECONDS = 300
|
||||
QUERY_TIMEOUT_ENV = "OPENULTRASAST_CPG_QUERY_TIMEOUT"
|
||||
# A JVM with no -Xmx takes a quarter of physical RAM for its heap. On a contributor's laptop that is the
|
||||
# difference between a scan running in the background and a scan the machine notices, and it made the
|
||||
# first repository measurements unreproducible: runs were killed under memory pressure at different
|
||||
@@ -210,7 +215,7 @@ class JoernBackend:
|
||||
|
||||
runner: Runner | None = None
|
||||
build_timeout: int = BUILD_TIMEOUT_SECONDS
|
||||
query_timeout: int = QUERY_TIMEOUT_SECONDS
|
||||
query_timeout: int = field(default_factory=lambda: _configured_timeout())
|
||||
heap_mb: int = 0 # 0 means read the environment, then fall back to CPG_HEAP_MB
|
||||
queries_dir: Path = field(default_factory=lambda: QUERIES_DIR)
|
||||
# Why the last build refused, so the driver can name it instead of reporting a bare `cpg_build_failed`.
|
||||
@@ -712,6 +717,14 @@ def _hoist_shared(rendered: dict[str, dict[str, str]]) -> dict[str, str]:
|
||||
return shared
|
||||
|
||||
|
||||
def _configured_timeout() -> int:
|
||||
"""The query ceiling, from the environment or the default. Never zero or negative."""
|
||||
raw = os.environ.get(QUERY_TIMEOUT_ENV, "").strip()
|
||||
if raw.isdigit() and int(raw) > 0:
|
||||
return int(raw)
|
||||
return QUERY_TIMEOUT_SECONDS
|
||||
|
||||
|
||||
def _render(value: object) -> str:
|
||||
"""CPGQL parameters are strings; a sequence becomes a comma-separated list the script splits."""
|
||||
if isinstance(value, str):
|
||||
|
||||
Reference in New Issue
Block a user