#!/usr/bin/env python3 """Generate the explicitly authorized selected-case release gate. This is an additive policy gate. It never rewrites the historical K8 gate or turns unresolved technical evidence into verified parity; it records the user-authorized risk acceptance for the selected 3axis tutorial bundle. """ from __future__ import annotations import argparse import hashlib import json from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parents[1] AUTHORIZATION = Path("coverage/release-authorization.json") HISTORICAL_GATE = Path("coverage/release-candidate-gate.report.json") T7_GATE = Path("coverage/wasm-simulation-release-gate-t7.report.json") VERIFICATION = Path("coverage/release-verification.report.json") OUTPUT = Path("coverage/release-authorized-gate.report.json") CONTEXT_ID = "linuxcnc-2.10.0-pre0-wasm-m1-py-c1" SELECTED_CASE = "linuxcnc/configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.ini" BLOCKERS = ( "manifest_seed_unassigned", "accepted_entries_missing", "official_oracle_missing", "configuration_resources_missing", "browser_matrix_unverified", "license_closure_incomplete", ) def canonical(value: Any) -> str: return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":")) def digest(value: Any) -> str: return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest() def file_digest(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() def artifact(root: Path, path: str, role: str) -> dict[str, Any]: relative = Path(path) full = root / relative if not full.is_file(): return {"path": relative.as_posix(), "role": role, "status": "missing"} return { "path": relative.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": file_digest(full), } def load(root: Path, path: Path) -> dict[str, Any]: value = json.loads((root / path).read_text(encoding="utf-8")) if not isinstance(value, dict): raise ValueError(f"{path} must contain an object") return value def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]: root = root.resolve() authorization = load(root, AUTHORIZATION) historical = load(root, HISTORICAL_GATE) t7 = load(root, T7_GATE) verification = load(root, VERIFICATION) waivers = authorization.get("waivers") waiver_by_id = { row.get("blocker"): row for row in waivers if isinstance(row, dict) } if isinstance(waivers, list) else {} waiver_ids = set(waiver_by_id) errors: list[dict[str, Any]] = [] if authorization.get("schema") != "release-authorization.v1": errors.append({"code": "authorization_schema_invalid"}) if authorization.get("context_id") != CONTEXT_ID: errors.append({"code": "authorization_context_mismatch", "observed": authorization.get("context_id")}) if authorization.get("authorized_by") != "workspace-user": errors.append({"code": "authorization_owner_invalid"}) if authorization.get("release_scope") != "selected_case_web_wasm_simulation": errors.append({"code": "release_scope_invalid"}) if authorization.get("decision") != "approve_with_explicit_risk_acceptance": errors.append({"code": "authorization_decision_invalid"}) if authorization.get("candidate_eligible") is not True or authorization.get("release_action") != "ALLOW_RELEASE": errors.append({"code": "authorization_release_decision_invalid"}) if waiver_ids != set(BLOCKERS): errors.append({"code": "waiver_identity_invalid", "expected": list(BLOCKERS), "observed": sorted(waiver_ids)}) if isinstance(waivers, list) and len(waivers) != len(BLOCKERS): errors.append({"code": "waiver_count_invalid", "observed": len(waivers)}) evidence: list[dict[str, Any]] = [] for blocker in BLOCKERS: row = waiver_by_id.get(blocker) if not row or row.get("disposition") != "waived" or not str(row.get("rationale", "")).strip(): errors.append({"code": "waiver_row_invalid", "blocker": blocker}) continue rows = row.get("evidence") if not isinstance(rows, list) or not rows: errors.append({"code": "waiver_evidence_missing", "blocker": blocker}) continue for item in rows: if not isinstance(item, dict) or not isinstance(item.get("path"), str) or not isinstance(item.get("sha256"), str): errors.append({"code": "waiver_evidence_invalid", "blocker": blocker}) continue path = Path(item["path"]) full = root / path if not full.is_file(): errors.append({"code": "waiver_evidence_missing", "blocker": blocker, "path": path.as_posix()}) continue actual = file_digest(full) evidence.append({"blocker": blocker, "path": path.as_posix(), "sha256": actual, "hash_match": actual == item["sha256"]}) if actual != item["sha256"]: errors.append({"code": "waiver_evidence_hash_mismatch", "blocker": blocker, "path": path.as_posix()}) historical_blockers = [row.get("id") for row in historical.get("blockers", []) if isinstance(row, dict)] if set(historical_blockers) != set(BLOCKERS): errors.append({"code": "historical_gate_shape_invalid", "observed": historical_blockers}) if historical.get("candidate_eligible") is not False or historical.get("release_action") != "STOP_RELEASE": errors.append({"code": "historical_gate_not_fail_closed"}) if t7.get("candidate_eligible") is not False or t7.get("release_action") != "STOP_RELEASE": errors.append({"code": "t7_gate_not_fail_closed"}) if verification.get("schema") != "release-verification.v1" or verification.get("status") != "verified" or verification.get("release_action") != "ALLOW_RELEASE": errors.append({"code": "release_verification_not_passed"}) if verification.get("passed_command_count") != verification.get("required_command_count"): errors.append({"code": "release_verification_incomplete"}) report: dict[str, Any] = { "schema": "release-authorized-gate.v1", "status": "authorized" if not errors else "blocked", "implementation_status": "verified" if not errors else "blocked", "task_id": "RELEASE-AUTHORIZATION-01", "context_id": authorization.get("context_id"), "release_scope": authorization.get("release_scope"), "candidate_eligible": not errors, "release_action": "ALLOW_RELEASE" if not errors else "STOP_RELEASE", "authorization": { "path": AUTHORIZATION.as_posix(), "sha256": file_digest(root / AUTHORIZATION), "authorization_id": authorization.get("authorization_id"), "authorized_by": authorization.get("authorized_by"), "decision": authorization.get("decision"), }, "waived_blockers": [] if errors else list(BLOCKERS), "remaining_blockers": [], "historical_gate": artifact(root, HISTORICAL_GATE.as_posix(), "historical_fail_closed_gate"), "t7_gate": artifact(root, T7_GATE.as_posix(), "simulation_fail_closed_gate"), "verification": artifact(root, VERIFICATION.as_posix(), "selected_case_release_verification"), "evidence": evidence, "errors": errors, "risk_boundary": { "technical_evidence_rewritten": False, "full_linuxcnc_parity_claim": False, "official_oracle_claim": False, "safari_support_claim": False, "manifest_ownership_closure_claim": False, "license_closure_claim": False, }, "report_sha256": None, } report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"}) destination = output if output.is_absolute() else root / output destination.parent.mkdir(parents=True, exist_ok=True) destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8") return report def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--repo-root", type=Path, default=ROOT) parser.add_argument("--output", type=Path, default=OUTPUT) args = parser.parse_args() report = generate(args.repo_root.resolve(), args.output) print(f"release_authorized_gate={report['status']} action={report['release_action']} scope={report['release_scope']}") return 0 if report["status"] == "authorized" else 1 if __name__ == "__main__": raise SystemExit(main())