# Manifest Server Dry-Run Prerequisites `make k8s-server-dry-run` checks committed manifests and rendered app charts against a Kubernetes API server using server-side dry-run. It catches schema and admission drift that Helm rendering alone cannot see. ## What The Command Does The helper in `tools/k8s-server-dry-run.sh`: 1. verifies `kubectl` and `helm` are installed; 2. verifies a Kubernetes API server is reachable; 3. optionally creates the target namespace when `DRY_RUN_CREATE_NAMESPACES=true`; 4. renders `charts/vergabe-teilnahme/` with `helm/vergabe-teilnahme-values.yaml`; 5. runs `kubectl apply --dry-run=server -f manifests`; 6. runs `kubectl apply --dry-run=server` against the rendered chart output. The namespace creation step is a real apply, not a dry-run. Use `DRY_RUN_CREATE_NAMESPACES=true` only against a disposable or approved representative cluster where creating the app namespace is acceptable. ## Representative Cluster Requirement The check expects a live Kubernetes API server whose version, admission webhooks, and installed APIs are close enough to Railiance to be meaningful. A pure local render or unseeded kind cluster is not enough. The current `vergabe-teilnahme` release uses built-in Kubernetes APIs: - `apps/v1` Deployment; - `v1` Service; - `v1` PersistentVolumeClaim when media persistence is enabled; - `networking.k8s.io/v1` Ingress. For realistic S5 validation, the representative cluster should also have the same ingress class, cert-manager issuer posture, NetworkPolicy posture, and admission policies as Railiance. Future app manifests that introduce CNPG, cert-manager, Traefik, External Secrets, or other CRDs require those CRDs and webhooks to be installed before the dry-run result is meaningful. ## Runner And Credential Requirements Local operator runs require: - `kubectl` context pointed at the representative cluster; - credentials with `get` access for API discovery; - server-side dry-run permission for the rendered resources; - namespace create/apply permission only when `DRY_RUN_CREATE_NAMESPACES=true`. CI runs require forge-owned runner prerequisites: - a runner label approved for S5 release checks, such as `s5-release-check` or `cluster-dry-run`; - approved kubeconfig or equivalent cluster access delivery; - runner placement that is allowed to reach the representative API server; - no kubeconfig, bearer token, package token, or secret value stored in Git. The runner label contract and secret boundary live in `/home/worsch/railiance-forge/docs/ci-runner-actions-gitops-ownership.md`. ## Failure Classification Treat these as release-blocking when the representative cluster and runner are known-good: - Helm render fails; - server-side dry-run rejects a changed manifest; - Kubernetes schema or admission policy rejects an app resource; - the rendered image reference or required Secret name is structurally invalid. Treat these as prerequisite gaps rather than app release failures: - no runner with the required label is available; - the runner cannot reach the representative cluster; - kubeconfig or secret delivery is missing; - required CRDs/admission webhooks are absent from the representative cluster; - namespace creation is forbidden while `DRY_RUN_CREATE_NAMESPACES=true`. For prerequisite gaps, link or create the owning forge, cluster, platform, or enablement workplan instead of weakening the S5 app chart. ## Enforcement Gate The workflow in `.gitea/workflows/manifest-server-dry-run.yaml` is ready to enforce PR checks only when: - forge has published the runner label and placement evidence; - cluster/platform have provided representative API access and secret delivery; - the namespace side effect is accepted or pre-provisioned; - at least one successful dry-run result is recorded for the current release surface.