From 84cdc8aad9fc107b9a155d0c6cdfbde582ee0b3e Mon Sep 17 00:00:00 2001 From: lukefoster11 Date: Thu, 6 Aug 2026 11:01:57 -0700 Subject: [PATCH 1/5] allow override --- charts/retool/Chart.yaml | 2 +- charts/retool/templates/_helpers.tpl | 10 ++++++++++ .../retool/templates/deployment_code_executor.yaml | 2 +- charts/retool/templates/deployment_js_executor.yaml | 2 +- charts/retool/values.yaml | 12 ++++++++++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/charts/retool/Chart.yaml b/charts/retool/Chart.yaml index a28459dc..fe890b27 100644 --- a/charts/retool/Chart.yaml +++ b/charts/retool/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: retool description: A Helm chart for Kubernetes type: application -version: 6.11.12 +version: 6.11.13 maintainers: - name: Retool Engineering email: engineering+helm@retool.com diff --git a/charts/retool/templates/_helpers.tpl b/charts/retool/templates/_helpers.tpl index 7a6fdccb..ae0a9519 100644 --- a/charts/retool/templates/_helpers.tpl +++ b/charts/retool/templates/_helpers.tpl @@ -1128,6 +1128,16 @@ Two classes of stale config are caught: {{- end -}} {{- end -}} +{{/* +Render the seccomp-install initContainer image reference. +Usage: (include "retool.initImage" .) +*/}} +{{- define "retool.initImage" -}} +{{- $i := .Values.initImage -}} +{{- printf "%s:%s" $i.repository (toString $i.tag) -}} +{{- if $i.digest }}@{{ $i.digest }}{{ end -}} +{{- end -}} + {{/* Set code executor image tag Usage: (template "retool.codeExecutor.image.tag" .) diff --git a/charts/retool/templates/deployment_code_executor.yaml b/charts/retool/templates/deployment_code_executor.yaml index 4dfd9bd7..32f4e355 100644 --- a/charts/retool/templates/deployment_code_executor.yaml +++ b/charts/retool/templates/deployment_code_executor.yaml @@ -57,7 +57,7 @@ spec: initContainers: {{- if $useSecComp }} - name: install-seccomp - image: busybox:1.37.0@sha256:b3255e7dfbcd10cb367af0d409747d511aeb66dfac98cf30e97e87e4207dd76f + image: {{ include "retool.initImage" . }} securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true diff --git a/charts/retool/templates/deployment_js_executor.yaml b/charts/retool/templates/deployment_js_executor.yaml index e8f5400c..e2a50e09 100644 --- a/charts/retool/templates/deployment_js_executor.yaml +++ b/charts/retool/templates/deployment_js_executor.yaml @@ -48,7 +48,7 @@ spec: {{- end }} initContainers: - name: install-seccomp - image: busybox:1.37.0@sha256:b3255e7dfbcd10cb367af0d409747d511aeb66dfac98cf30e97e87e4207dd76f + image: {{ include "retool.initImage" . }} securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true diff --git a/charts/retool/values.yaml b/charts/retool/values.yaml index 91e851d6..6483751e 100644 --- a/charts/retool/values.yaml +++ b/charts/retool/values.yaml @@ -55,6 +55,18 @@ image: tag: "" pullPolicy: "IfNotPresent" +# Small utility image for the initContainers that install the nsjail seccomp +# profile onto the host, on the code executor and JS executor. Only used when +# seccomp is in play. +# +# Override repository if every image has to come from one registry -- a private +# mirror, an air-gapped install, or GCP Marketplace, which rejects any artifact +# a consumer pulls from outside its own Artifact Registry. +initImage: + repository: busybox + tag: '1.37.0' + digest: 'sha256:b3255e7dfbcd10cb367af0d409747d511aeb66dfac98cf30e97e87e4207dd76f' + commandline: args: [] From 42798141b7d9313f143111a6924bd0ffc4ac35fa Mon Sep 17 00:00:00 2001 From: lukefoster11 Date: Thu, 6 Aug 2026 11:05:24 -0700 Subject: [PATCH 2/5] update base values --- values.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/values.yaml b/values.yaml index edca3cbe..397b611f 100644 --- a/values.yaml +++ b/values.yaml @@ -55,6 +55,18 @@ image: tag: "" pullPolicy: "IfNotPresent" +# Small utility image for the initContainers that install the nsjail seccomp +# profile onto the host, on the code executor and JS executor. Only used when +# seccomp is in play. +# +# Override repository if every image has to come from one registry -- a private +# mirror, an air-gapped install, or GCP Marketplace, which rejects any artifact +# a consumer pulls from outside its own Artifact Registry. +initImage: + repository: busybox + tag: '1.37.0' + digest: 'sha256:b3255e7dfbcd10cb367af0d409747d511aeb66dfac98cf30e97e87e4207dd76f' + commandline: args: [] From 450cd44aa9b99e4710f0e260b332efca132ab574 Mon Sep 17 00:00:00 2001 From: lukefoster11 Date: Thu, 6 Aug 2026 11:06:54 -0700 Subject: [PATCH 3/5] note about digest --- charts/retool/values.yaml | 35 ++++++++++------------------------- values.yaml | 4 +++- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/charts/retool/values.yaml b/charts/retool/values.yaml index 397b611f..b8c2633f 100644 --- a/charts/retool/values.yaml +++ b/charts/retool/values.yaml @@ -61,7 +61,9 @@ image: # # Override repository if every image has to come from one registry -- a private # mirror, an air-gapped install, or GCP Marketplace, which rejects any artifact -# a consumer pulls from outside its own Artifact Registry. +# a consumer pulls from outside its own Artifact Registry. Clear digest when you +# do: copying an image gives it a new digest, so keeping this one pins you back +# to the original registry and the pull fails. initImage: repository: busybox tag: '1.37.0' @@ -746,14 +748,14 @@ mcp: # Retool 4.0.7 and later support a simplified ingress setup: route all public # paths, including /mcp and /.well-known, to the main Retool Service on port # 3000. The main backend must also be able to relay /mcp to the in-cluster MCP - # Service. When mcp.enabled is true, the chart configures the backend with - # MCP_SERVICE_INGRESS_DOMAIN=http://-mcp:. - # You can override it through the top-level env, environmentSecrets, or - # environmentVariables settings. + # Service. Set its internal URL through the top-level env block: # - # With that setting, omit or disable the MCP-specific ingress or HTTPRoute - # rules below and keep only the normal "/" route to :3000. Replace - # with this chart release's full name. + # env: + # MCP_SERVICE_INGRESS_DOMAIN: http://-mcp:4010 + # + # With that backend setting, omit or disable the MCP-specific ingress or + # HTTPRoute rules below and keep only the normal "/" route to + # :3000. Replace with this chart release's full name. # # Retool versions before 4.0.7 require the explicit MCP routes below, # rendered before the main Retool route. External ingress must preserve this @@ -842,17 +844,6 @@ codeExecutor: useSeccompProfile: false seccompLocalhostProfile: profiles/nsjail-seccomp.json - # Deploy a DaemonSet that loads AppArmor profiles for nsjail on every node. - # When enabled, the code-executor and js-executor annotations switch from - # "unconfined" to "localhost/retool-executor", which satisfies Ubuntu 24.04+'s - # kernel.apparmor_restrict_unprivileged_userns=1 restriction by providing an - # explicit userns rule. Requires useSeccompProfile: true for code-executor to - # take effect (js-executor always uses the seccomp/AppArmor path). The - # DaemonSet itself renders whenever this is true and either workflows is - # enabled (for code-executor) or rr.jsExecutor is enabled -- it is not tied - # to workflows alone, since js-executor doesn't require workflows to run. - appArmorProfileInstaller: false - # === RR (Retool agent runtime) ============================================= # Master switch for the whole RR stack. Set `rr.enabled: true` to turn on the # components nested below — jsExecutor, agent, and agentSandbox — with a @@ -1060,12 +1051,6 @@ rr: # on every node automatically. seccompProfile: retool/gvisor-seccomp.json - # Deploy an AppArmor profile for agent-sandbox pods. When enabled, the - # node-installer DaemonSet loads a retool-agent-sandbox profile on every - # node, and sandbox Jobs use it instead of Unconfined. Required on - # Ubuntu 24.04+ hosts with kernel.apparmor_restrict_unprivileged_userns=1. - appArmorProfileInstaller: false - # S3-compatible snapshot storage. # When s3Bucket is set, snapshots are persisted to S3 and survive pod restarts. snapshotStorage: diff --git a/values.yaml b/values.yaml index 397b611f..03798e3d 100644 --- a/values.yaml +++ b/values.yaml @@ -61,7 +61,9 @@ image: # # Override repository if every image has to come from one registry -- a private # mirror, an air-gapped install, or GCP Marketplace, which rejects any artifact -# a consumer pulls from outside its own Artifact Registry. +# a consumer pulls from outside its own Artifact Registry. Clear digest when you +# do: copying an image gives it a new digest, so keeping this one pins you back +# to the original registry and the pull fails. initImage: repository: busybox tag: '1.37.0' From 42f833a805d8fd6d6892bf6871c44043f92f36ef Mon Sep 17 00:00:00 2001 From: lukefoster11 Date: Thu, 6 Aug 2026 11:50:01 -0700 Subject: [PATCH 4/5] fix --- charts/retool/templates/_helpers.tpl | 21 +++++++++++++++++++-- charts/retool/values.yaml | 12 ++++++++---- values.yaml | 12 ++++++++---- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/charts/retool/templates/_helpers.tpl b/charts/retool/templates/_helpers.tpl index b4378156..64e1db04 100644 --- a/charts/retool/templates/_helpers.tpl +++ b/charts/retool/templates/_helpers.tpl @@ -1177,12 +1177,29 @@ Two classes of stale config are caught: {{/* Render the seccomp-install initContainer image reference. + +The pinned digest lives here, not in values.yaml, so that overrides actually +take effect. Helm deep-merges values, so a default digest in values.yaml would +survive any user override of initImage.repository/tag and keep pulling the +original pinned image (a digest always wins over a tag in an image ref), or +fail outright against a mirror that lacks that digest. Instead we only append +the pinned digest when the repository and tag are still the chart defaults and +the user hasn't supplied their own digest. Usage: (include "retool.initImage" .) */}} {{- define "retool.initImage" -}} {{- $i := .Values.initImage -}} -{{- printf "%s:%s" $i.repository (toString $i.tag) -}} -{{- if $i.digest }}@{{ $i.digest }}{{ end -}} +{{- $defaultRepository := "busybox" -}} +{{- $defaultTag := "1.37.0" -}} +{{- $defaultDigest := "sha256:b3255e7dfbcd10cb367af0d409747d511aeb66dfac98cf30e97e87e4207dd76f" -}} +{{- $repository := $i.repository -}} +{{- $tag := toString $i.tag -}} +{{- $digest := $i.digest | default "" -}} +{{- if and (not $digest) (eq $repository $defaultRepository) (eq $tag $defaultTag) -}} +{{- $digest = $defaultDigest -}} +{{- end -}} +{{- printf "%s:%s" $repository $tag -}} +{{- if $digest }}@{{ $digest }}{{ end -}} {{- end -}} {{/* diff --git a/charts/retool/values.yaml b/charts/retool/values.yaml index b8c2633f..94bc07d1 100644 --- a/charts/retool/values.yaml +++ b/charts/retool/values.yaml @@ -61,13 +61,17 @@ image: # # Override repository if every image has to come from one registry -- a private # mirror, an air-gapped install, or GCP Marketplace, which rejects any artifact -# a consumer pulls from outside its own Artifact Registry. Clear digest when you -# do: copying an image gives it a new digest, so keeping this one pins you back -# to the original registry and the pull fails. +# a consumer pulls from outside its own Artifact Registry. +# +# The upstream busybox image is pinned to a known-good digest internally, but +# only while repository and tag are left at their defaults below. Overriding +# either drops that pin automatically (a copied image gets a new digest, so the +# original would pin you back to the source registry and fail the pull). Set +# digest here to pin your own mirrored image by digest. initImage: repository: busybox tag: '1.37.0' - digest: 'sha256:b3255e7dfbcd10cb367af0d409747d511aeb66dfac98cf30e97e87e4207dd76f' + digest: '' commandline: args: [] diff --git a/values.yaml b/values.yaml index 03798e3d..19e3d5d4 100644 --- a/values.yaml +++ b/values.yaml @@ -61,13 +61,17 @@ image: # # Override repository if every image has to come from one registry -- a private # mirror, an air-gapped install, or GCP Marketplace, which rejects any artifact -# a consumer pulls from outside its own Artifact Registry. Clear digest when you -# do: copying an image gives it a new digest, so keeping this one pins you back -# to the original registry and the pull fails. +# a consumer pulls from outside its own Artifact Registry. +# +# The upstream busybox image is pinned to a known-good digest internally, but +# only while repository and tag are left at their defaults below. Overriding +# either drops that pin automatically (a copied image gets a new digest, so the +# original would pin you back to the source registry and fail the pull). Set +# digest here to pin your own mirrored image by digest. initImage: repository: busybox tag: '1.37.0' - digest: 'sha256:b3255e7dfbcd10cb367af0d409747d511aeb66dfac98cf30e97e87e4207dd76f' + digest: '' commandline: args: [] From 26b6acfa3d96eb147e08fce2c8c52db7f2e06d1a Mon Sep 17 00:00:00 2001 From: lukefoster11 Date: Thu, 6 Aug 2026 11:51:11 -0700 Subject: [PATCH 5/5] fix --- charts/retool/values.yaml | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/charts/retool/values.yaml b/charts/retool/values.yaml index 94bc07d1..19e3d5d4 100644 --- a/charts/retool/values.yaml +++ b/charts/retool/values.yaml @@ -752,14 +752,14 @@ mcp: # Retool 4.0.7 and later support a simplified ingress setup: route all public # paths, including /mcp and /.well-known, to the main Retool Service on port # 3000. The main backend must also be able to relay /mcp to the in-cluster MCP - # Service. Set its internal URL through the top-level env block: + # Service. When mcp.enabled is true, the chart configures the backend with + # MCP_SERVICE_INGRESS_DOMAIN=http://-mcp:. + # You can override it through the top-level env, environmentSecrets, or + # environmentVariables settings. # - # env: - # MCP_SERVICE_INGRESS_DOMAIN: http://-mcp:4010 - # - # With that backend setting, omit or disable the MCP-specific ingress or - # HTTPRoute rules below and keep only the normal "/" route to - # :3000. Replace with this chart release's full name. + # With that setting, omit or disable the MCP-specific ingress or HTTPRoute + # rules below and keep only the normal "/" route to :3000. Replace + # with this chart release's full name. # # Retool versions before 4.0.7 require the explicit MCP routes below, # rendered before the main Retool route. External ingress must preserve this @@ -848,6 +848,17 @@ codeExecutor: useSeccompProfile: false seccompLocalhostProfile: profiles/nsjail-seccomp.json + # Deploy a DaemonSet that loads AppArmor profiles for nsjail on every node. + # When enabled, the code-executor and js-executor annotations switch from + # "unconfined" to "localhost/retool-executor", which satisfies Ubuntu 24.04+'s + # kernel.apparmor_restrict_unprivileged_userns=1 restriction by providing an + # explicit userns rule. Requires useSeccompProfile: true for code-executor to + # take effect (js-executor always uses the seccomp/AppArmor path). The + # DaemonSet itself renders whenever this is true and either workflows is + # enabled (for code-executor) or rr.jsExecutor is enabled -- it is not tied + # to workflows alone, since js-executor doesn't require workflows to run. + appArmorProfileInstaller: false + # === RR (Retool agent runtime) ============================================= # Master switch for the whole RR stack. Set `rr.enabled: true` to turn on the # components nested below — jsExecutor, agent, and agentSandbox — with a @@ -1055,6 +1066,12 @@ rr: # on every node automatically. seccompProfile: retool/gvisor-seccomp.json + # Deploy an AppArmor profile for agent-sandbox pods. When enabled, the + # node-installer DaemonSet loads a retool-agent-sandbox profile on every + # node, and sandbox Jobs use it instead of Unconfined. Required on + # Ubuntu 24.04+ hosts with kernel.apparmor_restrict_unprivileged_userns=1. + appArmorProfileInstaller: false + # S3-compatible snapshot storage. # When s3Bucket is set, snapshots are persisted to S3 and survive pod restarts. snapshotStorage: