Files
helm-charts/rallly/templates/rallly.deployment.yaml
T
jklein 37eda69fdd rallly: strict values.schema.json, ingress gate and null-safe hardening
Three changes, all about values that do not do what they promise:

1. values.schema.json (#68): additionalProperties: false on every
   chart-owned object level, so a key the chart does not read is rejected
   at render time instead of being silently ignored.

2. Ingress gate (#93): the Ingress template is wrapped in
   {{- if .Values.ingress.enabled }} and the key is added to values.yaml
   with default true, so behaviour is unchanged.

   ingress.domain is NOT a pure Ingress value here - it is also the app's
   public base URL (NEXT_PUBLIC_BASE_URL). Gating alone would therefore
   have introduced a new silent failure: with the Ingress switched off and
   no domain, the deployment rendered value: "https://" and every
   generated link would be broken. The deployment's read of the value is
   now required(), so that case fails loudly. Only clusterIssuer actually
   becomes unnecessary when the Ingress is off.

3. Null-safety for hardening, probes and resources (#99): an erased block
   fell back to "securityContext: null" (unhardened), a vanished probe or
   a container without resource accounting. Restoring the pod context
   matters especially here, because its fsGroup is what makes the Next.js
   cache emptyDir group-writable for the container.

rallly.cache is deliberately NOT null-safe: cache.path is required(), so
an erased block fails loudly and belongs to the loud class #99 excludes.

Apart from an added comment, the rendered manifest is unchanged.
2026-08-23 20:58:52 +02:00

172 lines
7.2 KiB
YAML

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
labels:
app: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
spec:
replicas: {{ include "rallly.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.rallly.replicas) }}
selector:
matchLabels:
app: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
template:
metadata:
name: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
labels:
app: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
spec:
automountServiceAccountToken: false
securityContext:
{{- include "rallly.podSecurityContext" .Values.rallly.securityContext | nindent 8 }}
containers:
- name: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
image: "lukevella/rallly:{{ .Chart.AppVersion }}"
imagePullPolicy: IfNotPresent
env:
# ingress.domain is not a pure Ingress value: it is also the app's
# public base URL, so it stays required even when the Ingress is
# switched off (an empty value would render "https://" and break
# every generated link silently).
- name: NEXT_PUBLIC_BASE_URL
value: "https://{{ required "A Domain/Host must be provided (ingress.domain)" .Values.ingress.domain }}"
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-secret
key: secret-key
- name: SUPPORT_EMAIL
value: "{{ required "A Support-Email must be provided" .Values.rallly.supportEmail }}"
{{- if .Values.rallly.smtp.enabled }}
- name: NOREPLY_EMAIL
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-smtp-secret
key: no-reply-email
- name: NOREPLY_EMAIL_NAME
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-smtp-secret
key: no-reply-email-name
- name: SMTP_HOST
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-smtp-secret
key: host
- name: SMTP_PORT
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-smtp-secret
key: port
- name: SMTP_SECURE
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-smtp-secret
key: secure
- name: SMTP_USER
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-smtp-secret
key: user
- name: SMTP_PWD
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-smtp-secret
key: password
- name: SMTP_REJECT_UNAUTHORIZED
value: "{{ .Values.rallly.smtp.rejectUnauthorized }}"
- name: SMTP_TLS_SERVERNAME
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-smtp-secret
key: tls-servername
{{- end }}
- name: EMAIL_LOGIN_ENABLED
value: "false"
- name: REGISTRATION_ENABLED
value: "false"
- name: OIDC_NAME
value: "{{ .Values.rallly.oidc.name }}"
- name: OIDC_NAME_CLAIM_PATH
value: "{{ .Values.rallly.oidc.nameClaimPath }}"
- name: OIDC_EMAIL_CLAIM_PATH
value: "{{ .Values.rallly.oidc.emailClaimPath }}"
- name: OIDC_PICTURE_CLAIM_PATH
value: "{{ .Values.rallly.oidc.pictureClaimPath }}"
- name: OIDC_DISCOVERY_URL
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret
key: discovery-url
- name: OIDC_CLIENT_ID
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret
key: client-id
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret
key: client-secret
- name: ALLOWED_EMAILS
value: "{{ .Values.rallly.allowedEmails }}"
- name: INITIAL_ADMIN_EMAIL
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-secret
key: initial-admin-email
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-{{ .Chart.Name }}-database-secret
key: database-url
# TODO: Add Storage Configuration
{{- range $value := .Values.rallly.env }}
{{- if $value.value }}
- name: {{ $value.name }}
value: {{ tpl $value.value $ }}
{{- else if $value.valueFrom }}
{{- if $value.valueFrom.secretKeyRef }}
- name: {{ $value.name }}
valueFrom:
secretKeyRef:
name: {{ tpl $value.valueFrom.secretKeyRef.name $ }}
key: {{ tpl $value.valueFrom.secretKeyRef.key $ }}
{{- else if $value.valueFrom.configMapKeyRef }}
- name: {{ $value.name }}
valueFrom:
configMapKeyRef:
name: {{ tpl $value.valueFrom.configMapKeyRef.name $ }}
key: {{ tpl $value.valueFrom.configMapKeyRef.key $ }}
{{- end }}
{{- end }}
{{- end }}
ports:
- containerPort: 3000
protocol: TCP
name: http
livenessProbe:
{{- include "rallly.livenessProbe" .Values.rallly.livenessProbe | nindent 12 }}
readinessProbe:
{{- include "rallly.readinessProbe" .Values.rallly.readinessProbe | nindent 12 }}
startupProbe:
{{- include "rallly.startupProbe" .Values.rallly.startupProbe | nindent 12 }}
resources:
{{- include "rallly.effectiveResources" .Values.rallly.resources | nindent 12 }}
securityContext:
{{- include "rallly.containerSecurityContext" .Values.rallly.securityContext | nindent 12 }}
volumeMounts:
# Next.js writes prerendered pages and optimized images into its
# cache directory; with a read-only root filesystem this must be a
# writable volume (see rallly.cache in values.yaml).
- name: next-cache
mountPath: {{ required "A cache path must be provided (rallly.cache.path)" .Values.rallly.cache.path | quote }}
volumes:
- name: next-cache
{{- if .Values.rallly.cache.sizeLimit }}
emptyDir:
sizeLimit: {{ .Values.rallly.cache.sizeLimit | quote }}
{{- else }}
emptyDir: {}
{{- end }}
restartPolicy: Always