openova/clusters/_template/bootstrap-kit/06a-bp-self-sovereign-cutover.yaml
e3mrah 142ea21534
fix(self-sovereign-cutover): Step-8 passive architectural verification (Cilium can't egressDeny+toFQDNs) (#856)
Live otech103: Step-8 (egress-block-test) failed because Cilium 1.16's CiliumNetworkPolicy schema doesn't support 'spec.egressDeny[].toFQDNs' — strict-decoding error 'unknown field'. FQDN-based matching in Cilium is only allowed in 'egress' (allow), not 'egressDeny'.

Pivot: Step-8 now asserts the architectural pivots from Steps 5-7 are actually live (GitRepository.url + all HelmRepositories + catalyst-api env all point at local Gitea/Harbor) BEFORE entering the durationSeconds survival window during which Flux Kustomization + HelmRelease readiness is polled. Same sovereignty proof, expressed in a form Cilium can evaluate.

Bumps 0.1.10 → 0.1.11 + slot 06a pin lockstep.

Co-authored-by: Hatice Yildiz <hatice.yildiz@openova.io>
2026-05-05 03:22:30 +04:00

141 lines
6.3 KiB
YAML

# bp-self-sovereign-cutover — Catalyst bootstrap-kit Blueprint, slot 06a.
#
# Post-handover Self-Sovereignty Cutover. Installs DORMANT — see chart
# README + ADR-0002. Eight step PodSpec ConfigMaps + the registry-pivot
# DaemonSet land on the new Sovereign at HelmRelease apply time; the
# catalyst-api cutover endpoint (issue #792) reads them by label
# selector and stamps Jobs only on operator action.
#
# Slot 06a sits between the existing post-handover slots in the
# bootstrap-kit ordering. It depends on bp-gitea + bp-harbor so the
# step ConfigMaps reference real, healthy local Gitea + Harbor
# Services at trigger time.
#
# Wrapper chart: platform/self-sovereign-cutover/chart/
# Reconciled by: Flux on the new Sovereign's k3s control plane.
#
# Why disableWait: true
# The chart is dormant — no Job is created at install time. The only
# workload that actually runs is the registry-pivot DaemonSet, which
# never converges on its own (it waits for the cutover-status
# ConfigMap to flip registriesYamlActive=v2). disableWait: true makes
# Helm exit when the manifests apply rather than waiting on a Ready
# condition that never fires.
---
apiVersion: v1
kind: Namespace
metadata:
name: catalyst
labels:
catalyst.openova.io/sovereign: ${SOVEREIGN_FQDN}
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: bp-self-sovereign-cutover
namespace: flux-system
spec:
type: oci
interval: 15m
# Pre-cutover (Phase-1) — sources from openova-io GHCR, identical to
# every other bootstrap-kit slot. The cutover itself (step 06,
# helmrepository-patches) is what flips this URL to the local Harbor
# post-handover; until then this Sovereign is soft-tethered like the
# rest of the kit.
url: oci://ghcr.io/openova-io
secretRef:
name: ghcr-pull
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: bp-self-sovereign-cutover
namespace: flux-system
spec:
interval: 15m
releaseName: self-sovereign-cutover
# targetNamespace = catalyst because the catalyst-api cutover endpoint
# defaults its discovery namespace to "catalyst"
# (CATALYST_CUTOVER_NAMESPACE in
# products/catalyst/bootstrap/api/internal/handler/cutover.go). Keeping
# the chart resources colocated with catalyst-api avoids a cross-
# namespace selector + a CATALYST_CUTOVER_NAMESPACE env override on
# every Sovereign.
targetNamespace: catalyst
dependsOn:
# Both bp-gitea and bp-harbor must be Ready before the chart's
# PodSpec ConfigMaps reference real Services. The chart itself is
# dormant so an early apply is benign — but operator workflow
# ordering puts cutover after these two come up.
- name: bp-gitea
- name: bp-harbor
chart:
spec:
chart: bp-self-sovereign-cutover
# 0.1.1: Step-1 gitea-mirror script uses BusyBox-wget-compatible
# Authorization: Basic <b64> header instead of --user/--password
# which alpine/git's BusyBox wget does not support.
# 0.1.2: Step-1 explicitly creates the Gitea org BEFORE the repo —
# POST /orgs/<org>/repos returns 404 if the org is missing, the
# /user/repos fallback would create under gitea_admin (wrong path
# for the subsequent push). Caught live on otech103 2026-05-04.
# 0.1.3: replace `git push --mirror` with `git push --all + --tags`
# so Gitea's hooks don't decline GitHub-specific refs/pull/<n>
# refs (which --mirror would try to push). Branches+tags are what
# Flux GitRepository needs; PR refs are upstream-only metadata.
# 0.1.4: Step-1 uses `git clone --bare` (not --mirror) + explicit
# refspec push of refs/heads/* and refs/tags/* only. --all in a
# mirror clone still pushed refs/pull/* — caught live otech103.
# 0.1.5: harborInternalURL fix — bp-harbor service is `harbor-core`
# not `harbor-harbor-core` (release name doesn't double-prefix).
# Caught live otech103 — Step-2 curl exit 6 (couldn't resolve).
# 0.1.6: proxy-ghcr registryType "github" → "github-ghcr" (the
# canonical Harbor adapter name for GHCR proxy-cache, per Harbor
# 2.x docs). Caught live otech103 — Harbor 500 "adapter factory
# for github not found".
# 0.1.7: proxy-quay registryType "quay" → "docker-registry" —
# Harbor's "quay" adapter rejects project metadata.proxy_cache
# with HTTP 400. Quay speaks plain v2 so generic docker-registry
# is correct. Caught live otech103 — 4/7 proxy-cache projects
# were created OK, blocked at proxy-quay.
# 0.1.8: bitnami/kubectl tag :1.31 → :1.31.4 (bitnami doesn't tag
# at minor-version, only patch). Caught live otech103 — Step-5
# Pod hit DeadlineExceeded after 10m of ImagePullBackOff for
# docker.io/bitnami/kubectl:1.31 (404 not found).
# 0.1.9: bitnami/kubectl :1.31.4 ALSO 404 (Bitnami deprecated
# public Docker Hub in 2025). Switched to alpine/k8s:1.31.4 —
# canonical alpine-based image with kubectl + helm + k8s CLI
# surface, actively maintained.
# 0.1.10: catalystAPI.namespace `catalyst-platform` → `catalyst-
# system` (the actual Sovereign-side namespace). Caught live
# otech103 — Step-7 `deployment catalyst-api not found`.
# 0.1.11: Step-8 egress-block-test pivoted from CiliumNetworkPolicy
# (egressDeny + toFQDNs unsupported in Cilium 1.16) to a passive
# architectural-state assertion + ${durationSeconds}s survival
# window. Same proof shape, valid Cilium policy. Caught live
# otech103 — strict-decoding error 'unknown field toFQDNs'.
version: 0.1.11
sourceRef:
kind: HelmRepository
name: bp-self-sovereign-cutover
namespace: flux-system
install:
disableWait: true
remediation:
retries: 3
upgrade:
disableWait: true
remediation:
retries: 3
# Per-Sovereign overrides — the chart's values.yaml carries
# placeholders so smoke renders pass; the real coordinates land
# here via Flux postBuild ${SOVEREIGN_FQDN} substitution.
values:
sovereign:
fqdn: ${SOVEREIGN_FQDN}
harborInternalURL: http://harbor-core.harbor.svc.cluster.local
harborPublicURL: https://harbor.${SOVEREIGN_FQDN}
giteaInternalURL: http://gitea-http.gitea.svc.cluster.local:3000
giteaPublicURL: https://gitea.${SOVEREIGN_FQDN}