#!/usr/bin/env python3 """Export a validated, public CCR as JSON for the stdlib node delivery helper. Uses the platform's existing PyYAML validator. No credential lookup or live call. After CCR status updates, YAML remains the source of truth; export and review its new JSON hash before an attended delivery. Draft exports remain non-executable. """ from __future__ import annotations import argparse import hashlib import importlib.util import json import os from pathlib import Path import sys from application_backup_credentials import PROFILES, contract ROOT = Path(__file__).resolve().parents[1] def render(source, application): spec = importlib.util.spec_from_file_location("backup_ccr_validator", ROOT / "scripts/credential-change.py") validator = importlib.util.module_from_spec(spec) spec.loader.exec_module(validator) ccr, errors, _ = validator.validate_ccr(source) if errors or validator.applier_policy_violations(ccr): raise ValueError("invalid_reader_contract") policy = validator.policy_artifact_diff(ccr) if not policy["matches"]: raise ValueError("policy_source_mismatch") ccr["source_ccr_sha256"] = hashlib.sha256(source.read_bytes()).hexdigest() ccr["policy_sha256"] = hashlib.sha256(validator.generated_policy_hcl(ccr).encode()).hexdigest() raw = (json.dumps(ccr, indent=2, sort_keys=True) + "\n").encode() contract(raw, application) return raw def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--ccr", type=Path, required=True) parser.add_argument("--application", choices=PROFILES, required=True) parser.add_argument("--output", type=Path, required=True) args = parser.parse_args() try: raw = render(args.ccr, args.application) fd = os.open(args.output, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600) with os.fdopen(fd, "wb") as stream: stream.write(raw) stream.flush() os.fsync(stream.fileno()) print(json.dumps({"status": "rendered", "application": args.application, "ccr_sha256": hashlib.sha256(raw).hexdigest(), "effects": ["public_contract_export"]})) return 0 except Exception: # noqa: BLE001 - metadata-only fixed diagnostics print('{"status":"failed","code":"contract_export_failed"}', file=sys.stderr) return 1 if __name__ == "__main__": raise SystemExit(main())