mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
feat(contributor-scan): 1.1 regions from entry points, 1.2 the repository driver
Pair scoring could rely on a labelled function; a contributor cannot supply one -- which code is risky is the question they are asking. Regions now come from entry points, with a file-level fallback that says it is one, and each carries only the families its shape and language admit. Ranking uses what EntryPointRecord already decided (access_level, trust_boundary) rather than a second opinion computed from the same evidence. A family is offered only where its arbiter could answer: access_control needs a handler, so a library file with no entry point is not asked about obligations it has no siblings to be inconsistent with. The driver makes the two costs that were free at pair scale explicit. ONE CPG per repository, reused across regions -- a build is 5-30s on a forty-line excerpt and per-region builds would make this unusable. And a budget that is a TOTAL for the run rather than the enumerator's per-region cap of eight, spent highest-rank-first, with whatever it does not reach counted into regions_unjudged. A tool that silently analyses a tenth of a repository and reports a clean result is worse than one that says what it skipped. Two flaws the tests caught, both mine and both about ownership: the budget counted calls by reading a client's own usage log, so it silently never tripped for a client that keeps none -- the driver now counts its own spend through a wrapper; and the driver trusted its caller to have sorted, when the order the budget is spent in belongs to whoever holds the budget. The third was worse and only surfaced because a test failed for the right reason: the driver passed candidates=() and never enumerated, so a repository scan would have reported only what the arbiters establish unaided and never populated the suspicion band -- which supplied 15 of 26 findings in the pair measurement. It enumerates now. Sibling audit (Req 8.5) done before writing: family routing lives in exactly one production place, pipeline._arbitrate, dispatching on spec type. regions_for returns family names and the driver resolves specs, so that stays true. 750 passing, mypy clean over 96 files, gates byte-identical, zero orphans. 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
64a27c4e30
commit
8663c1a5b3
@@ -0,0 +1,118 @@
|
||||
"""contributor-scan task 1.1: regions come from the code, not from a label (Req 2).
|
||||
|
||||
A contributor cannot tell the tool which function is interesting -- that is the whole question they are
|
||||
asking. Pair scoring could rely on a labelled function; a repository scan cannot. Regions therefore come from
|
||||
entry points, with a file-level fallback that says so, and each region carries only the families its shape and
|
||||
language actually admit.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def _entry(path="api/users.py", function="update_password", access="public", boundary="network"): # type: ignore[no-untyped-def]
|
||||
from openultrasast.mapping import EntryPointRecord
|
||||
|
||||
return EntryPointRecord(
|
||||
path=path,
|
||||
line=10,
|
||||
end_line=40,
|
||||
function_name=function,
|
||||
name=function,
|
||||
kind="route",
|
||||
access_level=access,
|
||||
trust_boundary=boundary,
|
||||
access_evidence=[],
|
||||
conditions=[],
|
||||
provenance="decorator",
|
||||
rationale="",
|
||||
)
|
||||
|
||||
|
||||
def _target(path="api/users.py", language="python"): # type: ignore[no-untyped-def]
|
||||
from openultrasast.preprocess import FileTarget
|
||||
|
||||
return FileTarget(
|
||||
path=path,
|
||||
absolute_path=f"/repo/{path}",
|
||||
language=language,
|
||||
loc=100,
|
||||
tags=[],
|
||||
has_fuzz_entry_point=False,
|
||||
static_hints=[],
|
||||
reachability_hints=[],
|
||||
)
|
||||
|
||||
|
||||
def test_an_entry_point_becomes_a_region() -> None:
|
||||
from openultrasast.model.regions import regions_for
|
||||
|
||||
regions = regions_for([_entry()], [_target()])
|
||||
assert len(regions) == 1
|
||||
assert regions[0].path == "api/users.py" and regions[0].function == "update_password"
|
||||
assert regions[0].source == "entry_point"
|
||||
|
||||
|
||||
def test_a_file_with_no_entry_point_still_gets_a_region_that_says_so() -> None:
|
||||
"""Req 2.2: a fallback is fine; a fallback that pretends to be an entry point is not."""
|
||||
from openultrasast.model.regions import regions_for
|
||||
|
||||
regions = regions_for([], [_target(path="lib/util.py")])
|
||||
assert len(regions) == 1
|
||||
assert regions[0].function is None
|
||||
assert regions[0].source == "file_fallback"
|
||||
|
||||
|
||||
def test_regions_carry_only_families_their_language_has_specs_for() -> None:
|
||||
"""Req 2.3. Asking every family of every region is the unbounded version of this."""
|
||||
from openultrasast.model.regions import regions_for
|
||||
|
||||
python = regions_for([_entry()], [_target()])[0]
|
||||
assert "injection" in python.families
|
||||
# C has no dominance or config facts; a C region must not claim them.
|
||||
c_region = regions_for([], [_target(path="src/x.c", language="c")])[0]
|
||||
assert "access_control" not in c_region.families
|
||||
assert "config_secrets" not in c_region.families
|
||||
|
||||
|
||||
def test_an_absence_family_is_only_offered_where_there_is_a_handler() -> None:
|
||||
"""An obligation needs a reachable operation. A library file with no entry point has no handler to
|
||||
be inconsistent about, so offering access_control there is asking a question the arbiter cannot answer."""
|
||||
from openultrasast.model.regions import regions_for
|
||||
|
||||
handler = regions_for([_entry()], [_target()])[0]
|
||||
library = regions_for([], [_target(path="lib/util.py")])[0]
|
||||
assert "access_control" in handler.families
|
||||
assert "access_control" not in library.families
|
||||
|
||||
|
||||
def test_public_entry_points_outrank_internal_ones() -> None:
|
||||
"""Ranking uses what EntryPointRecord already carries rather than inventing a signal."""
|
||||
from openultrasast.model.regions import regions_for
|
||||
|
||||
entries = [_entry(path="a.py", function="internal", access="local-only"), _entry(path="b.py", function="exposed", access="public")]
|
||||
targets = [_target(path="a.py"), _target(path="b.py")]
|
||||
ranked = regions_for(entries, targets)
|
||||
assert [r.function for r in ranked] == ["exposed", "internal"], "highest risk first"
|
||||
assert ranked[0].rank > ranked[1].rank
|
||||
|
||||
|
||||
def test_the_order_is_total_so_two_runs_agree() -> None:
|
||||
from openultrasast.model.regions import regions_for
|
||||
|
||||
entries = [_entry(path=f"{c}.py", function=f"h{i}") for i, c in enumerate("abc")]
|
||||
targets = [_target(path=f"{c}.py") for c in "abc"]
|
||||
assert regions_for(entries, targets) == regions_for(entries, targets)
|
||||
|
||||
|
||||
def test_a_file_with_an_entry_point_is_not_also_a_fallback_region() -> None:
|
||||
"""Otherwise every handler is scanned twice and the budget is spent on duplicates."""
|
||||
from openultrasast.model.regions import regions_for
|
||||
|
||||
regions = regions_for([_entry()], [_target()])
|
||||
assert len(regions) == 1
|
||||
|
||||
|
||||
def test_an_unsupported_language_yields_no_region() -> None:
|
||||
from openultrasast.model.regions import regions_for
|
||||
|
||||
assert regions_for([], [_target(path="x.rb", language="ruby")]) == ()
|
||||
Reference in New Issue
Block a user