#!/usr/bin/env python3 """Fail when the pinned issuer and the portals' OIDC authority stop agreeing. Keycloak pins one issuer (`KC_HOSTNAME`) and each portal is configured with one authority (`config.json`). A browser token carries the first; the BFF validates against what it discovers from the second (ADR-0010). When the two drift the symptom is three services away — a login that bounces back logged out, or a 401 from the BFF — so the chart builds both from one helper and this asserts it. It also pins the two halves of the public edge (ADR-0035): that setting `public.domain` actually publishes the hostnames, and that leaving it empty renders no edge at all, which is what compose, CI and a laptop cluster rely on. Run it with `make k8s-lint`. No cluster needed. """ import json import re import subprocess import sys from pathlib import Path CHART = Path(__file__).resolve().parent / "big-reference" DOMAIN = "example.test" def render(*sets: str) -> str: argv = ["helm", "template", "big", str(CHART), "-n", "big"] for s in sets: argv += ["--set", s] proc = subprocess.run(argv, capture_output=True, text=True) if proc.returncode != 0: sys.exit(f"helm template failed:\n{proc.stderr}") return proc.stdout def issuer(out: str) -> str: """The value of KC_HOSTNAME in the rendered manifests.""" m = re.search(r"name: KC_HOSTNAME\n\s+value: \"(\S+)\"", out) return m[1] if m else "" def authorities(out: str) -> set[str]: """Every portal's OIDC authority, with the realm path stripped.""" found = set() for line in re.findall(r'\{ "authority": .* \}', out): url = json.loads(line)["authority"] found.add(url.rsplit("/realms/", 1)[0]) return found def main() -> int: problems = [] public = render(f"public.domain={DOMAIN}") if issuer(public) != f"https://auth.{DOMAIN}": problems.append(f" with public.domain set, KC_HOSTNAME is {issuer(public)!r}, not https://auth.{DOMAIN}") if authorities(public) != {f"https://auth.{DOMAIN}"}: problems.append(f" with public.domain set, the portals point at {sorted(authorities(public))}") for host in (f"register.{DOMAIN}", f"mijn.{DOMAIN}", f"behandel.{DOMAIN}", f"beheer.{DOMAIN}", f"auth.{DOMAIN}"): if host not in public: problems.append(f" {host} is not published by the edge") private = render() if authorities(private) != {issuer(private)}: problems.append(f" by default the portals point at {sorted(authorities(private))}, the issuer is {issuer(private)!r}") if "caddy-edge" in private: problems.append(" the edge renders with no public.domain — compose, CI and a laptop cluster expect nothing") if problems: print("the chart's OIDC origin is inconsistent:\n" + "\n".join(problems)) print("\nBoth halves come from the `big.keycloakUrl` helper — change it, not one caller.") return 1 print(f"issuer + portal authority agree, with and without a public domain") return 0 if __name__ == "__main__": raise SystemExit(main())