#!/usr/bin/env python3 """Run deterministic Rekor/DSSE negative-path verification suite.""" from __future__ import annotations import argparse import hashlib import json import pathlib import tarfile import time from rekor_shim import RekorCase, default_cases, simulate_submit import sys TOOLS_DIR = pathlib.Path(__file__).resolve().parents[1] / "tools" sys.path.insert(0, str(TOOLS_DIR)) from emit_artifacts import TestCaseResult, write_junit # noqa: E402 def _classify(case: RekorCase, status: int, body: dict[str, object]) -> tuple[str, str | None]: reprocess_token = str(body.get("reprocessToken")) if body.get("reprocessToken") else None if status == 413: return "payload_too_large", None if status == 424: return "failed_dependency", reprocess_token or f"retry-{case.case_id}" if status == 504: return "upstream_timeout", f"timeout-{case.case_id}" if status == 202: return "reprocess_pending", reprocess_token or f"pending-{case.case_id}" if status == 400 and case.entry_type == "unknown": return "unsupported_entry_type", None return "unexpected_rekor_status", None def _token(case_id: str) -> str: return hashlib.sha256(case_id.encode("utf-8")).hexdigest()[:16] def _write_tar(source_dir: pathlib.Path, tar_path: pathlib.Path) -> None: tar_path.parent.mkdir(parents=True, exist_ok=True) with tarfile.open(tar_path, "w:gz") as archive: for file in sorted(path for path in source_dir.rglob("*") if path.is_file()): archive.add(file, arcname=file.relative_to(source_dir).as_posix()) def main() -> int: parser = argparse.ArgumentParser(description="Run Rekor negative path suite.") parser.add_argument( "--output", type=pathlib.Path, default=pathlib.Path("out/supply-chain/03-rekor-neg"), ) args = parser.parse_args() start = time.perf_counter() output = args.output.resolve() output.mkdir(parents=True, exist_ok=True) diagnostics_root = output / "diagnostics" diagnostics_root.mkdir(parents=True, exist_ok=True) cases = default_cases() junit_cases: list[TestCaseResult] = [] report_cases: list[dict[str, object]] = [] failures = 0 for case in cases: case_start = time.perf_counter() status, body, headers = simulate_submit(case) code, reprocess = _classify(case, status, body) expected = case.expected_code passed = code == expected if not passed: failures += 1 case_token = reprocess or _token(case.case_id) diagnostic = { "caseId": case.case_id, "upstream": { "statusCode": status, "body": body, "headers": headers, }, "machineReadableErrorClass": code, "expectedErrorClass": expected, "reprocessToken": case_token, } case_dir = diagnostics_root / case.case_id case_dir.mkdir(parents=True, exist_ok=True) (case_dir / "diagnostic_blob.json").write_text( json.dumps(diagnostic, sort_keys=True, indent=2) + "\n", encoding="utf-8", ) report_cases.append( { "caseId": case.case_id, "statusCode": status, "entryType": case.entry_type, "machineReadableErrorClass": code, "expectedErrorClass": expected, "reprocessToken": case_token, "passed": passed, } ) junit_cases.append( TestCaseResult( suite="03-rekor-neg", name=case.case_id, passed=passed, duration_seconds=time.perf_counter() - case_start, failure_message=None if passed else f"expected={expected} actual={code}", ) ) _write_tar(diagnostics_root, output / "rekor_negative_cases.tar.gz") report = { "durationSeconds": round(time.perf_counter() - start, 4), "failures": failures, "cases": report_cases, "machineReadableErrorClasses": sorted( { "payload_too_large", "unsupported_entry_type", "failed_dependency", "upstream_timeout", "reprocess_pending", } ), } (output / "report.json").write_text(json.dumps(report, sort_keys=True, indent=2) + "\n", encoding="utf-8") write_junit(output / "junit.xml", junit_cases) return 0 if failures == 0 else 1 if __name__ == "__main__": raise SystemExit(main())