"""Fail-closed checks for a public Git/Zenodo release candidate.""" from __future__ import annotations import hashlib import json from pathlib import Path import re import subprocess ROOT = Path(__file__).resolve().parents[1] CANONICAL_PDF = "output/pdf/dissecting_repository_scale_code_agent_harnesses.pdf" CANONICAL_DOI = "10.5281/zenodo.21781711" REQUIRED = { ".gitignore", ".zenodo.json", "CITATION.cff", "LICENSE", "LICENSE-DATA", "README.md", "README_ZENODO.md", "REPRODUCING.md", "THIRD_PARTY_NOTICES.md", "paper/main.tex", "paper/references.bib", CANONICAL_PDF, "output/pdf/SHA256SUMS", } SECRET_PATTERNS = { "private key": re.compile(r"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----"), "OpenAI-style key": re.compile(r"\bsk-[A-Za-z0-9_-]{20,}\b"), "GitHub token": re.compile(r"\b(?:gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,})\b"), "AWS access key": re.compile(r"\bAKIA[0-9A-Z]{16}\b"), } PORTABLE_SUFFIXES = {".py", ".toml", ".md", ".tex", ".bib", ".txt", ".lock"} PROVENANCE_PREFIXES = ( "results/", "tasks/patches/", "tasks/selection/", "tasks/validation/", ) def sha256(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() def candidate_files() -> list[str]: result = subprocess.run( ["git", "ls-files", "--cached", "--others", "--exclude-standard"], cwd=ROOT, check=True, capture_output=True, text=True, ) return sorted(set(result.stdout.splitlines())) def audit() -> dict[str, object]: errors: list[str] = [] files = candidate_files() missing = sorted(path for path in REQUIRED if not (ROOT / path).is_file()) if missing: errors.append(f"missing required release files: {missing}") pdfs = sorted( path for path in files if path.startswith("output/pdf/") and path.endswith(".pdf") and (ROOT / path).is_file() ) if pdfs != [CANONICAL_PDF]: errors.append(f"expected exactly one canonical PDF, found: {pdfs}") oversized = [] for relative in files: path = ROOT / relative if path.is_file() and path.stat().st_size > 10 * 1024 * 1024: oversized.append((relative, path.stat().st_size)) if oversized: errors.append(f"files larger than 10 MiB require explicit release handling: {oversized}") forbidden_outputs = [ path for path in files if path.startswith(("results/raw/", "indexes/", "data/repos/")) and not path.endswith(".gitkeep") ] if forbidden_outputs: errors.append(f"heavy local artifacts are tracked: {forbidden_outputs}") secret_hits: list[str] = [] portability_hits: list[str] = [] for relative in files: path = ROOT / relative if not path.is_file() or path.stat().st_size > 10 * 1024 * 1024: continue try: text = path.read_text(encoding="utf-8") except UnicodeDecodeError: continue for label, pattern in SECRET_PATTERNS.items(): if pattern.search(text): secret_hits.append(f"{relative}: {label}") if ( path.suffix in PORTABLE_SUFFIXES and not relative.startswith(PROVENANCE_PREFIXES) and re.search(r"/(?:Users|home)/[^/\s]+/", text) ): portability_hits.append(relative) if secret_hits: errors.append(f"possible credentials detected: {secret_hits}") if portability_hits: errors.append(f"machine-specific paths in executable/public text: {portability_hits}") zenodo_path = ROOT / ".zenodo.json" if zenodo_path.is_file(): metadata = json.loads(zenodo_path.read_text(encoding="utf-8")) for key in ("title", "upload_type", "publication_type", "creators", "license"): if not metadata.get(key): errors.append(f".zenodo.json missing {key}") if metadata.get("license") != "cc-by-4.0": errors.append("Zenodo content license must be cc-by-4.0") doi_files = ( "README.md", "README_ZENODO.md", "CITATION.cff", ".zenodo.json", "paper/main.tex", ) missing_doi = [ relative for relative in doi_files if not (ROOT / relative).is_file() or CANONICAL_DOI not in (ROOT / relative).read_text(encoding="utf-8") ] if missing_doi: errors.append(f"canonical DOI missing from release metadata: {missing_doi}") checksum_path = ROOT / "output/pdf/SHA256SUMS" pdf_path = ROOT / CANONICAL_PDF if checksum_path.is_file() and pdf_path.is_file(): expected_line = f"{sha256(pdf_path)} {pdf_path.name}" lines = [line.strip() for line in checksum_path.read_text().splitlines() if line.strip()] if lines != [expected_line]: errors.append("output/pdf/SHA256SUMS is stale or contains a noncanonical PDF") return { "status": "pass" if not errors else "fail", "files_checked": len(files), "canonical_pdf": CANONICAL_PDF, "errors": errors, } def main() -> None: result = audit() print(json.dumps(result, indent=2, sort_keys=True)) if result["status"] != "pass": raise SystemExit(1) if __name__ == "__main__": main()