mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 19:59:26 +00:00
feat(tree-sitter-overlay-extra): parse JS/C/Java overlay via optional extra
Add openultrasast[semantic] with official grammar wheels and one CST walker into FileIR. quick stays extra-free. Host CLI is not overlay-ready. Default CI stays extra-free; a semantic job runs pytest -m semantic.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
"""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"
|
||||
Reference in New Issue
Block a user