| """Tests for scanners.cve_trigger_runner."""
|
| from __future__ import annotations
|
|
|
| import pytest
|
|
|
| from scanners import cve_trigger_runner as ctr
|
|
|
|
|
|
|
|
|
|
|
|
|
| def _vuln(cve_id: str, fix: str = "99.0") -> dict:
|
| return {"rule": cve_id, "tool": "pip-audit", "message": f"fix in {fix}"}
|
|
|
|
|
|
|
|
|
|
|
|
|
| def test_no_trigger_files_returns_empty(tmp_path):
|
| """No Python files → no findings."""
|
| out, msg = ctr.cve_trigger(str(tmp_path), pip_audit_findings=[])
|
| assert out == []
|
| assert isinstance(msg, str)
|
|
|
|
|
| def test_torch_load_no_weights_only(tmp_path):
|
| """torch.load() in source + matching CVE should fire PYSEC-2026-139."""
|
| (tmp_path / "model.py").write_text("import torch\nm = torch.load('model.pt')\n")
|
| findings, _ = ctr.cve_trigger(
|
| str(tmp_path),
|
| pip_audit_findings=[_vuln("PYSEC-2026-139")],
|
| )
|
| rules = {f["rule"] for f in findings}
|
| assert "PYSEC-2026-139" in rules
|
|
|
|
|
| def test_torch_load_with_weights_only_is_clean(tmp_path):
|
| """torch.load(weights_only=True) should not fire."""
|
| (tmp_path / "safe.py").write_text(
|
| "import torch\nm = torch.load('model.pt', weights_only=True)\n"
|
| )
|
| out, _ = ctr.cve_trigger(str(tmp_path), pip_audit_findings=[])
|
|
|
| torch_findings = [f for f in out if "PYSEC-2026-139" in f.get("rule", "")]
|
| assert len(torch_findings) == 0
|
|
|
|
|
| def test_cve_forwarded_from_pip_audit(tmp_path):
|
| """CVE in pip_audit_findings + matching source trigger produces a finding."""
|
|
|
| (tmp_path / "load.py").write_text("import torch\nmodel = torch.load('weights.pt')\n")
|
| findings, msg = ctr.cve_trigger(
|
| str(tmp_path),
|
| pip_audit_findings=[_vuln("PYSEC-2026-139")],
|
| )
|
| assert any(f["rule"] == "PYSEC-2026-139" for f in findings), f"Expected PYSEC-2026-139 in {findings}"
|
|
|
|
|
| def test_severity_is_string(tmp_path):
|
| """All findings must have string severity."""
|
| (tmp_path / "x.py").write_text("import pickle; pickle.loads(data)\n")
|
| out, _ = ctr.cve_trigger(str(tmp_path), pip_audit_findings=[])
|
| for f in out:
|
| assert isinstance(f.get("severity"), str)
|
|
|
|
|
| def test_owasp_present(tmp_path):
|
| """Findings from pip_audit forwarding must include OWASP tag."""
|
| (tmp_path / "load.py").write_text("import torch\nm = torch.load('w.pt')\n")
|
| findings, _ = ctr.cve_trigger(
|
| str(tmp_path),
|
| pip_audit_findings=[_vuln("PYSEC-2026-139")],
|
| )
|
| for f in findings:
|
| assert "owasp" in f or "A0" in str(f.get("owasp", "A06"))
|
|
|