Complete 3axis tutorial native and Web/WASM parity tools
This commit is contained in:
64
scripts/validate_publish_gate.py
Normal file
64
scripts/validate_publish_gate.py
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate the active selected-case publication gate."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
GATE = Path("coverage/release-authorized-gate.report.json")
|
||||
EXPECTED_SCHEMA = "release-authorized-gate.v1"
|
||||
EXPECTED_SCOPE = "selected_case_web_wasm_simulation"
|
||||
|
||||
|
||||
def canonical(value: Any) -> str:
|
||||
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
||||
|
||||
|
||||
def validate(root: Path, gate_path: Path = GATE) -> dict[str, Any]:
|
||||
root = root.resolve()
|
||||
path = gate_path if gate_path.is_absolute() else root / gate_path
|
||||
report = json.loads(path.read_text(encoding="utf-8"))
|
||||
unsigned = {key: value for key, value in report.items() if key != "report_sha256"}
|
||||
expected_hash = hashlib.sha256(canonical(unsigned).encode("utf-8")).hexdigest()
|
||||
errors: list[str] = []
|
||||
if report.get("schema") != EXPECTED_SCHEMA:
|
||||
errors.append("schema_invalid")
|
||||
if report.get("status") != "authorized":
|
||||
errors.append("gate_not_authorized")
|
||||
if report.get("implementation_status") != "verified":
|
||||
errors.append("implementation_not_verified")
|
||||
if report.get("release_scope") != EXPECTED_SCOPE:
|
||||
errors.append("scope_invalid")
|
||||
if report.get("candidate_eligible") is not True:
|
||||
errors.append("candidate_not_eligible")
|
||||
if report.get("release_action") != "ALLOW_RELEASE":
|
||||
errors.append("release_action_not_allowed")
|
||||
if report.get("remaining_blockers") != []:
|
||||
errors.append("remaining_blockers_present")
|
||||
if report.get("report_sha256") != expected_hash:
|
||||
errors.append("report_hash_invalid")
|
||||
if not all(item.get("hash_match") is True for item in report.get("evidence", [])):
|
||||
errors.append("evidence_hash_invalid")
|
||||
if report.get("risk_boundary", {}).get("technical_evidence_rewritten") is not False:
|
||||
errors.append("technical_evidence_was_rewritten")
|
||||
return {"status": "authorized" if not errors else "blocked", "release_action": "ALLOW_RELEASE" if not errors else "STOP_RELEASE", "scope": report.get("release_scope"), "errors": errors, "report_sha256": report.get("report_sha256")}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--repo-root", type=Path, default=ROOT)
|
||||
parser.add_argument("--gate", type=Path, default=GATE)
|
||||
args = parser.parse_args()
|
||||
result = validate(args.repo_root, args.gate)
|
||||
print(json.dumps(result, ensure_ascii=False, sort_keys=True))
|
||||
return 0 if result["status"] == "authorized" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user