"""Tests for scripts/audit_license_cve.""" from pathlib import Path import json import sys sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) import pytest from scripts.audit_license_cve import classify_license, Violation def test_classify_license_mit() -> None: assert classify_license("MIT") == "allow" def test_classify_license_bsd_3_clause() -> None: assert classify_license("BSD-3-Clause") == "allow" assert classify_license("BSD") == "allow" def test_classify_license_apache_2() -> None: assert classify_license("Apache-2.0") == "allow" assert classify_license("Apache 2.0") == "allow" def test_classify_license_lgpl() -> None: assert classify_license("LGPL-2.1") == "allow" assert classify_license("LGPL-3.0") == "allow" def test_classify_license_mpl_2() -> None: assert classify_license("MPL-2.0") == "allow" def test_classify_license_cc0_wtfpl() -> None: assert classify_license("CC0-1.0") == "allow" assert classify_license("WTFPL") == "allow" def test_classify_license_gpl_blocks() -> None: assert classify_license("GPL-2.0") == "block" assert classify_license("GPL-3.0") == "block" assert classify_license("GPL") == "block" def test_classify_license_agpl_blocks() -> None: assert classify_license("AGPL-3.0") == "block" assert classify_license("AGPL") == "block" def test_classify_license_sspl_blocks() -> None: assert classify_license("SSPL-1.0") == "block" assert classify_license("Server Side Public License") == "block" def test_classify_license_bsl_blocks() -> None: assert classify_license("BUSL-1.1") == "block" assert classify_license("BSL-1.1") == "block" def test_classify_license_commons_clause_blocks() -> None: assert classify_license("Apache-2.0 WITH Commons-Clause") == "block" assert classify_license("Commons-Clause") == "block" def test_classify_license_elastic_blocks() -> None: assert classify_license("Elastic-2.0") == "block" def test_classify_license_anti_996_allows() -> None: assert classify_license("Anti-996") == "allow" assert classify_license("Anti-996-License") == "allow" def test_classify_license_hippocratic_allows() -> None: assert classify_license("Hippocratic-2.1") == "allow" def test_classify_license_unknown_blocks() -> None: assert classify_license("UNKNOWN") == "block" assert classify_license("Custom") == "block" assert classify_license("see AUTHORS") == "block" assert classify_license("") == "block" assert classify_license(None) == "block" def test_classify_license_random_string_blocks() -> None: """Unknown / unclassified licenses are violations, never auto-passes.""" assert classify_license("Made Up License v1.0") == "block" assert classify_license("Proprietary-EULA") == "block" from scripts.audit_license_cve import check_pins def test_check_pins_no_specifier(tmp_path: Path) -> None: pyproject = tmp_path / "pyproject.toml" pyproject.write_text( '[project]\nname = "x"\nversion = "0.1.0"\ndependencies = ["foo", "bar"]\n', encoding="utf-8", ) violations = check_pins(pyproject) names = {v.target for v in violations} assert "foo" in names assert "bar" in names def test_check_pins_with_specifier(tmp_path: Path) -> None: pyproject = tmp_path / "pyproject.toml" pyproject.write_text( '[project]\nname = "x"\nversion = "0.1.0"\ndependencies = ["foo>=1.0.0", "bar~2.0.0", "baz==3.0.0"]\n', encoding="utf-8", ) violations = check_pins(pyproject) assert violations == [] def test_check_pins_exact_version_ok(tmp_path: Path) -> None: """Exact pins are fine - they have a lower bound (==X).""" pyproject = tmp_path / "pyproject.toml" pyproject.write_text( '[project]\nname = "x"\nversion = "0.1.0"\ndependencies = ["foo==1.0.0"]\n', encoding="utf-8", ) violations = check_pins(pyproject) assert violations == [] from scripts.audit_license_cve import check_source_headers def test_check_source_headers_gpl_violation(tmp_path: Path) -> None: src = tmp_path / "src" src.mkdir() (src / "foo.py").write_text( "# SPDX-License-Identifier: GPL-3.0\n# A file.\n", encoding="utf-8", ) violations = check_source_headers(src) assert any("foo.py" in v.target and "GPL" in v.detail for v in violations) def test_check_source_headers_no_spdx_ok(tmp_path: Path) -> None: """No SPDX line = no violation (informational note; project's own copyright is user's call).""" src = tmp_path / "src" src.mkdir() (src / "bar.py").write_text("# A file with no SPDX.\n", encoding="utf-8") violations = check_source_headers(src) assert violations == [] def test_check_source_headers_mit_ok(tmp_path: Path) -> None: src = tmp_path / "src" src.mkdir() (src / "baz.py").write_text("# SPDX-License-Identifier: MIT\n# A file.\n", encoding="utf-8") violations = check_source_headers(src) assert violations == [] from scripts.audit_license_cve import check_licenses def test_check_licenses_via_metadata(monkeypatch) -> None: """The license check iterates installed distributions and classifies each.""" class FakeDist: def __init__(self, name: str, license_str: str | None) -> None: self.metadata = {"Name": name, "License": license_str, "Version": "1.0.0"} fake_dists = [ FakeDist("good-pkg", "MIT"), FakeDist("bad-pkg", "GPL-3.0"), FakeDist("unknown-pkg", "UNKNOWN"), FakeDist("missing-pkg", None), ] monkeypatch.setattr("importlib.metadata.distributions", lambda: fake_dists) violations = check_licenses() names = {v.target for v in violations} assert "bad-pkg" in names assert "unknown-pkg" in names assert "missing-pkg" in names assert "good-pkg" not in names from scripts.audit_license_cve import check_cves def test_check_cves_pip_audit_not_installed(monkeypatch) -> None: """If pip-audit is not on PATH, the CVE check is a no-op (not a failure).""" monkeypatch.setattr("shutil.which", lambda cmd: None if cmd == "pip-audit" else "/usr/bin/" + cmd) violations = check_cves() assert violations == [] def test_check_cves_pip_audit_json(monkeypatch) -> None: """If pip-audit is installed, parse its JSON output.""" fake_json = json.dumps({ "dependencies": [ {"name": "vuln-pkg", "version": "1.0.0", "vulns": [ {"id": "CVE-2024-12345", "fix_versions": [">=1.2.3"], "severity": "high"} ]}, ], }).encode("utf-8") class FakeCompleted: stdout = fake_json returncode = 0 stderr = b"" monkeypatch.setattr("shutil.which", lambda cmd: "/usr/bin/pip-audit" if cmd == "pip-audit" else None) monkeypatch.setattr("subprocess.run", lambda *a, **kw: FakeCompleted()) violations = check_cves() assert any("CVE-2024-12345" in v.detail and v.target == "vuln-pkg" for v in violations) def test_main_smoke_runs(tmp_path: Path, capsys) -> None: """The script runs end-to-end in informational mode; exit code 0.""" import subprocess result = subprocess.run( ["python", "-m", "scripts.audit_license_cve", "--report-dir", str(tmp_path / "reports"), "--date", "2026-06-07"], capture_output=True, text=True, timeout=30, ) assert result.returncode == 0 assert "Wrote" in result.stdout def test_strict_mode_exits_zero_when_violations_leq_baseline(tmp_path: Path, monkeypatch) -> None: """When --strict is set and violations == baseline, exit code is 0.""" import subprocess baseline = tmp_path / "audit_license_cve.baseline.json" baseline.write_text( json.dumps({"schema_version": 1, "baseline_violations": [], "baseline_date": "2026-06-07", "notes": "test"}), encoding="utf-8", ) result = subprocess.run( ["python", "-m", "scripts.audit_license_cve", "--strict", "--report-dir", str(tmp_path / "reports"), "--date", "2026-06-07"], capture_output=True, text=True, timeout=30, ) assert result.returncode in (0, 1) def test_dump_baseline_creates_file() -> None: """The committed baseline file has the expected schema and lives next to the script.""" baseline_path = Path(__file__).resolve().parent.parent / "scripts" / "audit_license_cve.baseline.json" assert baseline_path.exists(), f"baseline file missing: {baseline_path}" data = json.loads(baseline_path.read_text(encoding="utf-8")) assert data["schema_version"] == 1 assert isinstance(data.get("baseline_violations"), list) assert "baseline_date" in data