"""Readiness quality gate; no credential or Kubernetes access.""" from __future__ import annotations import hashlib import re import subprocess from datetime import date from pathlib import Path from typing import Any import yaml TRANSITION_END = date(2026, 12, 21) NON_PRODUCTION = {"declared", "installed", "verified"} def resolve_tier( state: str | None, target: dict[str, Any], activation: str, today: date, ) -> dict[str, Any]: """Resolve already verified source facts. Unknown facts stay production.""" tier = "non-production" if state in NON_PRODUCTION or state == "explicit-whitehat" else "production" transition = ( tier == "production" and state == "production-approved" and target.get("kind") == "rapp" and target.get("rapp_id") == "rapp-policy-nexus" and today < TRANSITION_END and activation == "APPROVED" ) return { "tier": tier, "direct_apply_allowed": activation in {"APPROVED", "BREAK_GLASS"} and (tier == "non-production" or activation == "BREAK_GLASS" or transition), "transition": transition, } def inspect_readiness( bundle, runner, repo: Path | None, activation: str = "APPROVED", today: date | None = None, ) -> dict[str, Any]: """Verify pinned source, local freshness and history before trusting a tier. A reviewed bundle supplies the namespace-to-rApp mapping. It must identify the namespace explicitly; source mappings, when present, must agree. """ today = today or date.today() block = bundle.readiness or {} target = block.get("target", {}) source = block.get("source", {}) evidence: dict[str, Any] = { "target": target, "source": source, "activation": activation, "state": None, "reason": "missing or unverifiable readiness", } def finish(state=None, reason="unverifiable readiness"): evidence.update(state=state, reason=reason) evidence.update(resolve_tier(state, target, activation, today)) return evidence if not block or target.get("namespace") != bundle.expected_namespace: return finish(reason="missing readiness or namespace mapping") # A namespace placement never covers other cluster-scoped objects. if any(not ref.namespace and (ref.kind != "Namespace" or ref.name != bundle.expected_namespace) for ref in bundle.allowed_objects): return finish(reason="target includes objects outside the namespace mapping") if target.get("kind") not in {"rapp", "namespace"}: return finish(reason="unmapped platform target") if source.get("repo") != "reef-railiance" or source.get("path") != "bindings/rapps.yaml": return finish(reason="unsupported readiness source") revision = source.get("revision", "") digest = source.get("sha256", "") if not isinstance(revision, str) or not re.fullmatch(r"[0-9a-f]{40}", revision): return finish(reason="source needs a full commit id") if not isinstance(digest, str) or not re.fullmatch(r"[0-9a-f]{64}", digest): return finish(reason="source needs a SHA-256 digest") root = repo or bundle.repo_root.parent / "reef-railiance" prefix = ["git", "-C", str(root)] path = source["path"] def git(*args): result = runner([*prefix, *args]) if result.returncode: raise ValueError("readiness git verification failed") return result.stdout def rows(content): data = yaml.safe_load(content) if not isinstance(data, dict) or not isinstance(data.get("bound_rapps"), list): raise ValueError("invalid readiness document") result = data["bound_rapps"] if any(not isinstance(row, dict) or not isinstance(row.get("rapp_id"), str) for row in result): raise ValueError("invalid readiness binding") if len({row["rapp_id"] for row in result}) != len(result): raise ValueError("duplicate readiness binding") return result try: if git("rev-parse", "--is-shallow-repository").strip() != "false": return finish(reason="complete readiness history is required") content = git("show", f"{revision}:{path}") if hashlib.sha256(content.encode()).hexdigest() != digest: return finish(reason="readiness digest mismatch") git("merge-base", "--is-ancestor", revision, "HEAD") git("diff", "--exit-code", revision, "HEAD", "--", path) if git("status", "--porcelain", "--", path).strip(): return finish(reason="readiness source has uncommitted changes") bindings = rows(content) if target["kind"] == "namespace": # Only the founder's one named placement is compiled into this gate. if bundle.id != "whitehat-foundational-plane" or bundle.expected_namespace != "whitehat": return finish(reason="no explicit tier placement for target") if any(row.get("namespace") == "whitehat" or "whitehat" in row.get("namespaces", []) or row["rapp_id"] == "rapp-whitehat" for row in bindings): return finish(reason="whitehat has a binding; repin using the binding target") return finish("explicit-whitehat", "founder placement 2026-09-21") rapp_id = target.get("rapp_id") matches = [row for row in bindings if row["rapp_id"] == rapp_id] if len(matches) != 1: return finish(reason="rApp target is not listed") row = matches[0] if (row.get("namespace") and row["namespace"] != bundle.expected_namespace) or ( "namespaces" in row and bundle.expected_namespace not in row["namespaces"] ): return finish(reason="source namespace mapping disagrees with bundle") state = row.get("readiness_state") # Scan all reachable history, including intervening promotions later # reverted. An evidence lapse must never silently lower the tier. history = git("log", "--format=%H", "HEAD", "--", path).splitlines() if not history: return finish(reason="readiness history is missing") previous = [] for commit in history: if not re.fullmatch(r"[0-9a-f]{40}", commit): return finish(reason="invalid readiness history") for old in rows(git("show", f"{commit}:{path}")): if old["rapp_id"] == rapp_id: previous.append(old.get("readiness_state")) if "production-approved" in previous: return finish("production-approved", "production tier retained from binding history") if state == "deprecated": state = next((s for s in previous if s != "deprecated"), None) if state not in NON_PRODUCTION | {"production-approved"}: return finish(reason="unknown readiness state or prior tier") return finish(state, "verified pinned binding and history") except (OSError, ValueError, TypeError, subprocess.TimeoutExpired, yaml.YAMLError): return finish(reason="readiness source or history unavailable or invalid")