From d1f474819caae532e5500dcc51dcdd061964c75a Mon Sep 17 00:00:00 2001 From: ThullyoCunha Date: Fri, 24 Apr 2026 10:59:41 -0300 Subject: [PATCH] fix(helm): expand CLICKHOUSE_PASSWORD in webapp CLICKHOUSE_URL via kubelet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When clickhouse.external.existingSecret is set, the chart rendered the CLICKHOUSE_URL env var with a literal shell-style ${CLICKHOUSE_PASSWORD} placeholder, expecting bash to expand it at container start. But docker/scripts/entrypoint.sh hands the value straight to goose with a single-pass sh expansion (export GOOSE_DBSTRING="$CLICKHOUSE_URL"), so the inner ${...} reaches goose as literal text and breaks the ClickHouse migration: goose run: parse "http://default:${CLICKHOUSE_PASSWORD}@host:8123?secure=false": net/url: invalid userinfo Switch to Kubernetes' $(VAR) syntax in both clickhouse URL helpers. Kubelet substitutes $(CLICKHOUSE_PASSWORD) at container-creation time from the CLICKHOUSE_PASSWORD env var the chart already sets just before CLICKHOUSE_URL, so the URL arrives at the entrypoint with the real password already inlined — no entrypoint change needed, works for any container image / shell. The plain-password branch (no existingSecret) is unchanged. Operator caveat: CLICKHOUSE_PASSWORD must be URL-userinfo-safe because kubelet substitutes verbatim without percent-encoding. Hex-encoded passwords (e.g. openssl rand -hex 32) are safe by construction. --- hosting/k8s/helm/templates/_helpers.tpl | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/hosting/k8s/helm/templates/_helpers.tpl b/hosting/k8s/helm/templates/_helpers.tpl index 0990151808..8615a34e0a 100644 --- a/hosting/k8s/helm/templates/_helpers.tpl +++ b/hosting/k8s/helm/templates/_helpers.tpl @@ -400,6 +400,19 @@ ClickHouse hostname {{/* ClickHouse URL for application (with secure parameter) + +Note on the external+existingSecret branch: the password is expanded via +Kubernetes' `$(VAR)` syntax, not shell `${VAR}`. Kubelet substitutes +`$(CLICKHOUSE_PASSWORD)` at container-creation time from the +CLICKHOUSE_PASSWORD env var declared just before CLICKHOUSE_URL in +webapp.yaml. Shell-style `${...}` does not work here because +`docker/scripts/entrypoint.sh` assigns CLICKHOUSE_URL to GOOSE_DBSTRING +with a single-pass expansion (`export GOOSE_DBSTRING="$CLICKHOUSE_URL"`), +so any inner `${...}` reaches goose verbatim and fails URL parsing. + +CLICKHOUSE_PASSWORD must contain only URL-userinfo-safe characters — the +value is substituted verbatim, so `@ : / ? # [ ] %` break the URL. Use a +hex-encoded password or percent-encode before storing in the Secret. */}} {{- define "trigger-v4.clickhouse.url" -}} {{- if .Values.clickhouse.deploy -}} @@ -410,7 +423,7 @@ ClickHouse URL for application (with secure parameter) {{- $protocol := ternary "https" "http" .Values.clickhouse.external.secure -}} {{- $secure := ternary "true" "false" .Values.clickhouse.external.secure -}} {{- if .Values.clickhouse.external.existingSecret -}} -{{ $protocol }}://{{ .Values.clickhouse.external.username }}:${CLICKHOUSE_PASSWORD}@{{ .Values.clickhouse.external.host }}:{{ .Values.clickhouse.external.httpPort | default 8123 }}?secure={{ $secure }} +{{ $protocol }}://{{ .Values.clickhouse.external.username }}:$(CLICKHOUSE_PASSWORD)@{{ .Values.clickhouse.external.host }}:{{ .Values.clickhouse.external.httpPort | default 8123 }}?secure={{ $secure }} {{- else -}} {{ $protocol }}://{{ .Values.clickhouse.external.username }}:{{ .Values.clickhouse.external.password }}@{{ .Values.clickhouse.external.host }}:{{ .Values.clickhouse.external.httpPort | default 8123 }}?secure={{ $secure }} {{- end -}} @@ -419,6 +432,9 @@ ClickHouse URL for application (with secure parameter) {{/* ClickHouse URL for replication (without secure parameter) + +See the note on clickhouse.url above — same `$(VAR)` vs `${VAR}` rationale +applies to the replication URL. */}} {{- define "trigger-v4.clickhouse.replication.url" -}} {{- if .Values.clickhouse.deploy -}} @@ -427,7 +443,7 @@ ClickHouse URL for replication (without secure parameter) {{- else if .Values.clickhouse.external.host -}} {{- $protocol := ternary "https" "http" .Values.clickhouse.external.secure -}} {{- if .Values.clickhouse.external.existingSecret -}} -{{ $protocol }}://{{ .Values.clickhouse.external.username }}:${CLICKHOUSE_PASSWORD}@{{ .Values.clickhouse.external.host }}:{{ .Values.clickhouse.external.httpPort | default 8123 }} +{{ $protocol }}://{{ .Values.clickhouse.external.username }}:$(CLICKHOUSE_PASSWORD)@{{ .Values.clickhouse.external.host }}:{{ .Values.clickhouse.external.httpPort | default 8123 }} {{- else -}} {{ $protocol }}://{{ .Values.clickhouse.external.username }}:{{ .Values.clickhouse.external.password }}@{{ .Values.clickhouse.external.host }}:{{ .Values.clickhouse.external.httpPort | default 8123 }} {{- end -}}