"""Tests for titan-iac supply-chain compliance report generation.""" from __future__ import annotations import json from pathlib import Path from ci.scripts import supply_chain_report def _write_json(path: Path, payload: dict): """Write compact JSON fixtures for report tests.""" path.write_text(json.dumps(payload), encoding="utf-8") def test_build_report_separates_waived_and_open_misconfigurations(tmp_path: Path): """Existing waivers suppress only exact target/id pairs.""" waivers = tmp_path / "waivers.json" _write_json( waivers, { "default_expires_at": "2026-05-22", "misconfigurations": [ { "id": "KSV-0014", "targets": ["services/example/deployment.yaml"], } ], }, ) trivy_payload = { "Results": [ { "Target": "services/example/deployment.yaml", "Misconfigurations": [ { "ID": "KSV-0014", "Status": "FAIL", "Severity": "HIGH", "Title": "Root file system is not read-only", }, { "ID": "KSV-0118", "Status": "FAIL", "Severity": "HIGH", "Title": "Default security context configured", }, ], } ] } report = supply_chain_report.build_report(trivy_payload, waivers, today_override="2026-04-22") assert report["status"] == "failed" assert report["waived_misconfigurations"] == 1 assert report["high_or_critical_misconfigurations"] == 1 assert report["open_misconfiguration_examples"] == [ { "id": "KSV-0118", "target": "services/example/deployment.yaml", "severity": "HIGH", "title": "Default security context configured", } ] def test_build_report_fails_expired_waivers_and_secrets(tmp_path: Path): """Expired waivers intentionally stop hiding old baseline debt.""" waivers = tmp_path / "waivers.json" _write_json( waivers, { "default_expires_at": "2026-04-01", "misconfigurations": [ { "id": "KSV-0014", "targets": ["services/example/deployment.yaml"], } ], }, ) trivy_payload = { "Results": [ { "Target": "services/example/deployment.yaml", "Secrets": [{"RuleID": "secret"}], "Misconfigurations": [ { "ID": "KSV-0014", "Status": "FAIL", "Severity": "CRITICAL", "Title": "Root file system is not read-only", } ], } ] } report = supply_chain_report.build_report(trivy_payload, waivers, today_override="2026-04-22") assert report["status"] == "failed" assert report["compliant"] is False assert report["secrets"] == 1 assert report["expired_waivers"] == 1 assert report["waived_misconfigurations"] == 0 def test_build_report_handles_missing_and_malformed_waiver_entries(tmp_path: Path): """Malformed waiver rows are ignored instead of hiding real findings.""" missing_waivers = tmp_path / "missing.json" empty_report = supply_chain_report.build_report({"Results": []}, missing_waivers, today_override="2026-04-22") assert empty_report["status"] == "ok" waivers = tmp_path / "waivers.json" _write_json( waivers, { "misconfigurations": [ "bad row", {"id": "", "targets": ["services/example/deployment.yaml"]}, {"id": "KSV-0014", "targets": "not a list"}, {"id": "KSV-0118", "expires_at": "2026-05-22", "targets": [""]}, ] }, ) trivy_payload = { "Results": [ "bad result", { "Target": "services/example/deployment.yaml", "Vulnerabilities": [ {"Severity": "HIGH"}, {"Severity": "CRITICAL"}, {"Severity": "LOW"}, ], "Misconfigurations": [ "bad misconfiguration", {"ID": "KSV-0001", "Status": "PASS", "Severity": "CRITICAL"}, {"ID": "KSV-0002", "Status": "FAIL", "Severity": "LOW"}, ], }, ] } report = supply_chain_report.build_report(trivy_payload, waivers, today_override="2026-04-22") assert report["status"] == "failed" assert report["critical_vulnerabilities"] == 1 assert report["high_vulnerabilities"] == 1 assert report["high_or_critical_misconfigurations"] == 0 def test_read_json_rejects_non_object_payload(tmp_path: Path): """Pipeline evidence files must be JSON objects, not arrays or scalars.""" path = tmp_path / "array.json" path.write_text("[]", encoding="utf-8") try: supply_chain_report._read_json(path) except ValueError as exc: assert "must contain a JSON object" in str(exc) else: # pragma: no cover - keeps the assertion message readable on failure raise AssertionError("expected ValueError") def test_main_writes_compliance_report(tmp_path: Path): """The Jenkins CLI path writes the exact report artifact it publishes.""" trivy_json = tmp_path / "trivy.json" output = tmp_path / "ironbank-compliance.json" _write_json(trivy_json, {"Results": []}) rc = supply_chain_report.main( [ "--trivy-json", str(trivy_json), "--output", str(output), "--today", "2026-04-22", ] ) assert rc == 0 payload = json.loads(output.read_text(encoding="utf-8")) assert payload["status"] == "ok" assert payload["compliant"] is True