diff --git a/runner/harness/canonical.py b/runner/harness/canonical.py index e176369..aa68f85 100644 --- a/runner/harness/canonical.py +++ b/runner/harness/canonical.py @@ -40,7 +40,17 @@ def is_enrolled(recipe: str) -> bool: def canonical_domain(recipe: str) -> str: - """Stable data-warm domain for the recipe's canonical.""" + """Stable data-warm domain for the recipe's canonical. + + For a recipe that is ALSO a live-warm provider (in `warm.WARM_DOMAINS` — e.g. keycloak, whose + always-on shared OIDC instance lives at `warm-keycloak…`), the data-warm canonical MUST use a + DISTINCT domain: otherwise the sweep's promote deploy/teardown at `warm-` collides with — + and could disrupt — the live shared service that other recipes (lasuite-*/drone) depend on. Give + those recipes a collision-free `warm-canon-` namespace (a separate stack/domain that can + never touch the live provider); every other recipe keeps the plain `warm-` scheme + (zero blast radius on the 15 existing canonicals).""" + if recipe in warm.WARM_DOMAINS: + return f"warm-canon-{recipe}.ci.commoninternet.net" return warm.stable_domain(recipe) diff --git a/tests/keycloak/recipe_meta.py b/tests/keycloak/recipe_meta.py index afd1bf8..9759eeb 100644 --- a/tests/keycloak/recipe_meta.py +++ b/tests/keycloak/recipe_meta.py @@ -7,10 +7,12 @@ DEPLOY_TIMEOUT = ( ) HTTP_TIMEOUT = 900 -# canon §2.B EXCEPTION (recorded in DECISIONS): keycloak is NOT a data-warm canonical. It is the -# project's LIVE-WARM OIDC dep provider — an always-on shared service at the SAME stable domain a -# data-warm canonical would use (warm-keycloak.ci.commoninternet.net). Enrolling it would make the -# sweep's promote deploy/teardown collide with the live provider that lasuite-*/drone depend on for -# SSO. keycloak is instead kept current by the sweep's roll_warm_infra step (the health-gated -# warm/infra reconciler, WC1.1) — so it never lacks coverage. WARM_CANONICAL stays False. -WARM_CANONICAL = False +# phase redfix: keycloak IS now a data-warm canonical. The original canon §2.B exception de-enrolled +# it because its canonical would have used the SAME domain as the live-warm OIDC provider +# (warm-keycloak.ci.commoninternet.net), so the sweep's promote deploy/teardown would collide with the +# live service lasuite-*/drone depend on. That collision is now structurally impossible: +# `canonical.canonical_domain()` routes any recipe in `warm.WARM_DOMAINS` (keycloak) to a distinct +# `warm-canon-` domain/stack, so the data-warm canonical and the live-warm provider are +# separate deployments that can never touch each other. keycloak therefore gets full data-warm +# canonical coverage (a real promote on its latest release) without risking the live OIDC service. +WARM_CANONICAL = True