mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 19:59:26 +00:00
fix(scan): attach change relationships in linear time
The third wall under the 13.3 replay, found by the streamed case log: the evidence and context passes finished at 14:53, then nothing -- no engine call, no log line -- for 82 minutes, until the case was killed 60 s past its 7,200 s deadline. `affected_context` tested membership with `relation not in relationships` on a list: 7,998,000 comparisons for 4,000 relationships (profiled, 83% of the time), and a push over a WordPress plugin attaches tens of thousands. The deadline is checked once per question, so a single late question could run for minutes, which is also why the process overran its cancellation allowance. Membership now goes through a set beside the ordered list, and each distinct context path is resolved once instead of once per row. Measured: 4,000 relationships 7.4 s -> 0.44 s; 400,000 in 16 s. The control counts comparisons rather than timing them, and fails on the old code with 7,998,000. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
982cb14115
commit
e7e2941e37
@@ -451,3 +451,24 @@ def test_the_evidence_pass_names_the_changed_files_to_the_engine(tmp_path):
|
||||
assert asked and all("contextFilter" not in r for r in asked)
|
||||
assert scan._changed_files(context("x\ny.php")) is None
|
||||
assert scan._changed_files(context("source.php")) == ("source.php",)
|
||||
|
||||
|
||||
def test_attaching_relationships_is_linear_in_what_it_attaches(tmp_path, monkeypatch):
|
||||
"""Membership went through a list: 8 million comparisons for 4,000 relationships, and a push over a
|
||||
WordPress plugin ran 82 minutes past its evidence pass and overran the deadline. Counted, not timed, so the
|
||||
control cannot flake under load."""
|
||||
from openultrasast.model.contracts import AffectedRelationship, QuestionIdentity
|
||||
from openultrasast.model.regions import affected_context
|
||||
|
||||
(tmp_path / "source.php").write_text("x\n" * 400)
|
||||
compared = []
|
||||
original = AffectedRelationship.__eq__
|
||||
monkeypatch.setattr(AffectedRelationship, "__eq__", lambda self, other: compared.append(1) or original(self, other))
|
||||
questions = [QuestionIdentity("unit", "php", f"f{i}.php", "run", "injection") for i in range(200)]
|
||||
rows = {
|
||||
q: [{"kind": "context_summary"}] + [{**row("source.php", function=f"m{j}"), "startLine": 1, "endLine": 400} for j in range(20)]
|
||||
for q in questions
|
||||
}
|
||||
enriched, _ = affected_context(context(), questions, rows, tmp_path)
|
||||
assert len(enriched.relationships) == 4000
|
||||
assert len(compared) < 4000, f"{len(compared)} comparisons for 4,000 relationships"
|
||||
|
||||
Reference in New Issue
Block a user