codeant-ai-for-open-source[bot] commented on code in PR #41777:
URL: https://github.com/apache/superset/pull/41777#discussion_r3524887189


##########
helm/superset/templates/_helpers.tpl:
##########
@@ -105,80 +106,560 @@ app.kubernetes.io/component: {{ .component }}
 {{- end -}}
 
 
-{{- define "superset-config" }}
+{{/*
+Coalescing resolvers for DB and Redis connection parameters.
+Each resolver checks (in order):
+  1. New top-level database.* / cache.* values
+  2. Legacy supersetNode.connections.* keys (deprecation path, using safe 
index to avoid errors on absent maps)
+  3. cluster.* service name overrides
+  4. Hard-coded defaults derived from the release name
+Call with root context: {{ include "superset.db.host" . }}
+*/}}
+
+{{/*
+Helper to safely read .Values.supersetNode.connections.<key> without erroring 
when maps are absent.
+*/}}
+{{- define "_superset.legacyConn" -}}
+{{- $sn := index .Values "supersetNode" | default dict -}}
+{{- $conn := index $sn "connections" | default dict -}}
+{{- $conn | toJson -}}
+{{- end -}}
+
+{{- define "superset.db.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.database.host (index $conn "db_host") 
.Values.cluster.databaseServiceName (printf "%s-postgresql" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.db.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.database.port -}}
+{{- .Values.database.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "db_port") "5432" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.db.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.user (index $conn "db_user") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.password (index $conn "db_pass") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.name" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.name (index $conn "db_name") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.driver" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.driver (index $conn "db_type") 
"postgresql+psycopg2" -}}
+{{- end -}}
+
+{{- define "superset.redis.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.cache.host (index $conn "redis_host") 
.Values.cluster.redisServiceName (printf "%s-redis-headless" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.redis.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.cache.port -}}
+{{- .Values.cache.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "redis_port") "6379" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.redis.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.user (index $conn "redis_user") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.password (index $conn "redis_password") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.cacheDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.cacheDb | toString) (index $conn "redis_cache_db") 
"1" -}}
+{{- end -}}
+
+{{- define "superset.redis.celeryDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.celeryDb | toString) (index $conn 
"redis_celery_db") "0" -}}
+{{- end -}}
+
+{{- define "superset.redis.proto" -}}
+{{- if .Values.cache.driver }}{{ .Values.cache.driver }}{{- else if 
.Values.cache.ssl.enabled }}rediss{{- else }}redis{{- end -}}
+{{- end -}}
+
+{{- define "superset.config" }}
+{{- /* SECURITY: Validate admin password is set if admin creation is enabled 
*/}}
+{{- if and .Values.init.createAdmin (or (not .Values.init.adminUser.password) 
(eq .Values.init.adminUser.password "")) }}
+{{- fail "SECURITY ERROR: init.createAdmin is true but init.adminUser.password 
is empty. You must set a secure password using --set 
init.adminUser.password='your-password' or via external secret." }}
+{{- end }}
+
 import os
+{{- if or .Values.config.cacheConfig .Values.config.dataCacheConfig 
.Values.config.resultsBackend .Values.config.celeryConfig .Values.cache.enabled 
}}
 from flask_caching.backends.rediscache import RedisCache
+{{- end }}
 
 def env(key, default=None):
     return os.getenv(key, default)
 
-# Redis Base URL
-{{- if .Values.supersetNode.connections.redis_password }}
-REDIS_BASE_URL=f"{env('REDIS_DRIVER') or 
env('REDIS_PROTO')}://{env('REDIS_USER', 
'')}:{env('REDIS_PASSWORD')}@{env('REDIS_HOST')}:{env('REDIS_PORT')}"
+{{- /* Database Configuration - Superset always requires a database */}}
+{{- if .Values.database.uri }}
+SQLALCHEMY_DATABASE_URI = {{ .Values.database.uri | quote }}
+{{- else }}
+{{- $driver := include "superset.db.driver" . }}
+{{- $sslParams := "" }}
+{{- if and (hasKey .Values.database "ssl") .Values.database.ssl.enabled }}
+{{- $sslMode := .Values.database.ssl.mode | default "require" }}
+{{- $sslParams = printf "?sslmode=%s" $sslMode }}
+{{- end }}
+SQLALCHEMY_DATABASE_URI = f"{{ $driver }}://{{ include "superset.db.user" . 
}}:{{ include "superset.db.password" . }}@{{ include "superset.db.host" . }}:{{ 
include "superset.db.port" . }}/{{ include "superset.db.name" . }}{{ $sslParams 
}}"
+{{- end }}
+{{- if hasKey .Values.config "SQLALCHEMY_TRACK_MODIFICATIONS" }}
+SQLALCHEMY_TRACK_MODIFICATIONS = {{ 
.Values.config.SQLALCHEMY_TRACK_MODIFICATIONS | lower }}

Review Comment:
   **Suggestion:** The generated Python uses lowercase boolean literals for 
this setting, but Python requires `True`/`False`. If users set this value, 
`superset_config.py` will fail to import with a `NameError` at startup. Render 
booleans using Python casing instead of piping through `lower`. [type error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Superset config import fails; web server does not start.
   - ⚠️ Helm deployment pods enter crashloop due to invalid configuration.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. Install the Helm chart in `helm/superset`, which renders
   `secret-superset-config.yaml:29-34` and uses `{{- include "superset.config" 
. }}` to
   generate the `superset_config.py` payload from `_helpers.tpl:200-671`.
   
   2. Set `.Values.config.SQLALCHEMY_TRACK_MODIFICATIONS` to `true` or `"True"` 
in your
   release values (documented as a generic config override in 
`helm/superset/README.md:30`),
   so `_helpers.tpl:226-227` renders `SQLALCHEMY_TRACK_MODIFICATIONS = true` 
into
   `superset_config.py`.
   
   3. Start Superset; `superset/config.py:2931-2952` checks 
`SUPERSET_CONFIG_PATH` (or falls
   back to importing `superset_config`) and executes the generated 
`superset_config.py`
   module via `importlib.util.spec_from_file_location`.
   
   4. During module execution, Python evaluates `SQLALCHEMY_TRACK_MODIFICATIONS 
= true` from
   `superset_config.py`, raising `NameError` because `true` is undefined, 
causing the config
   import to fail and preventing the Superset application from starting.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=4aa0a274d08849dabe3ecc566174cf58&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=4aa0a274d08849dabe3ecc566174cf58&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** helm/superset/templates/_helpers.tpl
   **Line:** 227:227
   **Comment:**
        *Type Error: The generated Python uses lowercase boolean literals for 
this setting, but Python requires `True`/`False`. If users set this value, 
`superset_config.py` will fail to import with a `NameError` at startup. Render 
booleans using Python casing instead of piping through `lower`.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=09aa860e06ff2ef4ff9bf2db39152e05e490aac2787736f6720e3203714895ad&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=09aa860e06ff2ef4ff9bf2db39152e05e490aac2787736f6720e3203714895ad&reaction=dislike'>πŸ‘Ž</a>



##########
helm/superset/templates/_helpers.tpl:
##########
@@ -105,80 +106,560 @@ app.kubernetes.io/component: {{ .component }}
 {{- end -}}
 
 
-{{- define "superset-config" }}
+{{/*
+Coalescing resolvers for DB and Redis connection parameters.
+Each resolver checks (in order):
+  1. New top-level database.* / cache.* values
+  2. Legacy supersetNode.connections.* keys (deprecation path, using safe 
index to avoid errors on absent maps)
+  3. cluster.* service name overrides
+  4. Hard-coded defaults derived from the release name
+Call with root context: {{ include "superset.db.host" . }}
+*/}}
+
+{{/*
+Helper to safely read .Values.supersetNode.connections.<key> without erroring 
when maps are absent.
+*/}}
+{{- define "_superset.legacyConn" -}}
+{{- $sn := index .Values "supersetNode" | default dict -}}
+{{- $conn := index $sn "connections" | default dict -}}
+{{- $conn | toJson -}}
+{{- end -}}
+
+{{- define "superset.db.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.database.host (index $conn "db_host") 
.Values.cluster.databaseServiceName (printf "%s-postgresql" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.db.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.database.port -}}
+{{- .Values.database.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "db_port") "5432" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.db.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.user (index $conn "db_user") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.password (index $conn "db_pass") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.name" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.name (index $conn "db_name") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.driver" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.driver (index $conn "db_type") 
"postgresql+psycopg2" -}}
+{{- end -}}
+
+{{- define "superset.redis.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.cache.host (index $conn "redis_host") 
.Values.cluster.redisServiceName (printf "%s-redis-headless" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.redis.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.cache.port -}}
+{{- .Values.cache.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "redis_port") "6379" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.redis.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.user (index $conn "redis_user") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.password (index $conn "redis_password") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.cacheDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.cacheDb | toString) (index $conn "redis_cache_db") 
"1" -}}
+{{- end -}}
+
+{{- define "superset.redis.celeryDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.celeryDb | toString) (index $conn 
"redis_celery_db") "0" -}}
+{{- end -}}
+
+{{- define "superset.redis.proto" -}}
+{{- if .Values.cache.driver }}{{ .Values.cache.driver }}{{- else if 
.Values.cache.ssl.enabled }}rediss{{- else }}redis{{- end -}}
+{{- end -}}
+
+{{- define "superset.config" }}
+{{- /* SECURITY: Validate admin password is set if admin creation is enabled 
*/}}
+{{- if and .Values.init.createAdmin (or (not .Values.init.adminUser.password) 
(eq .Values.init.adminUser.password "")) }}
+{{- fail "SECURITY ERROR: init.createAdmin is true but init.adminUser.password 
is empty. You must set a secure password using --set 
init.adminUser.password='your-password' or via external secret." }}
+{{- end }}
+
 import os
+{{- if or .Values.config.cacheConfig .Values.config.dataCacheConfig 
.Values.config.resultsBackend .Values.config.celeryConfig .Values.cache.enabled 
}}
 from flask_caching.backends.rediscache import RedisCache
+{{- end }}
 
 def env(key, default=None):
     return os.getenv(key, default)
 
-# Redis Base URL
-{{- if .Values.supersetNode.connections.redis_password }}
-REDIS_BASE_URL=f"{env('REDIS_DRIVER') or 
env('REDIS_PROTO')}://{env('REDIS_USER', 
'')}:{env('REDIS_PASSWORD')}@{env('REDIS_HOST')}:{env('REDIS_PORT')}"
+{{- /* Database Configuration - Superset always requires a database */}}
+{{- if .Values.database.uri }}
+SQLALCHEMY_DATABASE_URI = {{ .Values.database.uri | quote }}
+{{- else }}
+{{- $driver := include "superset.db.driver" . }}
+{{- $sslParams := "" }}
+{{- if and (hasKey .Values.database "ssl") .Values.database.ssl.enabled }}
+{{- $sslMode := .Values.database.ssl.mode | default "require" }}
+{{- $sslParams = printf "?sslmode=%s" $sslMode }}
+{{- end }}
+SQLALCHEMY_DATABASE_URI = f"{{ $driver }}://{{ include "superset.db.user" . 
}}:{{ include "superset.db.password" . }}@{{ include "superset.db.host" . }}:{{ 
include "superset.db.port" . }}/{{ include "superset.db.name" . }}{{ $sslParams 
}}"
+{{- end }}
+{{- if hasKey .Values.config "SQLALCHEMY_TRACK_MODIFICATIONS" }}
+SQLALCHEMY_TRACK_MODIFICATIONS = {{ 
.Values.config.SQLALCHEMY_TRACK_MODIFICATIONS | lower }}
 {{- else }}
-REDIS_BASE_URL=f"{env('REDIS_DRIVER') or 
env('REDIS_PROTO')}://{env('REDIS_HOST')}:{env('REDIS_PORT')}"
+SQLALCHEMY_TRACK_MODIFICATIONS = False
 {{- end }}
 
-# Redis URL Params
-{{- if .Values.supersetNode.connections.redis_ssl.enabled }}
-REDIS_URL_PARAMS = f"?ssl_cert_reqs={env('REDIS_SSL_CERT_REQS')}"
+{{- /* Redis Configuration - only if Redis cache is configured */}}
+{{- if .Values.cache.enabled }}
+{{- if .Values.cache.cacheUrl }}
+CACHE_REDIS_URL = {{ .Values.cache.cacheUrl | quote }}
+{{- else }}
+{{- $redisHost := include "superset.redis.host" . }}
+{{- $redisUser := include "superset.redis.user" . }}
+{{- $redisPort := include "superset.redis.port" . }}
+{{- $redisPassword := include "superset.redis.password" . }}
+{{- $useSSL := and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+{{- if $redisPassword }}
+{{- if $redisUser }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://{{ $redisUser 
}}:{{ $redisPassword }}@{{ $redisHost }}:{{ $redisPort }}"
+{{- else }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://:{{ $redisPassword 
}}@{{ $redisHost }}:{{ $redisPort }}"
+{{- end }}
+{{- else }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://{{ $redisHost 
}}:{{ $redisPort }}"
+{{- end }}
+{{- if $useSSL }}
+{{- $sslCertReqs := .Values.cache.ssl.ssl_cert_reqs | default "required" }}
+REDIS_URL_PARAMS = f"?ssl_cert_reqs={{ $sslCertReqs }}"
 {{- else }}
 REDIS_URL_PARAMS = ""
-{{- end}}
-
-# Build Redis URLs
-CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_DB', 1)}{REDIS_URL_PARAMS}"
-CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_CELERY_DB', 
0)}{REDIS_URL_PARAMS}"
+{{- end }}
+{{- $cacheDb := include "superset.redis.cacheDb" . }}
+CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{{ $cacheDb }}{REDIS_URL_PARAMS}"
+{{- end }}
+{{- if .Values.cache.celeryUrl }}
+CELERY_REDIS_URL = {{ .Values.cache.celeryUrl | quote }}
+{{- else if not .Values.cache.cacheUrl }}
+{{- $celeryDb := include "superset.redis.celeryDb" . }}
+CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{{ $celeryDb }}{REDIS_URL_PARAMS}"
+{{- else }}
+{{- if or .Values.config.celeryConfig (not .Values.cache.enabled) }}
+{{- /* Custom celeryConfig provided or cache disabled - OK */}}
+{{- else }}
+{{- fail "CONFIGURATION ERROR: cache.cacheUrl is set but cache.celeryUrl is 
not set. When using cacheUrl, you must also set celeryUrl for Celery to work. 
Alternatively, set config.celeryConfig to provide a custom Celery 
configuration." }}
+{{- end }}
+{{- end }}
+{{- end }}
 
-MAPBOX_API_KEY = env('MAPBOX_API_KEY', '')
+{{- /* Cache Configuration */}}
+{{- if .Values.config.cacheConfig }}
+CACHE_CONFIG = {{ .Values.config.cacheConfig | toJson | indent 2 }}
+{{- else if .Values.cache.enabled }}
 CACHE_CONFIG = {
-      'CACHE_TYPE': 'RedisCache',
-      'CACHE_DEFAULT_TIMEOUT': 300,
-      'CACHE_KEY_PREFIX': 'superset_',
-      'CACHE_REDIS_URL': CACHE_REDIS_URL,
+    'CACHE_TYPE': 'RedisCache',
+    'CACHE_DEFAULT_TIMEOUT': {{ .Values.cache.defaultTimeout | default 
(.Values.config.cacheDefaultTimeout | default 86400) | int }},
+    'CACHE_KEY_PREFIX': {{ .Values.cache.keyPrefix | default "superset_" | 
quote }},
+    'CACHE_REDIS_URL': CACHE_REDIS_URL,
 }
+{{- end }}
+
+{{- if .Values.config.dataCacheConfig }}
+DATA_CACHE_CONFIG = {{ .Values.config.dataCacheConfig | toJson | indent 2 }}
+{{- else if .Values.config.cacheConfig }}
+DATA_CACHE_CONFIG = CACHE_CONFIG
+{{- else if .Values.cache.enabled }}
 DATA_CACHE_CONFIG = CACHE_CONFIG
+{{- end }}
 
+{{- /* SQLLAB_ASYNC_TIME_LIMIT_SEC - Required for async_queries module import 
(default: 6 hours) */}}
+{{- if .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC }}
+SQLLAB_ASYNC_TIME_LIMIT_SEC = {{ .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC | 
int }}
+{{- else }}
+from datetime import timedelta
+SQLLAB_ASYNC_TIME_LIMIT_SEC = int(timedelta(hours=6).total_seconds())
+{{- end }}
 
-if os.getenv("SQLALCHEMY_DATABASE_URI"):
-    SQLALCHEMY_DATABASE_URI = os.getenv("SQLALCHEMY_DATABASE_URI")
-else:
-    {{- if eq .Values.supersetNode.connections.db_type "postgresql" }}
-    SQLALCHEMY_DATABASE_URI = 
f"postgresql+psycopg2://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
-    {{- else if eq .Values.supersetNode.connections.db_type "mysql" }}
-    SQLALCHEMY_DATABASE_URI = 
f"mysql+mysqldb://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
-    {{- else }}
-    {{ fail (printf "Unsupported database type: %s. Please use 'postgresql' or 
'mysql'." .Values.supersetNode.connections.db_type) }}
-    {{- end }}
+{{- /* Celery Configuration */}}
+{{- if .Values.config.celeryConfig }}
+{{- if kindIs "string" .Values.config.celeryConfig }}
+{{ .Values.config.celeryConfig }}
+{{- else }}
+class CeleryConfig:
+{{- range $key, $value := .Values.config.celeryConfig }}
+    {{ $key }} = {{ $value | toJson }}
+{{- end }}
+
+CELERY_IMPORTS = CeleryConfig.imports

Review Comment:
   **Suggestion:** This assumes every custom CeleryConfig defines an `imports` 
attribute; if users provide a minimal config without it, config import raises 
`AttributeError` and workers fail to start. Only assign this when `imports` 
exists or use a safe default. [api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Superset config import crashes if CeleryConfig lacks imports.
   - ❌ Celery workers fail starting; background tasks never execute.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. Configure a custom Celery settings map in Helm by setting 
`.Values.config.celeryConfig`
   in `helm/superset/values.yaml` to a YAML object containing keys like 
`broker_url` and
   `result_backend`, but not defining an `imports` key.
   
   2. When `secret-superset-config.yaml:29-34` renders, `_helpers.tpl:302-314` 
detects
   `.Values.config.celeryConfig` and, since `kindIs "string"` is false, emits a 
`class
   CeleryConfig:` with one attribute per key in the map; no `imports` attribute 
is generated
   unless the user provided it.
   
   3. Immediately after, `_helpers.tpl:312` writes `CELERY_IMPORTS = 
CeleryConfig.imports`
   and `CELERY_CONFIG = CeleryConfig` into `superset_config.py`, so the file 
contains an
   assignment accessing a non-existent `CeleryConfig.imports` attribute.
   
   4. On Superset startup, `superset/config.py:2931-2952` imports 
`superset_config` via
   `importlib.util.spec_from_file_location`; Python executes `CELERY_IMPORTS =
   CeleryConfig.imports`, raises `AttributeError` because `imports` is missing, 
and aborts
   config import, preventing Celery-based background workers (superset tasks 
like
   `superset.sql_lab` and schedulers) from starting properly.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=7c9e37accf5a4f9bbc3408477786ad2c&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=7c9e37accf5a4f9bbc3408477786ad2c&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** helm/superset/templates/_helpers.tpl
   **Line:** 312:312
   **Comment:**
        *Api Mismatch: This assumes every custom CeleryConfig defines an 
`imports` attribute; if users provide a minimal config without it, config 
import raises `AttributeError` and workers fail to start. Only assign this when 
`imports` exists or use a safe default.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=955747d165552f1837a91d98cc9bc175ce157f1d3c795689a340fd7c8882caad&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=955747d165552f1837a91d98cc9bc175ce157f1d3c795689a340fd7c8882caad&reaction=dislike'>πŸ‘Ž</a>



##########
helm/superset/templates/_helpers.tpl:
##########
@@ -105,80 +106,560 @@ app.kubernetes.io/component: {{ .component }}
 {{- end -}}
 
 
-{{- define "superset-config" }}
+{{/*
+Coalescing resolvers for DB and Redis connection parameters.
+Each resolver checks (in order):
+  1. New top-level database.* / cache.* values
+  2. Legacy supersetNode.connections.* keys (deprecation path, using safe 
index to avoid errors on absent maps)
+  3. cluster.* service name overrides
+  4. Hard-coded defaults derived from the release name
+Call with root context: {{ include "superset.db.host" . }}
+*/}}
+
+{{/*
+Helper to safely read .Values.supersetNode.connections.<key> without erroring 
when maps are absent.
+*/}}
+{{- define "_superset.legacyConn" -}}
+{{- $sn := index .Values "supersetNode" | default dict -}}
+{{- $conn := index $sn "connections" | default dict -}}
+{{- $conn | toJson -}}
+{{- end -}}
+
+{{- define "superset.db.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.database.host (index $conn "db_host") 
.Values.cluster.databaseServiceName (printf "%s-postgresql" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.db.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.database.port -}}
+{{- .Values.database.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "db_port") "5432" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.db.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.user (index $conn "db_user") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.password (index $conn "db_pass") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.name" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.name (index $conn "db_name") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.driver" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.driver (index $conn "db_type") 
"postgresql+psycopg2" -}}
+{{- end -}}
+
+{{- define "superset.redis.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.cache.host (index $conn "redis_host") 
.Values.cluster.redisServiceName (printf "%s-redis-headless" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.redis.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.cache.port -}}
+{{- .Values.cache.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "redis_port") "6379" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.redis.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.user (index $conn "redis_user") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.password (index $conn "redis_password") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.cacheDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.cacheDb | toString) (index $conn "redis_cache_db") 
"1" -}}
+{{- end -}}
+
+{{- define "superset.redis.celeryDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.celeryDb | toString) (index $conn 
"redis_celery_db") "0" -}}
+{{- end -}}
+
+{{- define "superset.redis.proto" -}}
+{{- if .Values.cache.driver }}{{ .Values.cache.driver }}{{- else if 
.Values.cache.ssl.enabled }}rediss{{- else }}redis{{- end -}}
+{{- end -}}
+
+{{- define "superset.config" }}
+{{- /* SECURITY: Validate admin password is set if admin creation is enabled 
*/}}
+{{- if and .Values.init.createAdmin (or (not .Values.init.adminUser.password) 
(eq .Values.init.adminUser.password "")) }}
+{{- fail "SECURITY ERROR: init.createAdmin is true but init.adminUser.password 
is empty. You must set a secure password using --set 
init.adminUser.password='your-password' or via external secret." }}
+{{- end }}
+
 import os
+{{- if or .Values.config.cacheConfig .Values.config.dataCacheConfig 
.Values.config.resultsBackend .Values.config.celeryConfig .Values.cache.enabled 
}}
 from flask_caching.backends.rediscache import RedisCache
+{{- end }}
 
 def env(key, default=None):
     return os.getenv(key, default)
 
-# Redis Base URL
-{{- if .Values.supersetNode.connections.redis_password }}
-REDIS_BASE_URL=f"{env('REDIS_DRIVER') or 
env('REDIS_PROTO')}://{env('REDIS_USER', 
'')}:{env('REDIS_PASSWORD')}@{env('REDIS_HOST')}:{env('REDIS_PORT')}"
+{{- /* Database Configuration - Superset always requires a database */}}
+{{- if .Values.database.uri }}
+SQLALCHEMY_DATABASE_URI = {{ .Values.database.uri | quote }}
+{{- else }}
+{{- $driver := include "superset.db.driver" . }}
+{{- $sslParams := "" }}
+{{- if and (hasKey .Values.database "ssl") .Values.database.ssl.enabled }}
+{{- $sslMode := .Values.database.ssl.mode | default "require" }}
+{{- $sslParams = printf "?sslmode=%s" $sslMode }}
+{{- end }}
+SQLALCHEMY_DATABASE_URI = f"{{ $driver }}://{{ include "superset.db.user" . 
}}:{{ include "superset.db.password" . }}@{{ include "superset.db.host" . }}:{{ 
include "superset.db.port" . }}/{{ include "superset.db.name" . }}{{ $sslParams 
}}"
+{{- end }}
+{{- if hasKey .Values.config "SQLALCHEMY_TRACK_MODIFICATIONS" }}
+SQLALCHEMY_TRACK_MODIFICATIONS = {{ 
.Values.config.SQLALCHEMY_TRACK_MODIFICATIONS | lower }}
 {{- else }}
-REDIS_BASE_URL=f"{env('REDIS_DRIVER') or 
env('REDIS_PROTO')}://{env('REDIS_HOST')}:{env('REDIS_PORT')}"
+SQLALCHEMY_TRACK_MODIFICATIONS = False
 {{- end }}
 
-# Redis URL Params
-{{- if .Values.supersetNode.connections.redis_ssl.enabled }}
-REDIS_URL_PARAMS = f"?ssl_cert_reqs={env('REDIS_SSL_CERT_REQS')}"
+{{- /* Redis Configuration - only if Redis cache is configured */}}
+{{- if .Values.cache.enabled }}
+{{- if .Values.cache.cacheUrl }}
+CACHE_REDIS_URL = {{ .Values.cache.cacheUrl | quote }}
+{{- else }}
+{{- $redisHost := include "superset.redis.host" . }}
+{{- $redisUser := include "superset.redis.user" . }}
+{{- $redisPort := include "superset.redis.port" . }}
+{{- $redisPassword := include "superset.redis.password" . }}
+{{- $useSSL := and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+{{- if $redisPassword }}
+{{- if $redisUser }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://{{ $redisUser 
}}:{{ $redisPassword }}@{{ $redisHost }}:{{ $redisPort }}"
+{{- else }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://:{{ $redisPassword 
}}@{{ $redisHost }}:{{ $redisPort }}"
+{{- end }}
+{{- else }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://{{ $redisHost 
}}:{{ $redisPort }}"
+{{- end }}
+{{- if $useSSL }}
+{{- $sslCertReqs := .Values.cache.ssl.ssl_cert_reqs | default "required" }}
+REDIS_URL_PARAMS = f"?ssl_cert_reqs={{ $sslCertReqs }}"
 {{- else }}
 REDIS_URL_PARAMS = ""
-{{- end}}
-
-# Build Redis URLs
-CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_DB', 1)}{REDIS_URL_PARAMS}"
-CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_CELERY_DB', 
0)}{REDIS_URL_PARAMS}"
+{{- end }}
+{{- $cacheDb := include "superset.redis.cacheDb" . }}
+CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{{ $cacheDb }}{REDIS_URL_PARAMS}"
+{{- end }}
+{{- if .Values.cache.celeryUrl }}
+CELERY_REDIS_URL = {{ .Values.cache.celeryUrl | quote }}
+{{- else if not .Values.cache.cacheUrl }}
+{{- $celeryDb := include "superset.redis.celeryDb" . }}
+CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{{ $celeryDb }}{REDIS_URL_PARAMS}"
+{{- else }}
+{{- if or .Values.config.celeryConfig (not .Values.cache.enabled) }}
+{{- /* Custom celeryConfig provided or cache disabled - OK */}}
+{{- else }}
+{{- fail "CONFIGURATION ERROR: cache.cacheUrl is set but cache.celeryUrl is 
not set. When using cacheUrl, you must also set celeryUrl for Celery to work. 
Alternatively, set config.celeryConfig to provide a custom Celery 
configuration." }}
+{{- end }}
+{{- end }}
+{{- end }}
 
-MAPBOX_API_KEY = env('MAPBOX_API_KEY', '')
+{{- /* Cache Configuration */}}
+{{- if .Values.config.cacheConfig }}
+CACHE_CONFIG = {{ .Values.config.cacheConfig | toJson | indent 2 }}
+{{- else if .Values.cache.enabled }}
 CACHE_CONFIG = {
-      'CACHE_TYPE': 'RedisCache',
-      'CACHE_DEFAULT_TIMEOUT': 300,
-      'CACHE_KEY_PREFIX': 'superset_',
-      'CACHE_REDIS_URL': CACHE_REDIS_URL,
+    'CACHE_TYPE': 'RedisCache',
+    'CACHE_DEFAULT_TIMEOUT': {{ .Values.cache.defaultTimeout | default 
(.Values.config.cacheDefaultTimeout | default 86400) | int }},
+    'CACHE_KEY_PREFIX': {{ .Values.cache.keyPrefix | default "superset_" | 
quote }},
+    'CACHE_REDIS_URL': CACHE_REDIS_URL,
 }
+{{- end }}
+
+{{- if .Values.config.dataCacheConfig }}
+DATA_CACHE_CONFIG = {{ .Values.config.dataCacheConfig | toJson | indent 2 }}
+{{- else if .Values.config.cacheConfig }}
+DATA_CACHE_CONFIG = CACHE_CONFIG
+{{- else if .Values.cache.enabled }}
 DATA_CACHE_CONFIG = CACHE_CONFIG
+{{- end }}
 
+{{- /* SQLLAB_ASYNC_TIME_LIMIT_SEC - Required for async_queries module import 
(default: 6 hours) */}}
+{{- if .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC }}
+SQLLAB_ASYNC_TIME_LIMIT_SEC = {{ .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC | 
int }}
+{{- else }}
+from datetime import timedelta
+SQLLAB_ASYNC_TIME_LIMIT_SEC = int(timedelta(hours=6).total_seconds())
+{{- end }}
 
-if os.getenv("SQLALCHEMY_DATABASE_URI"):
-    SQLALCHEMY_DATABASE_URI = os.getenv("SQLALCHEMY_DATABASE_URI")
-else:
-    {{- if eq .Values.supersetNode.connections.db_type "postgresql" }}
-    SQLALCHEMY_DATABASE_URI = 
f"postgresql+psycopg2://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
-    {{- else if eq .Values.supersetNode.connections.db_type "mysql" }}
-    SQLALCHEMY_DATABASE_URI = 
f"mysql+mysqldb://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
-    {{- else }}
-    {{ fail (printf "Unsupported database type: %s. Please use 'postgresql' or 
'mysql'." .Values.supersetNode.connections.db_type) }}
-    {{- end }}
+{{- /* Celery Configuration */}}
+{{- if .Values.config.celeryConfig }}
+{{- if kindIs "string" .Values.config.celeryConfig }}
+{{ .Values.config.celeryConfig }}
+{{- else }}
+class CeleryConfig:
+{{- range $key, $value := .Values.config.celeryConfig }}
+    {{ $key }} = {{ $value | toJson }}
+{{- end }}
+
+CELERY_IMPORTS = CeleryConfig.imports
+CELERY_CONFIG = CeleryConfig
+{{- end }}
+{{- else if .Values.cache.enabled }}
+from celery.schedules import crontab
+from datetime import timedelta
 
 class CeleryConfig:
-  imports  = ("superset.sql_lab", )
-  broker_url = CELERY_REDIS_URL
-  result_backend = CELERY_REDIS_URL
+    imports = (
+        "superset.sql_lab",
+        "superset.tasks.scheduler",
+        "superset.tasks.thumbnails",
+        "superset.tasks.cache",
+    )
+    broker_connection_retry_on_startup = True
+    worker_prefetch_multiplier = 10
+    task_acks_late = True
+    broker_url = CELERY_REDIS_URL
+    result_backend = CELERY_REDIS_URL
+    task_annotations = {
+        "sql_lab.get_sql_results": {
+            "rate_limit": "100/s",
+        },
+    }
+    beat_schedule = {
+        "reports.scheduler": {
+            "task": "reports.scheduler",
+            "schedule": crontab(minute="*", hour="*"),
+            "options": {"expires": int(timedelta(weeks=1).total_seconds())},
+        },
+        "reports.prune_log": {
+            "task": "reports.prune_log",
+            "schedule": crontab(minute=0, hour=0),
+        },
+    }
 
+CELERY_IMPORTS = CeleryConfig.imports
 CELERY_CONFIG = CeleryConfig
+{{- end }}
+
+{{- /* Celery Worker Health Check - File-based health probes for Kubernetes 
*/}}
+{{- if and .Values.supersetWorker.healthCheck 
.Values.supersetWorker.healthCheck.enabled }}
+# Celery Worker Health Check Configuration
+import threading
+from celery import bootsteps
+from celery.signals import worker_ready, worker_shutdown, worker_init
+
+_readiness_file = {{ .Values.supersetWorker.healthCheck.readinessFile | 
default "/tmp/celery_worker_ready" | quote }}
+_liveness_file = {{ .Values.supersetWorker.healthCheck.livenessFile | default 
"/tmp/celery_worker_alive" | quote }}
+_heartbeat_interval = {{ 
.Values.supersetWorker.healthCheck.livenessHeartbeatInterval | default 10 | int 
}}
+_liveness_thread = None
+_liveness_stop_event = None
+
+@worker_ready.connect
+def create_ready_file(sender, **kwargs):
+    try:
+        open(_readiness_file, 'w').close()
+    except Exception as e:
+        print(f"Warning: Could not create readiness file: {e}")
+
+@worker_shutdown.connect
+def remove_ready_file(sender, **kwargs):
+    global _liveness_thread, _liveness_stop_event
+    if _liveness_stop_event:
+        _liveness_stop_event.set()
+    if _liveness_thread:
+        _liveness_thread.join(timeout=5)
+    try:
+        if os.path.exists(_readiness_file):
+            os.remove(_readiness_file)
+        if os.path.exists(_liveness_file):
+            os.remove(_liveness_file)
+    except Exception as e:
+        print(f"Warning: Could not remove health check files: {e}")
+
+@worker_init.connect
+def start_liveness_heartbeat(sender, **kwargs):
+    global _liveness_thread, _liveness_stop_event
+    _liveness_stop_event = threading.Event()
+
+    def update_liveness():
+        while not _liveness_stop_event.is_set():
+            try:
+                with open(_liveness_file, 'w') as f:
+                    f.write(str(os.getpid()))
+            except Exception as e:
+                print(f"Warning: Could not update liveness file: {e}")
+            _liveness_stop_event.wait(_heartbeat_interval)
+
+    _liveness_thread = threading.Thread(target=update_liveness, daemon=True)
+    _liveness_thread.start()
+{{- else }}
+CELERY_WORKER_HEALTH_CHECK_ENABLED = False
+{{- end }}
+
+{{- /* Results Backend */}}
+{{- $redisHostForBackend := include "superset.redis.host" . }}
+{{- $redisPortForBackend := include "superset.redis.port" . }}
+{{- $redisPasswordForBackend := include "superset.redis.password" . }}
+{{- if .Values.config.resultsBackend }}
+{{- if kindIs "string" .Values.config.resultsBackend }}
+RESULTS_BACKEND = {{ .Values.config.resultsBackend }}
+{{- else }}
+RESULTS_BACKEND = RedisCache(
+    host={{ $redisHostForBackend | quote }},
+    {{- if $redisPasswordForBackend }}
+    password={{ $redisPasswordForBackend | quote }},
+    {{- end }}
+    port={{ $redisPortForBackend | int }},
+    key_prefix={{ .Values.cache.resultsBackendKeyPrefix | default 
"superset_results" | quote }},
+    {{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+    ssl=True,
+    ssl_cert_reqs={{ .Values.cache.ssl.ssl_cert_reqs | default "required" | 
quote }},
+    {{- end }}
+)
+{{- end }}
+{{- else if .Values.cache.enabled }}
 RESULTS_BACKEND = RedisCache(
-      host=env('REDIS_HOST'),
-      {{- if .Values.supersetNode.connections.redis_password }}
-      password=env('REDIS_PASSWORD'),
-      {{- end }}
-      port=env('REDIS_PORT'),
-      key_prefix='superset_results',
-      {{- if .Values.supersetNode.connections.redis_ssl.enabled }}
-      ssl=True,
-      ssl_cert_reqs=env('REDIS_SSL_CERT_REQS'),
-      {{- end }}
+    host={{ $redisHostForBackend | quote }},
+    {{- if $redisPasswordForBackend }}
+    password={{ $redisPasswordForBackend | quote }},
+    {{- end }}
+    port={{ $redisPortForBackend | int }},
+    key_prefix={{ .Values.cache.resultsBackendKeyPrefix | default 
"superset_results" | quote }},
+    {{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+    ssl=True,
+    ssl_cert_reqs={{ .Values.cache.ssl.ssl_cert_reqs | default "required" | 
quote }},
+    {{- end }}
 )
+{{- end }}
+
+{{- /* Global Async Queries Cache Backend */}}
+{{- $redisUserForGaq := include "superset.redis.user" . }}
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_CACHE_BACKEND }}
+GLOBAL_ASYNC_QUERIES_CACHE_BACKEND = {{ 
.Values.config.GLOBAL_ASYNC_QUERIES_CACHE_BACKEND | toJson | indent 2 }}
+{{- else if .Values.cache.enabled }}
+GLOBAL_ASYNC_QUERIES_CACHE_BACKEND = {
+    "CACHE_TYPE": "RedisCache",
+    "CACHE_REDIS_HOST": {{ $redisHostForBackend | quote }},
+    "CACHE_REDIS_PORT": {{ $redisPortForBackend | int }},
+    "CACHE_REDIS_USER": {{ $redisUserForGaq | quote }},
+    {{- if $redisPasswordForBackend }}
+    "CACHE_REDIS_PASSWORD": {{ $redisPasswordForBackend | quote }},
+    {{- else }}
+    "CACHE_REDIS_PASSWORD": "",
+    {{- end }}
+    "CACHE_REDIS_DB": {{ .Values.cache.asyncQueries.db | default 
.Values.cache.cacheDb | default 0 | int }},
+    "CACHE_KEY_PREFIX": {{ .Values.cache.asyncQueries.keyPrefix | default 
"qc-" | quote }},
+    "CACHE_DEFAULT_TIMEOUT": {{ .Values.cache.asyncQueries.timeout | default 
86400 | int }},
+    {{- if .Values.cache.sentinel }}
+    {{- if .Values.cache.sentinel.sentinels }}
+    "CACHE_REDIS_SENTINELS": {{ .Values.cache.sentinel.sentinels | toJson }},
+    {{- else }}
+    {{- fail "CONFIGURATION ERROR: cache.sentinel.enabled is true but 
cache.sentinel.sentinels is not set. You must provide Sentinel host(s) in 
cache.sentinel.sentinels (e.g., [['sentinel-host', 26379]])." }}
+    {{- end }}
+    "CACHE_REDIS_SENTINEL_MASTER": {{ .Values.cache.sentinel.master | default 
"mymaster" | quote }},
+    {{- if .Values.cache.sentinel.password }}
+    "CACHE_REDIS_SENTINEL_PASSWORD": {{ .Values.cache.sentinel.password | 
quote }},
+    {{- else }}
+    "CACHE_REDIS_SENTINEL_PASSWORD": None,
+    {{- end }}
+    {{- end }}
+    {{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+    "CACHE_REDIS_SSL": True,
+    "CACHE_REDIS_SSL_CERTFILE": {{ .Values.cache.ssl.certfile | default "None" 
}},
+    "CACHE_REDIS_SSL_KEYFILE": {{ .Values.cache.ssl.keyfile | default "None" 
}},
+    "CACHE_REDIS_SSL_CERT_REQS": {{ .Values.cache.ssl.ssl_cert_reqs | default 
"required" | quote }},
+    "CACHE_REDIS_SSL_CA_CERTS": {{ .Values.cache.ssl.ca_certs | default "None" 
}},
+    {{- else }}
+    "CACHE_REDIS_SSL": False,
+    "CACHE_REDIS_SSL_CERTFILE": None,
+    "CACHE_REDIS_SSL_KEYFILE": None,
+    "CACHE_REDIS_SSL_CERT_REQS": {{ .Values.cache.ssl.ssl_cert_reqs | default 
"required" | quote }},
+    "CACHE_REDIS_SSL_CA_CERTS": None,
+    {{- end }}
+}
+{{- end }}
+
+{{- /* Global Async Queries Results Backend */}}
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND }}
+GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND = {{ 
.Values.config.GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND | toJson | indent 2 }}
+{{- else if .Values.cache.enabled }}
+GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND = {
+    "backend": "redis",
+    "host": {{ $redisHostForBackend | quote }},
+    "port": {{ $redisPortForBackend | int }},
+    "prefix": {{ .Values.cache.asyncQueries.keyPrefix | default "qc-" | quote 
}},
+    "db": {{ .Values.cache.asyncQueries.db | default .Values.cache.cacheDb | 
default 0 | int }},
+    {{- if $redisPasswordForBackend }}
+    "password": {{ $redisPasswordForBackend | quote }},
+    {{- end }}
+}
+{{- end }}
+
+{{- /* Feature Flags */}}
+{{- if .Values.featureFlags }}
+FEATURE_FLAGS = {
+{{- range $key, $value := .Values.featureFlags }}
+{{- if kindIs "bool" $value }}
+    "{{ $key }}": {{ if $value }}True{{ else }}False{{ end }},
+{{- else if kindIs "string" $value }}
+    "{{ $key }}": {{ $value | quote }},
+{{- else if kindIs "float64" $value }}
+    "{{ $key }}": {{ $value }},
+{{- else if kindIs "int" $value }}
+    "{{ $key }}": {{ $value }},
+{{- else }}
+    "{{ $key }}": {{ $value | toJson }},
+{{- end }}
+{{- end }}
+}
+{{- end }}
+
+{{- /* FAB Security API - Required for List Roles view in 6.0.0+ */}}
+{{- if not (hasKey .Values.config "FAB_ADD_SECURITY_API") }}
+FAB_ADD_SECURITY_API = True
+{{- end }}
+{{- if not (hasKey .Values.config "FAB_ADD_SECURITY_VIEWS") }}
+FAB_ADD_SECURITY_VIEWS = True
+{{- end }}
 
-{{ if .Values.configOverrides }}
-# Overrides
+{{- /* Global Async Queries Transport - Auto-configure for websockets if 
enabled */}}
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_TRANSPORT }}
+GLOBAL_ASYNC_QUERIES_TRANSPORT = {{ 
.Values.config.GLOBAL_ASYNC_QUERIES_TRANSPORT | quote }}
+{{- else if .Values.supersetWebsockets.enabled }}
+GLOBAL_ASYNC_QUERIES_TRANSPORT = "ws"
+{{- else }}
+GLOBAL_ASYNC_QUERIES_TRANSPORT = "polling"
+{{- end }}
+
+{{- /* Global Async Queries WebSocket URL */}}
+{{- $wsUrl := "" }}
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL }}
+{{- $wsUrl = .Values.config.GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL }}
+GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL = {{ $wsUrl | quote }}
+{{- else if and .Values.supersetWebsockets.enabled 
.Values.supersetWebsockets.websocketUrl }}
+{{- $wsUrl = .Values.supersetWebsockets.websocketUrl }}
+GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL = {{ $wsUrl | quote }}
+{{- else if .Values.supersetWebsockets.enabled }}
+{{- $wsServiceName := .Values.cluster.websocketServiceName }}
+{{- if not $wsServiceName }}
+{{- $wsServiceName = printf "%s-ws" (include "superset.fullname" .) }}
+{{- end }}
+{{- $wsPort := .Values.supersetWebsockets.service.port | default 8080 }}
+{{- $wsPath := "/ws" }}
+{{- $clusterDomain := .Values.cluster.domain | default ".svc.cluster.local" }}
+{{- $wsUrl = printf "ws://%s.%s%s:%d%s" $wsServiceName .Release.Namespace 
$clusterDomain $wsPort $wsPath }}
+GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL = {{ $wsUrl | quote }}
+{{- end }}
+
+{{- /* Global Async Queries JWT Secret */}}
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_JWT_SECRET }}
+GLOBAL_ASYNC_QUERIES_JWT_SECRET = {{ 
.Values.config.GLOBAL_ASYNC_QUERIES_JWT_SECRET | quote }}
+{{- else if and .Values.supersetWebsockets.enabled 
.Values.supersetWebsockets.config.jwtSecret }}
+GLOBAL_ASYNC_QUERIES_JWT_SECRET = {{ 
.Values.supersetWebsockets.config.jwtSecret | quote }}
+{{- end }}
+
+{{- /* Global Async Queries JWT Cookie Settings */}}
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE }}
+GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = {{ if 
.Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE }}True{{ else }}False{{ 
end }}
+{{- else if and .Values.supersetWebsockets.enabled (or (hasPrefix "wss://" 
$wsUrl) .Values.ingress.tls) }}
+GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = True

Review Comment:
   **Suggestion:** This condition checks truthiness instead of key presence, so 
an explicit `false` value is treated as β€œunset” and gets overwritten by 
auto-detection. That breaks user intent and can force secure-cookie behavior 
unexpectedly. Check with `hasKey` (or equivalent) before applying defaults. 
[falsy zero check]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ User-set JWT cookie secure flag silently overridden.
   - ⚠️ Configuration values behave unexpectedly under WebSocket TLS.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. Configure the Helm chart in `helm/superset/values.yaml` with
   `.Values.supersetWebsockets.enabled = true` and TLS (`.Values.ingress.tls` 
non-empty), and
   explicitly set `.Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = 
false`.
   
   2. When `secret-superset-config.yaml:29-34` renders, `_helpers.tpl:570-575` 
handles the
   value: the condition `if 
.Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE` treats the
   explicit `false` as falsy, so the template skips the user branch and enters 
the TLS
   branch, emitting `GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = True` into
   `superset_config.py`.
   
   3. Superset loads configuration via `superset/config.py:2931-2952`, importing
   `superset_config` and copying its uppercase settings (including
   `GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE`) into the main `superset.config` 
module and
   `app.config`.
   
   4. `superset/async_events/async_query_manager.py:150-151` reads
   `app.config["GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE"]` to configure the JWT 
cookie; the
   value is `True` because of auto-detection, ignoring the user’s explicit 
`False`, so
   secure-cookie behavior cannot be disabled as intended.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=ad7816c3ac344746974d4fa5d5675a9c&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=ad7816c3ac344746974d4fa5d5675a9c&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** helm/superset/templates/_helpers.tpl
   **Line:** 570:573
   **Comment:**
        *Falsy Zero Check: This condition checks truthiness instead of key 
presence, so an explicit `false` value is treated as β€œunset” and gets 
overwritten by auto-detection. That breaks user intent and can force 
secure-cookie behavior unexpectedly. Check with `hasKey` (or equivalent) before 
applying defaults.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=f5a95405cf3995c2780524a17f9df481cee24c130478c285e5a0134a6b7b3889&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=f5a95405cf3995c2780524a17f9df481cee24c130478c285e5a0134a6b7b3889&reaction=dislike'>πŸ‘Ž</a>



##########
helm/superset/templates/_helpers.tpl:
##########
@@ -105,80 +106,560 @@ app.kubernetes.io/component: {{ .component }}
 {{- end -}}
 
 
-{{- define "superset-config" }}
+{{/*
+Coalescing resolvers for DB and Redis connection parameters.
+Each resolver checks (in order):
+  1. New top-level database.* / cache.* values
+  2. Legacy supersetNode.connections.* keys (deprecation path, using safe 
index to avoid errors on absent maps)
+  3. cluster.* service name overrides
+  4. Hard-coded defaults derived from the release name
+Call with root context: {{ include "superset.db.host" . }}
+*/}}
+
+{{/*
+Helper to safely read .Values.supersetNode.connections.<key> without erroring 
when maps are absent.
+*/}}
+{{- define "_superset.legacyConn" -}}
+{{- $sn := index .Values "supersetNode" | default dict -}}
+{{- $conn := index $sn "connections" | default dict -}}
+{{- $conn | toJson -}}
+{{- end -}}
+
+{{- define "superset.db.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.database.host (index $conn "db_host") 
.Values.cluster.databaseServiceName (printf "%s-postgresql" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.db.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.database.port -}}
+{{- .Values.database.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "db_port") "5432" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.db.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.user (index $conn "db_user") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.password (index $conn "db_pass") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.name" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.name (index $conn "db_name") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.driver" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.driver (index $conn "db_type") 
"postgresql+psycopg2" -}}
+{{- end -}}
+
+{{- define "superset.redis.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.cache.host (index $conn "redis_host") 
.Values.cluster.redisServiceName (printf "%s-redis-headless" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.redis.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.cache.port -}}
+{{- .Values.cache.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "redis_port") "6379" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.redis.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.user (index $conn "redis_user") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.password (index $conn "redis_password") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.cacheDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.cacheDb | toString) (index $conn "redis_cache_db") 
"1" -}}
+{{- end -}}
+
+{{- define "superset.redis.celeryDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.celeryDb | toString) (index $conn 
"redis_celery_db") "0" -}}
+{{- end -}}
+
+{{- define "superset.redis.proto" -}}
+{{- if .Values.cache.driver }}{{ .Values.cache.driver }}{{- else if 
.Values.cache.ssl.enabled }}rediss{{- else }}redis{{- end -}}
+{{- end -}}
+
+{{- define "superset.config" }}
+{{- /* SECURITY: Validate admin password is set if admin creation is enabled 
*/}}
+{{- if and .Values.init.createAdmin (or (not .Values.init.adminUser.password) 
(eq .Values.init.adminUser.password "")) }}
+{{- fail "SECURITY ERROR: init.createAdmin is true but init.adminUser.password 
is empty. You must set a secure password using --set 
init.adminUser.password='your-password' or via external secret." }}
+{{- end }}
+
 import os
+{{- if or .Values.config.cacheConfig .Values.config.dataCacheConfig 
.Values.config.resultsBackend .Values.config.celeryConfig .Values.cache.enabled 
}}
 from flask_caching.backends.rediscache import RedisCache
+{{- end }}
 
 def env(key, default=None):
     return os.getenv(key, default)
 
-# Redis Base URL
-{{- if .Values.supersetNode.connections.redis_password }}
-REDIS_BASE_URL=f"{env('REDIS_DRIVER') or 
env('REDIS_PROTO')}://{env('REDIS_USER', 
'')}:{env('REDIS_PASSWORD')}@{env('REDIS_HOST')}:{env('REDIS_PORT')}"
+{{- /* Database Configuration - Superset always requires a database */}}
+{{- if .Values.database.uri }}
+SQLALCHEMY_DATABASE_URI = {{ .Values.database.uri | quote }}
+{{- else }}
+{{- $driver := include "superset.db.driver" . }}
+{{- $sslParams := "" }}
+{{- if and (hasKey .Values.database "ssl") .Values.database.ssl.enabled }}
+{{- $sslMode := .Values.database.ssl.mode | default "require" }}
+{{- $sslParams = printf "?sslmode=%s" $sslMode }}
+{{- end }}
+SQLALCHEMY_DATABASE_URI = f"{{ $driver }}://{{ include "superset.db.user" . 
}}:{{ include "superset.db.password" . }}@{{ include "superset.db.host" . }}:{{ 
include "superset.db.port" . }}/{{ include "superset.db.name" . }}{{ $sslParams 
}}"
+{{- end }}
+{{- if hasKey .Values.config "SQLALCHEMY_TRACK_MODIFICATIONS" }}
+SQLALCHEMY_TRACK_MODIFICATIONS = {{ 
.Values.config.SQLALCHEMY_TRACK_MODIFICATIONS | lower }}
 {{- else }}
-REDIS_BASE_URL=f"{env('REDIS_DRIVER') or 
env('REDIS_PROTO')}://{env('REDIS_HOST')}:{env('REDIS_PORT')}"
+SQLALCHEMY_TRACK_MODIFICATIONS = False
 {{- end }}
 
-# Redis URL Params
-{{- if .Values.supersetNode.connections.redis_ssl.enabled }}
-REDIS_URL_PARAMS = f"?ssl_cert_reqs={env('REDIS_SSL_CERT_REQS')}"
+{{- /* Redis Configuration - only if Redis cache is configured */}}
+{{- if .Values.cache.enabled }}
+{{- if .Values.cache.cacheUrl }}
+CACHE_REDIS_URL = {{ .Values.cache.cacheUrl | quote }}
+{{- else }}
+{{- $redisHost := include "superset.redis.host" . }}
+{{- $redisUser := include "superset.redis.user" . }}
+{{- $redisPort := include "superset.redis.port" . }}
+{{- $redisPassword := include "superset.redis.password" . }}
+{{- $useSSL := and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+{{- if $redisPassword }}
+{{- if $redisUser }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://{{ $redisUser 
}}:{{ $redisPassword }}@{{ $redisHost }}:{{ $redisPort }}"
+{{- else }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://:{{ $redisPassword 
}}@{{ $redisHost }}:{{ $redisPort }}"
+{{- end }}
+{{- else }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://{{ $redisHost 
}}:{{ $redisPort }}"
+{{- end }}
+{{- if $useSSL }}
+{{- $sslCertReqs := .Values.cache.ssl.ssl_cert_reqs | default "required" }}
+REDIS_URL_PARAMS = f"?ssl_cert_reqs={{ $sslCertReqs }}"
 {{- else }}
 REDIS_URL_PARAMS = ""
-{{- end}}
-
-# Build Redis URLs
-CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_DB', 1)}{REDIS_URL_PARAMS}"
-CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_CELERY_DB', 
0)}{REDIS_URL_PARAMS}"
+{{- end }}
+{{- $cacheDb := include "superset.redis.cacheDb" . }}
+CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{{ $cacheDb }}{REDIS_URL_PARAMS}"
+{{- end }}
+{{- if .Values.cache.celeryUrl }}
+CELERY_REDIS_URL = {{ .Values.cache.celeryUrl | quote }}
+{{- else if not .Values.cache.cacheUrl }}
+{{- $celeryDb := include "superset.redis.celeryDb" . }}
+CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{{ $celeryDb }}{REDIS_URL_PARAMS}"
+{{- else }}
+{{- if or .Values.config.celeryConfig (not .Values.cache.enabled) }}
+{{- /* Custom celeryConfig provided or cache disabled - OK */}}
+{{- else }}
+{{- fail "CONFIGURATION ERROR: cache.cacheUrl is set but cache.celeryUrl is 
not set. When using cacheUrl, you must also set celeryUrl for Celery to work. 
Alternatively, set config.celeryConfig to provide a custom Celery 
configuration." }}
+{{- end }}
+{{- end }}
+{{- end }}
 
-MAPBOX_API_KEY = env('MAPBOX_API_KEY', '')
+{{- /* Cache Configuration */}}
+{{- if .Values.config.cacheConfig }}
+CACHE_CONFIG = {{ .Values.config.cacheConfig | toJson | indent 2 }}
+{{- else if .Values.cache.enabled }}
 CACHE_CONFIG = {
-      'CACHE_TYPE': 'RedisCache',
-      'CACHE_DEFAULT_TIMEOUT': 300,
-      'CACHE_KEY_PREFIX': 'superset_',
-      'CACHE_REDIS_URL': CACHE_REDIS_URL,
+    'CACHE_TYPE': 'RedisCache',
+    'CACHE_DEFAULT_TIMEOUT': {{ .Values.cache.defaultTimeout | default 
(.Values.config.cacheDefaultTimeout | default 86400) | int }},
+    'CACHE_KEY_PREFIX': {{ .Values.cache.keyPrefix | default "superset_" | 
quote }},
+    'CACHE_REDIS_URL': CACHE_REDIS_URL,
 }
+{{- end }}
+
+{{- if .Values.config.dataCacheConfig }}
+DATA_CACHE_CONFIG = {{ .Values.config.dataCacheConfig | toJson | indent 2 }}
+{{- else if .Values.config.cacheConfig }}
+DATA_CACHE_CONFIG = CACHE_CONFIG
+{{- else if .Values.cache.enabled }}
 DATA_CACHE_CONFIG = CACHE_CONFIG
+{{- end }}
 
+{{- /* SQLLAB_ASYNC_TIME_LIMIT_SEC - Required for async_queries module import 
(default: 6 hours) */}}
+{{- if .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC }}
+SQLLAB_ASYNC_TIME_LIMIT_SEC = {{ .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC | 
int }}
+{{- else }}
+from datetime import timedelta
+SQLLAB_ASYNC_TIME_LIMIT_SEC = int(timedelta(hours=6).total_seconds())
+{{- end }}
 
-if os.getenv("SQLALCHEMY_DATABASE_URI"):
-    SQLALCHEMY_DATABASE_URI = os.getenv("SQLALCHEMY_DATABASE_URI")
-else:
-    {{- if eq .Values.supersetNode.connections.db_type "postgresql" }}
-    SQLALCHEMY_DATABASE_URI = 
f"postgresql+psycopg2://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
-    {{- else if eq .Values.supersetNode.connections.db_type "mysql" }}
-    SQLALCHEMY_DATABASE_URI = 
f"mysql+mysqldb://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
-    {{- else }}
-    {{ fail (printf "Unsupported database type: %s. Please use 'postgresql' or 
'mysql'." .Values.supersetNode.connections.db_type) }}
-    {{- end }}
+{{- /* Celery Configuration */}}
+{{- if .Values.config.celeryConfig }}
+{{- if kindIs "string" .Values.config.celeryConfig }}
+{{ .Values.config.celeryConfig }}
+{{- else }}
+class CeleryConfig:
+{{- range $key, $value := .Values.config.celeryConfig }}
+    {{ $key }} = {{ $value | toJson }}
+{{- end }}
+
+CELERY_IMPORTS = CeleryConfig.imports
+CELERY_CONFIG = CeleryConfig
+{{- end }}
+{{- else if .Values.cache.enabled }}
+from celery.schedules import crontab
+from datetime import timedelta
 
 class CeleryConfig:
-  imports  = ("superset.sql_lab", )
-  broker_url = CELERY_REDIS_URL
-  result_backend = CELERY_REDIS_URL
+    imports = (
+        "superset.sql_lab",
+        "superset.tasks.scheduler",
+        "superset.tasks.thumbnails",
+        "superset.tasks.cache",
+    )
+    broker_connection_retry_on_startup = True
+    worker_prefetch_multiplier = 10
+    task_acks_late = True
+    broker_url = CELERY_REDIS_URL
+    result_backend = CELERY_REDIS_URL
+    task_annotations = {
+        "sql_lab.get_sql_results": {
+            "rate_limit": "100/s",
+        },
+    }
+    beat_schedule = {
+        "reports.scheduler": {
+            "task": "reports.scheduler",
+            "schedule": crontab(minute="*", hour="*"),
+            "options": {"expires": int(timedelta(weeks=1).total_seconds())},
+        },
+        "reports.prune_log": {
+            "task": "reports.prune_log",
+            "schedule": crontab(minute=0, hour=0),
+        },
+    }
 
+CELERY_IMPORTS = CeleryConfig.imports
 CELERY_CONFIG = CeleryConfig
+{{- end }}
+
+{{- /* Celery Worker Health Check - File-based health probes for Kubernetes 
*/}}
+{{- if and .Values.supersetWorker.healthCheck 
.Values.supersetWorker.healthCheck.enabled }}
+# Celery Worker Health Check Configuration
+import threading
+from celery import bootsteps
+from celery.signals import worker_ready, worker_shutdown, worker_init
+
+_readiness_file = {{ .Values.supersetWorker.healthCheck.readinessFile | 
default "/tmp/celery_worker_ready" | quote }}
+_liveness_file = {{ .Values.supersetWorker.healthCheck.livenessFile | default 
"/tmp/celery_worker_alive" | quote }}
+_heartbeat_interval = {{ 
.Values.supersetWorker.healthCheck.livenessHeartbeatInterval | default 10 | int 
}}
+_liveness_thread = None
+_liveness_stop_event = None
+
+@worker_ready.connect
+def create_ready_file(sender, **kwargs):
+    try:
+        open(_readiness_file, 'w').close()
+    except Exception as e:
+        print(f"Warning: Could not create readiness file: {e}")
+
+@worker_shutdown.connect
+def remove_ready_file(sender, **kwargs):
+    global _liveness_thread, _liveness_stop_event
+    if _liveness_stop_event:
+        _liveness_stop_event.set()
+    if _liveness_thread:
+        _liveness_thread.join(timeout=5)
+    try:
+        if os.path.exists(_readiness_file):
+            os.remove(_readiness_file)
+        if os.path.exists(_liveness_file):
+            os.remove(_liveness_file)
+    except Exception as e:
+        print(f"Warning: Could not remove health check files: {e}")
+
+@worker_init.connect
+def start_liveness_heartbeat(sender, **kwargs):
+    global _liveness_thread, _liveness_stop_event
+    _liveness_stop_event = threading.Event()
+
+    def update_liveness():
+        while not _liveness_stop_event.is_set():
+            try:
+                with open(_liveness_file, 'w') as f:
+                    f.write(str(os.getpid()))
+            except Exception as e:
+                print(f"Warning: Could not update liveness file: {e}")
+            _liveness_stop_event.wait(_heartbeat_interval)
+
+    _liveness_thread = threading.Thread(target=update_liveness, daemon=True)
+    _liveness_thread.start()
+{{- else }}
+CELERY_WORKER_HEALTH_CHECK_ENABLED = False
+{{- end }}
+
+{{- /* Results Backend */}}
+{{- $redisHostForBackend := include "superset.redis.host" . }}
+{{- $redisPortForBackend := include "superset.redis.port" . }}
+{{- $redisPasswordForBackend := include "superset.redis.password" . }}
+{{- if .Values.config.resultsBackend }}
+{{- if kindIs "string" .Values.config.resultsBackend }}
+RESULTS_BACKEND = {{ .Values.config.resultsBackend }}
+{{- else }}
+RESULTS_BACKEND = RedisCache(
+    host={{ $redisHostForBackend | quote }},
+    {{- if $redisPasswordForBackend }}
+    password={{ $redisPasswordForBackend | quote }},
+    {{- end }}
+    port={{ $redisPortForBackend | int }},
+    key_prefix={{ .Values.cache.resultsBackendKeyPrefix | default 
"superset_results" | quote }},
+    {{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+    ssl=True,
+    ssl_cert_reqs={{ .Values.cache.ssl.ssl_cert_reqs | default "required" | 
quote }},
+    {{- end }}
+)
+{{- end }}
+{{- else if .Values.cache.enabled }}
 RESULTS_BACKEND = RedisCache(
-      host=env('REDIS_HOST'),
-      {{- if .Values.supersetNode.connections.redis_password }}
-      password=env('REDIS_PASSWORD'),
-      {{- end }}
-      port=env('REDIS_PORT'),
-      key_prefix='superset_results',
-      {{- if .Values.supersetNode.connections.redis_ssl.enabled }}
-      ssl=True,
-      ssl_cert_reqs=env('REDIS_SSL_CERT_REQS'),
-      {{- end }}
+    host={{ $redisHostForBackend | quote }},
+    {{- if $redisPasswordForBackend }}
+    password={{ $redisPasswordForBackend | quote }},
+    {{- end }}
+    port={{ $redisPortForBackend | int }},
+    key_prefix={{ .Values.cache.resultsBackendKeyPrefix | default 
"superset_results" | quote }},
+    {{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+    ssl=True,
+    ssl_cert_reqs={{ .Values.cache.ssl.ssl_cert_reqs | default "required" | 
quote }},
+    {{- end }}
 )
+{{- end }}
+
+{{- /* Global Async Queries Cache Backend */}}
+{{- $redisUserForGaq := include "superset.redis.user" . }}
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_CACHE_BACKEND }}
+GLOBAL_ASYNC_QUERIES_CACHE_BACKEND = {{ 
.Values.config.GLOBAL_ASYNC_QUERIES_CACHE_BACKEND | toJson | indent 2 }}
+{{- else if .Values.cache.enabled }}
+GLOBAL_ASYNC_QUERIES_CACHE_BACKEND = {
+    "CACHE_TYPE": "RedisCache",
+    "CACHE_REDIS_HOST": {{ $redisHostForBackend | quote }},
+    "CACHE_REDIS_PORT": {{ $redisPortForBackend | int }},
+    "CACHE_REDIS_USER": {{ $redisUserForGaq | quote }},
+    {{- if $redisPasswordForBackend }}
+    "CACHE_REDIS_PASSWORD": {{ $redisPasswordForBackend | quote }},
+    {{- else }}
+    "CACHE_REDIS_PASSWORD": "",
+    {{- end }}
+    "CACHE_REDIS_DB": {{ .Values.cache.asyncQueries.db | default 
.Values.cache.cacheDb | default 0 | int }},
+    "CACHE_KEY_PREFIX": {{ .Values.cache.asyncQueries.keyPrefix | default 
"qc-" | quote }},
+    "CACHE_DEFAULT_TIMEOUT": {{ .Values.cache.asyncQueries.timeout | default 
86400 | int }},
+    {{- if .Values.cache.sentinel }}
+    {{- if .Values.cache.sentinel.sentinels }}
+    "CACHE_REDIS_SENTINELS": {{ .Values.cache.sentinel.sentinels | toJson }},
+    {{- else }}
+    {{- fail "CONFIGURATION ERROR: cache.sentinel.enabled is true but 
cache.sentinel.sentinels is not set. You must provide Sentinel host(s) in 
cache.sentinel.sentinels (e.g., [['sentinel-host', 26379]])." }}
+    {{- end }}
+    "CACHE_REDIS_SENTINEL_MASTER": {{ .Values.cache.sentinel.master | default 
"mymaster" | quote }},
+    {{- if .Values.cache.sentinel.password }}
+    "CACHE_REDIS_SENTINEL_PASSWORD": {{ .Values.cache.sentinel.password | 
quote }},
+    {{- else }}
+    "CACHE_REDIS_SENTINEL_PASSWORD": None,
+    {{- end }}
+    {{- end }}
+    {{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+    "CACHE_REDIS_SSL": True,
+    "CACHE_REDIS_SSL_CERTFILE": {{ .Values.cache.ssl.certfile | default "None" 
}},
+    "CACHE_REDIS_SSL_KEYFILE": {{ .Values.cache.ssl.keyfile | default "None" 
}},
+    "CACHE_REDIS_SSL_CERT_REQS": {{ .Values.cache.ssl.ssl_cert_reqs | default 
"required" | quote }},
+    "CACHE_REDIS_SSL_CA_CERTS": {{ .Values.cache.ssl.ca_certs | default "None" 
}},

Review Comment:
   **Suggestion:** These values are emitted without quoting, so string file 
paths render as bare Python tokens (for example `/etc/ssl/cert.pem`) and 
produce invalid syntax in `superset_config.py`. Emit proper quoted strings (or 
explicit `None`) for these fields. [type error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Superset config file contains invalid Redis SSL paths.
   - ⚠️ Global async query cache backend cannot start with SSL.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. Enable Redis SSL for global async queries in `helm/superset/values.yaml` 
by setting
   `.Values.cache.enabled = true` and `.Values.cache.ssl.enabled = true` with 
file path
   values such as `certfile: "/etc/ssl/cert.pem"`, `keyfile: 
"/etc/ssl/key.pem"`, and
   `ca_certs: "/etc/ssl/ca.pem"`.
   
   2. When Helm renders `secret-superset-config.yaml:29-34`, it includes 
`superset.config`;
   inside `_helpers.tpl:474-480`, the SSL-enabled branch of the
   `GLOBAL_ASYNC_QUERIES_CACHE_BACKEND` dict executes.
   
   3. That branch emits lines like `"CACHE_REDIS_SSL_CERTFILE": 
/etc/ssl/cert.pem` and
   `"CACHE_REDIS_SSL_CA_CERTS": /etc/ssl/ca.pem` without quotes, so the 
generated
   `superset_config.py` contains bare path tokens inside a Python dict literal, 
which are not
   valid Python expressions.
   
   4. Superset loads configuration using `superset/config.py:2931-2952`, 
importing and
   executing `superset_config.py`; Python parsing the dict with unquoted paths 
raises a
   `SyntaxError`, causing config import to fail and preventing the global async 
queries Redis
   cache backend from starting when SSL is configured.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=676e87cfa3f741048b8224403e029770&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=676e87cfa3f741048b8224403e029770&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** helm/superset/templates/_helpers.tpl
   **Line:** 476:479
   **Comment:**
        *Type Error: These values are emitted without quoting, so string file 
paths render as bare Python tokens (for example `/etc/ssl/cert.pem`) and 
produce invalid syntax in `superset_config.py`. Emit proper quoted strings (or 
explicit `None`) for these fields.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=36c51cdcecdd4dd5b8d3edd7e139a7608574bfaf3487d3dd970eadd0749baca1&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=36c51cdcecdd4dd5b8d3edd7e139a7608574bfaf3487d3dd970eadd0749baca1&reaction=dislike'>πŸ‘Ž</a>



##########
helm/superset/templates/_helpers.tpl:
##########
@@ -105,80 +106,560 @@ app.kubernetes.io/component: {{ .component }}
 {{- end -}}
 
 
-{{- define "superset-config" }}
+{{/*
+Coalescing resolvers for DB and Redis connection parameters.
+Each resolver checks (in order):
+  1. New top-level database.* / cache.* values
+  2. Legacy supersetNode.connections.* keys (deprecation path, using safe 
index to avoid errors on absent maps)
+  3. cluster.* service name overrides
+  4. Hard-coded defaults derived from the release name
+Call with root context: {{ include "superset.db.host" . }}
+*/}}
+
+{{/*
+Helper to safely read .Values.supersetNode.connections.<key> without erroring 
when maps are absent.
+*/}}
+{{- define "_superset.legacyConn" -}}
+{{- $sn := index .Values "supersetNode" | default dict -}}
+{{- $conn := index $sn "connections" | default dict -}}
+{{- $conn | toJson -}}
+{{- end -}}
+
+{{- define "superset.db.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.database.host (index $conn "db_host") 
.Values.cluster.databaseServiceName (printf "%s-postgresql" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.db.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.database.port -}}
+{{- .Values.database.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "db_port") "5432" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.db.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.user (index $conn "db_user") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.password (index $conn "db_pass") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.name" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.name (index $conn "db_name") "superset" -}}
+{{- end -}}
+
+{{- define "superset.db.driver" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.database.driver (index $conn "db_type") 
"postgresql+psycopg2" -}}
+{{- end -}}
+
+{{- define "superset.redis.host" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- tpl (coalesce .Values.cache.host (index $conn "redis_host") 
.Values.cluster.redisServiceName (printf "%s-redis-headless" .Release.Name)) $ 
-}}
+{{- end -}}
+
+{{- define "superset.redis.port" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- if .Values.cache.port -}}
+{{- .Values.cache.port | toString -}}
+{{- else -}}
+{{- coalesce (index $conn "redis_port") "6379" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "superset.redis.user" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.user (index $conn "redis_user") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.password" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce .Values.cache.password (index $conn "redis_password") "" -}}
+{{- end -}}
+
+{{- define "superset.redis.cacheDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.cacheDb | toString) (index $conn "redis_cache_db") 
"1" -}}
+{{- end -}}
+
+{{- define "superset.redis.celeryDb" -}}
+{{- $conn := include "_superset.legacyConn" . | fromJson -}}
+{{- coalesce (.Values.cache.celeryDb | toString) (index $conn 
"redis_celery_db") "0" -}}
+{{- end -}}
+
+{{- define "superset.redis.proto" -}}
+{{- if .Values.cache.driver }}{{ .Values.cache.driver }}{{- else if 
.Values.cache.ssl.enabled }}rediss{{- else }}redis{{- end -}}
+{{- end -}}
+
+{{- define "superset.config" }}
+{{- /* SECURITY: Validate admin password is set if admin creation is enabled 
*/}}
+{{- if and .Values.init.createAdmin (or (not .Values.init.adminUser.password) 
(eq .Values.init.adminUser.password "")) }}
+{{- fail "SECURITY ERROR: init.createAdmin is true but init.adminUser.password 
is empty. You must set a secure password using --set 
init.adminUser.password='your-password' or via external secret." }}
+{{- end }}
+
 import os
+{{- if or .Values.config.cacheConfig .Values.config.dataCacheConfig 
.Values.config.resultsBackend .Values.config.celeryConfig .Values.cache.enabled 
}}
 from flask_caching.backends.rediscache import RedisCache
+{{- end }}
 
 def env(key, default=None):
     return os.getenv(key, default)
 
-# Redis Base URL
-{{- if .Values.supersetNode.connections.redis_password }}
-REDIS_BASE_URL=f"{env('REDIS_DRIVER') or 
env('REDIS_PROTO')}://{env('REDIS_USER', 
'')}:{env('REDIS_PASSWORD')}@{env('REDIS_HOST')}:{env('REDIS_PORT')}"
+{{- /* Database Configuration - Superset always requires a database */}}
+{{- if .Values.database.uri }}
+SQLALCHEMY_DATABASE_URI = {{ .Values.database.uri | quote }}
+{{- else }}
+{{- $driver := include "superset.db.driver" . }}
+{{- $sslParams := "" }}
+{{- if and (hasKey .Values.database "ssl") .Values.database.ssl.enabled }}
+{{- $sslMode := .Values.database.ssl.mode | default "require" }}
+{{- $sslParams = printf "?sslmode=%s" $sslMode }}
+{{- end }}
+SQLALCHEMY_DATABASE_URI = f"{{ $driver }}://{{ include "superset.db.user" . 
}}:{{ include "superset.db.password" . }}@{{ include "superset.db.host" . }}:{{ 
include "superset.db.port" . }}/{{ include "superset.db.name" . }}{{ $sslParams 
}}"
+{{- end }}
+{{- if hasKey .Values.config "SQLALCHEMY_TRACK_MODIFICATIONS" }}
+SQLALCHEMY_TRACK_MODIFICATIONS = {{ 
.Values.config.SQLALCHEMY_TRACK_MODIFICATIONS | lower }}
 {{- else }}
-REDIS_BASE_URL=f"{env('REDIS_DRIVER') or 
env('REDIS_PROTO')}://{env('REDIS_HOST')}:{env('REDIS_PORT')}"
+SQLALCHEMY_TRACK_MODIFICATIONS = False
 {{- end }}
 
-# Redis URL Params
-{{- if .Values.supersetNode.connections.redis_ssl.enabled }}
-REDIS_URL_PARAMS = f"?ssl_cert_reqs={env('REDIS_SSL_CERT_REQS')}"
+{{- /* Redis Configuration - only if Redis cache is configured */}}
+{{- if .Values.cache.enabled }}
+{{- if .Values.cache.cacheUrl }}
+CACHE_REDIS_URL = {{ .Values.cache.cacheUrl | quote }}
+{{- else }}
+{{- $redisHost := include "superset.redis.host" . }}
+{{- $redisUser := include "superset.redis.user" . }}
+{{- $redisPort := include "superset.redis.port" . }}
+{{- $redisPassword := include "superset.redis.password" . }}
+{{- $useSSL := and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+{{- if $redisPassword }}
+{{- if $redisUser }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://{{ $redisUser 
}}:{{ $redisPassword }}@{{ $redisHost }}:{{ $redisPort }}"
+{{- else }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://:{{ $redisPassword 
}}@{{ $redisHost }}:{{ $redisPort }}"
+{{- end }}
+{{- else }}
+REDIS_BASE_URL = f"{{ include "superset.redis.proto" . }}://{{ $redisHost 
}}:{{ $redisPort }}"
+{{- end }}
+{{- if $useSSL }}
+{{- $sslCertReqs := .Values.cache.ssl.ssl_cert_reqs | default "required" }}
+REDIS_URL_PARAMS = f"?ssl_cert_reqs={{ $sslCertReqs }}"
 {{- else }}
 REDIS_URL_PARAMS = ""
-{{- end}}
-
-# Build Redis URLs
-CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_DB', 1)}{REDIS_URL_PARAMS}"
-CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{env('REDIS_CELERY_DB', 
0)}{REDIS_URL_PARAMS}"
+{{- end }}
+{{- $cacheDb := include "superset.redis.cacheDb" . }}
+CACHE_REDIS_URL = f"{REDIS_BASE_URL}/{{ $cacheDb }}{REDIS_URL_PARAMS}"
+{{- end }}
+{{- if .Values.cache.celeryUrl }}
+CELERY_REDIS_URL = {{ .Values.cache.celeryUrl | quote }}
+{{- else if not .Values.cache.cacheUrl }}
+{{- $celeryDb := include "superset.redis.celeryDb" . }}
+CELERY_REDIS_URL = f"{REDIS_BASE_URL}/{{ $celeryDb }}{REDIS_URL_PARAMS}"
+{{- else }}
+{{- if or .Values.config.celeryConfig (not .Values.cache.enabled) }}
+{{- /* Custom celeryConfig provided or cache disabled - OK */}}
+{{- else }}
+{{- fail "CONFIGURATION ERROR: cache.cacheUrl is set but cache.celeryUrl is 
not set. When using cacheUrl, you must also set celeryUrl for Celery to work. 
Alternatively, set config.celeryConfig to provide a custom Celery 
configuration." }}
+{{- end }}
+{{- end }}
+{{- end }}
 
-MAPBOX_API_KEY = env('MAPBOX_API_KEY', '')
+{{- /* Cache Configuration */}}
+{{- if .Values.config.cacheConfig }}
+CACHE_CONFIG = {{ .Values.config.cacheConfig | toJson | indent 2 }}
+{{- else if .Values.cache.enabled }}
 CACHE_CONFIG = {
-      'CACHE_TYPE': 'RedisCache',
-      'CACHE_DEFAULT_TIMEOUT': 300,
-      'CACHE_KEY_PREFIX': 'superset_',
-      'CACHE_REDIS_URL': CACHE_REDIS_URL,
+    'CACHE_TYPE': 'RedisCache',
+    'CACHE_DEFAULT_TIMEOUT': {{ .Values.cache.defaultTimeout | default 
(.Values.config.cacheDefaultTimeout | default 86400) | int }},
+    'CACHE_KEY_PREFIX': {{ .Values.cache.keyPrefix | default "superset_" | 
quote }},
+    'CACHE_REDIS_URL': CACHE_REDIS_URL,
 }
+{{- end }}
+
+{{- if .Values.config.dataCacheConfig }}
+DATA_CACHE_CONFIG = {{ .Values.config.dataCacheConfig | toJson | indent 2 }}
+{{- else if .Values.config.cacheConfig }}
+DATA_CACHE_CONFIG = CACHE_CONFIG
+{{- else if .Values.cache.enabled }}
 DATA_CACHE_CONFIG = CACHE_CONFIG
+{{- end }}
 
+{{- /* SQLLAB_ASYNC_TIME_LIMIT_SEC - Required for async_queries module import 
(default: 6 hours) */}}
+{{- if .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC }}
+SQLLAB_ASYNC_TIME_LIMIT_SEC = {{ .Values.config.SQLLAB_ASYNC_TIME_LIMIT_SEC | 
int }}
+{{- else }}
+from datetime import timedelta
+SQLLAB_ASYNC_TIME_LIMIT_SEC = int(timedelta(hours=6).total_seconds())
+{{- end }}
 
-if os.getenv("SQLALCHEMY_DATABASE_URI"):
-    SQLALCHEMY_DATABASE_URI = os.getenv("SQLALCHEMY_DATABASE_URI")
-else:
-    {{- if eq .Values.supersetNode.connections.db_type "postgresql" }}
-    SQLALCHEMY_DATABASE_URI = 
f"postgresql+psycopg2://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
-    {{- else if eq .Values.supersetNode.connections.db_type "mysql" }}
-    SQLALCHEMY_DATABASE_URI = 
f"mysql+mysqldb://{os.getenv('DB_USER')}:{os.getenv('DB_PASS')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
-    {{- else }}
-    {{ fail (printf "Unsupported database type: %s. Please use 'postgresql' or 
'mysql'." .Values.supersetNode.connections.db_type) }}
-    {{- end }}
+{{- /* Celery Configuration */}}
+{{- if .Values.config.celeryConfig }}
+{{- if kindIs "string" .Values.config.celeryConfig }}
+{{ .Values.config.celeryConfig }}
+{{- else }}
+class CeleryConfig:
+{{- range $key, $value := .Values.config.celeryConfig }}
+    {{ $key }} = {{ $value | toJson }}
+{{- end }}
+
+CELERY_IMPORTS = CeleryConfig.imports
+CELERY_CONFIG = CeleryConfig
+{{- end }}
+{{- else if .Values.cache.enabled }}
+from celery.schedules import crontab
+from datetime import timedelta
 
 class CeleryConfig:
-  imports  = ("superset.sql_lab", )
-  broker_url = CELERY_REDIS_URL
-  result_backend = CELERY_REDIS_URL
+    imports = (
+        "superset.sql_lab",
+        "superset.tasks.scheduler",
+        "superset.tasks.thumbnails",
+        "superset.tasks.cache",
+    )
+    broker_connection_retry_on_startup = True
+    worker_prefetch_multiplier = 10
+    task_acks_late = True
+    broker_url = CELERY_REDIS_URL
+    result_backend = CELERY_REDIS_URL
+    task_annotations = {
+        "sql_lab.get_sql_results": {
+            "rate_limit": "100/s",
+        },
+    }
+    beat_schedule = {
+        "reports.scheduler": {
+            "task": "reports.scheduler",
+            "schedule": crontab(minute="*", hour="*"),
+            "options": {"expires": int(timedelta(weeks=1).total_seconds())},
+        },
+        "reports.prune_log": {
+            "task": "reports.prune_log",
+            "schedule": crontab(minute=0, hour=0),
+        },
+    }
 
+CELERY_IMPORTS = CeleryConfig.imports
 CELERY_CONFIG = CeleryConfig
+{{- end }}
+
+{{- /* Celery Worker Health Check - File-based health probes for Kubernetes 
*/}}
+{{- if and .Values.supersetWorker.healthCheck 
.Values.supersetWorker.healthCheck.enabled }}
+# Celery Worker Health Check Configuration
+import threading
+from celery import bootsteps
+from celery.signals import worker_ready, worker_shutdown, worker_init
+
+_readiness_file = {{ .Values.supersetWorker.healthCheck.readinessFile | 
default "/tmp/celery_worker_ready" | quote }}
+_liveness_file = {{ .Values.supersetWorker.healthCheck.livenessFile | default 
"/tmp/celery_worker_alive" | quote }}
+_heartbeat_interval = {{ 
.Values.supersetWorker.healthCheck.livenessHeartbeatInterval | default 10 | int 
}}
+_liveness_thread = None
+_liveness_stop_event = None
+
+@worker_ready.connect
+def create_ready_file(sender, **kwargs):
+    try:
+        open(_readiness_file, 'w').close()
+    except Exception as e:
+        print(f"Warning: Could not create readiness file: {e}")
+
+@worker_shutdown.connect
+def remove_ready_file(sender, **kwargs):
+    global _liveness_thread, _liveness_stop_event
+    if _liveness_stop_event:
+        _liveness_stop_event.set()
+    if _liveness_thread:
+        _liveness_thread.join(timeout=5)
+    try:
+        if os.path.exists(_readiness_file):
+            os.remove(_readiness_file)
+        if os.path.exists(_liveness_file):
+            os.remove(_liveness_file)
+    except Exception as e:
+        print(f"Warning: Could not remove health check files: {e}")
+
+@worker_init.connect
+def start_liveness_heartbeat(sender, **kwargs):
+    global _liveness_thread, _liveness_stop_event
+    _liveness_stop_event = threading.Event()
+
+    def update_liveness():
+        while not _liveness_stop_event.is_set():
+            try:
+                with open(_liveness_file, 'w') as f:
+                    f.write(str(os.getpid()))
+            except Exception as e:
+                print(f"Warning: Could not update liveness file: {e}")
+            _liveness_stop_event.wait(_heartbeat_interval)
+
+    _liveness_thread = threading.Thread(target=update_liveness, daemon=True)
+    _liveness_thread.start()
+{{- else }}
+CELERY_WORKER_HEALTH_CHECK_ENABLED = False
+{{- end }}
+
+{{- /* Results Backend */}}
+{{- $redisHostForBackend := include "superset.redis.host" . }}
+{{- $redisPortForBackend := include "superset.redis.port" . }}
+{{- $redisPasswordForBackend := include "superset.redis.password" . }}
+{{- if .Values.config.resultsBackend }}
+{{- if kindIs "string" .Values.config.resultsBackend }}
+RESULTS_BACKEND = {{ .Values.config.resultsBackend }}
+{{- else }}
+RESULTS_BACKEND = RedisCache(
+    host={{ $redisHostForBackend | quote }},
+    {{- if $redisPasswordForBackend }}
+    password={{ $redisPasswordForBackend | quote }},
+    {{- end }}
+    port={{ $redisPortForBackend | int }},
+    key_prefix={{ .Values.cache.resultsBackendKeyPrefix | default 
"superset_results" | quote }},
+    {{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+    ssl=True,
+    ssl_cert_reqs={{ .Values.cache.ssl.ssl_cert_reqs | default "required" | 
quote }},
+    {{- end }}
+)
+{{- end }}
+{{- else if .Values.cache.enabled }}
 RESULTS_BACKEND = RedisCache(
-      host=env('REDIS_HOST'),
-      {{- if .Values.supersetNode.connections.redis_password }}
-      password=env('REDIS_PASSWORD'),
-      {{- end }}
-      port=env('REDIS_PORT'),
-      key_prefix='superset_results',
-      {{- if .Values.supersetNode.connections.redis_ssl.enabled }}
-      ssl=True,
-      ssl_cert_reqs=env('REDIS_SSL_CERT_REQS'),
-      {{- end }}
+    host={{ $redisHostForBackend | quote }},
+    {{- if $redisPasswordForBackend }}
+    password={{ $redisPasswordForBackend | quote }},
+    {{- end }}
+    port={{ $redisPortForBackend | int }},
+    key_prefix={{ .Values.cache.resultsBackendKeyPrefix | default 
"superset_results" | quote }},
+    {{- if and (hasKey .Values.cache "ssl") .Values.cache.ssl.enabled }}
+    ssl=True,
+    ssl_cert_reqs={{ .Values.cache.ssl.ssl_cert_reqs | default "required" | 
quote }},
+    {{- end }}
 )
+{{- end }}
+
+{{- /* Global Async Queries Cache Backend */}}
+{{- $redisUserForGaq := include "superset.redis.user" . }}
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_CACHE_BACKEND }}
+GLOBAL_ASYNC_QUERIES_CACHE_BACKEND = {{ 
.Values.config.GLOBAL_ASYNC_QUERIES_CACHE_BACKEND | toJson | indent 2 }}
+{{- else if .Values.cache.enabled }}
+GLOBAL_ASYNC_QUERIES_CACHE_BACKEND = {
+    "CACHE_TYPE": "RedisCache",
+    "CACHE_REDIS_HOST": {{ $redisHostForBackend | quote }},
+    "CACHE_REDIS_PORT": {{ $redisPortForBackend | int }},
+    "CACHE_REDIS_USER": {{ $redisUserForGaq | quote }},
+    {{- if $redisPasswordForBackend }}
+    "CACHE_REDIS_PASSWORD": {{ $redisPasswordForBackend | quote }},
+    {{- else }}
+    "CACHE_REDIS_PASSWORD": "",
+    {{- end }}
+    "CACHE_REDIS_DB": {{ .Values.cache.asyncQueries.db | default 
.Values.cache.cacheDb | default 0 | int }},
+    "CACHE_KEY_PREFIX": {{ .Values.cache.asyncQueries.keyPrefix | default 
"qc-" | quote }},
+    "CACHE_DEFAULT_TIMEOUT": {{ .Values.cache.asyncQueries.timeout | default 
86400 | int }},
+    {{- if .Values.cache.sentinel }}
+    {{- if .Values.cache.sentinel.sentinels }}
+    "CACHE_REDIS_SENTINELS": {{ .Values.cache.sentinel.sentinels | toJson }},
+    {{- else }}
+    {{- fail "CONFIGURATION ERROR: cache.sentinel.enabled is true but 
cache.sentinel.sentinels is not set. You must provide Sentinel host(s) in 
cache.sentinel.sentinels (e.g., [['sentinel-host', 26379]])." }}
+    {{- end }}

Review Comment:
   **Suggestion:** The sentinel block activates whenever `cache.sentinel` is 
any non-null map, even if users set `enabled: false`. This can trigger 
validation failures or sentinel-only settings when sentinel is intentionally 
disabled. Gate this block on `cache.sentinel.enabled` explicitly. [incorrect 
condition logic]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Helm template rendering fails when sentinel map present disabled.
   - ⚠️ Redis Sentinel toggles unusable without fully removing configuration.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. Define Redis cache values in `helm/superset/values.yaml` with 
`.Values.cache.enabled =
   true` and `.Values.cache.sentinel` set to a map containing `enabled: false` 
(or similar)
   but omitting `sentinels`, so Sentinel is conceptually disabled but the 
configuration
   object exists.
   
   2. During chart rendering, `secret-superset-config.yaml:29-34` includes 
`superset.config`;
   inside `_helpers.tpl:443-487` the `GLOBAL_ASYNC_QUERIES_CACHE_BACKEND` dict 
is built.
   
   3. At `_helpers.tpl:461-466`, the condition `{{- if .Values.cache.sentinel 
}}` evaluates
   truthy because `.Values.cache.sentinel` is a non-null map, and `{{- if
   .Values.cache.sentinel.sentinels }}` evaluates falsy, so the template 
executes the `fail`
   call with the message β€œCONFIGURATION ERROR: cache.sentinel.enabled is true 
but
   cache.sentinel.sentinels is not set…”.
   
   4. As a result, `helm install` or `helm upgrade` fails while rendering
   `superset_config.py`, even though `cache.sentinel.enabled` is false and 
Sentinel was
   intentionally disabled, preventing deployment and blocking configuration of 
the global
   async queries cache backend.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=8de4e0c5831b4e57ab142d4d0c8759aa&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=8de4e0c5831b4e57ab142d4d0c8759aa&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** helm/superset/templates/_helpers.tpl
   **Line:** 461:466
   **Comment:**
        *Incorrect Condition Logic: The sentinel block activates whenever 
`cache.sentinel` is any non-null map, even if users set `enabled: false`. This 
can trigger validation failures or sentinel-only settings when sentinel is 
intentionally disabled. Gate this block on `cache.sentinel.enabled` explicitly.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=1c65a8f4b12785598fe9f3b3caa3a6c3250114e9c520a8617ff5060f3aad05f8&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=1c65a8f4b12785598fe9f3b3caa3a6c3250114e9c520a8617ff5060f3aad05f8&reaction=dislike'>πŸ‘Ž</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to