{{- /*
Provisioning service GitHub-token Secret for franchised Sovereigns
(issue #866).

Why this template exists:
  The SME `provisioning` service Deployment references
  `secret/provisioning-github-token` with key `GITHUB_TOKEN` as a
  required env (provisioning.yaml). On contabo-mkt this Secret is
  pre-provisioned via SealedSecret. On a freshly franchised Sovereign
  nothing equivalent existed — caught live on otech103 (2026-05-04)
  where the provisioning Pod was the last 1/13 still in
  CreateContainerConfigError after #859 + #861 + #863 cleared the
  other 12 pods.

  This template materialises the Secret as part of the chart so any
  Sovereign that flips MARKETPLACE_ENABLED=true gets a working
  provisioning Pod out of the box, completing the SME stack
  (12/13 → 13/13 Running 1/1).

Approach (issue #866 Option C — local Gitea target):
  Post-cutover the canonical Git target on a Sovereign IS the local
  Gitea instance (the GitRepository CRs already point there), not
  upstream GitHub. So we mirror the Gitea admin password — already
  generated by platform/gitea/chart/templates/admin-secret.yaml with
  the same lookup-persistence pattern used here — into the `sme`
  namespace under the canonical key name `GITHUB_TOKEN` that the
  provisioning service reads. The env-var name stays GITHUB_TOKEN
  because the provisioning service code (core/services/provisioning/
  main.go) reads that exact env name; renaming it to GIT_TOKEN would
  ripple through provisioning.yaml + main.go + provisioning Go
  packages without changing behaviour.

  Per docs/INVIOLABLE-PRINCIPLES.md #3 (no workarounds): full Gitea
  REST-API target support in core/services/provisioning/github/
  client.go (which currently hardcodes https://api.github.com) is a
  separate follow-up. This Secret unblocks the Pod reaching Running
  1/1 — completing the SME stack — and gives the operator a valid
  credential to point the provisioning service at local Gitea via a
  per-Sovereign overlay env override (GITHUB_API_BASE_URL once that
  env knob lands; tracked in the same #866 follow-up).

Why not Reflector annotations on gitea-admin-secret?
  platform/gitea/chart/templates/admin-secret.yaml already carries
  reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "catalyst"
  — that is the deliberate mirror target for bp-self-sovereign-cutover
  Step 1's gitea-mirror Job, which reads the credentials from the
  catalyst namespace. Adding `sme` to that list would couple the
  gitea chart's mirror policy to a sister-product's deployment
  topology; the lookup-and-mirror pattern used here keeps the
  coupling local to bp-catalyst-platform (where it belongs) and
  matches the precedent set by valkey-cross-ns-secret.yaml (#863)
  and sme-secrets.yaml (#859). Reflector also reflects the entire
  source Secret bytes — we want only the password byte, exposed
  under the GITHUB_TOKEN key, not the full username+password pair.

First-install ordering:
  bp-gitea (slot 10) reaches Ready before bp-catalyst-platform (slot
  13) — the Flux dependsOn chain in clusters/_template/bootstrap-kit/
  13-bp-catalyst-platform.yaml lists bp-gitea explicitly. So by the
  time this template renders, gitea-admin-secret EXISTS in the gitea
  namespace and lookup returns its decoded password.

  In the rare degraded path where bp-gitea is mid-reconcile when this
  template runs (e.g. helm upgrade race), lookup may return nil —
  in that case this template renders no Secret, the provisioning Pod
  stays in CreateContainerConfigError, and Flux's 15m reconcile picks
  up the mirror once gitea-admin-secret exists. Provisioning Pod's
  restart-on-config-error backoff handles that gracefully (steady
  state is ~2-5 minutes after bp-gitea reaches Ready).

Per docs/INVIOLABLE-PRINCIPLES.md #10: NO plaintext credentials in this
template. The password lives only in gitea-admin-secret and is read
back via lookup; the bytes never appear in chart source or rendered
manifests on disk.

Per #4 (never hardcode): source/destination namespace + Secret names
flow through .Values.smeServices.provisioning.gitToken.* with sensible
defaults that match the upstream gitea + provisioning shapes.

Cutover ownership handover (TBD-C18b, 2026-05-18):
  bp-self-sovereign-cutover Step 09 (09-gitea-token-mint-job.yaml) mints
  a REAL Gitea API token via POST /api/v1/users/{user}/tokens, then
  PATCHes this Secret's GITHUB_TOKEN field with the new bytes and stamps
  two annotations onto the Secret:
    catalyst.openova.io/token-minted-at:  <RFC3339 timestamp>
    catalyst.openova.io/token-source:     "self-sovereign-cutover-step-09"
  The Gitea ADMIN PASSWORD is NOT a valid API token (Gitea treats Bearer
  credentials as sha1-hashed access-token rows in the `users` table, not
  as the admin password) — so the password placeholder this template
  writes on first install is enough to boot the Pod past
  CreateContainerConfigError but NOT enough to actually mint tenant repos
  in Gitea. Step 09's minted token is the canonical credential.

  Without the lookup-persistence guard added below, every chart reconcile
  (every 15 min by default Flux interval) overwrites the minted token
  back to the admin password, undoing Step 09 silently. Verified live
  on t22 (2026-05-18): Step 09 ran 13:43:33Z setting GITHUB_TOKEN to a
  real API token, then ~5 min later helm reconcile of catalyst-platform
  rewrote GITHUB_TOKEN back to the admin password byte. C18 fix was
  ephemeral until this guard landed.

  Guard semantics: lookup the destination Secret first. If it exists
  AND has the `catalyst.openova.io/token-source` annotation set to
  "self-sovereign-cutover-step-09", preserve the existing GITHUB_TOKEN
  bytes verbatim (re-emit the b64 byte string from the live Secret).
  Otherwise fall through to the first-install bootstrap branch that
  mirrors gitea-admin-secret.password (so a freshly-franchised Sovereign
  still boots the provisioning Pod past CreateContainerConfigError
  before Step 09 has had a chance to run).
*/}}
{{- if and .Values.ingress .Values.ingress.marketplace .Values.ingress.marketplace.enabled -}}
{{- $sourceNamespace := .Values.smeServices.provisioning.gitToken.sourceNamespace | default "gitea" -}}
{{- $sourceSecretName := .Values.smeServices.provisioning.gitToken.sourceSecretName | default "gitea-admin-secret" -}}
{{- $sourcePasswordKey := .Values.smeServices.provisioning.gitToken.sourcePasswordKey | default "password" -}}
{{- $destNamespace := .Values.smeServices.provisioning.gitToken.destNamespace | default "sme" -}}
{{- $destSecretName := .Values.smeServices.provisioning.gitToken.destSecretName | default "provisioning-github-token" -}}
{{- $destKey := .Values.smeServices.provisioning.gitToken.destKey | default "GITHUB_TOKEN" -}}
{{- /* Lookup the destination Secret first to detect whether Step 09 of
       bp-self-sovereign-cutover has already taken ownership. If yes,
       preserve the minted token bytes verbatim — the chart MUST NOT
       clobber the cutover-issued credential. */ -}}
{{- $destSecret := lookup "v1" "Secret" $destNamespace $destSecretName -}}
{{- $cutoverOwned := false -}}
{{- $existingTokenB64 := "" -}}
{{- $preservedMintedAt := "" -}}
{{- if and $destSecret $destSecret.metadata $destSecret.metadata.annotations -}}
  {{- $tokenSource := index $destSecret.metadata.annotations "catalyst.openova.io/token-source" -}}
  {{- if eq $tokenSource "self-sovereign-cutover-step-09" -}}
    {{- if and $destSecret.data (index $destSecret.data $destKey) -}}
      {{- $cutoverOwned = true -}}
      {{- $existingTokenB64 = index $destSecret.data $destKey -}}
      {{- $preservedMintedAt = index $destSecret.metadata.annotations "catalyst.openova.io/token-minted-at" -}}
    {{- end -}}
  {{- end -}}
{{- end -}}
{{- $sourceSecret := lookup "v1" "Secret" $sourceNamespace $sourceSecretName -}}
{{- $haveBootstrap := false -}}
{{- $bootstrapTokenB64 := "" -}}
{{- if and $sourceSecret $sourceSecret.data (index $sourceSecret.data $sourcePasswordKey) -}}
  {{- $haveBootstrap = true -}}
  {{- $bootstrapTokenB64 = index $sourceSecret.data $sourcePasswordKey -}}
{{- end -}}
{{- if or $cutoverOwned $haveBootstrap -}}
apiVersion: v1
kind: Secret
metadata:
  name: {{ $destSecretName }}
  namespace: {{ $destNamespace }}
  labels:
    catalyst.openova.io/blueprint: bp-catalyst-platform
    catalyst.openova.io/component: provisioning-github-token
    app.kubernetes.io/part-of: sme
  annotations:
    # Identifies the upstream source for ops visibility — `kubectl describe
    # secret provisioning-github-token -n sme` makes the provenance obvious
    # without tribal knowledge.
    catalyst.openova.io/mirrored-from: {{ printf "%s/%s" $sourceNamespace $sourceSecretName | quote }}
    # Survive helm uninstall — the Secret outlives the release. A
    # subsequent helm install picks the bytes back up via lookup, so
    # the provisioning Pod stays Running across reinstalls without a
    # restart-storm.
    helm.sh/resource-policy: keep
    # Reflector mirror into `catalyst-system` (TBD-C18, issue #1745):
    # the catalyst-api Pod (in catalyst-system) reads GITHUB_TOKEN via
    # secretKeyRef to source CATALYST_GITOPS_TOKEN — the real Gitea
    # API token minted by bp-self-sovereign-cutover Step 09. Without
    # this mirror, catalyst-api's POST /api/v1/sovereigns/{id}/
    # marketplace and the SME tenant gitops writer both return 503
    # "gitops token unconfigured — set CATALYST_GITOPS_TOKEN" because
    # K8s secretKeyRef is same-namespace-only and Step 09's destination
    # lives in `sme`.
    #
    # Pattern mirrors sme-secrets.yaml's reflector block (same chart,
    # same destination namespace) — see that file for the field-by-
    # field rationale.
    reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
    reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "catalyst-system"
    reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
    reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "catalyst-system"
    {{- if $cutoverOwned }}
    # bp-self-sovereign-cutover Step 09 has minted a real Gitea API
    # token and patched this Secret. Preserve the token-source +
    # token-minted-at annotations so subsequent reconciles continue to
    # honour the cutover ownership (the cutoverOwned branch below
    # re-emits the existing token bytes verbatim).
    catalyst.openova.io/token-source: "self-sovereign-cutover-step-09"
    {{- if $preservedMintedAt }}
    catalyst.openova.io/token-minted-at: {{ $preservedMintedAt | quote }}
    {{- end }}
    {{- end }}
type: Opaque
data:
  {{- if $cutoverOwned }}
  # Preserve the cutover-minted token bytes verbatim. Do NOT overwrite
  # with gitea-admin-secret.password — that placeholder is only useful
  # for first-install bootstrap before Step 09 has had a chance to run.
  # See TBD-C18b for the live regression this guard prevents.
  {{ $destKey }}: {{ $existingTokenB64 | quote }}
  {{- else }}
  # First-install bootstrap: emit the gitea admin password verbatim under
  # the env-name the provisioning service reads. This lets the
  # provisioning Pod reach Running before bp-self-sovereign-cutover
  # Step 09 mints the real API token. The bytes here are NOT a valid
  # Gitea API token — they only unblock the Pod's CreateContainer phase.
  {{ $destKey }}: {{ $bootstrapTokenB64 | quote }}
  {{- end }}
{{- end }}
{{- end }}
