#!/usr/bin/env python3 """Validate requested public web ports against an ADR-0008 reef declaration.""" from __future__ import annotations import argparse import json import sys from pathlib import Path from typing import Any import yaml class GrantError(ValueError): pass def validate(payload: Any, ports: list[int]) -> dict[str, Any]: if not isinstance(payload, dict): raise GrantError("reef declaration must be a YAML object") if any(port == 6443 for port in ports): raise GrantError("6443 is operator-only and cannot be publicly granted") if any(port not in {80, 443} for port in ports): raise GrantError("the public web gate accepts only ports 80 and 443") if not payload.get("primary_rail") and not payload.get("hosted_rails"): raise GrantError("provider-delegated reefs cannot publish a public listener") exposure = payload.get("exposure") or {} if exposure.get("posture") != "public": raise GrantError("reef exposure.posture must be public") grants = exposure.get("grants") or [] for port in ports: matches = [grant for grant in grants if isinstance(grant, dict) and grant.get("port") in {port, str(port)}] if not matches: raise GrantError(f"reef has no substrate grant for port {port}") grant = matches[0] missing = [field for field in ("reason", "approved_on", "residual_risk_owner") if not grant.get(field)] if missing: raise GrantError(f"port {port} grant is missing {', '.join(missing)}") return { "reef_id": payload.get("reef_id"), "posture": "public", "validated_ports": sorted(set(ports)), } def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--reef-declaration", type=Path, required=True) parser.add_argument("--ports", required=True, help="Comma-separated ports; only 80 and 443 are grantable") args = parser.parse_args() try: ports = [int(value) for value in args.ports.split(",") if value] if not ports: raise GrantError("at least one requested port is required") payload = yaml.safe_load(args.reef_declaration.read_text(encoding="utf-8")) result = validate(payload, ports) except (OSError, yaml.YAMLError, ValueError) as exc: print(f"reef exposure validation failed: {exc}", file=sys.stderr) return 1 print(json.dumps(result, sort_keys=True)) return 0 if __name__ == "__main__": raise SystemExit(main())