{{- /*
Catalyst-curated Harbor admin credentials Secret (issue #935).

Background
──────────
The upstream goharbor/harbor chart writes its own `harbor-core` Secret
with key HARBOR_ADMIN_PASSWORD when no `existingSecretAdminPassword`
value is supplied. That secret has TWO problems for Catalyst:

  1. The default password (`Harbor12345` from upstream values.yaml) is
     identical across every Sovereign that doesn't explicitly override
     it — a credential-hygiene catastrophe per
     docs/INVIOLABLE-PRINCIPLES.md #10.

  2. The Secret lives in the `harbor` namespace ONLY. The
     bp-self-sovereign-cutover Step 02 (harbor-projects) Job runs in
     the `catalyst` namespace and references the admin password via
     secretKeyRef. Kubernetes forbids cross-namespace secretKeyRef, so
     the Job hits `secret "harbor-core" not found` indefinitely.
     Caught live on otech113 2026-05-05 — Step 02 in
     CreateContainerConfigError for 11+ retries.

Fix
───
This umbrella chart owns the admin Secret end-to-end:

  • On FIRST install, `lookup` returns nil → randAlphaNum 32 generates
    a fresh password. The Secret carries `helm.sh/resource-policy: keep`
    so `helm uninstall` does NOT delete the bytes.
  • On every subsequent reconcile, `lookup` finds the existing Secret
    and re-emits the SAME password. Stable across helm upgrade /
    rollback / Flux re-reconcile. (Same pattern as
    platform/gitea/chart/templates/admin-secret.yaml.)
  • Reflector annotations mirror the Secret into the namespaces listed
    in .Values.harborAdmin.reflectionAllowedNamespaces (default
    "catalyst") so the cutover Job's secretKeyRef resolves
    automatically. Reflector keeps the mirror in lockstep on every
    change — no manual sync, no operator action.
  • The upstream chart consumes the Secret via
    `harbor.existingSecretAdminPassword: harbor-admin` (set in
    values.yaml under the `harbor:` subchart key). Upstream ALSO emits
    its own `harbor-core` Secret with the SAME bytes (it copies from
    the existing Secret), but the canonical reference for cross-
    namespace consumers is THIS Secret, not the subchart's copy.

Per docs/INVIOLABLE-PRINCIPLES.md
  • #4 (never hardcode): `harborAdmin.password` is operator-overridable;
    the secret name + reflection namespace list are configurable values.
  • #10 (credential hygiene): the password is fully-random 32-char
    alphanum (190 bits entropy), generated server-side by sprig's
    randAlphaNum and persisted only in the Secret bytes — never echoed
    or printed.

Why a single key (HARBOR_ADMIN_PASSWORD)
────────────────────────────────────────
The upstream Harbor chart's `existingSecretAdminPassword` reads ONE
key (configurable via `existingSecretAdminPasswordKey`, default
HARBOR_ADMIN_PASSWORD). The Harbor admin username is HARDCODED to
`admin` in upstream — there is no way to override it via a Secret.
The bp-self-sovereign-cutover Step 02 Job already handles this with
`: "${HARBOR_USERNAME:=admin}"` and `optional: true` on the
HARBOR_ADMIN_USERNAME secretKeyRef, so a single-key Secret here is
sufficient.
*/ -}}
{{- $secretName := .Values.harborAdmin.secretName | default "harbor-admin" -}}
{{- $reflectNS := .Values.harborAdmin.reflectionAllowedNamespaces | default "catalyst" -}}
{{- /* Look up an existing Secret of the same name to preserve the
       password across reconciles. lookup returns nil on first install
       OR when running `helm template` outside a cluster (the smoke-
       render path) — in either case we generate a fresh one. */ -}}
{{- $existing := lookup "v1" "Secret" .Release.Namespace $secretName -}}
{{- $password := "" -}}
{{- if and $existing $existing.data (index $existing.data "HARBOR_ADMIN_PASSWORD") -}}
  {{- /* Steady state — every reconcile after first lands here. */ -}}
  {{- $password = index $existing.data "HARBOR_ADMIN_PASSWORD" | b64dec -}}
{{- end -}}
{{- /* Operator override wins over both lookup and randAlphaNum. */ -}}
{{- if .Values.harborAdmin.password -}}
  {{- $password = .Values.harborAdmin.password -}}
{{- end -}}
{{- /* First install (or smoke-render): generate a 32-char alphanum
       password. randAlphaNum is sprig's RNG; on a real install that
       runs once and the lookup branch wins forever after. 32 chars
       alphanum = 190 bits entropy per feedback_passwords.md. */ -}}
{{- if not $password -}}
  {{- $password = randAlphaNum 32 -}}
{{- end -}}
apiVersion: v1
kind: Secret
metadata:
  name: {{ $secretName }}
  namespace: {{ .Release.Namespace }}
  labels:
    # NB: the canonical bp-harbor.labels helper (defined in
    # _helpers.tpl) emits app.kubernetes.io/name + catalyst.openova.io/
    # component which COLLIDE with the admin-credential-specific values
    # below. Helm's strict YAML post-render path rejects duplicate
    # mapping keys, so we cannot `include` the helper here AND override
    # those keys — Helm 1.2.14 hit
    # `mapping key "app.kubernetes.io/name" already defined` on
    # otech113 (issue #949). The labels are therefore inlined: every
    # key the helper emits is reproduced verbatim except the two that
    # need a Secret-specific value (component + an explicit
    # admin-credentials sub-component).
    app.kubernetes.io/name: harbor
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
    app.kubernetes.io/component: admin-credentials
    catalyst.openova.io/blueprint: bp-harbor
    catalyst.openova.io/component: harbor-admin
  annotations:
    # Survive helm uninstall — the Secret outlives the release. A
    # subsequent helm install picks up the bytes via lookup.
    helm.sh/resource-policy: keep
    # bp-reflector mirrors this Secret into the namespaces listed below
    # so cross-namespace consumers (bp-self-sovereign-cutover Step 02
    # harbor-projects Job in the `catalyst` namespace) can mount the
    # same credentials without a cross-namespace secretKeyRef (which
    # K8s forbids). reflector keeps the mirror in lockstep on every
    # change. Caught live on otech113 2026-05-05 (issue #935).
    # See https://github.com/emberstack/kubernetes-reflector.
    reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
    reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: {{ $reflectNS | quote }}
    reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
    reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: {{ $reflectNS | quote }}
type: Opaque
data:
  HARBOR_ADMIN_PASSWORD: {{ $password | b64enc | quote }}
