Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """Fail-closed public claim lint for pre-live ProofFrame submissions.""" | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| from pathlib import Path | |
| import re | |
| from typing import Any | |
| from proofframe.submission_gate import build_submission_gate | |
| ROOT = Path(__file__).resolve().parents[1] | |
| ACTIVE_PUBLIC_COPY_FILES = [ | |
| "README.md", | |
| "docs/submission.md", | |
| "docs/assets/devpost-submission-packet.md", | |
| "docs/assets/devpost-submission-packet.json", | |
| "docs/assets/devpost-form-kit.md", | |
| "docs/assets/devpost-form-kit.json", | |
| ] | |
| PRE_LIVE_ALLOWED_MARKERS = ( | |
| "final gate", | |
| "final submission gate", | |
| "submission gate", | |
| "target", | |
| "pending", | |
| "requires", | |
| "require ", | |
| "after t020", | |
| "after t021", | |
| "after proof", | |
| "until live", | |
| "not ", | |
| "do not say", | |
| "safe after", | |
| "verified run", | |
| ) | |
| PRE_LIVE_FORBIDDEN_PATTERNS = [ | |
| re.compile(r"(?i)\bstores?\b.*\b(?:in|through|to)\b.*\bbackblaze b2\b"), | |
| re.compile(r"(?i)\bbackblaze b2-backed\b"), | |
| re.compile(r"(?i)\bgenerates?\b.*\b(?:with|through)\b.*\bgenblaze\b"), | |
| re.compile(r"(?i)\bgenblaze-generated\b"), | |
| re.compile(r"(?i)\buses?\b.*\bb2 storage\b.*\bend[- ]to[- ]end\b"), | |
| re.compile(r"(?i)\bevery asset\b.*\bb2\b"), | |
| re.compile(r"(?i)\blive b2 object packet\b"), | |
| ] | |
| def load_json(path: Path) -> dict[str, Any] | None: | |
| try: | |
| return json.loads(path.read_text(encoding="utf-8")) | |
| except (FileNotFoundError, json.JSONDecodeError): | |
| return None | |
| def line_is_contextualized(line: str) -> bool: | |
| lowered = line.lower() | |
| return any(marker in lowered for marker in PRE_LIVE_ALLOWED_MARKERS) | |
| def scan_public_copy(root: Path) -> list[dict[str, Any]]: | |
| findings: list[dict[str, Any]] = [] | |
| for relative_path in ACTIVE_PUBLIC_COPY_FILES: | |
| path = root / relative_path | |
| if not path.exists(): | |
| findings.append( | |
| { | |
| "path": relative_path, | |
| "line": None, | |
| "status": "missing", | |
| "detail": "Active public copy file is missing.", | |
| } | |
| ) | |
| continue | |
| for line_number, line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1): | |
| if line_is_contextualized(line): | |
| continue | |
| for pattern in PRE_LIVE_FORBIDDEN_PATTERNS: | |
| if pattern.search(line): | |
| findings.append( | |
| { | |
| "path": relative_path, | |
| "line": line_number, | |
| "status": "unsafe-pre-live-claim", | |
| "detail": line.strip(), | |
| } | |
| ) | |
| break | |
| return findings | |
| def proof_ready_from_gate(gate: dict[str, Any]) -> bool: | |
| task_statuses = {item["id"]: item["ok"] for item in gate.get("task_gates", [])} | |
| return bool(gate["evidence_gate"]["ok"] and task_statuses.get("T020") and task_statuses.get("T021")) | |
| def check_packet_mode(root: Path, proof_ready: bool) -> list[dict[str, Any]]: | |
| packet_path = root / "docs" / "assets" / "devpost-submission-packet.json" | |
| packet = load_json(packet_path) | |
| if packet is None: | |
| return [ | |
| { | |
| "path": str(packet_path.relative_to(root)), | |
| "line": None, | |
| "status": "missing", | |
| "detail": "Devpost packet JSON is missing or invalid.", | |
| } | |
| ] | |
| mode = packet.get("mode") | |
| if not proof_ready and mode != "pre_live_safe": | |
| return [ | |
| { | |
| "path": str(packet_path.relative_to(root)), | |
| "line": None, | |
| "status": "unsafe-packet-mode", | |
| "detail": f"Expected pre_live_safe before final evidence, got {mode!r}.", | |
| } | |
| ] | |
| return [] | |
| def build_claim_report(root: Path = ROOT) -> dict[str, Any]: | |
| root = root.resolve() | |
| gate = build_submission_gate(root) | |
| proof_ready = proof_ready_from_gate(gate) | |
| findings: list[dict[str, Any]] = [] | |
| findings.extend(check_packet_mode(root, proof_ready)) | |
| if not proof_ready: | |
| findings.extend(scan_public_copy(root)) | |
| return { | |
| "ok": not findings, | |
| "mode": "post_live_verified" if proof_ready else "pre_live_safe", | |
| "final_gate": { | |
| "ok": gate["ok"], | |
| "proof_ready": proof_ready, | |
| "summary": gate["summary"], | |
| "evidence_status": gate["evidence_gate"]["status"], | |
| "packet_status": gate["packet_gate"]["status"], | |
| }, | |
| "scanned_files": ACTIVE_PUBLIC_COPY_FILES, | |
| "findings": findings, | |
| } | |
| def build_parser() -> argparse.ArgumentParser: | |
| parser = argparse.ArgumentParser(description="Lint ProofFrame public copy for unsafe claims.") | |
| parser.add_argument("--root", type=Path, default=ROOT) | |
| return parser | |
| def main() -> None: | |
| args = build_parser().parse_args() | |
| report = build_claim_report(args.root) | |
| print(json.dumps(report, indent=2)) | |
| raise SystemExit(0 if report["ok"] else 2) | |
| if __name__ == "__main__": | |
| main() | |