Files
cms-plugins/deploy/helm/values.yaml
T
Oleks 8c119efff8 harden(deploy): apply safe fixes from review report-only items
- #3 Liveness probe targets full SSR DB-querying / route, coupling pod liveness to SQLite
- #4 Chart values-staging/production.yaml are dead config under Flux; drift trap
- #6 tsconfig includes gitignored emdash-env.d.ts that only the dev server generates
- #7 Dockerfile package-lock glob + npm install fallback can silently build an unlocked image
- #8 Dockerfile creates runtime user without pinning its GID
- #9 entrypoint.sh gates `emdash init` on data.db absence, skipping migrations on PVC reuse
- #10 pullPolicy: Always vs digest pinning
- #11 Dockerfile state symlinks contradict the STATE_DIR contract; Dockerfile does not set ENV STATE_DIR
- #12 astro is a production dependency, so npm prune --omit=dev keeps build-only tooling
- #14 Two ImageUpdateAutomations write back to the same anton-helm-workloads main branch
- #16 memoryCache provider is per-process; correctness depends implicitly on replicas:1
- #17 Root catch-all [slug].astro couples nav links to pages-collection rows + DB hit per unmatched path
- #18 Detail pages render a 200-style body under a 404 status and have no try/catch around getEmDash* calls
- #19 vite allowedHosts hardcodes ddev hostnames (dev-only; no prod impact)
2026-06-02 04:50:54 +03:00

107 lines
3.5 KiB
YAML

# Defaults for the cms-plugins chart.
# Per-env overrides: Flux applies ONLY the HelmRelease `values:` block.
# values-staging.yaml / values-production.yaml are for direct `helm upgrade -f`
# use and are NOT read by Flux — keep them in sync with the HR by hand.
image:
repository: git.oleks.space/oleks/cms-plugins
tag: develop-latest
# `Always` is here for the chart-default FLOATING-TAG path: with no
# `digest` set, the image renders as `repository:<branch>-latest`
# (a mutable pointer CI retags onto each build), so kubelet must
# re-pull or it would pin to the first cached digest and never roll.
# NOTE: the deployed overlays pin by `digest` (repository@sha256:…),
# where a tag change instead changes the image *reference string*, so
# `helm upgrade` already detects it and `Always` is a no-op (a digest
# is content-addressed — it can never resolve to different bytes).
# `IfNotPresent` would be marginally better on the digest path but is
# left as `Always` so both render paths share one safe value.
pullPolicy: Always
service:
port: 4321
ingress:
enabled: true
host: cms-plugins.kotkanagrilli.fi
# TLS terminates at the Caddy reverse-proxy at the cluster edge
# (matches the woodpecker / emdash-kotkanagrilli pattern). The
# Ingress object is plain — no inline TLS, no cert-manager Certificate.
className: kube-system-traefik
# SQLite is single-writer — pin to one node so the local-path PV is sticky.
# kotkan hosts the kotkanagrilli subdomain pool, matching the
# anton-helm-workloads convention (hello-kotkan, kotkanagrilli, etc.).
nodeSelector:
kubernetes.io/hostname: kotkan
tolerations: []
affinity: {}
persistence:
enabled: true
storageClass: local-path
size: 5Gi
# Mounted at /app/state. The image symlinks /app/data.db and /app/uploads
# into this volume, so a single PVC covers SQLite + uploaded media.
mountPath: /app/state
# Plain env values (non-secret).
env:
HOST: "0.0.0.0"
PORT: "4321"
NODE_ENV: production
DEPLOY_TARGET: node
STATE_DIR: /app/state
EMDASH_ALLOWED_ORIGINS: ""
# All secrets project from one Secret. Keys expected:
# - EMDASH_ENCRYPTION_KEY (required)
existingSecret: cms-plugins-secrets
imagePullSecrets:
- name: gitea-registry-creds
probes:
liveness:
# /_emdash/api/health requires auth (401 to unauthenticated requests),
# so we probe the public site root instead. But `/` is server-rendered
# and queries SQLite content, so a content/render or DB fault makes it
# 500 while the Node process is perfectly alive. Liveness must NOT
# crash-loop the single SQLite replica over a transient content/DB
# error: keep failureThreshold high so only a genuinely wedged process
# (sustained failures) triggers a restart. Readiness (below) is what
# sheds traffic on a content 500.
path: /
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 6
readiness:
# Probe the public site root. A content/render 500 here removes the pod
# from Endpoints (stops serving 500s) WITHOUT the kubelet killing the
# process — readiness failures never restart the container.
path: /
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
podSecurityContext:
fsGroup: 1001
containerSecurityContext:
runAsNonRoot: true
runAsUser: 1001
runAsGroup: 1001
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]