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


##########
helm/superset/templates/_helpers.tpl:
##########
@@ -105,80 +106,564 @@ 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 
}}"

Review Comment:
   **Suggestion:** The database URI is assembled by interpolating raw username 
and password into the URL without percent-encoding, so common special 
characters (for example `@`, `:`, `/`, `#`) in credentials will produce an 
invalid connection string and fail database connectivity. Encode credentials 
before embedding them into the URI. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   ❌ Superset web fails connecting metadata DB via SQLAlchemy.
   ❌ Init job superset db upgrade crashes on invalid URI.
   ⚠️ Deployments with complex passwords require manual workarounds or escaping.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure the chart with database credentials containing reserved URL 
characters, for
   example `--set database.user='dbuser' --set database.password='pa@ss:word'` 
as defined in
   `helm/superset/values.yaml:270-287`.
   
   2. Leave `.Values.database.uri` unset (the default at 
`values.yaml:272-274`); in this case
   `superset.config` at `helm/superset/templates/_helpers.tpl:214-225` 
constructs
   `SQLALCHEMY_DATABASE_URI` using the f-string at line 224, interpolating the 
raw username
   and password into `dbuser:pa@ss:word@host:port/dbname`.
   
   3. Secret `helm/superset/templates/secret-superset-config.yaml:20-30` writes 
this URI into
   `superset_config.py`, which is mounted by the web deployment 
(`deployment.yaml:192-195`)
   and init job (`init-job.yaml:136-139`) via the `superset-config` secret at
   `configMountPath`.
   
   4. When the init job runs `superset db upgrade` (command defined at
   `helm/superset/values.yaml:909-913`) and the web server starts 
(`supersetNode.command` at
   `values.yaml:372-377`), Superset and SQLAlchemy attempt to parse
   `SQLALCHEMY_DATABASE_URI`; the unescaped `@` and `:` in the password corrupt 
the authority
   portion of the URI, causing connection failures and preventing the metadata 
database from
   being reached.
   ```
   </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=571ffb70f3a44804b0f0f602e43b9528&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=571ffb70f3a44804b0f0f602e43b9528&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:** 224:224
   **Comment:**
        *Logic Error: The database URI is assembled by interpolating raw 
username and password into the URL without percent-encoding, so common special 
characters (for example `@`, `:`, `/`, `#`) in credentials will produce an 
invalid connection string and fail database connectivity. Encode credentials 
before embedding them into the URI.
   
   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=083a2cf0305091179ab604754b454bd8b28816c1f9855598e90ae96a936620ec&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=083a2cf0305091179ab604754b454bd8b28816c1f9855598e90ae96a936620ec&reaction=dislike'>👎</a>



##########
helm/superset/templates/_helpers.tpl:
##########
@@ -105,80 +106,564 @@ 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 | toString | title }}
 {{- 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 }}"

Review Comment:
   **Suggestion:** The Redis URL builder has the same escaping problem as the 
SQL URI: raw credentials are inserted directly into the URL, so special 
characters in usernames/passwords can generate malformed Redis URLs and break 
cache/Celery startup. Percent-encode credential components before composing the 
URL. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   ❌ Redis-backed cache fails; web nodes start without caching.
   ❌ Celery workers cannot connect Redis broker, tasks stuck.
   ⚠️ Async queries features unreliable when Redis URL malformed.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure Redis credentials with special characters, for example `--set
   cache.user='redis-user' --set cache.password='p@ss:word'` using the cache 
configuration
   documented at `helm/superset/values.yaml:293-337`.
   
   2. With `.Values.cache.cacheUrl` unset (default at `values.yaml:299-300`),
   `superset.config` in `helm/superset/templates/_helpers.tpl:232-259` computes
   `REDIS_BASE_URL`; when `$redisPassword` is set, line 244 builds
   `redis://redis-user:p@ss:word@host:port` without percent-encoding the 
credential
   components.
   
   3. Subsequent lines in `_helpers.tpl` derive `CACHE_REDIS_URL` and 
`CELERY_REDIS_URL` from
   `REDIS_BASE_URL` at 257-264, and these are injected into `CACHE_CONFIG` 
(lines 274-283)
   and the Celery configuration (317-351); web, worker, and beat deployments 
consume these
   settings via the mounted `superset_config.py` secret 
(`secret-superset-config.yaml:29-32`
   and volume mounts in `deployment.yaml:121-124`, 
`deployment-worker.yaml:115-118`,
   `deployment-beat.yaml:110-116`).
   
   4. At runtime the Redis client parses the malformed URL; the embedded `@` 
and `:` in the
   password confuse the parser, leading to authentication or host parsing 
errors, so cache
   initialization, Celery broker connections, and async query features relying 
on Redis all
   fail, surfacing connection errors in Superset logs.
   ```
   </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=ac589ce2c5394298a81f3fb186bccccc&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=ac589ce2c5394298a81f3fb186bccccc&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:** 244:244
   **Comment:**
        *Logic Error: The Redis URL builder has the same escaping problem as 
the SQL URI: raw credentials are inserted directly into the URL, so special 
characters in usernames/passwords can generate malformed Redis URLs and break 
cache/Celery startup. Percent-encode credential components before composing the 
URL.
   
   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=730625871a4716ff2af1a85d0dd79165cd4f4d617a487971ea8019efdb8d65dd&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=730625871a4716ff2af1a85d0dd79165cd4f4d617a487971ea8019efdb8d65dd&reaction=dislike'>👎</a>



##########
helm/superset/templates/_helpers.tpl:
##########
@@ -105,80 +106,564 @@ 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 | toString | title }}
 {{- 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 }}
+
+{{- if hasKey .Values.config.celeryConfig "imports" }}
+CELERY_IMPORTS = CeleryConfig.imports
+{{- end }}
+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 }},
+    {{- if $redisUserForGaq }}
+    "CACHE_REDIS_USER": {{ $redisUserForGaq | quote }},
+    {{- end }}
+    {{- 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 and .Values.cache.sentinel .Values.cache.sentinel.enabled }}
+    {{- 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": {{ if .Values.cache.ssl.certfile }}{{ 
.Values.cache.ssl.certfile | quote }}{{ else }}None{{ end }},
+    "CACHE_REDIS_SSL_KEYFILE": {{ if .Values.cache.ssl.keyfile }}{{ 
.Values.cache.ssl.keyfile | quote }}{{ else }}None{{ end }},
+    "CACHE_REDIS_SSL_CERT_REQS": {{ .Values.cache.ssl.ssl_cert_reqs | default 
"required" | quote }},
+    "CACHE_REDIS_SSL_CA_CERTS": {{ if .Values.cache.ssl.ca_certs }}{{ 
.Values.cache.ssl.ca_certs | quote }}{{ else }}None{{ end }},
+    {{- 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 }}
+
+{{- /* 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 hasKey .Values.config "GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE" }}
+GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = {{ 
.Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE | toString | title }}
+{{- else if and .Values.supersetWebsockets.enabled (or (hasPrefix "wss://" 
$wsUrl) .Values.ingress.tls) }}
+GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = True
+{{- else if .Values.supersetWebsockets.enabled }}
+GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = False
+{{- end }}
+
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE }}
+GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE = {{ 
.Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE | quote }}
+{{- else if .Values.supersetWebsockets.enabled }}
+GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE = "Lax"
+{{- end }}
+
+{{- if .Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME }}
+GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME = {{ 
.Values.config.GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME | quote }}
+{{- else if and .Values.supersetWebsockets.enabled 
.Values.supersetWebsockets.config.jwtCookieName }}
+GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME = {{ 
.Values.supersetWebsockets.config.jwtCookieName | quote }}
+{{- end }}
+
+{{- /* Content Security Policy (CSP) */}}
+{{- if and .Values.supersetWebsockets.enabled $wsUrl (not (hasKey 
.Values.config "TALISMAN_CONFIG")) }}
+TALISMAN_CONFIG = {
+    "content_security_policy": {
+        "base-uri": ["'self'"],
+        "default-src": ["'self'"],
+        "img-src": [
+            "'self'",
+            "blob:",
+            "data:",
+            "https://apachesuperset.gateway.scarf.sh";,
+            "https://static.scarf.sh/";,
+            "ows.terrestris.de",
+            "https://cdn.document360.io";,
+        ],
+        "worker-src": ["'self'", "blob:"],
+        "connect-src": [
+            "'self'",
+            {{ $wsUrl | quote }},
+            "https://api.mapbox.com";,
+            "https://events.mapbox.com";,
+            "https://tile.openstreetmap.org";,
+            "https://tile.osm.ch";,
+        ],
+        "object-src": "'none'",
+        "style-src": [
+            "'self'",
+            "'unsafe-inline'",
+        ],
+        "script-src": ["'self'", "'strict-dynamic'"],
+    },
+    "content_security_policy_nonce_in": ["script-src"],
+    {{- if or (hasPrefix "wss://" $wsUrl) .Values.ingress.tls }}
+    "force_https": True,
+    "session_cookie_secure": True,
+    {{- else }}
+    "force_https": False,
+    "session_cookie_secure": False,
+    {{- end }}
+}
+{{- end }}
 
-{{ if .Values.configOverrides }}
-# Overrides
+{{- /* General Configuration - iterate through all config values */}}
+{{- range $key, $value := .Values.config }}
+{{- if and (ne $key "cacheConfig") (ne $key "dataCacheConfig") (ne $key 
"celeryConfig") (ne $key "resultsBackend") (ne $key 
"GLOBAL_ASYNC_QUERIES_CACHE_BACKEND") (ne $key 
"GLOBAL_ASYNC_QUERIES_RESULTS_BACKEND") (ne $key 
"GLOBAL_ASYNC_QUERIES_TRANSPORT") (ne $key 
"GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL") (ne $key 
"GLOBAL_ASYNC_QUERIES_JWT_SECRET") (ne $key 
"GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE") (ne $key 
"GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE") (ne $key 
"GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME") (ne $key "TALISMAN_CONFIG") (ne $key 
"SQLLAB_ASYNC_TIME_LIMIT_SEC") (ne $key "SQLALCHEMY_TRACK_MODIFICATIONS") }}
+{{- if kindIs "map" $value }}
+{{ $key }} = {{ $value | toJson | indent 2 }}

Review Comment:
   **Suggestion:** Rendering map values with `toJson` directly into Python 
assignments can produce JSON literals like `true`, `false`, and `null`, which 
are invalid Python names at runtime; this will break `superset_config.py` 
import for configs containing booleans or nulls. Render Python-safe literals 
instead of raw JSON for dict values. [type error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   ❌ Web deployment fails importing rendered superset_config.py secret.
   ❌ Worker and beat deployments crash due to config syntax.
   ⚠️ Helm users face confusing Python errors on startup.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure the Helm release with a nested config map containing booleans, 
for example
   via `--set config.MY_FEATURE.enabled=true` (config keys documented at
   `helm/superset/values.yaml:338-345`).
   
   2. During template rendering, `superset.config` in
   `helm/superset/templates/_helpers.tpl:636-655` iterates `.Values.config`; 
for map values
   it hits the branch at line 639 and emits `MY_FEATURE = { "enabled": true }` 
using `toJson`
   at line 640, producing JSON literals `true`/`null`.
   
   3. Secret `helm/superset/templates/secret-superset-config.yaml:20-32` embeds 
this rendered
   text into `stringData.superset_config.py`, which is then mounted by the web 
and worker
   deployments at `helm/superset/templates/deployment.yaml:121-124` and
   `deployment-worker.yaml:115-118` via the `superset-config` volume.
   
   4. At runtime Superset imports `superset_config.py` as configuration (see 
docker docs at
   `docker/pythonpath_dev/superset_config_local.example:22-23` describing how
   `superset_config.py` is loaded); Python evaluates the dict literal containing
   `true`/`null` and raises a `NameError`, causing the module import and 
Superset processes
   to crash.
   ```
   </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=39cf8417fdae4d9788c886d0627fc0c8&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=39cf8417fdae4d9788c886d0627fc0c8&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:** 639:640
   **Comment:**
        *Type Error: Rendering map values with `toJson` directly into Python 
assignments can produce JSON literals like `true`, `false`, and `null`, which 
are invalid Python names at runtime; this will break `superset_config.py` 
import for configs containing booleans or nulls. Render Python-safe literals 
instead of raw JSON for dict values.
   
   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=654861b226c165da47a546896d64a6c5f364fd66f52085063760bb8112e93a7f&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=654861b226c165da47a546896d64a6c5f364fd66f52085063760bb8112e93a7f&reaction=dislike'>👎</a>



##########
helm/superset/templates/_helpers.tpl:
##########
@@ -187,7 +672,54 @@ RESULTS_BACKEND = RedisCache(
 {{- end }}
 {{- end }}
 
+{{- end -}}
+
+{{- define "superset.initScript" -}}
+#!/bin/sh
+set -eu
+echo "Upgrading DB schema..."
+superset db upgrade
+echo "Initializing roles and permissions..."
+superset init
+echo "Init job: Creating admin user and loading initial data..."
+{{- if .Values.init.createAdmin }}
+echo "Creating admin user..."
+superset fab create-admin \
+    --username {{ .Values.init.adminUser.username | quote }} \
+    --firstname {{ .Values.init.adminUser.firstname | quote }} \
+    --lastname {{ .Values.init.adminUser.lastname | quote }} \
+    --email {{ .Values.init.adminUser.email | quote }} \
+    --password {{ .Values.init.adminUser.password | quote }} \
+    || true

Review Comment:
   **Suggestion:** Swallowing all errors from admin creation makes the init job 
report success even when user creation fails for real reasons (not just 
“already exists”), leaving the deployment in a partially initialized state. 
Handle only the idempotent “already exists” case and fail on other errors. 
[logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   ⚠️ Init job reports success despite failing admin user creation.
   ⚠️ Cluster starts without expected bootstrap admin account configured.
   ⚠️ Real initialization errors masked, complicating troubleshooting 
post-upgrade.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Use the default init settings in `helm/superset/values.yaml:895-927` where
   `.Values.init.enabled=true` and `.Values.init.createAdmin=true`; Helm renders
   `superset.initScript` from `helm/superset/templates/_helpers.tpl:677-708` 
into
   `superset_init.sh` via `secret-superset-config.yaml:29-32`.
   
   2. The init Job manifest 
`helm/superset/templates/init-job.yaml:20-32,65-102` mounts the
   `superset-config` secret at `configMountPath` and executes the command from
   `values.yaml:909-913`, which sources `superset_bootstrap.sh` and then 
`superset_init.sh`.
   
   3. If the `superset fab create-admin` command in `_helpers.tpl:687-693` 
fails for a real
   error (for example a database permission issue, invalid admin email, or 
future CLI
   change), the leading `set -eu` at line 679 would normally terminate the 
script, but the
   `|| true` at line 693 forces the shell to ignore the non-zero exit code and 
continue.
   
   4. The script proceeds to load examples and prints "Init job complete." 
(lines 697-707),
   and Kubernetes reports the post-install/post-upgrade Job as succeeded (hook 
annotations at
   `helm/superset/values.yaml:915-917`), even though the admin user was not 
created, leaving
   the deployment partially initialized and masking the underlying failure from 
operators.
   ```
   </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=8fffcd292c23431cad035370c0cfc950&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=8fffcd292c23431cad035370c0cfc950&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:** 687:693
   **Comment:**
        *Logic Error: Swallowing all errors from admin creation makes the init 
job report success even when user creation fails for real reasons (not just 
“already exists”), leaving the deployment in a partially initialized state. 
Handle only the idempotent “already exists” case and fail on other errors.
   
   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=e189dec55d396505626057ded2ee7ea26b878033ba49cf81d49feead9218904c&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41777&comment_hash=e189dec55d396505626057ded2ee7ea26b878033ba49cf81d49feead9218904c&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