mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
71 lines
2.6 KiB
Python
71 lines
2.6 KiB
Python
"""Extra-on CST walker and overlay. Skips when wheels are absent."""
|
|||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from openultrasast.findings import quick_scan_findings
|
||
|
|
from openultrasast.preprocess import preprocess_repository
|
||
|
|
from openultrasast.rank import rank_targets
|
||
|
|
from openultrasast.semantic import adjudicate, has_semantic_extra
|
||
|
|
from openultrasast.semantic.ir import parse_file
|
||
|
|
|
||
|
|
pytestmark = pytest.mark.semantic
|
||
|
|
|
||
|
|
|
||
|
|
def _require_extra() -> None:
|
||
|
|
if not has_semantic_extra():
|
||
|
|
pytest.skip("requires openultrasast[semantic]")
|
||
|
|
|
||
|
|
|
||
|
|
def test_javascript_eval_query_is_tree_sitter_call() -> None:
|
||
|
|
_require_extra()
|
||
|
|
ir = parse_file("app.js", "eval(req.query.x)\n", "javascript")
|
||
|
|
assert ir.parse_ok is True
|
||
|
|
assert ir.engine == "tree-sitter"
|
||
|
|
calls = [call for function in ir.functions for call in function.calls]
|
||
|
|
eval_calls = [call for call in calls if call.name == "eval"]
|
||
|
|
assert eval_calls
|
||
|
|
assert any("req.query" in arg for arg in eval_calls[0].arg_texts)
|
||
|
|
|
||
|
|
|
||
|
|
def test_broken_javascript_is_parse_failed() -> None:
|
||
|
|
_require_extra()
|
||
|
|
ir = parse_file("app.js", "eval(req.query.x\n", "javascript")
|
||
|
|
assert ir.parse_ok is False
|
||
|
|
assert ir.reason == "parse_failed"
|
||
|
|
|
||
|
|
|
||
|
|
def test_javascript_eval_promotes(tmp_path: Path) -> None:
|
||
|
|
_require_extra()
|
||
|
|
root = tmp_path / "repo"
|
||
|
|
root.mkdir()
|
||
|
|
(root / "app.js").write_text("eval(req.query.x)\n")
|
||
|
|
_, targets = preprocess_repository(root)
|
||
|
|
findings = quick_scan_findings(root, targets, rank_targets(targets))
|
||
|
|
records = adjudicate(root=root, targets=targets, findings=findings)
|
||
|
|
eval_records = [record for record in records if "js-eval" in record.proposal_id]
|
||
|
|
assert eval_records
|
||
|
|
assert eval_records[0].disposition == "promote"
|
||
|
|
assert eval_records[0].evidence_level == "static_corroboration"
|
||
|
|
assert eval_records[0].engine == "tree-sitter"
|
||
|
|
|
||
|
|
|
||
|
|
def test_c_constant_system_demotes(tmp_path: Path) -> None:
|
||
|
|
_require_extra()
|
||
|
|
root = tmp_path / "repo"
|
||
|
|
root.mkdir()
|
||
|
|
(root / "run.c").write_text('void f(void) { system("ls"); }\n')
|
||
|
|
_, targets = preprocess_repository(root)
|
||
|
|
findings = quick_scan_findings(root, targets, rank_targets(targets))
|
||
|
|
records = adjudicate(root=root, targets=targets, findings=findings)
|
||
|
|
hits = [record for record in records if record.path == "run.c"]
|
||
|
|
assert hits
|
||
|
|
assert all(record.disposition != "unadjudicated" or record.reason != "language_unsupported" for record in hits)
|
||
|
|
demoted = [record for record in hits if record.disposition == "demote"]
|
||
|
|
assert demoted
|
||
|
|
assert demoted[0].dominating_fact == "constant"
|
||
|
|
assert demoted[0].evidence_level == "static_corroboration"
|