Adds cutover-step-11-crossplane-provider-pivot, modelled on step 10's two-phase pattern, that rewrites every `pkg.crossplane.io/v1.Provider` CR's `spec.package` host literal from `xpkg.upbound.io/...` to `harbor.<SOVEREIGN_FQDN>/proxy-xpkg/...` and pushes the same edit to local Gitea so the bootstrap-kit Kustomization reconcile doesn't revert the live patch. Why Step 04 (containerd registries.yaml.v2 mirror) does NOT cover this even though it registers `xpkg.upbound.io → harbor.<sov>/proxy-xpkg`: Crossplane's package manager uses `go-containerregistry`'s `remote.Image()` DIRECTLY from inside the `crossplane-system` controller Pod (source: `internal/xpkg/fetch.go`), NOT through the kubelet/containerd CRI client. Containerd mirror config is irrelevant to it. The ONLY way to redirect Provider package fetches is to rewrite each Provider's `spec.package` host literal. The bootstrap-kit ships THREE Provider CRs all carrying the upstream xpkg literal (clusters/_template + clusters/omantel.omani.works + clusters/otech.omani.works). None were patched by any prior cutover step — so every Provider package fetch (initial install, version bump, ProviderRevision reconcile of an inactive revision, Pod-restart-with- evicted-cache, any new operator-installed Provider) hit xpkg.upbound.io directly post-handover. Principle #11 violation. Caught by the TBD-V24 empirical investigation 2026-05-20. Step 11 changes: - NEW templates/11-crossplane-provider-pivot-job.yaml (~270 lines): Phase 1 kubectl patches every Provider CR (cluster-scoped, idempotent, skip-if-CRD-absent for early-handover window); Phase 2 git push edits every clusters/*/infrastructure/provider-*.yaml in local Gitea. - 09-cutover-status-configmap.yaml: totalSteps "10" → "11" plus step.crossplane-provider-pivot.* status keys. - values.yaml: append `xpkg.upbound.io` to harbor.mothershipAuthsToStrip (credential hygiene now covers the xpkg upstream too) and to egressTest.blockedDomains (TBD-V23's deny-egress hold proof must block xpkg.upbound.io alongside the other 3 mothership families); add stepTimeouts.crossplaneProviderPivotSeconds (600s) and crossplaneProviderPivot.{upstreamHost,registryPath} overlay knobs. - rbac.yaml: ClusterRole gains pkg.crossplane.io.providers [get,list,watch,update,patch] + apiextensions.k8s.io. customresourcedefinitions [get,list,watch] (for CRD-presence probe). - Chart.yaml: 0.1.36 → 0.1.37 with full changelog entry. - blueprint.yaml: 0.1.36 → 0.1.37 lockstep. - clusters/_template/bootstrap-kit/06a-bp-self-sovereign-cutover.yaml: pin 0.1.36 → 0.1.37 with comment. - chart/tests/cutover-contract.sh: bump step_count + mode_job_count assertions 10 → 11 / 9 → 10; new Case 22 verifies Step 11 patches Provider CRs, rewrites Gitea YAML, and the RBAC + values are wired. Validation: - `helm template platform/self-sovereign-cutover/chart` smoke-renders cleanly with all 11 step ConfigMaps. - `bash platform/self-sovereign-cutover/chart/tests/cutover-contract.sh` green on all 22 cases. - `go test ./products/catalyst/bootstrap/api/internal/handler/... -count=1` passes (62.8s) — cutover handler reads steps dynamically via label selector, no hardcoded list to update. - Did NOT use --dry-run=server. Cluster-side validation deferred to the operator walk on a fresh multi-region prov per anti-theater discipline. Refs #2034 (TBD-V24 — closes only after operator-walk-with-screenshot on a fresh multi-region prov verifies Provider CRs reconcile from harbor.<sov-fqdn>/proxy-xpkg, NOT from xpkg.upbound.io). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
353 lines
20 KiB
YAML
353 lines
20 KiB
YAML
apiVersion: v2
|
|
name: bp-self-sovereign-cutover
|
|
# 0.1.28 (Fix #158, 2026-05-11): values.yaml comment cleanup — chart
|
|
# already migrated off bitnami/kubectl on 0.1.10 (alpine/k8s for kubectl,
|
|
# alpine for chroot-pivot). Comment text now reflects the platform-wide
|
|
# Fix #158 migration to bitnamilegacy/kubectl across other Blueprints.
|
|
# No functional change in this Blueprint.
|
|
#
|
|
# 0.1.29 (Fix #163, 2026-05-11, MIRROR-EVERYTHING): every default image
|
|
# reference (kubectl/git/curl/hostExec + the hardcoded alpine/k8s in
|
|
# step 06) now uses the explicit harbor.openova.io/proxy-dockerhub
|
|
# prefix per CLAUDE.md inviolable rule. The Sovereign cloudinit already
|
|
# routes containerd through this proxy at node-boot time, so the
|
|
# pre-cutover Jobs can reach the explicit URL just fine. Operator
|
|
# override via .Values.global.imageRegistry remains intact for true
|
|
# air-gap or alternate mirror deployments.
|
|
#
|
|
# 0.1.30 (TBD-C18, 2026-05-18): NEW step 09 (gitea-token-mint) —
|
|
# bootstraps a real Gitea API token at cutover and patches Secret
|
|
# `sme/provisioning-github-token.GITHUB_TOKEN`. The catalyst-platform
|
|
# chart's existing provisioning-github-token.yaml template mirrors the
|
|
# Gitea admin PASSWORD into that Secret; the SME provisioning service
|
|
# then sends `Authorization: token <PWD>` to Gitea, which 401s because
|
|
# the password is not an API token. Result on t22: voucher checkout
|
|
# completed, /jobs redirect fired, but NO Organization CR was ever
|
|
# materialised (the provisioning service kept failing the Gitea token
|
|
# auth). Step 09 fixes this end-to-end: idempotent DELETE-then-POST
|
|
# /api/v1/users/gitea_admin/tokens, validate via GET /api/v1/user,
|
|
# kubectl-patch the dest Secret with stringData, rollout-restart
|
|
# provisioning Deployment (best-effort). Order 9 (last) is fine
|
|
# functionally — none of steps 02-08 read the provisioning-github-token
|
|
# Secret, and the SME provisioning service first consumes the token at
|
|
# voucher checkout time (always postdates cutover). Order 9 avoids
|
|
# renumbering 01..08 which would invalidate operator history.
|
|
#
|
|
# 0.1.31 (TBD-C19, 2026-05-18): step-06 now also pivots the
|
|
# `openova-catalog` HelmRepository. The HR is rendered by the bp-
|
|
# catalyst-platform Helm chart (not directly from a bootstrap-kit slot
|
|
# file) from `.Values.catalog.helmRepository.url`. Phase-1 patches the
|
|
# live HR; new Phase-1.6 patches the parent HelmRelease's
|
|
# spec.values.catalog.helmRepository.url so the next chart reconcile
|
|
# preserves the local URL; new Phase-2.5 injects (or rewrites) the
|
|
# same override into 13-bp-catalyst-platform.yaml in the local Gitea
|
|
# repo so bootstrap-kit Kustomization reconcile doesn't revert it.
|
|
# Without this fix step-08's egress-block-test catches
|
|
# `openova-catalog` as the lone OFFENDER ~1 min after step-06
|
|
# completes (chart re-render reverts phase-1). Caught live on
|
|
# t22.omantel.biz 2026-05-18.
|
|
#
|
|
# 0.1.32 (issue #1871, 2026-05-19): Step-06 helmrepository-patches Job
|
|
# gains a NEW Phase -1 (gateway-wait) that runs BEFORE Phase-0
|
|
# (ghcr-pull auth merge) and Phase-1 (URL rewrite). The Job blocks
|
|
# until `gateway.networking.k8s.io/v1.Gateway cilium-gateway` in
|
|
# `kube-system` reports `Programmed=True`, which proves the Cilium
|
|
# Gateway has a listener on *.<SOVEREIGN_FQDN>:443 serving TLS
|
|
# against the wildcard cert — i.e. `registry.<SOVEREIGN_FQDN>` will
|
|
# answer 200, not TLS-handshake EOF. Closes the cutover↔gateway
|
|
# circular deadlock discovered on t26 zero-touch
|
|
# (99bb823cb0513f4b, A55 diagnostic JSON):
|
|
# 1) cutover Step-06 rewrote 50 HelmRepository URLs to
|
|
# oci://registry.t26.omani.works/openova-io
|
|
# 2) source-controller pull → TLS handshake EOF
|
|
# (Gateway not yet Programmed)
|
|
# 3) bp-catalyst-platform HR Ready=False
|
|
# 4) bootstrap-kit Ks Reconciling
|
|
# 5) sovereign-tls Ks DependencyNotReady on bootstrap-kit
|
|
# 6) Gateway never installed → loop forever
|
|
# Adding the Phase -1 wait inside the Job (rather than as a cross-
|
|
# kind dependsOn) is the only viable seam: Flux HR dependsOn can only
|
|
# reference HelmReleases, NOT Kustomizations, so the natural
|
|
# `dependsOn: sovereign-tls` (PR #1875, superseded by this version)
|
|
# never resolved — helm-controller logged "helmreleases.helm.toolkit.
|
|
# fluxcd.io \"sovereign-tls\" not found" forever (t27 A84 empirical
|
|
# test). RBAC: ClusterRole gains gateway.networking.k8s.io.gateways
|
|
# {get,list,watch}. Configurable via `.Values.gateway.{namespace,
|
|
# name,waitTimeoutSeconds}`; default 30 min timeout safely covers
|
|
# the slowest Hetzner cold-start observed (≈18 min).
|
|
#
|
|
# 0.1.33 (TBD-A37, issue #1899, 2026-05-19): NEW post-cutover continuous
|
|
# mirror re-sync CronJob (template 11-mirror-resync-cronjob.yaml). Step
|
|
# 01 (gitea-mirror) only ever runs ONCE at cutover and produces a
|
|
# STANDALONE local Gitea repo (PR #1029 — pull-mirror semantics block
|
|
# Step-06's HelmRepository URL rewrite push, so cutover migrated off
|
|
# Gitea's built-in pull-mirror). Without an ongoing re-sync, upstream
|
|
# chart bumps merged AFTER cutover never reach the Sovereign. Live
|
|
# regression on t31 2026-05-19 (A145 verifier): sandbox-controller
|
|
# stuck at image :8017700 from 2026-05-16 even though PR #1862 had
|
|
# merged 2 days earlier with the NATS consume-leg update — the
|
|
# upstream values.yaml bump never crossed the mirror seam.
|
|
#
|
|
# This chart bump adds gitea-mirror-resync CronJob (schedule */5
|
|
# default — 5 min cadence covers the chart-bump → upstream-merge →
|
|
# Sovereign-reconcile loop in ~10 min end-to-end while staying well
|
|
# under GitHub anonymous-clone rate limits). The CronJob fires the
|
|
# same idempotent bare-clone + push --mirror --force as Step 01 step
|
|
# (3); pre-cutover fires are no-ops (the script detects missing
|
|
# local repo and exits 0), post-cutover fires close the loop.
|
|
#
|
|
# Per-Sovereign overlay knobs under `.Values.mirrorResync.{schedule,
|
|
# suspended,jobTimeoutSeconds}`; defaults are canonical fresh-prov
|
|
# behaviour (active, 5m, 15m timeout). No new RBAC needed — the
|
|
# CronJob talks to GitHub anonymously + local Gitea via BasicAuth
|
|
# from the same reflector-mirrored gitea-admin-secret Step-01 mounts.
|
|
# Smoke render unaffected (CronJob lacks the cutover-step labels so
|
|
# the contract test's exactly-9-steps assertion still passes).
|
|
#
|
|
# 0.1.34 (TBD-V25, issue #2035, 2026-05-20): fix the stale
|
|
# `totalSteps: "8"` literal in 09-cutover-status-configmap.yaml — the
|
|
# chart shipped 9 step ConfigMaps since 0.1.30 (TBD-C18 added step 09
|
|
# gitea-token-mint) but the initial-state status ConfigMap still
|
|
# claimed 8. Post-trigger this is overwritten by catalyst-api on
|
|
# /start (cutover.go:763 patches with `strconv.Itoa(len(steps))`), so
|
|
# the bug only surfaces in the pre-trigger window between chart
|
|
# install and the auto-trigger Job firing — typically seconds, but up
|
|
# to ~25 min on a slow cold-start cluster. UIs rendering progress as
|
|
# `<currentIndex>/<totalSteps>` during that window showed the wrong
|
|
# denominator. Single-literal swap; contract test (asserts step_count
|
|
# -eq 9) already gates against future drift. No code change required
|
|
# in cutover.go — its post-start patch path was always correct.
|
|
#
|
|
# 0.1.35 (TBD-V24 MISS-2, issue #2034, 2026-05-20): step-06 Phase-0
|
|
# now STRIPS mothership-side auth entries from the `ghcr-pull` Secret
|
|
# AFTER merging the local Harbor entry — closing the credential-
|
|
# hygiene gap flagged by TBD-V24 (Pillar-5 Sovereign-independence
|
|
# claim). The strip list is driven by
|
|
# `.Values.harbor.mothershipAuthsToStrip` (defaults: ghcr.io,
|
|
# harbor.openova.io) and runs in the SAME jq pipeline as the add so
|
|
# the Secret takes a single resourceVersion bump per Phase-0
|
|
# invocation. Idempotency check extended: re-runs skip when BOTH the
|
|
# local Harbor entry is in place AND every strip target is already
|
|
# absent. The strip pipeline never touches the local harbor host
|
|
# (defence-in-depth guard) even if an operator overlay erroneously
|
|
# lists it. ORDERING: this fix lives in Phase-0 which executes
|
|
# BEFORE Phase-1 URL rewrites, but AFTER step-04 (registries.yaml
|
|
# v2) and AFTER any future TBD-V24 MISS-1 step that may pivot
|
|
# vCluster image refs — there is no dependency on MISS-1 because
|
|
# the strip operates on the Secret data plane, not on chart values.
|
|
# Per CLAUDE.md §3 Principle #11 the post-cutover cluster MUST NOT
|
|
# carry standing auth for any openova-io-rooted registry. Operator
|
|
# walk on a fresh prov verifies `kubectl get secret ghcr-pull -n
|
|
# flux-system -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
|
|
# | jq '.auths | keys'` returns ONLY `[harbor.<sov-fqdn>]`. Refs
|
|
# #2034 (closes after operator-walk-with-screenshot per anti-theater
|
|
# discipline).
|
|
#
|
|
# 0.1.36 (TBD-V24 MISS-1, issue #2034, 2026-05-20): NEW step 10
|
|
# (vcluster-registry-pivot) — pivots the THREE bp-*-vcluster
|
|
# HelmReleases' `image.repository` from `harbor.openova.io/proxy-ghcr/
|
|
# loft-sh/vcluster` to `harbor.<SOVEREIGN_FQDN>/proxy-ghcr/loft-sh/
|
|
# vcluster` so the MGMT/RTZ/DMZ vCluster control-plane Pods pull from
|
|
# the Sovereign-local Harbor mirror post-cutover.
|
|
#
|
|
# Root cause this addresses: the chart's own comment at
|
|
# `platform/bp-mgmt-vcluster/chart/values.yaml:77-79` promised
|
|
# "post-handover, the per-Sovereign overlay rewrites to
|
|
# `harbor.<sovereign-fqdn>/proxy-ghcr/...`" but the rewrite step was
|
|
# never implemented anywhere in the cutover sequence. As a result,
|
|
# every Sovereign post-handover keeps pulling vCluster control-plane
|
|
# images from `harbor.openova.io` indefinitely — a direct violation
|
|
# of Principle #11 (no tether to harbor.openova.io after handover).
|
|
# Caught by the TBD-V24 tether audit (2026-05-20).
|
|
#
|
|
# Step 04 (containerd registries.yaml pivot) does NOT catch this
|
|
# because registries.yaml.v2 only mirrors the 7 canonical UPSTREAMS
|
|
# (ghcr.io, docker.io, registry.k8s.io, etc.). The host
|
|
# `harbor.openova.io` is treated as a literal endpoint, NOT an
|
|
# upstream, so containerd routes those pulls direct.
|
|
#
|
|
# This step adds a Phase-1 live `kubectl patch helmrelease` against
|
|
# each of {bp-mgmt-vcluster, bp-rtz-vcluster, bp-dmz-vcluster} in
|
|
# flux-system, patching BOTH:
|
|
# - spec.values.<role>Vcluster.image.repository (umbrella chart)
|
|
# - spec.values.vcluster.controlPlane.statefulSet.image.{registry,repository} (subchart)
|
|
# A Phase-2 git push to local Gitea injects the same override blocks
|
|
# into clusters/_template/bootstrap-kit/{54,58,59}-bp-*-vcluster.yaml
|
|
# so the bootstrap-kit Kustomization reconcile doesn't revert the
|
|
# live patch. Idempotent on re-run (skip-if-already-pivoted on
|
|
# Phase-1, sentinel-comment guard on Phase-2). Topology-aware:
|
|
# secondaries skip the MGMT HR (not present on secondary), primary
|
|
# skips the RTZ HR (not present on primary).
|
|
#
|
|
# RBAC: ClusterRole gains helm.toolkit.fluxcd.io.helmreleases
|
|
# {update,patch}. Step-06 Phase-1.6 was already silently relying on
|
|
# this verb (it patches bp-catalyst-platform HR for the openova-catalog
|
|
# URL override) — chart 0.1.31's RBAC change was missed, so this bump
|
|
# ALSO closes a latent permission gap.
|
|
#
|
|
# totalSteps bumped from "9" → "10" in 09-cutover-status-configmap.yaml.
|
|
# Contract test (tests/cutover-contract.sh) asserts shift from 9 → 10
|
|
# step ConfigMaps and from 8 → 9 job-mode ConfigMaps. New Case 21
|
|
# verifies Step 10's wrapper + subchart patches are wired.
|
|
#
|
|
# 0.1.37 (TBD-V24 MISS-3, issue #2034, 2026-05-20): NEW step 11
|
|
# (crossplane-provider-pivot) — pivots every `pkg.crossplane.io/v1.
|
|
# Provider` CR's `spec.package` host literal from `xpkg.upbound.io/...`
|
|
# to `harbor.<SOVEREIGN_FQDN>/proxy-xpkg/...` so the Crossplane package
|
|
# manager fetches Provider packages from the Sovereign-local Harbor
|
|
# `proxy-xpkg` project, NOT from xpkg.upbound.io.
|
|
#
|
|
# Root cause this addresses: Crossplane's package manager uses
|
|
# `github.com/google/go-containerregistry`'s `remote.Image()` DIRECTLY
|
|
# from the `crossplane-system` controller Pod (source:
|
|
# `internal/xpkg/fetch.go`). It does NOT route fetches through the
|
|
# kubelet's CRI containerd client, so `/etc/containerd/certs.d/` and
|
|
# `/etc/rancher/k3s/registries.yaml` mirror config (rewritten by Step
|
|
# 04's DaemonSet) is irrelevant to it. The bootstrap-kit ships THREE
|
|
# Provider CRs all carrying `spec.package =
|
|
# xpkg.upbound.io/crossplane-contrib/provider-hcloud:v0.4.0`
|
|
# (clusters/_template + clusters/omantel.omani.works +
|
|
# clusters/otech.omani.works) — none were patched by any prior cutover
|
|
# step. Result: every Provider package fetch (initial install,
|
|
# version bump, ProviderRevision reconcile of an inactive revision,
|
|
# Pod-restart-with-evicted-cache, any new operator-installed Provider)
|
|
# hit xpkg.upbound.io directly post-handover — a direct violation of
|
|
# Principle #11 (no tether to external upstreams after handover).
|
|
# Caught by the TBD-V24 empirical investigation 2026-05-20.
|
|
#
|
|
# Step 04 (containerd registries.yaml.v2) does NOT catch this even
|
|
# though it DOES register `xpkg.upbound.io → harbor.<sov>/proxy-xpkg`
|
|
# — that mirror is consumed only by containerd (kubelet image pulls),
|
|
# which Crossplane bypasses. The ONLY way to redirect Provider package
|
|
# fetches is to rewrite each Provider's `spec.package` host literal.
|
|
#
|
|
# Step 11 adds a Phase-1 live `kubectl patch provider.pkg.crossplane.io`
|
|
# loop over every Provider CR (cluster-scoped). Skip-if-absent guards
|
|
# for: the CRD not yet installed (very-early-handover window) and an
|
|
# already-pivoted package literal (re-run idempotency). Phase-2 git
|
|
# pushes sed edits of every `clusters/*/infrastructure/provider-*.yaml`
|
|
# to local Gitea so the bootstrap-kit Kustomization reconcile doesn't
|
|
# revert the Phase-1 live patch within ~1 min.
|
|
#
|
|
# Lockstep changes:
|
|
# - `harbor.mothershipAuthsToStrip` gains `xpkg.upbound.io` (Step 06
|
|
# Phase-0 credential hygiene now covers the xpkg upstream too).
|
|
# - `egressTest.blockedDomains` gains `xpkg.upbound.io` (TBD-V23's
|
|
# deny-egress hold proof must block xpkg.upbound.io alongside the
|
|
# other 3 mothership families).
|
|
# - `stepTimeouts.crossplaneProviderPivotSeconds` (600s default).
|
|
# - `crossplaneProviderPivot.{upstreamHost,registryPath}` overlay
|
|
# knobs (defaults: xpkg.upbound.io, proxy-xpkg).
|
|
# - RBAC ClusterRole gains `pkg.crossplane.io.providers
|
|
# {get,list,watch,update,patch}` + `apiextensions.k8s.io.
|
|
# customresourcedefinitions {get,list,watch}` (the latter for the
|
|
# CRD-presence probe).
|
|
#
|
|
# totalSteps bumped from "10" → "11" in 09-cutover-status-configmap.yaml.
|
|
# Contract test (tests/cutover-contract.sh) asserts shift from 10 → 11
|
|
# step ConfigMaps and from 9 → 10 job-mode ConfigMaps. New Case 22
|
|
# verifies Step 11 patches Provider CRs and rewrites Gitea YAML.
|
|
# (Refs #2034 — closes after operator-walk-with-screenshot on a fresh
|
|
# multi-region prov verifies Provider CRs reconcile from
|
|
# harbor.<sov-fqdn>/proxy-xpkg.)
|
|
version: 0.1.37
|
|
description: |
|
|
Catalyst Self-Sovereignty Cutover Blueprint. Installs DORMANT — this
|
|
chart ships eight step ConfigMaps (PodSpec ConfigMaps, one per step),
|
|
the registry-pivot DaemonSet, the mutable cutover-status ConfigMap,
|
|
plus ServiceAccount/RBAC scoped to the cutover work. NO Helm
|
|
post-install hooks fire any of the steps; the catalyst-api cutover
|
|
endpoint (issue #792) reads each step ConfigMap by label selector,
|
|
stamps a real batch/v1 Job from the embedded PodSpec, and updates
|
|
the status ConfigMap as each step completes.
|
|
|
|
Trigger semantics (post-handover, per #790 scope-correction comment):
|
|
the operator clicks "Achieve True Sovereignty" in admin console (or
|
|
catalyst-api auto-fires after first successful operator login on the
|
|
new Sovereign). The handed-over Sovereign starts soft-tethered to
|
|
harbor.openova.io for image-pull rate-limit safety, then becomes
|
|
hard-independent only after this cutover sequence completes.
|
|
|
|
Step inventory (label app.kubernetes.io/component=cutover-step):
|
|
01 cutover-step-01-gitea-mirror mode=job
|
|
git push --mirror github.com/openova-io/openova into local Gitea.
|
|
02 cutover-step-02-harbor-projects mode=job
|
|
Create 7 proxy-cache projects in local Harbor.
|
|
03 cutover-step-03-harbor-prewarm mode=job
|
|
HEAD-pull every image referenced by the bootstrap-kit through
|
|
the proxy-cache.
|
|
04 cutover-step-04-registry-pivot mode=daemonset-wait
|
|
DaemonSet runs on every node + writes /etc/rancher/k3s/registries.yaml
|
|
v2 once the status ConfigMap key registriesYamlActive flips to v2.
|
|
05 cutover-step-05-flux-gitrepository-patch mode=job
|
|
Patch flux-system/openova GitRepository.url → local Gitea.
|
|
06 cutover-step-06-helmrepository-patches mode=job
|
|
Patch every OCI HelmRepository → oci://harbor.<sov-fqdn>/openova-io.
|
|
07 cutover-step-07-catalyst-api-env-patch mode=job
|
|
kubectl set env deploy/catalyst-api CATALYST_GITOPS_REPO_URL=...
|
|
08 cutover-step-08-egress-block-test mode=job
|
|
Apply CiliumNetworkPolicy denying egress to github.com / ghcr.io
|
|
/ harbor.openova.io for 10 min, assert all reconciles stay Ready.
|
|
09 cutover-step-09-gitea-token-mint mode=job
|
|
POST /api/v1/users/gitea_admin/tokens, capture .sha1, patch
|
|
Secret sme/provisioning-github-token.GITHUB_TOKEN with the real
|
|
API token (the chart previously mirrored the admin password
|
|
verbatim — Gitea then 401s on `Authorization: token <PWD>`,
|
|
blocking tenant voucher checkout at journey step 16). Rolls
|
|
the provisioning Deployment so the new token takes effect
|
|
immediately. (TBD-C18)
|
|
10 cutover-step-10-vcluster-registry-pivot mode=job
|
|
Patch the bp-mgmt-vcluster / bp-rtz-vcluster / bp-dmz-vcluster
|
|
HelmReleases' image.repository from harbor.openova.io →
|
|
harbor.<SOVEREIGN_FQDN> so vCluster control-plane Pods pull
|
|
from the Sovereign-local Harbor mirror post-cutover. Phase-1
|
|
kubectl patch; Phase-2 git push to local Gitea so the
|
|
bootstrap-kit Kustomization doesn't revert the override.
|
|
(TBD-V24 MISS-1)
|
|
11 cutover-step-11-crossplane-provider-pivot mode=job
|
|
Patch every `pkg.crossplane.io/v1.Provider` CR's spec.package
|
|
from `xpkg.upbound.io/...` → `harbor.<SOVEREIGN_FQDN>/
|
|
proxy-xpkg/...` so the Crossplane package manager fetches
|
|
Provider packages from Sovereign-local Harbor, NOT from
|
|
xpkg.upbound.io. Phase-1 kubectl patch (skip if CRD absent or
|
|
already-pivoted); Phase-2 git push to local Gitea so the
|
|
bootstrap-kit Kustomization doesn't revert the override.
|
|
Crossplane bypasses containerd (uses go-containerregistry
|
|
directly), so Step 04's registries.yaml mirror does NOT catch
|
|
Provider package fetches. (TBD-V24 MISS-3)
|
|
|
|
Plus:
|
|
self-sovereign-cutover-status ConfigMap
|
|
Initial state machine state (cutoverComplete: "false" + per-step
|
|
empty fields). catalyst-api updates this ConfigMap as each step
|
|
advances.
|
|
registry-pivot DaemonSet
|
|
Always-on per-node reconcile loop; idempotent.
|
|
gitea-mirror-resync CronJob (post-cutover)
|
|
Re-runs Step 01's idempotent bare-clone + push --mirror every
|
|
5 min so upstream chart bumps merged AFTER cutover continue
|
|
crossing the seam into local Gitea. Pre-cutover fires are
|
|
no-ops. (TBD-A37, chart 0.1.33)
|
|
bp-self-sovereign-cutover-runner ServiceAccount + ClusterRole +
|
|
ClusterRoleBinding for the
|
|
stamped Jobs and the DaemonSet.
|
|
|
|
This Blueprint legitimately ships NO upstream subchart — the entire
|
|
payload is Catalyst-authored ConfigMaps, ServiceAccount, RBAC, and one
|
|
DaemonSet. The blueprint-release CI hollow-chart guard reads the
|
|
annotation below and skips the dependencies-required rule.
|
|
type: application
|
|
keywords:
|
|
- catalyst
|
|
- blueprint
|
|
- self-sovereignty
|
|
- cutover
|
|
- gitea
|
|
- harbor
|
|
maintainers:
|
|
- name: OpenOva Catalyst
|
|
email: catalyst@openova.io
|
|
|
|
annotations:
|
|
catalyst.openova.io/no-upstream: "true"
|