--- # Gitea headless-install bootstrap patch (WS-APPS, Phase 6). # # WHY THIS IS A SUPPLEMENTARY MANIFEST (renderer follow-up): # The ServiceDefinition schema/renderer (catalog/render.py) does not yet express per-container # `env`, `envFrom`, `lifecycle`, or `initContainers`. Gitea needs all three to come up INSTALLED # without the interactive web wizard and with a persistent SECRET_KEY. Rather than widen the # renderer contract for a single app (out of scope for this task), this is a minimal, Gitea-only # kustomize strategic-merge patch layered onto the rendered apps/gitea.yaml Deployment. It is # fully GitOps-reconciled (Flux applies it), so nothing here is a manual pod hack Flux would revert. # TODO(renderer): fold generic `env`/`envFrom`/`lifecycle` support into the ServiceDefinition # schema + render.py, then delete this patch. # # WHAT IT DOES: # - GITEA__security__INSTALL_LOCK=true -> skip the first-run web installer (headless install). # - GITEA__security__SECRET_KEY (from the gitea-bootstrap SOPS Secret) -> a FIXED, persistent # SECRET_KEY. It must NOT regenerate per restart or previously-encrypted data breaks; sourcing # it from a committed SOPS secret pins it across pod restarts/reschedules. # - GITEA__server__ROOT_URL / __DOMAIN -> correct public clone/redirect URLs for the git host # that TLS-terminates at the shared Gateway (gitea.home.keithjackson.dev). # - A postStart lifecycle hook creates a BREAK-GLASS local admin idempotently (only if absent), # so an IdP outage never locks the operator out of recovery tools (docs/15 availability caveat). # All state (repos, SQLite DB, app.ini, INTERNAL_TOKEN) lands on the /data Longhorn PVC. apiVersion: apps/v1 kind: Deployment metadata: name: gitea namespace: gitea spec: template: spec: containers: - name: gitea env: - name: GITEA__security__INSTALL_LOCK value: "true" - name: GITEA__security__SECRET_KEY valueFrom: secretKeyRef: name: gitea-bootstrap key: secret-key - name: GITEA__server__DOMAIN value: gitea.home.keithjackson.dev - name: GITEA__server__ROOT_URL value: https://gitea.home.keithjackson.dev/ - name: GITEA_ADMIN_USERNAME valueFrom: secretKeyRef: name: gitea-bootstrap key: admin-username - name: GITEA_ADMIN_PASSWORD valueFrom: secretKeyRef: name: gitea-bootstrap key: admin-password lifecycle: postStart: exec: command: - /bin/sh - -c - | # Idempotent break-glass admin bootstrap. Runs alongside the gitea entrypoint # (which, with INSTALL_LOCK=true, headless-installs + migrates the DB on first # boot). Waits for the DB, then creates the admin only if it does not exist. set -u export HOME=/data/git i=0 until su-exec git gitea admin user list >/dev/null 2>&1; do i=$((i + 1)) [ "$i" -ge 150 ] && { echo "[gitea-bootstrap] DB not ready after wait; skipping" >&2; exit 0; } sleep 2 done if su-exec git gitea admin user list --admin 2>/dev/null | awk 'NR>1{print $2}' | grep -qx "$GITEA_ADMIN_USERNAME"; then echo "[gitea-bootstrap] admin '$GITEA_ADMIN_USERNAME' already present" exit 0 fi n=0 until su-exec git gitea admin user create \ --username "$GITEA_ADMIN_USERNAME" \ --password "$GITEA_ADMIN_PASSWORD" \ --email "$GITEA_ADMIN_USERNAME@home.local" \ --admin --must-change-password=false; do n=$((n + 1)) [ "$n" -ge 10 ] && { echo "[gitea-bootstrap] admin create failed after retries" >&2; exit 0; } sleep 3 done echo "[gitea-bootstrap] created break-glass admin '$GITEA_ADMIN_USERNAME'"