# Helm charts

Two example charts for deploying [zddc-server](../zddc/) on Kubernetes.
Both compile zddc-server from source via an init container — no
container image needs to be pulled from a registry, and no binary needs
to be built ahead of time. The init container clones the repo at a
configured git ref and runs `go build`; the main container is plain
alpine + the freshly built static binary.

## Charts

| Chart | When to use |
|---|---|
| **`zddc-server-prod/`** | Production. Pin `zddc.gitRef` to a stable tag (`zddc-server-vX.Y.Z`). Slower probe cadence; image-pull policy `IfNotPresent`. |
| **`zddc-server-dev/`** | Development / soak. Tracks `main` by default; `helm upgrade` triggers a pod recreate so each rollout pulls the latest commit. Faster probes; debug-level logging (request headers logged — sensitive). |

The chart values are nearly identical between the two; the differences
are encoded as defaults in each chart's `values.yaml.example`.

## Quick start

```sh
# Pre-requisite: a PersistentVolumeClaim for ZDDC_ROOT data
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: zddc-root
spec:
  accessModes: [ReadWriteMany]    # or RWO if single replica is fine
  resources: { requests: { storage: 100Gi } }
  storageClassName: your-shared-fs   # NFS, CephFS, SMB, etc.
EOF

# Production install
cp helm/zddc-server-prod/values.yaml.example my-prod-values.yaml
$EDITOR my-prod-values.yaml          # set zddc.gitRef, hostnames, etc.
helm install zddc-server-prod helm/zddc-server-prod/ -f my-prod-values.yaml

# Dev install (tracks main HEAD)
cp helm/zddc-server-dev/values.yaml.example my-dev-values.yaml
$EDITOR my-dev-values.yaml
helm install zddc-server-dev helm/zddc-server-dev/ -f my-dev-values.yaml

# Trigger a rebuild from latest main HEAD (dev chart)
helm upgrade zddc-server-dev helm/zddc-server-dev/ -f my-dev-values.yaml
```

## What the chart does and doesn't do

**Does:**

- Clones the configured `zddc.gitRepo` at `zddc.gitRef` in an init
  container, builds the Go binary, copies it to a shared `emptyDir`,
  and starts the main container against that binary.
- Wires the `ZDDC_*` environment-variable contract (root path, addr,
  email header, CORS allowlist, log level, index path).
- Mounts a caller-supplied PersistentVolumeClaim at `ZDDC_ROOT`.
- Optionally creates an Ingress (`ingress.enabled: true`).

**Does not:**

- Create the PVC. Operators provision storage themselves; the chart
  only references it by name.
- Manage TLS for the pod. zddc-server runs in plain HTTP mode behind
  whatever ingress / authenticating reverse proxy the cluster already
  has. `ZDDC_TLS_CERT=none` and `ZDDC_INSECURE_DIRECT=1` are hardcoded
  in the templates because the chart is opinionated about the
  TLS-terminated-upstream deployment shape.
- Authenticate users. zddc-server reads the user's email from a header
  set by the upstream proxy (`X-Auth-Request-Email` by default). The
  chart does not deploy oauth2-proxy / nginx-auth-request / Pomerium /
  etc. — bring your own.
- Manage secrets. `values.yaml.example` contains no secrets and never
  should. ACL email lists belong in `.zddc` files inside the data
  volume; image-pull credentials and TLS certs (if you enable ingress
  TLS) reference Kubernetes secrets you've created separately.

## Why build from source instead of using a registry image

Three reasons:

1. **Reproducibility.** The init container's logs show exactly which
   git ref was built. There's no opaque "what did I deploy" question
   that a registry tag can introduce.
2. **One distribution channel.** Codeberg release-asset binaries
   already exist for direct downloads; the chart compiles its own
   binary from the same source git ref so there's nothing extra to
   maintain (no separate image registry, no image-promotion pipeline).
3. **Smaller blast radius.** A compromised build image affects only
   pods that pull during the compromise window. A compromised registry
   image stays compromised across rollbacks until the digest is rotated.

The cost: every pod start takes 30-60s to clone + `go build` instead
of pulling a pre-baked image. Acceptable for both chart audiences
(production rollouts are infrequent; dev rollouts trade build time
for tracking-main convenience).

## Linting

```sh
helm lint helm/zddc-server-prod/
helm lint helm/zddc-server-dev/

# Render to inspect (uses default values from values.yaml.example):
helm template test-prod helm/zddc-server-prod/ \
  --values helm/zddc-server-prod/values.yaml.example
```
