#!/usr/bin/env python3 """Fail when publication-only repository boundaries are violated.""" from __future__ import annotations import subprocess import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] BLOCKED_PATHS = {".mcp.json"} BLOCKED_PREFIXES = ( ".codex-input/", ".codex-artifacts/", ".playwright-mcp/", "artifacts/", "data/", ) BLOCKED_SUFFIXES = (".db", ".db-shm", ".db-wal") BLOCKED_CONTENT = ( b"192.168." + b"10.150", b"geointel." + b"itworx.tech", b"itworx_" + b"unraid_deploy", b"/mnt/user/appdata/" + b"dockdeck", b"tower" + b".local", ) LARGE_FILE_LIMIT = 20 * 1024 * 1024 LARGE_FILE_ALLOWLIST_PREFIXES = ( "docs/assets/", "frontend/public/portfolio/", "output/pdf/", ) def tracked_files() -> list[str]: result = subprocess.run( ["git", "ls-files", "-z"], cwd=ROOT, check=True, capture_output=True, ) return [item for item in result.stdout.decode("utf-8").split("\0") if item] def main() -> int: violations: list[str] = [] for relative in tracked_files(): normalized = relative.replace("\\", "/") if normalized in BLOCKED_PATHS or normalized.startswith(BLOCKED_PREFIXES): violations.append( f"{normalized}: local or cross-project state must not be tracked" ) continue if normalized.endswith(BLOCKED_SUFFIXES): violations.append( f"{normalized}: database runtime state must not be tracked" ) continue path = ROOT / relative if not path.is_file(): continue size = path.stat().st_size if size > LARGE_FILE_LIMIT and not normalized.startswith( LARGE_FILE_ALLOWLIST_PREFIXES ): violations.append( f"{normalized}: {size} bytes exceeds the {LARGE_FILE_LIMIT}-byte tracked-file budget" ) content = path.read_bytes() for marker in BLOCKED_CONTENT: if marker in content: violations.append( f"{normalized}: contains private publication marker {marker.decode('ascii')}" ) if violations: print("Repository hygiene violations:", file=sys.stderr) for violation in violations: print(f" - {violation}", file=sys.stderr) return 1 print("Repository hygiene check passed.") return 0 if __name__ == "__main__": raise SystemExit(main())