"""AC-10: SBOM diff script + OpenCV pin gate exist and run on stub builds.""" from __future__ import annotations import json import subprocess import sys from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[2] CI_DIR = REPO_ROOT / "ci" def test_sbom_diff_pass_on_subset(tmp_path: Path) -> None: # Arrange research = tmp_path / "research_sbom.json" deployment = tmp_path / "deployment_sbom.json" research.write_text( json.dumps( [ {"name": "numpy", "version": "1.26.4"}, {"name": "scipy", "version": "1.11.3"}, {"name": "okvis2", "version": "0.1.0"}, ] ) ) deployment.write_text( json.dumps( [ {"name": "numpy", "version": "1.26.4"}, {"name": "okvis2", "version": "0.1.0"}, ] ) ) # Act result = subprocess.run( [ sys.executable, str(CI_DIR / "sbom_diff.py"), "--deployment", str(deployment), "--research", str(research), ], capture_output=True, text=True, check=False, ) # Assert assert result.returncode == 0, f"sbom_diff stderr:\n{result.stderr}" def test_sbom_diff_fails_on_forbidden_component(tmp_path: Path) -> None: # Arrange — ADR-002 / R02: vins_mono must not appear in deployment SBOM research = tmp_path / "research_sbom.json" deployment = tmp_path / "deployment_sbom.json" research.write_text(json.dumps([{"name": "vins_mono", "version": "0.1"}])) deployment.write_text(json.dumps([{"name": "vins_mono", "version": "0.1"}])) # Act result = subprocess.run( [ sys.executable, str(CI_DIR / "sbom_diff.py"), "--deployment", str(deployment), "--research", str(research), ], capture_output=True, text=True, check=False, ) # Assert assert result.returncode != 0, ( "sbom_diff must fail when a research-only component appears in deployment" ) def test_opencv_pin_gate_passes_on_412_minimum() -> None: # Act result = subprocess.run( [ sys.executable, str(CI_DIR / "opencv_pin_gate.py"), "--pyproject", str(REPO_ROOT / "pyproject.toml"), ], capture_output=True, text=True, check=False, ) # Assert assert result.returncode == 0, f"opencv_pin_gate stderr:\n{result.stderr}" def test_opencv_pin_gate_fails_on_lower_version(tmp_path: Path) -> None: # Arrange bad_pyproject = tmp_path / "pyproject.toml" bad_pyproject.write_text( '[project]\nname = "x"\nversion = "0.1"\ndependencies = ["opencv-python>=4.10,<5"]\n' ) # Act result = subprocess.run( [ sys.executable, str(CI_DIR / "opencv_pin_gate.py"), "--pyproject", str(bad_pyproject), ], capture_output=True, text=True, check=False, ) # Assert assert result.returncode != 0, ( "opencv_pin_gate must reject `opencv-python>=4.10` (D-CROSS-CVE-1 ≥ 4.12.0)" )