feat(three-stage-scan): report map and honor fail-on worth-fixing

This commit is contained in:
Marius Ciepluch
2026-09-04 00:18:33 +02:00
parent a916e2d173
commit 818a0b10d3
11 changed files with 330 additions and 7 deletions
+66
View File
@@ -9,6 +9,7 @@ from pathlib import Path
import pytest
from openultrasast.cli import main
from openultrasast.sandbox import FakeSandboxRunner, SandboxResult
from openultrasast.sandbox import runner as sandbox_runner
_VULN = "@app.route('/admin')\ndef admin():\n return eval(request.data)\n"
@@ -48,6 +49,20 @@ def _latest_run(repo: Path) -> Path:
return sorted((repo / ".runs").iterdir())[-1]
def _crash_runner() -> FakeSandboxRunner:
return FakeSandboxRunner(SandboxResult(exit_code=139, stdout="", stderr="Segmentation fault\n", timed_out=False))
def _enable_crash_sandbox(monkeypatch: pytest.MonkeyPatch) -> FakeSandboxRunner:
from openultrasast import cli
fake = _crash_runner()
monkeypatch.setenv("OPENULTRASAST_RUNS_DIR", ".runs")
monkeypatch.setenv("OPENULTRASAST_SANDBOX_PROBE", "1")
monkeypatch.setattr(cli, "resolve_sandbox_runner", lambda: fake)
return fake
def test_deep_scan_skips_regress_when_sandbox_unavailable(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
repo = _repo(tmp_path)
monkeypatch.setenv("OPENULTRASAST_RUNS_DIR", ".runs")
@@ -99,6 +114,20 @@ def test_deep_scan_with_fake_runner_writes_verdicts(tmp_path: Path, monkeypatch:
assert "path" in item
assert manifest["artifacts"]["verdicts"] == "verdicts.json"
assert manifest["artifacts"]["complexity_map"] == "complexity_map.json"
assert manifest["worth_fixing"]["count"] == sum(1 for item in payload["verdicts"] if item.get("worth_fixing"))
report = (run_dir / "report.md").read_text()
inventory_at = report.index("## Inventory")
map_at = report.index("## Complexity map")
worth_at = report.index("## Worth fixing")
assert inventory_at < map_at < worth_at
map_section = report[map_at:worth_at]
assert "app.py" in map_section
assert "Gap:" in map_section
ledger_path = repo / ".openultrasast" / "calibration" / "complexity_ledger.json"
assert ledger_path.is_file()
ledger = json.loads(ledger_path.read_text())
assert ledger
assert any(entry.get("last_verdict") in {"triggerable", "not_triggerable"} for entry in ledger.values())
def test_deep_scan_unsafe_hunter_snippet_is_safety_rejected_without_docker_job(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
@@ -132,3 +161,40 @@ def test_deep_scan_unsafe_hunter_snippet_is_safety_rejected_without_docker_job(t
for item in payload["verdicts"]:
if item["reason"] == "safety_rejected":
assert item["verdict"] == "inconclusive"
def test_deep_scan_fail_on_worth_fixing_exits_one_when_triggerable(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
repo = _repo(tmp_path)
_enable_crash_sandbox(monkeypatch)
docker_argv = _guard_docker(monkeypatch)
assert main(["scan", str(repo), "--mode", "deep", "--fail-on", "worth-fixing"]) == 1
assert docker_argv == []
run_dir = _latest_run(repo)
payload = json.loads((run_dir / "verdicts.json").read_text())
manifest = json.loads((run_dir / "manifest.json").read_text())
report = (run_dir / "report.md").read_text()
worth_fixing = [item for item in payload["verdicts"] if item.get("worth_fixing")]
assert worth_fixing
assert len(worth_fixing) >= 1
assert any(item["verdict"] == "triggerable" for item in worth_fixing)
assert manifest["worth_fixing"]["count"] == len(worth_fixing)
assert "## Complexity map" in report
assert "## Worth fixing" in report
assert "triggerable" in report
ledger = json.loads((repo / ".openultrasast" / "calibration" / "complexity_ledger.json").read_text())
assert any(entry.get("last_verdict") == "triggerable" for entry in ledger.values())
def test_deep_scan_fail_on_never_exits_zero_with_worth_fixing_verdict(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
repo = _repo(tmp_path)
_enable_crash_sandbox(monkeypatch)
docker_argv = _guard_docker(monkeypatch)
assert main(["scan", str(repo), "--mode", "deep", "--fail-on", "never"]) == 0
assert docker_argv == []
payload = json.loads((_latest_run(repo) / "verdicts.json").read_text())
assert any(item.get("worth_fixing") for item in payload["verdicts"])