This is an automated email from the ASF dual-hosted git repository.

Miretpl pushed a commit to branch chart/v1-2x-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/chart/v1-2x-test by this push:
     new c6bc3a1945c [chart/v1-2x-test] Add securityContexts.disableDefaults 
flag for OpenShift SCC compatibility (#70238) (#72108)
c6bc3a1945c is described below

commit c6bc3a1945c40da6ee11e550a16e1d8f5308ff04
Author: Aaryan Mahajan <[email protected]>
AuthorDate: Thu Sep 10 02:12:54 2026 +0530

    [chart/v1-2x-test] Add securityContexts.disableDefaults flag for OpenShift 
SCC compatibility (#70238) (#72108)
    
    * Allow runAsUser and fsGroup to be explicitly null in pod securityContexts
    
    OpenShift assigns runAsUser/fsGroup automatically via SCC and rejects
    pods that hard-code them, so users need to null these out in the
    rendered pod securityContext. The vendored PodSecurityContext schema
    required these fields to be integers, so setting them to null failed
    Helm's values.schema.json validation before the templates ever
    rendered (the templates already pass through explicit nulls
    correctly).
    
    Introduces a new AirflowPodSecurityContext schema definition (not
    io.k8s.*-prefixed, so it survives vendor_k8s_json_schema.py
    regeneration) that allows null for runAsUser/runAsGroup/fsGroup, and
    points all 16 securityContexts.pod $refs at it instead of the vendored
    definition.
    
    closes: #41630
    
    * Add newsfragment for Helm chart securityContexts fix
    
    * Rename newsfragment to match this PR's number
    
    Named after the GitHub issue instead of the actual PR number, which
    the check-newsfragment-pr-number CI check expects.
    
    * Replace null-based OpenShift SCC workaround with a 
securityContexts.disableDefaults flag
    
    Explicit null in securityContexts.pod/containers was fragile and made every
    call site guess whether to render a key at all. A dedicated flag is more
    explicit about intent and lets the chart omit the default runAsUser/fsGroup
    (and related) values entirely on platforms like OpenShift where the 
cluster's
    SCC assigns them automatically and rejects hard-coded values.
    
    * Update production guide for the disableDefaults securityContexts flag
    
    The OpenShift SCC guidance still described the earlier null-based
    workaround, which no longer omits the rendered securityContext keys.
    
    * Fix docs spellcheck failure from unescaped securityContexts.* in schema 
description
    
    securityContexts.pod / securityContexts.containers appeared as plain text in
    the disableDefaults description, which the docs build renders as prose 
rather
    than code, tripping the spellchecker on the camelCase identifier.
    
    * Deprecate implicit securityContexts.disableDefaults default and unify 
helper argument order
    
    Address review feedback: mark the disableDefaults false default as
    deprecated (surfaced via NOTES.txt, values.yaml, values.schema.json and
    the newsfragment) since it will flip to true in a future release, and
    align airflowPodSecurityContextsIds's argument order with the rest of
    the security-context helpers in the chart. Also adds coverage for
    component-level securityContexts overrides taking priority over
    disableDefaults, both for Deployments and for the pod-template-file
    path used by KubernetesExecutor/KubernetesPodOperator.
    
    * Extend disableDefaults component-override test coverage to all chart 
components
    
    The disableDefaults escape hatch touches every component's security
    context, but the regression test only exercised scheduler and
    workers.celery. Parametrize it across all 13 affected components so a
    future template change can't silently break the override behavior for
    components that were previously untested, and add databaseCleanup
    coverage that no other test in this file provided either.
    
    * Tidy disableDefaults wording in values.yaml and values.schema.json
    
    The parenthetical note doesn't need a trailing period, and the
    values.yaml comment was missing backticks around the referenced keys
    that every other comment in the file uses.
    
    * Address review feedback on disableDefaults test coverage
    
    Split the mixed CronJob/Deployment assertions in
    test_disable_defaults_pod_and_container into separate tests instead of
    branching on list position, replace per-doc Python loops and
    init-container name comprehensions with jmespath expressions to match
    the rest of the file, and drop docstrings that only restated what the
    test name already says.
    
    * Update chart/values.schema.json
    
    
    
    * Update chart/values.yaml
    
    
    
    * Fixing PR comments
    
    ---------
    (cherry picked from commit 3ac385170905a327fe4363abb4404acc7bdd8eb8)
    
    Co-authored-by: Przemysław Mirowski 
<[email protected]>
---
 chart/docs/production-guide.rst                    |  22 ++
 chart/newsfragments/70238.significant.rst          |   3 +
 chart/templates/NOTES.txt                          |   8 +
 chart/templates/_helpers.yaml                      |  68 ++++---
 .../api-server/api-server-deployment.yaml          |   6 +
 chart/templates/cleanup/cleanup-cronjob.yaml       |   4 +
 .../dag-processor/dag-processor-deployment.yaml    |   8 +
 .../database-cleanup/database-cleanup-cronjob.yaml |   4 +
 chart/templates/flower/flower-deployment.yaml      |   4 +
 chart/templates/jobs/create-user-job.yaml          |   4 +
 chart/templates/jobs/migrate-database-job.yaml     |   4 +
 .../templates/pgbouncer/pgbouncer-deployment.yaml  |  12 +-
 chart/templates/redis/redis-statefulset.yaml       |   8 +-
 .../templates/scheduler/scheduler-deployment.yaml  |   8 +
 chart/templates/statsd/statsd-deployment.yaml      |   8 +-
 .../templates/triggerer/triggerer-deployment.yaml  |   8 +
 chart/templates/workers/worker-deployment.yaml     |  19 +-
 chart/values.schema.json                           |   6 +
 chart/values.yaml                                  |   5 +
 .../airflow_aux/test_pod_template_file.py          |  37 ++++
 .../helm_tests/security/test_security_context.py   | 225 +++++++++++++++++++++
 21 files changed, 436 insertions(+), 35 deletions(-)

diff --git a/chart/docs/production-guide.rst b/chart/docs/production-guide.rst
index 49d12a99946..4c3b7c00cda 100644
--- a/chart/docs/production-guide.rst
+++ b/chart/docs/production-guide.rst
@@ -816,6 +816,28 @@ This will generate the following scheduler deployment:
            - name: scheduler
          ...
 
+Omitting default ``securityContext`` values
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+On OpenShift, the ``restricted`` SCC assigns ``runAsUser`` and ``fsGroup`` 
automatically and rejects Pods
+that request specific values without the ``anyuid`` SCC in place. Since an 
empty ``securityContexts.pod``
+falls back to :ref:`uid <parameters:Airflow>` / :ref:`gid 
<parameters:Airflow>` (as shown above), leaving
+it empty is not enough to avoid hard-coded values. Set 
``securityContexts.disableDefaults`` to stop the
+chart from filling in these defaults wherever ``securityContexts.pod`` / 
``securityContexts.containers``
+(or the equivalent per-component overrides) are left empty:
+
+.. code-block:: yaml
+   :caption: values.yaml
+
+   securityContexts:
+     disableDefaults: true
+
+This omits ``runAsUser`` / ``fsGroup`` (pod) and ``runAsUser`` (container) 
from the rendered
+``securityContext`` entirely wherever they are not explicitly set, allowing 
the SCC to supply its own
+values. Explicit values set in ``securityContexts.pod`` / 
``securityContexts.containers`` (or a
+component's local override, e.g. ``scheduler.securityContexts.pod``) still 
take priority over
+``disableDefaults``.
+
 Built-in secrets and environment variables
 ------------------------------------------
 
diff --git a/chart/newsfragments/70238.significant.rst 
b/chart/newsfragments/70238.significant.rst
new file mode 100644
index 00000000000..369f43d7a6c
--- /dev/null
+++ b/chart/newsfragments/70238.significant.rst
@@ -0,0 +1,3 @@
+Added ``securityContexts.disableDefaults`` (default ``false``) to the Helm 
chart. When set, the chart no longer fills in the default 
``runAsUser``/``fsGroup`` (pod) or ``runAsUser`` (container) values when 
``securityContexts.pod`` / ``securityContexts.containers`` (or the equivalent 
per-component overrides) are left empty, allowing platforms such as OpenShift 
to assign them automatically via SCC instead of the chart hard-coding them.
+
+Value ``false`` for ``securityContexts.disableDefaults`` is deprecated and 
will be ``true`` by default in the next major release. Please adjust your 
configuration accordingly.
diff --git a/chart/templates/NOTES.txt b/chart/templates/NOTES.txt
index 8855f8f04ca..3765f88e979 100644
--- a/chart/templates/NOTES.txt
+++ b/chart/templates/NOTES.txt
@@ -1053,6 +1053,14 @@ DEPRECATION WARNING:
 
 {{- end }}
 
+{{- if not .Values.securityContexts.disableDefaults }}
+
+ DEPRECATION WARNING:
+    `securityContexts.disableDefaults` equal `false` is deprecated and will 
default to `true` in a future release.
+    Please set `securityContexts.disableDefaults: true` explicitly, or provide 
values via `securityContexts.pod` / `securityContexts.containers` (or 
per-component overrides), before the default changes.
+
+{{- end }}
+
 {{- if not (or .Values.webserverSecretKey .Values.webserverSecretKeySecretName 
.Values.apiSecretKey .Values.apiSecretKeySecretName) }}
 {{ if (semverCompare ">=3.0.0" .Values.airflowVersion) }}
 #####################################################
diff --git a/chart/templates/_helpers.yaml b/chart/templates/_helpers.yaml
index 655374282ec..17bc1803238 100644
--- a/chart/templates/_helpers.yaml
+++ b/chart/templates/_helpers.yaml
@@ -226,7 +226,10 @@ If release name contains chart name it will be used as a 
full name.
 - name: {{ .Values.dags.gitSync.containerName }}{{ if .is_init }}-init{{ end }}
   image: {{ template "git_sync_image" . }}
   imagePullPolicy: {{ .Values.images.gitSync.pullPolicy }}
-  securityContext: {{- include "localContainerSecurityContext" 
.Values.dags.gitSync | nindent 4 }}
+  {{- $gitSyncContainerSecurityContext := include 
"localContainerSecurityContext" (list .Values.dags.gitSync .Values) }}
+  {{- if $gitSyncContainerSecurityContext }}
+  securityContext: {{ $gitSyncContainerSecurityContext | nindent 4 }}
+  {{- end }}
   envFrom: {{- include "custom_git_sync_environment_from" . | default "\n  []" 
| indent 2 }}
   env:
     - name: GIT_SYNC_REV
@@ -930,7 +933,7 @@ Priority of values are from left to right, meaning if first 
value is not empty,
   {{- end }}
   {{- if $result }}
     {{- toYaml $result | print }}
-  {{- else }}
+  {{- else if not $.securityContexts.disableDefaults }}
 runAsUser: {{ $.uid }}
 fsGroup: {{ $.gid }}
   {{- end }}
@@ -945,17 +948,20 @@ If no value is passed for <node>.securityContexts.pod or 
<node>.securityContext,
     +-----------------------------+      +------------------------+      
+------------+
 
 The template can be called like so:
-  include "localPodSecurityContext" (list . .Values.schedule)
+  include "localPodSecurityContext" (list .Values.redis .Values)
 
+Where `.Values` is the global variables scope and `.Values.redis` the local 
variables scope for the redis template.
 It is important to pass the local variables scope to this template as it is 
used to determine the local node value for uid.
 */}}
 {{- define "localPodSecurityContext" -}}
-  {{- if .securityContexts.pod -}}
-    {{ toYaml .securityContexts.pod | print }}
-  {{- else if .securityContext -}}
-    {{ toYaml .securityContext | print }}
-  {{- else -}}
-runAsUser: {{ .uid }}
+  {{- $ := last . }}
+  {{- $node := first . }}
+  {{- if $node.securityContexts.pod -}}
+    {{ toYaml $node.securityContexts.pod | print }}
+  {{- else if $node.securityContext -}}
+    {{ toYaml $node.securityContext | print }}
+  {{- else if not $.securityContexts.disableDefaults -}}
+runAsUser: {{ $node.uid }}
   {{- end -}}
 {{- end -}}
 
@@ -968,17 +974,20 @@ If no value is passed for 
<node>.securityContexts.container or <node>.securityCo
     +-----------------------------------+      +------------------------+      
+------------+
 
 The template can be called like so:
-  include "localContainerSecurityContext" .Values.statsd
+  include "localContainerSecurityContext" (list .Values.dags.gitSync .Values)
 
+Where `.Values` is the global variables scope and `.Values.dags.gitSync` the 
local variables scope.
 It is important to pass the local variables scope to this template as it is 
used to determine the local node value for uid.
 */}}
 {{- define "localContainerSecurityContext" -}}
-  {{- if .securityContexts.container -}}
-    {{ toYaml .securityContexts.container | print }}
-  {{- else if .securityContext -}}
-    {{ toYaml .securityContext | print }}
-  {{- else -}}
-runAsUser: {{ .uid }}
+  {{- $ := last . }}
+  {{- $node := first . }}
+  {{- if $node.securityContexts.container -}}
+    {{ toYaml $node.securityContexts.container | print }}
+  {{- else if $node.securityContext -}}
+    {{ toYaml $node.securityContext | print }}
+  {{- else if not $.securityContexts.disableDefaults -}}
+runAsUser: {{ $node.uid }}
   {{- end -}}
 {{- end -}}
 
@@ -994,21 +1003,24 @@ The template looks for `runAsUser` and `fsGroup` 
specifically, any other paramet
 Values are not accumulated meaning that if runAsUser is set to 10 in 
<node>.securityContexts.pod,
 any extra values set to securityContexts or uid+gid will be ignored.
 
+If securityContexts.disableDefaults is true and no explicit runAsUser/fsGroup 
is set anywhere,
+this template renders an empty string, since there is no id to chown to.
+
 The template can be called like so:
-   include "airflowPodSecurityContextsIds" (list . .Values.webserver)
+   include "airflowPodSecurityContextsIds" (list .Values.webserver .)
 
-Where `.` is the global variables scope and `.Values.workers` the local 
variables scope for the workers template.
+Where `.Values.workers` is the local variables scope for the workers template 
and `.` the global variables scope.
 */}}
 {{- define "airflowPodSecurityContextsIds" -}}
-  {{- $ := index . 0 -}}
-  {{- with index . 1 }}
+  {{- $ := last . -}}
+  {{- with first . }}
     {{- if .securityContexts.pod -}}
       {{ pluck "runAsUser" .securityContexts.pod | first | default 
$.Values.uid }}:{{ pluck "fsGroup" .securityContexts.pod | first | default 
$.Values.gid }}
     {{- else if $.Values.securityContext -}}
       {{ pluck "runAsUser" $.Values.securityContext | first | default 
$.Values.uid }}:{{ pluck "fsGroup" $.Values.securityContext | first | default 
$.Values.gid }}
     {{- else if $.Values.securityContexts.pod -}}
       {{ pluck "runAsUser" $.Values.securityContexts.pod | first | default 
$.Values.uid }}:{{ pluck "fsGroup" $.Values.securityContexts.pod | first | 
default $.Values.gid }}
-    {{- else -}}
+    {{- else if not $.Values.securityContexts.disableDefaults -}}
 {{ $.Values.uid }}:{{ $.Values.gid }}
     {{- end -}}
   {{- end -}}
@@ -1041,7 +1053,7 @@ Priority of values are from left to right, meaning if 
first value is not empty,
     {{- toYaml $result | print }}
   {{- else if and (hasKey $ "securityContexts") (hasKey $.securityContexts 
"containers") $.securityContexts.containers }}
     {{- toYaml $.securityContexts.containers | print }}
-  {{- else -}}
+  {{- else if not $.securityContexts.disableDefaults }}
 allowPrivilegeEscalation: false
 capabilities:
   drop:
@@ -1058,12 +1070,16 @@ If no value is passed for 
<node>.securityContexts.container, defaults to deny pr
     +-----------------------------------+      
+------------------------------------------------------------+
 
 The template can be called like so:
-  include "externalContainerSecurityContext" .Values.statsd
+  include "externalContainerSecurityContext" (list .Values.statsd .Values)
+
+Where `.Values` is the global variables scope and `.Values.statsd` the local 
variables scope.
 */}}
 {{- define "externalContainerSecurityContext" -}}
-  {{- if .securityContexts.container -}}
-    {{ toYaml .securityContexts.container | print }}
-  {{- else -}}
+  {{- $ := last . }}
+  {{- $node := first . }}
+  {{- if $node.securityContexts.container -}}
+    {{ toYaml $node.securityContexts.container | print }}
+  {{- else if not $.securityContexts.disableDefaults -}}
 allowPrivilegeEscalation: false
 capabilities:
   drop:
diff --git a/chart/templates/api-server/api-server-deployment.yaml 
b/chart/templates/api-server/api-server-deployment.yaml
index dafe2a78eb8..0f115cc4cbd 100644
--- a/chart/templates/api-server/api-server-deployment.yaml
+++ b/chart/templates/api-server/api-server-deployment.yaml
@@ -130,7 +130,9 @@ spec:
       tolerations: {{- toYaml $tolerations | nindent 8 }}
       topologySpreadConstraints: {{- toYaml $topologySpreadConstraints | 
nindent 8 }}
       restartPolicy: Always
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       imagePullSecrets: {{- include "image_pull_secrets" . | nindent 8 }}
       initContainers:
         {{- if .Values.apiServer.waitForMigrations.enabled }}
@@ -138,7 +140,9 @@ spec:
           resources: {{- toYaml .Values.apiServer.resources | nindent 12 }}
           image: {{ template "airflow_image_for_migrations" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextWaitForMigrations }}
           securityContext: {{ $containerSecurityContextWaitForMigrations | 
nindent 12 }}
+          {{- end }}
           volumeMounts:
             {{- include "airflow_config_mount" . | nindent 12 }}
             {{- if .Values.volumeMounts }}
@@ -163,7 +167,9 @@ spec:
         - name: api-server
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks  }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
diff --git a/chart/templates/cleanup/cleanup-cronjob.yaml 
b/chart/templates/cleanup/cleanup-cronjob.yaml
index fe3d6a33b48..e639b71fe26 100644
--- a/chart/templates/cleanup/cleanup-cronjob.yaml
+++ b/chart/templates/cleanup/cleanup-cronjob.yaml
@@ -88,12 +88,16 @@ spec:
           serviceAccountName: {{ include "cleanup.serviceAccountName" . }}
           {{- include "serviceLinks" . | nindent 10 }}
           imagePullSecrets: {{- include "image_pull_secrets" . | nindent 12 }}
+          {{- if $securityContext }}
           securityContext: {{ $securityContext | nindent 12 }}
+          {{- end }}
           containers:
             - name: airflow-cleanup-pods
               image: {{ template "airflow_image" . }}
               imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+              {{- if $containerSecurityContext }}
               securityContext: {{ $containerSecurityContext | nindent 16 }}
+              {{- end }}
               {{- if $containerLifecycleHooks }}
               lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 
16 }}
               {{- end }}
diff --git a/chart/templates/dag-processor/dag-processor-deployment.yaml 
b/chart/templates/dag-processor/dag-processor-deployment.yaml
index 35c7215b479..d7f883718ac 100644
--- a/chart/templates/dag-processor/dag-processor-deployment.yaml
+++ b/chart/templates/dag-processor/dag-processor-deployment.yaml
@@ -115,7 +115,9 @@ spec:
       restartPolicy: Always
       serviceAccountName: {{ include "dagProcessor.serviceAccountName" . }}
       {{- include "serviceLinks" . | nindent 6 }}
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       imagePullSecrets: {{ include "image_pull_secrets" . | nindent 8 }}
       initContainers:
         {{- if .Values.dagProcessor.waitForMigrations.enabled }}
@@ -123,7 +125,9 @@ spec:
           resources: {{- toYaml .Values.dagProcessor.resources | nindent 12 }}
           image: {{ template "airflow_image_for_migrations" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextWaitForMigrations }}
           securityContext: {{ $containerSecurityContextWaitForMigrations | 
nindent 12 }}
+          {{- end }}
           volumeMounts:
             {{- if .Values.volumeMounts }}
               {{- toYaml .Values.volumeMounts | nindent 12 }}
@@ -151,7 +155,9 @@ spec:
         - name: dag-processor
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks  }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
@@ -203,7 +209,9 @@ spec:
           resources: {{- toYaml 
.Values.dagProcessor.logGroomerSidecar.resources | nindent 12 }}
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextLogGroomerSidecar }}
           securityContext: {{ $containerSecurityContextLogGroomerSidecar | 
nindent 12 }}
+          {{- end }}
           {{- if .Values.dagProcessor.logGroomerSidecar.command }}
           command: {{ tpl (toYaml 
.Values.dagProcessor.logGroomerSidecar.command) . | nindent 12 }}
           {{- end }}
diff --git a/chart/templates/database-cleanup/database-cleanup-cronjob.yaml 
b/chart/templates/database-cleanup/database-cleanup-cronjob.yaml
index 140e6f3c5f7..6295b10a43c 100644
--- a/chart/templates/database-cleanup/database-cleanup-cronjob.yaml
+++ b/chart/templates/database-cleanup/database-cleanup-cronjob.yaml
@@ -91,12 +91,16 @@ spec:
           serviceAccountName: {{ include "databaseCleanup.serviceAccountName" 
. }}
           {{- include "serviceLinks" . | nindent 10 }}
           imagePullSecrets: {{- include "image_pull_secrets" . | nindent 12 }}
+          {{- if $securityContext }}
           securityContext: {{ $securityContext | nindent 12 }}
+          {{- end }}
           containers:
             - name: database-cleanup
               image: {{ template "airflow_image" . }}
               imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+              {{- if $containerSecurityContext }}
               securityContext: {{ $containerSecurityContext | nindent 16 }}
+              {{- end }}
               {{- if $containerLifecycleHooks }}
               lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 
16 }}
               {{- end }}
diff --git a/chart/templates/flower/flower-deployment.yaml 
b/chart/templates/flower/flower-deployment.yaml
index 62f38715ebd..07ae24d85e2 100644
--- a/chart/templates/flower/flower-deployment.yaml
+++ b/chart/templates/flower/flower-deployment.yaml
@@ -84,13 +84,17 @@ spec:
       priorityClassName: {{ .Values.flower.priorityClassName }}
       {{- end }}
       restartPolicy: Always
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       imagePullSecrets: {{- include "image_pull_secrets" . | nindent 8 }}
       containers:
         - name: flower
           image: {{ template "flower_image" . }}
           imagePullPolicy: {{ .Values.images.flower.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks  }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
diff --git a/chart/templates/jobs/create-user-job.yaml 
b/chart/templates/jobs/create-user-job.yaml
index 1d0cf23e238..cce10fdf711 100644
--- a/chart/templates/jobs/create-user-job.yaml
+++ b/chart/templates/jobs/create-user-job.yaml
@@ -73,7 +73,9 @@ spec:
         {{- end }}
       {{- end }}
     spec:
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       restartPolicy: {{ .Values.createUserJob.restartPolicy }}
       {{- if .Values.createUserJob.priorityClassName }}
       priorityClassName: {{ .Values.createUserJob.priorityClassName }}
@@ -96,7 +98,9 @@ spec:
         - name: create-user
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks  }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
diff --git a/chart/templates/jobs/migrate-database-job.yaml 
b/chart/templates/jobs/migrate-database-job.yaml
index b18d3c9290e..f7944399547 100644
--- a/chart/templates/jobs/migrate-database-job.yaml
+++ b/chart/templates/jobs/migrate-database-job.yaml
@@ -73,7 +73,9 @@ spec:
         {{- end }}
       {{- end }}
     spec:
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       restartPolicy: {{ .Values.migrateDatabaseJob.restartPolicy }}
       {{- if .Values.migrateDatabaseJob.priorityClassName }}
       priorityClassName: {{ .Values.migrateDatabaseJob.priorityClassName }}
@@ -96,7 +98,9 @@ spec:
         - name: run-airflow-migrations
           image: {{ template "airflow_image_for_migrations" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks  }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
diff --git a/chart/templates/pgbouncer/pgbouncer-deployment.yaml 
b/chart/templates/pgbouncer/pgbouncer-deployment.yaml
index 96f523a6d9e..7423b6cfa50 100644
--- a/chart/templates/pgbouncer/pgbouncer-deployment.yaml
+++ b/chart/templates/pgbouncer/pgbouncer-deployment.yaml
@@ -26,9 +26,9 @@
 {{- $tolerations := or .Values.pgbouncer.tolerations .Values.tolerations }}
 {{- $topologySpreadConstraints := or 
.Values.pgbouncer.topologySpreadConstraints .Values.topologySpreadConstraints }}
 {{- $revisionHistoryLimit := include "airflow.revisionHistoryLimit" (list 
.Values.pgbouncer.revisionHistoryLimit .Values.revisionHistoryLimit) }}
-{{- $securityContext := include "localPodSecurityContext" .Values.pgbouncer }}
-{{- $containerSecurityContext := include "externalContainerSecurityContext" 
.Values.pgbouncer }}
-{{- $containerSecurityContextMetricsExporter := include 
"externalContainerSecurityContext" .Values.pgbouncer.metricsExporterSidecar }}
+{{- $securityContext := include "localPodSecurityContext" (list 
.Values.pgbouncer .Values) }}
+{{- $containerSecurityContext := include "externalContainerSecurityContext" 
(list .Values.pgbouncer .Values) }}
+{{- $containerSecurityContextMetricsExporter := include 
"externalContainerSecurityContext" (list 
.Values.pgbouncer.metricsExporterSidecar .Values) }}
 {{- $containerLifecycleHooks := .Values.pgbouncer.containerLifecycleHooks }}
 {{- $containerLifecycleHooksMetricsExporter := 
.Values.pgbouncer.metricsExporterSidecar.containerLifecycleHooks }}
 apiVersion: apps/v1
@@ -90,14 +90,18 @@ spec:
       terminationGracePeriodSeconds: {{ 
.Values.pgbouncer.terminationGracePeriodSeconds }}
       serviceAccountName: {{ include "pgbouncer.serviceAccountName" . }}
       {{- include "serviceLinks" . | nindent 6 }}
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       restartPolicy: Always
       imagePullSecrets: {{- include "image_pull_secrets" . | nindent 8 }}
       containers:
         - name: pgbouncer
           image: {{ template "pgbouncer_image" . }}
           imagePullPolicy: {{ .Values.images.pgbouncer.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if .Values.pgbouncer.command }}
           command: {{ tpl (toYaml .Values.pgbouncer.command) . | nindent 12 }}
           {{- end }}
@@ -161,7 +165,9 @@ spec:
           resources: {{- toYaml 
.Values.pgbouncer.metricsExporterSidecar.resources | nindent 12 }}
           image: {{ template "pgbouncer_exporter_image" . }}
           imagePullPolicy: {{ .Values.images.pgbouncerExporter.pullPolicy }}
+          {{- if $containerSecurityContextMetricsExporter }}
           securityContext: {{ $containerSecurityContextMetricsExporter | 
nindent 12 }}
+          {{- end }}
           env:
             - name: DATABASE_URL
               valueFrom:
diff --git a/chart/templates/redis/redis-statefulset.yaml 
b/chart/templates/redis/redis-statefulset.yaml
index 7e55fe52a62..8cfd9ca0ddd 100644
--- a/chart/templates/redis/redis-statefulset.yaml
+++ b/chart/templates/redis/redis-statefulset.yaml
@@ -25,8 +25,8 @@
 {{- $affinity := or .Values.redis.affinity .Values.affinity }}
 {{- $tolerations := or .Values.redis.tolerations .Values.tolerations }}
 {{- $topologySpreadConstraints := or .Values.redis.topologySpreadConstraints 
.Values.topologySpreadConstraints }}
-{{- $securityContext := include "localPodSecurityContext" .Values.redis }}
-{{- $containerSecurityContext := include "externalContainerSecurityContext" 
.Values.redis }}
+{{- $securityContext := include "localPodSecurityContext" (list .Values.redis 
.Values) }}
+{{- $containerSecurityContext := include "externalContainerSecurityContext" 
(list .Values.redis .Values) }}
 {{- $containerLifecycleHooks := .Values.redis.containerLifecycleHooks }}
 {{- $persistence := .Values.redis.persistence.enabled }}
 apiVersion: apps/v1
@@ -88,12 +88,16 @@ spec:
       schedulerName: {{ .Values.schedulerName }}
       {{- end }}
       imagePullSecrets: {{ include "image_pull_secrets" . | nindent 8 }}
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       containers:
         - name: redis
           image: {{ template "redis_image" . }}
           imagePullPolicy: {{ .Values.images.redis.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
diff --git a/chart/templates/scheduler/scheduler-deployment.yaml 
b/chart/templates/scheduler/scheduler-deployment.yaml
index 9b353fed724..9999d856627 100644
--- a/chart/templates/scheduler/scheduler-deployment.yaml
+++ b/chart/templates/scheduler/scheduler-deployment.yaml
@@ -141,7 +141,9 @@ spec:
       {{- if and (eq (include "airflow.podLaunchingExecutor" .) "true") (not 
.Values.scheduler.serviceAccount.automountServiceAccountToken) }}
       automountServiceAccountToken: false
       {{- end }}
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       imagePullSecrets: {{ include "image_pull_secrets" . | nindent 8 }}
       {{- if .Values.scheduler.hostAliases }}
       hostAliases: {{- toYaml .Values.scheduler.hostAliases | nindent 8 }}
@@ -152,7 +154,9 @@ spec:
           resources: {{- toYaml .Values.scheduler.resources | nindent 12 }}
           image: {{ template "airflow_image_for_migrations" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextWaitForMigrations }}
           securityContext: {{ $containerSecurityContextWaitForMigrations | 
nindent 12 }}
+          {{- end }}
           volumeMounts:
             - name: logs
               mountPath: "/opt/airflow/logs"
@@ -188,7 +192,9 @@ spec:
         - name: scheduler
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
@@ -267,7 +273,9 @@ spec:
           resources: {{- toYaml .Values.scheduler.logGroomerSidecar.resources 
| nindent 12 }}
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextLogGroomerSidecar }}
           securityContext: {{ $containerSecurityContextLogGroomerSidecar | 
nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooksLogGroomerSidecar  }}
           lifecycle: {{- tpl (toYaml 
$containerLifecycleHooksLogGroomerSidecar) . | nindent 12 }}
           {{- end }}
diff --git a/chart/templates/statsd/statsd-deployment.yaml 
b/chart/templates/statsd/statsd-deployment.yaml
index 9963ccd4858..e5aabe4b819 100644
--- a/chart/templates/statsd/statsd-deployment.yaml
+++ b/chart/templates/statsd/statsd-deployment.yaml
@@ -26,8 +26,8 @@
 {{- $tolerations := or .Values.statsd.tolerations .Values.tolerations }}
 {{- $topologySpreadConstraints := or .Values.statsd.topologySpreadConstraints 
.Values.topologySpreadConstraints }}
 {{- $revisionHistoryLimit := include "airflow.revisionHistoryLimit" (list 
.Values.statsd.revisionHistoryLimit .Values.revisionHistoryLimit) }}
-{{- $securityContext := include "localPodSecurityContext" .Values.statsd }}
-{{- $containerSecurityContext := include "externalContainerSecurityContext" 
.Values.statsd }}
+{{- $securityContext := include "localPodSecurityContext" (list .Values.statsd 
.Values) }}
+{{- $containerSecurityContext := include "externalContainerSecurityContext" 
(list .Values.statsd .Values) }}
 {{- $containerLifecycleHooks := .Values.statsd.containerLifecycleHooks }}
 apiVersion: apps/v1
 kind: Deployment
@@ -85,14 +85,18 @@ spec:
       terminationGracePeriodSeconds: {{ 
.Values.statsd.terminationGracePeriodSeconds }}
       serviceAccountName: {{ include "statsd.serviceAccountName" . }}
       {{- include "serviceLinks" . | nindent 6 }}
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       restartPolicy: Always
       imagePullSecrets: {{ include "image_pull_secrets" . | nindent 8 }}
       containers:
         - name: statsd
           image: {{ template "statsd_image" . }}
           imagePullPolicy: {{ .Values.images.statsd.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
diff --git a/chart/templates/triggerer/triggerer-deployment.yaml 
b/chart/templates/triggerer/triggerer-deployment.yaml
index 24414a575f8..cc557191f25 100644
--- a/chart/templates/triggerer/triggerer-deployment.yaml
+++ b/chart/templates/triggerer/triggerer-deployment.yaml
@@ -128,7 +128,9 @@ spec:
       restartPolicy: Always
       serviceAccountName: {{ include "triggerer.serviceAccountName" . }}
       {{- include "serviceLinks" . | nindent 6 }}
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       imagePullSecrets: {{ include "image_pull_secrets" . | nindent 8 }}
       initContainers:
         {{- if .Values.triggerer.waitForMigrations.enabled }}
@@ -137,7 +139,9 @@ spec:
             {{- toYaml .Values.triggerer.resources | nindent 12 }}
           image: {{ template "airflow_image_for_migrations" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextWaitForMigrations }}
           securityContext: {{ $containerSecurityContextWaitForMigrations | 
nindent 12 }}
+          {{- end }}
           volumeMounts:
             - name: logs
               mountPath: "/opt/airflow/logs"
@@ -173,7 +177,9 @@ spec:
         - name: triggerer
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
@@ -231,7 +237,9 @@ spec:
           resources: {{- toYaml .Values.triggerer.logGroomerSidecar.resources 
| nindent 12 }}
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextLogGroomer }}
           securityContext: {{ $containerSecurityContextLogGroomer | nindent 12 
}}
+          {{- end }}
           {{- if $containerLifecycleHooksLogGroomerSidecar }}
           lifecycle: {{- tpl (toYaml 
$containerLifecycleHooksLogGroomerSidecar) . | nindent 12 }}
           {{- end }}
diff --git a/chart/templates/workers/worker-deployment.yaml 
b/chart/templates/workers/worker-deployment.yaml
index c9f8fff22e6..5c49888b1df 100644
--- a/chart/templates/workers/worker-deployment.yaml
+++ b/chart/templates/workers/worker-deployment.yaml
@@ -44,6 +44,7 @@
 {{- $topologySpreadConstraints := or .Values.workers.topologySpreadConstraints 
.Values.topologySpreadConstraints }}
 {{- $revisionHistoryLimit := include "airflow.revisionHistoryLimit" (list 
.Values.workers.revisionHistoryLimit .Values.revisionHistoryLimit) }}
 {{- $securityContext := include "airflowPodSecurityContext" (list 
.Values.workers .Values) }}
+{{- $securityContextsIds := include "airflowPodSecurityContextsIds" (list 
.Values.workers .) }}
 {{- $containerSecurityContext := include "containerSecurityContext" (list 
.Values.workers .Values) }}
 {{- $containerSecurityContextPersistence := include "containerSecurityContext" 
(list .Values.workers.persistence .Values) }}
 {{- $containerSecurityContextWaitForMigrations := include 
"containerSecurityContext" (list .Values.workers.waitForMigrations .Values) }}
@@ -160,10 +161,12 @@ spec:
       restartPolicy: Always
       serviceAccountName: {{ include "worker.serviceAccountName" . }}
       {{- include "serviceLinks" . | nindent 6 }}
+      {{- if $securityContext }}
       securityContext: {{ $securityContext | nindent 8 }}
+      {{- end }}
       imagePullSecrets: {{ include "image_pull_secrets" . | nindent 8 }}
       initContainers:
-        {{- if and $persistence .Values.workers.persistence.fixPermissions }}
+        {{- if and $persistence .Values.workers.persistence.fixPermissions 
$securityContextsIds }}
         - name: volume-permissions
           resources: {{- toYaml .Values.workers.resources | nindent 12 }}
           image: {{ template "airflow_image" . }}
@@ -171,9 +174,11 @@ spec:
           command:
             - chown
             - -R
-            - "{{ include "airflowPodSecurityContextsIds" (list . 
.Values.workers) }}"
+            - "{{ $securityContextsIds }}"
             - {{ template "airflow_logs" . }}
+          {{- if $containerSecurityContextPersistence }}
           securityContext: {{ $containerSecurityContextPersistence | nindent 
12 }}
+          {{- end }}
           volumeMounts:
             - name: logs
               mountPath: {{ template "airflow_logs" . }}
@@ -184,7 +189,9 @@ spec:
         {{- if .Values.workers.kerberosInitContainer.enabled }}
         - name: kerberos-init
           image: {{ template "airflow_image" . }}
+          {{- if $containerSecurityContextKerberosInitContainer }}
           securityContext: {{ $containerSecurityContextKerberosInitContainer | 
nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooksKerberosInitContainer }}
           lifecycle: {{- tpl (toYaml 
$containerLifecycleHooksKerberosInitContainer) . | nindent 12 }}
           {{- end }}
@@ -232,7 +239,9 @@ spec:
           resources: {{- toYaml .Values.workers.resources | nindent 12 }}
           image: {{ template "airflow_image_for_migrations" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextWaitForMigrations }}
           securityContext: {{ $containerSecurityContextWaitForMigrations | 
nindent 12 }}
+          {{- end }}
           volumeMounts:
             - name: logs
               mountPath: "/opt/airflow/logs"
@@ -268,7 +277,9 @@ spec:
         - name: worker
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContext }}
           securityContext: {{ $containerSecurityContext | nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooks }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooks) . | nindent 12 
}}
           {{- end }}
@@ -354,7 +365,9 @@ spec:
         - name: worker-log-groomer
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextLogGroomerSidecar }}
           securityContext: {{ $containerSecurityContextLogGroomerSidecar | 
nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooksLogGroomerSidecar }}
           lifecycle: {{- tpl (toYaml 
$containerLifecycleHooksLogGroomerSidecar) . | nindent 12 }}
           {{- end }}
@@ -411,7 +424,9 @@ spec:
         - name: worker-kerberos
           image: {{ template "airflow_image" . }}
           imagePullPolicy: {{ .Values.images.airflow.pullPolicy }}
+          {{- if $containerSecurityContextKerberosSidecar }}
           securityContext: {{ $containerSecurityContextKerberosSidecar | 
nindent 12 }}
+          {{- end }}
           {{- if $containerLifecycleHooksKerberosSidecar }}
           lifecycle: {{- tpl (toYaml $containerLifecycleHooksKerberosSidecar) 
. | nindent 12 }}
           {{- end }}
diff --git a/chart/values.schema.json b/chart/values.schema.json
index 011849f7a3c..142de64f9f5 100644
--- a/chart/values.schema.json
+++ b/chart/values.schema.json
@@ -141,6 +141,12 @@
                             "allowPrivilegeEscalation": false
                         }
                     ]
+                },
+                "disableDefaults": {
+                    "description": "If `true`, the chart will not set any 
default `securityContext` values when `securityContexts.pod` / 
`securityContexts.containers` (or the equivalent per-component overrides) are 
left empty (default `false` is deprecated and will change to `true` in a future 
release).",
+                    "type": "boolean",
+                    "default": false,
+                    "x-docsSection": "Kubernetes"
                 }
             }
         },
diff --git a/chart/values.yaml b/chart/values.yaml
index d8793c5b431..41a61171d33 100644
--- a/chart/values.yaml
+++ b/chart/values.yaml
@@ -53,6 +53,11 @@ securityContext: {}
 securityContexts:
   pod: {}
   containers: {}
+  # If `true`, the chart will not set any default `securityContext` values when
+  # `securityContexts.pod` / `securityContexts.containers` (or the equivalent 
per-component
+  # overrides) are left empty (default `false` is deprecated and will change 
to `true`
+  # in a future release).
+  disableDefaults: false
 
 # Global container lifecycle hooks for Airflow containers
 containerLifecycleHooks: {}
diff --git a/helm-tests/tests/helm_tests/airflow_aux/test_pod_template_file.py 
b/helm-tests/tests/helm_tests/airflow_aux/test_pod_template_file.py
index df0a50eb832..02b611c6bbd 100644
--- a/helm-tests/tests/helm_tests/airflow_aux/test_pod_template_file.py
+++ b/helm-tests/tests/helm_tests/airflow_aux/test_pod_template_file.py
@@ -995,6 +995,43 @@ class TestPodTemplateFile:
             "allowPrivilegeEscalation": False
         }
 
+    def test_pod_security_context_disable_defaults(self):
+        docs = render_chart(
+            values={"securityContexts": {"disableDefaults": True}},
+            show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
+        )
+
+        assert jmespath.search("spec.securityContext", docs[0]) is None
+
+    def test_container_security_context_disable_defaults(self):
+        docs = render_chart(
+            values={"securityContexts": {"disableDefaults": True}},
+            show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
+        )
+
+        assert jmespath.search("spec.containers[0].securityContext", docs[0]) 
is None
+
+    @pytest.mark.parametrize(
+        "values",
+        [
+            {"securityContexts": {"disableDefaults": True, "pod": 
{"runAsUser": 10}}},
+            {
+                "securityContexts": {"disableDefaults": True},
+                "workers": {"kubernetes": {"securityContexts": {"pod": 
{"runAsUser": 10}}}},
+            },
+        ],
+    )
+    def test_pod_security_context_set_overrides_disable_defaults(self, values):
+        docs = render_chart(
+            values=values,
+            show_only=["templates/pod-template-file.yaml"],
+            chart_dir=self.temp_chart_dir,
+        )
+
+        assert jmespath.search("spec.securityContext", docs[0]) == 
{"runAsUser": 10}
+
     def test_should_add_gid_to_the_pod_template(self):
         docs = render_chart(
             values={"gid": 1},
diff --git a/helm-tests/tests/helm_tests/security/test_security_context.py 
b/helm-tests/tests/helm_tests/security/test_security_context.py
index 39e9281d04b..b8fc29cb0dd 100644
--- a/helm-tests/tests/helm_tests/security/test_security_context.py
+++ b/helm-tests/tests/helm_tests/security/test_security_context.py
@@ -1103,6 +1103,231 @@ class TestSecurityContext:
             assert 
jmespath.search("spec.template.spec.securityContext.runAsUser", doc) == 9000
             assert 
jmespath.search("spec.template.spec.securityContext.fsGroup", doc) == 90
 
+    def test_disable_defaults_pod_and_container(self):
+        docs = render_chart(
+            values={
+                "securityContexts": {"disableDefaults": True},
+                "flower": {"enabled": True},
+                "pgbouncer": {"enabled": True},
+                "statsd": {"enabled": True},
+            },
+            show_only=[
+                "templates/flower/flower-deployment.yaml",
+                "templates/scheduler/scheduler-deployment.yaml",
+                "templates/api-server/api-server-deployment.yaml",
+                "templates/dag-processor/dag-processor-deployment.yaml",
+                "templates/workers/worker-deployment.yaml",
+                "templates/jobs/create-user-job.yaml",
+                "templates/jobs/migrate-database-job.yaml",
+                "templates/triggerer/triggerer-deployment.yaml",
+                "templates/pgbouncer/pgbouncer-deployment.yaml",
+                "templates/statsd/statsd-deployment.yaml",
+                "templates/redis/redis-statefulset.yaml",
+            ],
+        )
+
+        assert all(v is None for v in 
jmespath.search("[].spec.template.spec.securityContext", docs))
+        assert all(
+            v is None for v in 
jmespath.search("[].spec.template.spec.containers[0].securityContext", docs)
+        )
+
+    def test_disable_defaults_pod_and_container_cronjob(self):
+        docs = render_chart(
+            values={
+                "securityContexts": {"disableDefaults": True},
+                "executor": "CeleryExecutor,KubernetesExecutor",
+                "cleanup": {"enabled": True},
+            },
+            show_only=["templates/cleanup/cleanup-cronjob.yaml"],
+        )
+
+        assert 
jmespath.search("spec.jobTemplate.spec.template.spec.securityContext", docs[0]) 
is None
+        assert (
+            
jmespath.search("spec.jobTemplate.spec.template.spec.containers[0].securityContext",
 docs[0])
+            is None
+        )
+
+    def test_disable_defaults_gitsync_containers(self):
+        docs = render_chart(
+            values={
+                "securityContexts": {"disableDefaults": True},
+                "dags": {"gitSync": {"enabled": True}},
+            },
+            show_only=[
+                "templates/workers/worker-deployment.yaml",
+                "templates/triggerer/triggerer-deployment.yaml",
+                "templates/dag-processor/dag-processor-deployment.yaml",
+            ],
+        )
+
+        for doc in docs:
+            assert (
+                jmespath.search(
+                    
"spec.template.spec.initContainers[?name=='git-sync-init'].securityContext | 
[0]",
+                    doc,
+                )
+                is None
+            )
+            assert (
+                jmespath.search(
+                    
"spec.template.spec.containers[?name=='git-sync'].securityContext | [0]",
+                    doc,
+                )
+                is None
+            )
+
+    def test_disable_defaults_volume_permissions_init_container_skipped(self):
+        """With no explicit uid/gid override, the volume-permissions init 
container is omitted entirely."""
+        docs = render_chart(
+            values={
+                "securityContexts": {"disableDefaults": True},
+                "workers": {
+                    "persistence": {"enabled": True, "fixPermissions": True},
+                },
+            },
+            show_only=["templates/workers/worker-deployment.yaml"],
+        )
+
+        assert (
+            
jmespath.search("spec.template.spec.initContainers[?name=='volume-permissions']",
 docs[0]) == []
+        )
+
+    def test_disable_defaults_explicit_override_still_applied(self):
+        ctx_value = {"runAsUser": 7000}
+        docs = render_chart(
+            values={
+                "securityContexts": {"disableDefaults": True, "pod": 
ctx_value},
+                "workers": {
+                    "persistence": {"enabled": True, "fixPermissions": True},
+                },
+            },
+            show_only=[
+                "templates/scheduler/scheduler-deployment.yaml",
+                "templates/workers/worker-deployment.yaml",
+            ],
+        )
+
+        for doc in docs:
+            assert ctx_value == 
jmespath.search("spec.template.spec.securityContext", doc)
+
+        assert (
+            
jmespath.search("spec.template.spec.initContainers[?name=='volume-permissions']",
 docs[1]) != []
+        )
+
+    @pytest.mark.parametrize(
+        ("component_values", "show_only", "security_context_path"),
+        [
+            (
+                {"scheduler": {"securityContexts": {"pod": {"runAsUser": 
8000}}}},
+                "templates/scheduler/scheduler-deployment.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"apiServer": {"securityContexts": {"pod": {"runAsUser": 
8000}}}},
+                "templates/api-server/api-server-deployment.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"dagProcessor": {"securityContexts": {"pod": {"runAsUser": 
8000}}}},
+                "templates/dag-processor/dag-processor-deployment.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"triggerer": {"securityContexts": {"pod": {"runAsUser": 
8000}}}},
+                "templates/triggerer/triggerer-deployment.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"workers": {"securityContexts": {"pod": {"runAsUser": 
8000}}}},
+                "templates/workers/worker-deployment.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"flower": {"enabled": True, "securityContexts": {"pod": 
{"runAsUser": 8000}}}},
+                "templates/flower/flower-deployment.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"statsd": {"securityContexts": {"pod": {"runAsUser": 8000}}}},
+                "templates/statsd/statsd-deployment.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"pgbouncer": {"enabled": True, "securityContexts": {"pod": 
{"runAsUser": 8000}}}},
+                "templates/pgbouncer/pgbouncer-deployment.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"redis": {"securityContexts": {"pod": {"runAsUser": 8000}}}},
+                "templates/redis/redis-statefulset.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"createUserJob": {"securityContexts": {"pod": {"runAsUser": 
8000}}}},
+                "templates/jobs/create-user-job.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {"migrateDatabaseJob": {"securityContexts": {"pod": 
{"runAsUser": 8000}}}},
+                "templates/jobs/migrate-database-job.yaml",
+                "spec.template.spec.securityContext",
+            ),
+            (
+                {
+                    "executor": "CeleryExecutor,KubernetesExecutor",
+                    "cleanup": {"enabled": True, "securityContexts": {"pod": 
{"runAsUser": 8000}}},
+                },
+                "templates/cleanup/cleanup-cronjob.yaml",
+                "spec.jobTemplate.spec.template.spec.securityContext",
+            ),
+            (
+                {"databaseCleanup": {"enabled": True, "securityContexts": 
{"pod": {"runAsUser": 8000}}}},
+                "templates/database-cleanup/database-cleanup-cronjob.yaml",
+                "spec.jobTemplate.spec.template.spec.securityContext",
+            ),
+        ],
+        ids=[
+            "scheduler",
+            "apiServer",
+            "dagProcessor",
+            "triggerer",
+            "workers",
+            "flower",
+            "statsd",
+            "pgbouncer",
+            "redis",
+            "createUserJob",
+            "migrateDatabaseJob",
+            "cleanup",
+            "databaseCleanup",
+        ],
+    )
+    def test_disable_defaults_component_level_override_still_applied(
+        self, component_values, show_only, security_context_path
+    ):
+        docs = render_chart(
+            values={"securityContexts": {"disableDefaults": True}, 
**component_values},
+            show_only=[show_only],
+        )
+
+        assert jmespath.search(security_context_path, docs[0]) == 
{"runAsUser": 8000}
+
+    def 
test_disable_defaults_workers_volume_permissions_init_container_still_added(self):
+        docs = render_chart(
+            values={
+                "securityContexts": {"disableDefaults": True},
+                "workers": {
+                    "securityContexts": {"pod": {"runAsUser": 8000}},
+                    "persistence": {"enabled": True, "fixPermissions": True},
+                },
+            },
+            show_only=["templates/workers/worker-deployment.yaml"],
+        )
+
+        assert (
+            
jmespath.search("spec.template.spec.initContainers[?name=='volume-permissions']",
 docs[0]) != []
+        )
+
     def test_workers_overwrite_local(self):
         docs = render_chart(
             values={

Reply via email to