#!/usr/bin/env python3 """Vendor or verify the CUST-WP-0071-T05 weekly allocation assessment sources. The CronJob mounts its code and data from a ConfigMap generated from argocd/platform-addons/custodian-allocation-review/src/. Owner sources stay in their repositories; this script copies them at an exact clean commit and writes vendor.lock.json (repo, commit, path, sha256). The YAML ownership map is rendered to JSON so the job needs no PyYAML. scripts/vendor_custodian_allocation_review.py # refresh from ~/ scripts/vendor_custodian_allocation_review.py --check # lock matches src/ """ from __future__ import annotations import argparse import hashlib import json from pathlib import Path import subprocess import sys ROOT = Path(__file__).resolve().parents[1] ADDON = ROOT / "argocd/platform-addons/custodian-allocation-review" SOURCES = { "weekly_allocation_incluster.py": ("the-custodian", "scripts/weekly_allocation_incluster.py"), "weekly_allocation_report.py": ("the-custodian", "scripts/weekly_allocation_report.py"), "reconcile_railiance_allocation.py": ("the-custodian", "scripts/reconcile_railiance_allocation.py"), "weekly-allocation-queries.json": ("the-custodian", "config/weekly-allocation-queries.json"), "namespace-ownership.json": ("the-custodian", "docs/evidence/namespace-ownership.yaml"), "observe_cluster_resources.py": ("railiance-cluster", "tools/observe_cluster_resources.py"), "reef-railiance-k3s.json": ("resource-control", "data/resources/reef-railiance-k3s.json"), } def sha(data: bytes) -> str: return hashlib.sha256(data).hexdigest() def git(repo: Path, *args: str) -> str: return subprocess.check_output(["git", "-C", str(repo), *args], text=True).strip() def refresh(base: Path) -> dict: lock = {"schema": "railiance-platform.vendor-lock.v1", "workplan": "CUST-WP-0071-T05", "files": {}} (ADDON / "src").mkdir(parents=True, exist_ok=True) for name, (repo, path) in sorted(SOURCES.items()): checkout = base / repo if git(checkout, "status", "--porcelain", "--", path): raise SystemExit(f"{repo}/{path} has uncommitted changes; commit it first") commit = git(checkout, "rev-parse", "HEAD") source = subprocess.check_output(["git", "-C", str(checkout), "show", f"{commit}:{path}"]) data = source if path.endswith(".yaml"): import yaml data = (json.dumps(yaml.safe_load(source), indent=2, sort_keys=True) + "\n").encode() (ADDON / "src" / name).write_bytes(data) lock["files"][name] = {"repo": repo, "commit": commit, "path": path, "source_sha256": sha(source), "vendored_sha256": sha(data)} (ADDON / "vendor.lock.json").write_text(json.dumps(lock, indent=2, sort_keys=True) + "\n") return lock def check() -> list[str]: lock = json.loads((ADDON / "vendor.lock.json").read_text()) problems = [] if set(lock["files"]) != set(SOURCES): problems.append("lock file set differs from SOURCES") for name, entry in lock["files"].items(): target = ADDON / "src" / name if not target.exists() or sha(target.read_bytes()) != entry["vendored_sha256"]: problems.append(f"{name}: vendored content does not match vendor.lock.json") return problems def main() -> int: parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--check", action="store_true") parser.add_argument("--base", type=Path, default=Path.home(), help="directory holding the owner checkouts") args = parser.parse_args() if args.check: problems = check() for problem in problems: print(problem, file=sys.stderr) return 1 if problems else 0 lock = refresh(args.base) for name, entry in sorted(lock["files"].items()): print(f"{name}: {entry['repo']}@{entry['commit'][:12]} {entry['vendored_sha256'][:12]}") return 0 if __name__ == "__main__": raise SystemExit(main())