From ddf038987c62457d14a6c0c33206ac8fe784f94f Mon Sep 17 00:00:00 2001 From: Wyatt Walter Date: Wed, 24 Jun 2026 21:55:31 +0000 Subject: [PATCH 1/4] fix(helm): guard against unsupported redis.auth.password configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit redis.auth.password is a Bitnami subchart passthrough the Appsmith templates never read. Used with the chart defaults it silently vanishes (Bitnami ignores it because existingSecret is non-empty), and used with existingSecret:"" but no URL it splits the credential between Redis and the app. Add a render-time guard (appsmith.validateRedisAuth, invoked from configMap.yaml so it always evaluates): if redis.auth.password is set, require both redis.auth.existingSecret="" and applicationConfig.APPSMITH_REDIS_URL, else fail with a message stating the two supported options. This leaves exactly one valid redis.auth.password path: fully self-managed. Also skip the password-bootstrap hook when redis.auth.password is set — safe only because the guard eliminates the case that previously broke (a non-empty existingSecret pointing at a now-uncreated secret); noted in a comment. Co-Authored-By: Claude Opus 4.8 (1M context) --- deploy/helm/templates/_helpers.tpl | 21 +++++++++++++++++++++ deploy/helm/templates/configMap.yaml | 1 + deploy/helm/templates/hooks/redis.yaml | 11 ++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/deploy/helm/templates/_helpers.tpl b/deploy/helm/templates/_helpers.tpl index 04100291cae..9add8500c67 100644 --- a/deploy/helm/templates/_helpers.tpl +++ b/deploy/helm/templates/_helpers.tpl @@ -237,6 +237,27 @@ Uses existing secret if provided, otherwise derives "{release}-redis-secret" {{- .Values.redis.auth.existingSecret | default (printf "%s-redis-secret" .Release.Name) -}} {{- end -}} +{{/* +Redis: validate the redis.auth.password configuration. + +redis.auth.password is a Bitnami subchart passthrough that the Appsmith +templates never read on their own. There is exactly ONE supported way to use +it: the fully self-managed path, where the operator also disables the chart's +bootstrap secret (existingSecret: "") and hands the app a matching connection +string via applicationConfig.APPSMITH_REDIS_URL. Any other use silently splits +the password between Redis and the app, so we fail fast instead. + +Invoked from a template that always renders (configMap.yaml) so it evaluates on +every `helm template`/install/upgrade. +*/}} +{{- define "appsmith.validateRedisAuth" -}} +{{- if .Values.redis.auth.password -}} +{{- if or .Values.redis.auth.existingSecret (not .Values.applicationConfig.APPSMITH_REDIS_URL) -}} +{{ fail (printf "redis.auth.password is set, which is only supported on the self-managed path. Choose one of:\n 1. Leave redis.auth.password unset and let the chart bootstrap a password (default), or supply your own secret via redis.auth.existingSecret / redis.auth.existingSecretPasswordKey.\n 2. Self-manage the password: set redis.auth.password, set redis.auth.existingSecret: \"\", and set applicationConfig.APPSMITH_REDIS_URL=redis://:@%s-redis-master:6379 so the app uses the same credential." .Release.Name) }} +{{- end -}} +{{- end -}} +{{- end -}} + {{/* Redis: master service hostname (FQDN inside the cluster). Derived from the release name to stay uniform with the chart's other components. diff --git a/deploy/helm/templates/configMap.yaml b/deploy/helm/templates/configMap.yaml index 0f633731344..91dd5c66f12 100644 --- a/deploy/helm/templates/configMap.yaml +++ b/deploy/helm/templates/configMap.yaml @@ -6,6 +6,7 @@ {{- $postgresqlPassword := .Values.postgresql.auth.password -}} {{- $postgresqlDatabase := .Values.postgresql.auth.database -}} {{- $releaseName := .Release.Name -}} +{{- include "appsmith.validateRedisAuth" . -}} apiVersion: v1 kind: ConfigMap metadata: diff --git a/deploy/helm/templates/hooks/redis.yaml b/deploy/helm/templates/hooks/redis.yaml index 30b9231e75b..43e507bc463 100644 --- a/deploy/helm/templates/hooks/redis.yaml +++ b/deploy/helm/templates/hooks/redis.yaml @@ -14,7 +14,16 @@ secret (or a user who pre-created their own) is left untouched. The resulting Secret has no Helm release labels/annotations and no ownerReferences, so ArgoCD does not track or diff it. */}} -{{- if and .Values.redis.enabled .Values.redis.auth.enabled }} +{{/* +Skip the bootstrap entirely when redis.auth.password is set: on that path the +operator self-manages the credential (Bitnami uses redis.auth.password directly) +and there is no chart secret to create. Safe ONLY because appsmith.validateRedisAuth +(see _helpers.tpl, invoked from configMap.yaml) rejects every redis.auth.password +configuration except the self-managed one (existingSecret: "" + a matching +APPSMITH_REDIS_URL) — so this can no longer leave a non-empty existingSecret +pointing at a secret the hook never creates. +*/}} +{{- if and .Values.redis.enabled .Values.redis.auth.enabled (not .Values.redis.auth.password) }} {{- $secretName := include "appsmith.redisSecretName" . -}} {{- $passwordKey := .Values.redis.auth.existingSecretPasswordKey -}} {{- $jobName := printf "%s-redis-password-init" (include "appsmith.fullname" .) | trunc 63 | trimSuffix "-" -}} From 319b4c7c53e7fc7c148006c93177ccbe2dd9f2ca Mon Sep 17 00:00:00 2001 From: Wyatt Walter Date: Wed, 24 Jun 2026 22:05:35 +0000 Subject: [PATCH 2/4] fix(helm): skip redis-init-container REDISCLI_AUTH on self-managed password path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The redis readiness init-container pulled REDISCLI_AUTH from the chart-managed Redis Secret whenever redis.auth.enabled. On the self-managed redis.auth.password path (existingSecret:"" + APPSMITH_REDIS_URL, the only path the new guard allows) no chart Secret exists — the bootstrap hook is skipped and Bitnami stores the password under its own -redis Secret — so the secretKeyRef was unresolvable and wedged the pod in CreateContainerConfigError. Caught by the live upgrade test, not the render matrix (helm template can't see the missing Secret). Gate REDISCLI_AUTH on the same (not applicationConfig.APPSMITH_REDIS_URL) condition the main container already uses for its Redis env. The wait still works without auth: `redis-cli ping` against an auth-required server replies NOAUTH but exits 0. Default and BYO-secret paths keep REDISCLI_AUTH (URL unset there). Co-Authored-By: Claude Opus 4.8 (1M context) --- deploy/helm/templates/deployment.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/deploy/helm/templates/deployment.yaml b/deploy/helm/templates/deployment.yaml index c45c8891f31..dc5a8c11122 100644 --- a/deploy/helm/templates/deployment.yaml +++ b/deploy/helm/templates/deployment.yaml @@ -80,7 +80,13 @@ spec: image: "{{ .Values.redis.image.registry }}/{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}" {{- end }} command: ['sh', '-c', "until redis-cli -h {{ include "appsmith.redisMasterHost" . }} ping ; do echo waiting for redis; sleep 2; done"] - {{- if .Values.redis.auth.enabled }} + {{- if and .Values.redis.auth.enabled (not .Values.applicationConfig.APPSMITH_REDIS_URL) }} + # Pull the password from the chart-managed Secret so the readiness ping can + # authenticate. Skipped when the operator supplies their own APPSMITH_REDIS_URL + # (the self-managed redis.auth.password path), because then no chart Secret exists + # to reference and an unresolvable secretKeyRef would wedge the pod in + # CreateContainerConfigError. The wait still works unauthenticated: `redis-cli ping` + # against an auth-required server replies NOAUTH but exits 0, satisfying the loop. env: - name: REDISCLI_AUTH valueFrom: From d279beaa4b68ac3c39aab636f60f6a5fca5318e3 Mon Sep 17 00:00:00 2001 From: Wyatt Walter Date: Wed, 24 Jun 2026 22:11:58 +0000 Subject: [PATCH 3/4] docs(helm): record redis.auth.password self-managed-path invariants in AGENTS.md Co-Authored-By: Claude Opus 4.8 (1M context) --- deploy/helm/AGENTS.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/deploy/helm/AGENTS.md b/deploy/helm/AGENTS.md index 18f9bb92ef7..790e4a452ce 100644 --- a/deploy/helm/AGENTS.md +++ b/deploy/helm/AGENTS.md @@ -26,3 +26,20 @@ Each documented value in `values.yaml` carries up to three comment layers (all p - `# @section -- Section Name` — helm-docs groups the value into a named section table When adding a new value, include at least the `# --` and `# @section --` lines so it lands in the correct README section. The `## @param` line is optional but preferred for consistency. + +## Redis auth + +`redis.auth.password` is a Bitnami subchart passthrough the Appsmith templates never read +directly. There is exactly ONE supported way to use it — fully self-managed: set +`redis.auth.password`, set `redis.auth.existingSecret: ""`, AND set +`applicationConfig.APPSMITH_REDIS_URL` so the app uses the same credential. Every other use +is rejected at render time by `appsmith.validateRedisAuth` (in `_helpers.tpl`, invoked from +`configMap.yaml` so it always evaluates). Leave the password unset for the default +(hook-bootstrapped secret) or BYO-secret paths. + +Gotcha worth remembering: `helm template` cannot catch the self-managed path's runtime hazard. +When a password is set the bootstrap hook is skipped, so the chart-managed Redis secret never +exists — any pod referencing it (e.g. the `redis-init-container`'s `REDISCLI_AUTH`) must also be +skipped on that path (gate on `not applicationConfig.APPSMITH_REDIS_URL`), or the pod wedges in +`CreateContainerConfigError`. The init-container readiness ping needs no auth regardless: +`redis-cli ping` against an auth-required server replies `NOAUTH` but exits 0, satisfying the wait. From f175f918ec6682e66f37cf5ca954a898af3ed3a0 Mon Sep 17 00:00:00 2001 From: Wyatt Walter Date: Thu, 25 Jun 2026 13:34:02 +0000 Subject: [PATCH 4/4] Revert "docs(helm): record redis.auth.password self-managed-path invariants in AGENTS.md" This reverts commit d279beaa4b68ac3c39aab636f60f6a5fca5318e3. --- deploy/helm/AGENTS.md | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/deploy/helm/AGENTS.md b/deploy/helm/AGENTS.md index 790e4a452ce..18f9bb92ef7 100644 --- a/deploy/helm/AGENTS.md +++ b/deploy/helm/AGENTS.md @@ -26,20 +26,3 @@ Each documented value in `values.yaml` carries up to three comment layers (all p - `# @section -- Section Name` — helm-docs groups the value into a named section table When adding a new value, include at least the `# --` and `# @section --` lines so it lands in the correct README section. The `## @param` line is optional but preferred for consistency. - -## Redis auth - -`redis.auth.password` is a Bitnami subchart passthrough the Appsmith templates never read -directly. There is exactly ONE supported way to use it — fully self-managed: set -`redis.auth.password`, set `redis.auth.existingSecret: ""`, AND set -`applicationConfig.APPSMITH_REDIS_URL` so the app uses the same credential. Every other use -is rejected at render time by `appsmith.validateRedisAuth` (in `_helpers.tpl`, invoked from -`configMap.yaml` so it always evaluates). Leave the password unset for the default -(hook-bootstrapped secret) or BYO-secret paths. - -Gotcha worth remembering: `helm template` cannot catch the self-managed path's runtime hazard. -When a password is set the bootstrap hook is skipped, so the chart-managed Redis secret never -exists — any pod referencing it (e.g. the `redis-init-container`'s `REDISCLI_AUTH`) must also be -skipped on that path (gate on `not applicationConfig.APPSMITH_REDIS_URL`), or the pod wedges in -`CreateContainerConfigError`. The init-container readiness ping needs no auth regardless: -`redis-cli ping` against an auth-required server replies `NOAUTH` but exits 0, satisfying the wait.