Skill: Legend Helm + Flux GitOps work

How to work on the Legend OpenShift/GitOps effort (charts, Flux, air-gap). Written by the coach 2026-06-12. Authoritative design: docs-site/docs/design/helm-flux-airgapped-openshift.md in the legend repo — read it before any task in this stream.

Repo facts

  • gitlab.paralla.org/legion/legend (project id 36).
  • Never push to main. CI on main deploys to the live Legend cluster and runs ~40 min of regressions. Always: feature branch MR coach/pvs review. Branch CI only builds (safe).
  • CI lint images-via-repo-docker fails ANY hardcoded public registry. Every image must go through the customer mirror variable (${REPO_DOCKER} in raw manifests, {{ .Values.global.repoDocker }} in charts).
  • Existing raw manifests: k8s/00-core (postgres, mariadb, redis, ingress-nginx, netpols), k8s/01-auth (keycloak, oauth2-proxy), k8s/02-proxy (nginx), k8s/03-apps (one file per service). k8s/00-core/longhorn-multipath-fix.yaml is ops-only — never package it.

Target layout (from the design doc)

charts/legend/                 # umbrella chart = Core (always-on)
charts/services/<svc>/         # one subchart per optional service
clusters/<env>/flux-system/    # rendered Flux controllers (air-gapped)
clusters/<env>/core.yaml       # HelmRelease for Core
clusters/<env>/services/*.yaml # one HelmRelease file per enabled service

A service is installed iff its HelmRelease file exists. Add/remove = one file in git.

Tools (installed at /opt/data/bin/)

  • helm v3.16.4 — helm lint <chart>, helm template <name> <chart> --set k=v, helm template ... | grep -E '^kind:|^ name:' to compare object coverage vs raw manifests.
  • flux v2.4.0 — air-gapped render (NEVER flux bootstrap, it phones GitHub): flux install --registry=<mirror>/fluxcd --export > clusters/<env>/flux-system/gotk-components.yaml

Chart conventions

  • global: values: repoDocker, baseDomain, imageTag, storageClass, platform: openshift|k8s (platform gates SCC-sensitive bits; on openshift everything runs under restricted-v2 — non-root, no privilege escalation, no fixed UIDs).
  • Preserve the securityContexts already in the raw manifests — they are the restricted-v2 work.
  • Keep resource names and labels identical to the raw manifests (future in-place adoption).
  • Hostnames: {{ printf "chat.%s" .Values.global.baseDomain }} style, no hardcoded domains.

Definition of done for any chart task

helm lint clean + helm template renders every object the raw manifests had + no hardcoded registry/domain + MR open with green branch CI + a Note on the task with the MR URL.