openova/platform/self-sovereign-cutover
e3mrah 88a8ecd8bb
fix(cutover): Reflector-mirror harbor-admin Secret + in-cluster trigger endpoint (#935) (#947)
Two bugs surfaced live on otech113 2026-05-05 blocking Self-Sovereignty
Cutover end-to-end. Fix both in lockstep:

Bug 1 — bp-self-sovereign-cutover Step 02 (harbor-projects) Job in
`catalyst` namespace was hitting `secret "harbor-core" not found` for
11+ retries because the upstream Harbor `harbor-core` Secret only
exists in the `harbor` namespace and Kubernetes forbids cross-namespace
secretKeyRef. Step 02 was stuck in CreateContainerConfigError forever.

  Fix: bp-harbor 1.2.13 → 1.2.14 ships a Catalyst-curated `harbor-admin`
  Secret in the `harbor` namespace with Reflector mirror annotations
  (allowed-namespaces=catalyst, auto-enabled). The same Secret name
  auto-materialises in `catalyst` so the cutover Job's secretKeyRef
  resolves natively. Password is randomly generated on first install
  (32-char alphanum, 190 bits entropy per feedback_passwords.md) and
  preserved across reconciles via `lookup`. The upstream Harbor subchart
  consumes it via `existingSecretAdminPassword: harbor-admin`.
  bp-self-sovereign-cutover 0.1.16 → 0.1.17 updates
  `harbor.adminSecretRef.name` from `harbor-core` to `harbor-admin`.

Bug 2 — The 0.1.16 auto-trigger Helm post-install Job (#933) POSTed
/api/v1/sovereign/cutover/start which sits behind RequireSession
middleware. The Job has no human session cookie — every request 401'd
forever and cutover never started.

  Fix: new catalyst-api endpoint POST /api/v1/internal/cutover/trigger
  lives OUTSIDE RequireSession and validates the bearer token via the
  apiserver's TokenReview API + checks the resolved username matches
  the canonical `bp-self-sovereign-cutover-runner` SA. Same engine,
  same idempotency, same state machine — different auth surface.
  The auto-trigger Job now mounts its projected SA token at
  /var/run/secrets/kubernetes.io/serviceaccount/token and sends it
  as `Authorization: Bearer <token>`. SA username + accepted list are
  runtime-overridable per Inviolable Principle #4.

Tests
  - 6 Go unit tests for HandleCutoverInternalTrigger covering happy
    path, missing bearer (401), TokenReview rejection (502), wrong SA
    (403), idempotency (no Jobs created when complete), wrong method
    (405). All pass.
  - bp-harbor admin-secret contract test (5 cases) — Secret renders,
    HARBOR_ADMIN_PASSWORD key present, Reflector annotations, keep
    policy, upstream consumes via existingSecretAdminPassword.
  - bp-self-sovereign-cutover cutover-contract test extended with 3
    new cases — auto-trigger uses /internal/cutover/trigger, sends
    SA bearer token, references harbor-admin (not harbor-core).
  - All 12 cutover-contract gates green; all 4 observability-toggle
    gates green; helm template + helm lint clean on both charts.

Bootstrap-kit slot pins
  - clusters/_template/bootstrap-kit/19-harbor.yaml: 1.2.13 → 1.2.14
  - clusters/_template/bootstrap-kit/06a-bp-self-sovereign-cutover.yaml:
    0.1.16 → 0.1.17

Closes #935

Co-authored-by: hatiyildiz <269457768+hatiyildiz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 15:12:50 +04:00
..
chart fix(cutover): Reflector-mirror harbor-admin Secret + in-cluster trigger endpoint (#935) (#947) 2026-05-05 15:12:50 +04:00
blueprint.yaml fix(bp-self-sovereign-cutover): auto-sync local Gitea mirror from upstream GitHub (#870) (#875) 2026-05-05 08:35:40 +04:00