From 1f370c4daabea21bcb061fd0d6d4ab36a750016f Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:22:29 -0600 Subject: [PATCH 01/13] fix(openhands): restore charts and replicated to 0.71.1 images Base for 0.71.3: 0.71.2's Copa image pins don't carry forward. charts/ and replicated/ are restored from openhands/0.71.1; .github/ and the chart version (0.71.2) are kept so release-please cuts 0.71.3. --- .../openhands/charts/agent-canvas/values.yaml | 4 +- .../openhands/charts/automation/values.yaml | 4 +- .../charts/plugin-directory/values.yaml | 8 ++-- .../openhands/charts/runtime-api/values.yaml | 8 ++-- .../templates/troubleshoot/_tls-hostname.tpl | 2 +- charts/openhands/values.yaml | 41 ++++++++----------- replicated/openhands.yaml | 40 +++++++++--------- 7 files changed, 49 insertions(+), 58 deletions(-) diff --git a/charts/openhands/charts/agent-canvas/values.yaml b/charts/openhands/charts/agent-canvas/values.yaml index c377a314d..b863b7cc4 100644 --- a/charts/openhands/charts/agent-canvas/values.yaml +++ b/charts/openhands/charts/agent-canvas/values.yaml @@ -8,12 +8,12 @@ # screen. image: - repository: ghcr.io/openhands/patched/agent-canvas + repository: ghcr.io/openhands/agent-canvas # Pinned to a semver release tag (agent-canvas publishes release-tagged # images via Release Please). Environments that want a specific build can # override this, but the default should track a published release so the # chart ships a known-good version out of the box. - tag: "1.23.0-patched@sha256:63b7824a3a1a67bab899eb65d1daa2fceaa2739dff5ac5f7c9eac02a2773cc14" + tag: "1.23.0" pullPolicy: IfNotPresent imagePullSecrets: [] diff --git a/charts/openhands/charts/automation/values.yaml b/charts/openhands/charts/automation/values.yaml index 35a78deb0..aa850ae89 100644 --- a/charts/openhands/charts/automation/values.yaml +++ b/charts/openhands/charts/automation/values.yaml @@ -1,8 +1,8 @@ image: - repository: ghcr.io/openhands/patched/automation + repository: ghcr.io/openhands/automation # You must use a stable, semver tag. Do not use sha-based tags. # If you are hotfixing, you MUST create a patch release and use the semver tag. - tag: "1.14.0-patched@sha256:e0963f3cac040087fa7bcb829a9d17c53a49fab6871c3c5522c7d206627f5697" + tag: 1.14.0 imagePullSecrets: [] diff --git a/charts/openhands/charts/plugin-directory/values.yaml b/charts/openhands/charts/plugin-directory/values.yaml index 47b9d9518..8caf588da 100644 --- a/charts/openhands/charts/plugin-directory/values.yaml +++ b/charts/openhands/charts/plugin-directory/values.yaml @@ -14,8 +14,8 @@ databaseMigrations: # Client container configuration (React Router SSR) client: image: - repository: ghcr.io/openhands/patched/plugin-directory-client - tag: "1.2.0-patched@sha256:667252f537f005dd9da6e52a20398c87276cb18608996d734e0a070f395f818c" + repository: ghcr.io/openhands/plugin-directory-client + tag: "1.2.0" resources: requests: memory: 256Mi @@ -26,10 +26,10 @@ client: # Server container configuration (FastAPI backend) server: image: - repository: ghcr.io/openhands/patched/plugin-directory-server + repository: ghcr.io/openhands/plugin-directory-server # You must use a stable, semver tag. Do not use sha-based tags. # If you are hotfixing, you MUST create a patch release and use the semver tag. - tag: "1.2.0-patched@sha256:463981dfb39efa6574f7ccaf1dfa40363330cbc2123ef0f793314eef94993640" + tag: "1.2.0" resources: requests: memory: 256Mi diff --git a/charts/openhands/charts/runtime-api/values.yaml b/charts/openhands/charts/runtime-api/values.yaml index 335ebc15c..632ba0d0b 100644 --- a/charts/openhands/charts/runtime-api/values.yaml +++ b/charts/openhands/charts/runtime-api/values.yaml @@ -1,8 +1,8 @@ image: - repository: ghcr.io/openhands/patched/runtime-api + repository: ghcr.io/openhands/runtime-api # You must use a stable, semver tag. Do not use sha-based tags. # If you are hotfixing, you MUST create a patch release and use the semver tag. - tag: "0.10.0-patched@sha256:bae96ecbe18e30bd1e6e67e92b8932919141b7e8dc9a813814540efb24267638" + tag: 0.10.0 pullPolicy: Always nameOverride: "" @@ -357,8 +357,8 @@ global: # that omits its own `image`. In the openhands umbrella the parent chart's # global wins; this default only applies when rendering the subchart alone. agentServerImage: - repository: ghcr.io/openhands/patched/agent-server - tag: "1.49.5-python-patched@sha256:c143d7113ba6df06caeb2be61a2c5a119c05074889a633b1f36e99d435eaac28" + repository: ghcr.io/openhands/agent-server + tag: 1.49.5-python security: # This allows using the bitnamilegacy image repo. # See: https://github.com/bitnami/containers/issues/83267 diff --git a/charts/openhands/templates/troubleshoot/_tls-hostname.tpl b/charts/openhands/templates/troubleshoot/_tls-hostname.tpl index 21312e165..53679d427 100644 --- a/charts/openhands/templates/troubleshoot/_tls-hostname.tpl +++ b/charts/openhands/templates/troubleshoot/_tls-hostname.tpl @@ -51,7 +51,7 @@ analyticsHost: {{ $lamFrontIng.hostname | default "" | quote }} routingMode: {{ $rtApiEnv.RUNTIME_ROUTING_MODE | default "" | quote }} rtSeparator: {{ $rtApiEnv.RUNTIME_URL_SEPARATOR | default "." | quote }} analyticsEnabled: {{ $lam.enabled | default false }} -probeImage: {{ printf "%s/docker.io/alpine/openssl:3.5.6" (trimSuffix "/ghcr.io/openhands/enterprise-server" (trimSuffix "/ghcr.io/openhands/patched/enterprise-server" $repo)) | quote }} +probeImage: {{ printf "%s/docker.io/alpine/openssl:3.5.6" (trimSuffix "/ghcr.io/openhands/enterprise-server" $repo) | quote }} {{- end -}} {{- define "troubleshoot.collectors.tlsHostname" -}} diff --git a/charts/openhands/values.yaml b/charts/openhands/values.yaml index 5f3933f60..80c62edb6 100644 --- a/charts/openhands/values.yaml +++ b/charts/openhands/values.yaml @@ -9,10 +9,10 @@ allowedUsers: null enabled: true image: - repository: ghcr.io/openhands/patched/enterprise-server + repository: ghcr.io/openhands/enterprise-server # You must use a stable, semver tag. Do not use sha-based tags. # If you are hotfixing, you MUST create a patch release and use the semver tag. - tag: "1.64.0-patched@sha256:b8180530ba277738b5177a97eac96d0a684c8c4e22a48c83d25aed2c1f5944fb" + tag: 1.64.0 autoscaling: enabled: false @@ -469,10 +469,7 @@ uvicorn: keycloak: enabled: false image: - registry: ghcr.io - repository: openhands/patched/keycloak - tag: 26.3.0-debian-12-r0-patched - digest: sha256:aa1657e0405de7e4700a72d663392793788a97c7e6dcb4e3cd2aa66a16cea1fc + repository: bitnamilegacy/keycloak # Parent-chart flag (not consumed by the Keycloak subchart): run the # realm-config init container that creates the OpenHands realm, its OIDC # client, and identity providers if missing, and updates them otherwise. @@ -541,7 +538,7 @@ keycloak: - name: KC_DB_URL_PROPERTIES value: 'sslmode={{ .Values.externalDatabase.sslMode | default "prefer" }}' waitForDb: - image: "ghcr.io/openhands/patched/postgresql:16.4.0-debian-12-r14-patched@sha256:08649d38a65ab3ee6d8f7699c8c903bf1583cc99ba93bc3aa2726f9ad3f24b58" + image: "bitnamilegacy/postgresql:latest" initContainers: - name: wait-for-db # The Bitnami Keycloak subchart renders initContainers through common.tplvalues.render, @@ -830,10 +827,7 @@ rustfs: postgresql: enabled: true image: - registry: ghcr.io - repository: openhands/patched/postgresql - tag: 16.4.0-debian-12-r14-patched - digest: sha256:08649d38a65ab3ee6d8f7699c8c903bf1583cc99ba93bc3aa2726f9ad3f24b58 + repository: bitnamilegacy/postgresql auth: username: postgres existingSecret: postgres-password @@ -870,10 +864,7 @@ externalDatabase: redis: enabled: true image: - registry: ghcr.io - repository: openhands/patched/redis - tag: 7.4.1-debian-12-r2-patched - digest: sha256:0a36c1ecdbc656b6f91c6cc4f43e48d7c78abaf3b71959a9d14c169e7ae4a33c + repository: bitnamilegacy/redis architecture: standalone auth: enabled: true @@ -1137,13 +1128,13 @@ plugin-directory: client: image: - repository: ghcr.io/openhands/patched/plugin-directory-client - tag: "1.2.0-patched@sha256:667252f537f005dd9da6e52a20398c87276cb18608996d734e0a070f395f818c" + repository: ghcr.io/openhands/plugin-directory-client + # tag: set via helm args or override server: image: - repository: ghcr.io/openhands/patched/plugin-directory-server - tag: "1.2.0-patched@sha256:463981dfb39efa6574f7ccaf1dfa40363330cbc2123ef0f793314eef94993640" + repository: ghcr.io/openhands/plugin-directory-server + # tag: set via helm args or override imagePullSecrets: [] @@ -1220,8 +1211,8 @@ automation: enabled: false image: - repository: ghcr.io/openhands/patched/automation - tag: "1.14.0-patched@sha256:e0963f3cac040087fa7bcb829a9d17c53a49fab6871c3c5522c7d206627f5697" + repository: ghcr.io/openhands/automation + # tag: set via helm args or override imagePullSecrets: [] @@ -1409,8 +1400,8 @@ global: # any warm-runtime configsByName entry that omits its own `image`. Override # either of those for per-use exceptions; set it here to move them together. agentServerImage: - repository: ghcr.io/openhands/patched/agent-server - tag: "1.49.5-python-patched@sha256:c143d7113ba6df06caeb2be61a2c5a119c05074889a633b1f36e99d435eaac28" + repository: ghcr.io/openhands/agent-server + tag: 1.49.5-python security: # This allows using the bitnamilegacy image repo. # See: https://github.com/bitnami/containers/issues/83267 @@ -1638,8 +1629,8 @@ agent-canvas: enabled: false image: - repository: ghcr.io/openhands/patched/agent-canvas - tag: "1.23.0-patched@sha256:63b7824a3a1a67bab899eb65d1daa2fceaa2739dff5ac5f7c9eac02a2773cc14" + repository: ghcr.io/openhands/agent-canvas + # tag: supplied at deploy time via the OpenHands deploy workflow. ingress: enabled: false diff --git a/replicated/openhands.yaml b/replicated/openhands.yaml index eec99e6ae..e1b549db1 100644 --- a/replicated/openhands.yaml +++ b/replicated/openhands.yaml @@ -20,7 +20,7 @@ spec: # admin-supplied custom image). The default tag is pinned in the chart's # global.agentServerImage. agentServerImage: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/agent-server' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/agent-server' # Runtime (agent-server sandbox) env vars. The chart serialises this map # into OH_AGENT_SERVER_ENV and mirrors it into every warm-runtime entry's # env (runtime-api claims warm pods by exact env match, so a key here @@ -35,7 +35,7 @@ spec: NODE_EXTRA_CA_CERTS: /etc/openhands/ca-bundle/ca-bundle.crt image: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/enterprise-server' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/enterprise-server' imagePullSecrets: - name: '{{repl ImagePullSecretName }}' @@ -169,12 +169,12 @@ spec: existingSecretUserKey: username existingSecretPasswordKey: password image: - repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/keycloak' + repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/keycloak' keycloakConfigCli: image: repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/keycloak-config-cli' waitForDb: - image: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/postgresql:16.4.0-debian-12-r14-patched@sha256:08649d38a65ab3ee6d8f7699c8c903bf1583cc99ba93bc3aa2726f9ad3f24b58' + image: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/postgresql:latest' # caBundle wiring: mount the trust-manager Bundle ConfigMap and point # Keycloak's truststore at the merged PEM. Repeats the chart's default # KC_* env vars because helm value merging replaces arrays — adding @@ -321,7 +321,7 @@ spec: podAnnotations: checksum/admin-password: 'repl{{ sha256sum (ConfigOption "admin_password") }}' image: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/runtime-api' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/runtime-api' # Do not override the image tag here. Pin to a stable version in the chart. imagePullSecrets: - name: '{{repl ImagePullSecretName }}' @@ -491,7 +491,7 @@ spec: redis: enabled: true image: - repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/redis' + repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/redis' auth: password: '{{repl ConfigOption "redis_password" | Base64Encode }}' # Conversation/session files live on the bundled MinIO, which is durable @@ -513,11 +513,11 @@ spec: memory: 2Gi # Preserve the existing server/client bytes when changing registries. image: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/ohe-minio' - tag: 'RELEASE.2023-05-18T00-05-36Z-amd64-patched@sha256:17dbdf60833de2cd75aabb6a4937d7bd01944c0341c02cecc3151f38f619dc2a' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/ohe-minio' + tag: 'RELEASE.2023-05-18T00-05-36Z-amd64@sha256:52c9c477179216d0418c95e8aad047db6d406fa475b7d624b5ba990fe7099279' mcImage: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/ohe-minio-mc' - tag: 'RELEASE.2023-05-18T16-59-00Z-amd64-patched@sha256:207216603c84d00844c4eaf94594964a1dc7bdd527b083fa91e24992690acd30' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/ohe-minio-mc' + tag: 'RELEASE.2023-05-18T16-59-00Z-amd64@sha256:9e46d9ed12fa66361f6482b0081d65c2d68e01cbbdede8b964950f76e5a35701' imagePullSecrets: - name: '{{repl ImagePullSecretName }}' # sha256 of every secret (password) config value. Changing any secret in the @@ -721,7 +721,7 @@ spec: caBundle: enabled: true image: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/automation' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/automation' imagePullSecrets: - name: '{{repl ImagePullSecretName }}' openhandsApiUrl: 'https://{{repl ConfigOption "computed_app_hostname" }}' @@ -760,7 +760,7 @@ spec: values: postgresql: image: - repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/postgresql' + repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/postgresql' keycloak: postgresql: image: @@ -790,7 +790,7 @@ spec: image: repository: '{{repl LocalRegistryNamespace }}/keycloak-config-cli' waitForDb: - image: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/postgresql:16.4.0-debian-12-r14-patched@sha256:08649d38a65ab3ee6d8f7699c8c903bf1583cc99ba93bc3aa2726f9ad3f24b58' + image: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/postgresql:latest' postgresql: image: repository: '{{repl LocalRegistryNamespace }}/postgresql' @@ -1245,10 +1245,10 @@ spec: issuerUrl: 'https://{{repl ConfigOption "computed_auth_hostname" }}' client: image: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/plugin-directory-client' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/plugin-directory-client' server: image: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/plugin-directory-server' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/plugin-directory-server' imagePullSecrets: - name: '{{repl ImagePullSecretName }}' - when: '{{repl ConfigOptionEquals "agent_canvas_enabled" "1" }}' @@ -1262,7 +1262,7 @@ spec: agent-canvas: enabled: true image: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/patched/agent-canvas' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/agent-canvas' imagePullSecrets: - name: '{{repl ImagePullSecretName }}' ingress: @@ -1352,11 +1352,11 @@ spec: minio: enabled: true image: - repository: ghcr.io/openhands/patched/ohe-minio - tag: 'RELEASE.2023-05-18T00-05-36Z-amd64-patched@sha256:17dbdf60833de2cd75aabb6a4937d7bd01944c0341c02cecc3151f38f619dc2a' + repository: ghcr.io/openhands/ohe-minio + tag: 'RELEASE.2023-05-18T00-05-36Z-amd64@sha256:52c9c477179216d0418c95e8aad047db6d406fa475b7d624b5ba990fe7099279' mcImage: - repository: ghcr.io/openhands/patched/ohe-minio-mc - tag: 'RELEASE.2023-05-18T16-59-00Z-amd64-patched@sha256:207216603c84d00844c4eaf94594964a1dc7bdd527b083fa91e24992690acd30' + repository: ghcr.io/openhands/ohe-minio-mc + tag: 'RELEASE.2023-05-18T16-59-00Z-amd64@sha256:9e46d9ed12fa66361f6482b0081d65c2d68e01cbbdede8b964950f76e5a35701' postgresql: enabled: true redis: From f695a25d20fa6d80fb9633cf7410fad7995a0940 Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:24:42 -0600 Subject: [PATCH 02/13] test: expect 0.71.1's MinIO image refs again Follows the restore: 0.71.2 pointed this test at the Copa-patched paths. --- scripts/test_replicated_minio_images.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/test_replicated_minio_images.py b/scripts/test_replicated_minio_images.py index d0b20b695..508242a06 100644 --- a/scripts/test_replicated_minio_images.py +++ b/scripts/test_replicated_minio_images.py @@ -12,12 +12,12 @@ "image": ( "ohe-minio", "RELEASE.2023-05-18T00-05-36Z", - "17dbdf60833de2cd75aabb6a4937d7bd01944c0341c02cecc3151f38f619dc2a", + "52c9c477179216d0418c95e8aad047db6d406fa475b7d624b5ba990fe7099279", ), "mcImage": ( "ohe-minio-mc", "RELEASE.2023-05-18T16-59-00Z", - "207216603c84d00844c4eaf94594964a1dc7bdd527b083fa91e24992690acd30", + "9e46d9ed12fa66361f6482b0081d65c2d68e01cbbdede8b964950f76e5a35701", ), } @@ -52,12 +52,12 @@ def test_minio_server_and_jobs_use_verified_images(mode, tmp_path): values = yaml.safe_load(text) for key, (name, tag, digest) in IMAGES.items(): expected_repo = { - "online": f"images.r9.all-hands.dev/proxy/test-app/ghcr.io/openhands/patched/{name}", + "online": f"images.r9.all-hands.dev/proxy/test-app/ghcr.io/openhands/{name}", "airgap": f"registry.test/test-app/{name}", - "builder": f"ghcr.io/openhands/patched/{name}", + "builder": f"ghcr.io/openhands/{name}", }[mode] assert values[key]["repository"] == expected_repo - assert values[key]["tag"] == f"{tag}-amd64-patched@sha256:{digest}" + assert values[key]["tag"] == f"{tag}-amd64@sha256:{digest}" # Render the actual pinned dependency, including its post-install job. values.update( mode="standalone", From c6f715d784c46e5108e5656181098862bc61ff73 Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:28:50 -0600 Subject: [PATCH 03/13] ci: accept -rN hotfix suffix in the agent-server sync check Rebuilt hotfix releases (1.64.0-r1, 1.49.5-r1-python) name the release they rebuild; release_tag() now strips -rN as it already strips -patched and digest pins. --- scripts/check_agent_server_sync.py | 6 +++--- scripts/test_check_agent_server_sync.py | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/scripts/check_agent_server_sync.py b/scripts/check_agent_server_sync.py index 4ff475a5b..e9e7a23a8 100644 --- a/scripts/check_agent_server_sync.py +++ b/scripts/check_agent_server_sync.py @@ -65,8 +65,8 @@ # no tag to look up on the remote -- the commit itself is the ref. _SHA_TAG_RE = re.compile(r"^sha-(?P[0-9a-f]{7,40})$") -# Copa-patched rebuilds (`1.64.0-patched@sha256:...`) carry the release they patch. -_PATCHED_SUFFIX_RE = re.compile(r"(?:-patched)?(?:@sha256:[0-9a-f]{64})?$") +# Rebuilds of a release (`1.64.0-patched@sha256:...`, `1.64.0-r1`) carry the release they rebuild. +_PATCHED_SUFFIX_RE = re.compile(r"(?:-(?:patched|r\d+))?(?:@sha256:[0-9a-f]{64})?$") # `openhands-agent-server[extra]==1.43.1 ; python_version >= "3.12"` _REQUIREMENT_RE = re.compile( @@ -135,7 +135,7 @@ def read_pin(repo_root: Path, pin: Pin) -> str: def release_tag(tag: str) -> str: - """Strip a Copa ``-patched`` suffix and digest pin, leaving the release tag.""" + """Strip a ``-patched``/``-rN`` rebuild suffix and digest pin, leaving the release tag.""" return _PATCHED_SUFFIX_RE.sub("", tag, count=1) diff --git a/scripts/test_check_agent_server_sync.py b/scripts/test_check_agent_server_sync.py index 381e0b7d7..95daad72a 100644 --- a/scripts/test_check_agent_server_sync.py +++ b/scripts/test_check_agent_server_sync.py @@ -149,6 +149,28 @@ def test_copa_patched_pins_resolve_to_the_release_they_patch(tmp_path, fake_remo assert "git/ref/tags/1.56.0" in fake_remote["calls"] +def test_r1_hotfix_pins_resolve_to_the_release_they_rebuild(tmp_path, fake_remote): + digest = "@sha256:" + "c" * 64 + write_charts(tmp_path, f"1.56.0-r1{digest}", f"1.43.1-r1-python{digest}") + + assert run_check(tmp_path) + assert "git/ref/tags/1.56.0" in fake_remote["calls"] + + +def test_plain_r1_enterprise_tag_resolves_to_the_release(tmp_path, fake_remote): + write_charts(tmp_path, "1.56.0-r1", "1.43.1-r1-python") + + assert run_check(tmp_path) + assert "git/ref/tags/1.56.0" in fake_remote["calls"] + + +def test_r1_agent_server_pin_still_fails_on_sdk_mismatch(tmp_path, fake_remote): + write_charts(tmp_path, "1.56.0-r1", "1.42.0-r1-python") + + with pytest.raises(CheckError, match="1.42.0"): + run_check(tmp_path) + + def test_agent_server_pins_must_agree_with_each_other(tmp_path, fake_remote): write_charts(tmp_path, "1.56.0", "1.43.1-python") drifted = AGENT_SERVER_PINS[-1] From d7f0efe35f6eea1f7a2cdeace39d73ddf637620e Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:29:02 -0600 Subject: [PATCH 04/13] TEST-ONLY: hotfix candidate pins (replace with -r1 release digests) Pins the PR-build candidate digests of the 7 in-house images, default ghcr.io/openhands/* repositories. The -r1 tags do not exist yet; the tag text is ignored because a digest is present. Replace each digest with the rescanned -r1 release digest once the hotfix PRs are tagged. agent-canvas carries the STAGING PostHog key (OpenHands#18258 candidate build) and must never ship: it needs the manual cancel-and-dispatch release before this pin is final. agent-server tag keeps 1.49.5 as its first segment so enterprise's get_agent_server_image() rewrite (default repository only) leaves it unchanged. --- charts/image-loader/values.yaml | 2 +- charts/openhands/charts/agent-canvas/values.yaml | 2 +- charts/openhands/charts/automation/values.yaml | 2 +- charts/openhands/charts/plugin-directory/values.yaml | 4 ++-- charts/openhands/charts/runtime-api/values.yaml | 4 ++-- charts/openhands/values.yaml | 12 ++++++------ 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/charts/image-loader/values.yaml b/charts/image-loader/values.yaml index cdebee6c1..8e20ed6df 100644 --- a/charts/image-loader/values.yaml +++ b/charts/image-loader/values.yaml @@ -1,7 +1,7 @@ # Agent-server image the loader pre-pulls onto nodes; keep tag in sync with the sandbox runtime. image: repository: ghcr.io/openhands/agent-server - tag: 1.49.5-python + tag: "1.49.5-r1-python@sha256:5f2919fbfc33934c023092926fc79a5da9acecc809d5773e582b44b8093d8d3f" pullPolicy: Always resources: diff --git a/charts/openhands/charts/agent-canvas/values.yaml b/charts/openhands/charts/agent-canvas/values.yaml index b863b7cc4..0def9cb8b 100644 --- a/charts/openhands/charts/agent-canvas/values.yaml +++ b/charts/openhands/charts/agent-canvas/values.yaml @@ -13,7 +13,7 @@ image: # images via Release Please). Environments that want a specific build can # override this, but the default should track a published release so the # chart ships a known-good version out of the box. - tag: "1.23.0" + tag: "1.23.0-r1@sha256:7f024e6802eaa0e7ca54b8f6134b57941bf370436b22f9d61e13488cf267da5a" pullPolicy: IfNotPresent imagePullSecrets: [] diff --git a/charts/openhands/charts/automation/values.yaml b/charts/openhands/charts/automation/values.yaml index aa850ae89..eab5422a3 100644 --- a/charts/openhands/charts/automation/values.yaml +++ b/charts/openhands/charts/automation/values.yaml @@ -2,7 +2,7 @@ image: repository: ghcr.io/openhands/automation # You must use a stable, semver tag. Do not use sha-based tags. # If you are hotfixing, you MUST create a patch release and use the semver tag. - tag: 1.14.0 + tag: "1.14.0-r1@sha256:6c2c8bd220c92d6fc2c981a361b52e74207578a16ebacd6ac54fce82c47a6001" imagePullSecrets: [] diff --git a/charts/openhands/charts/plugin-directory/values.yaml b/charts/openhands/charts/plugin-directory/values.yaml index 8caf588da..41c582bf2 100644 --- a/charts/openhands/charts/plugin-directory/values.yaml +++ b/charts/openhands/charts/plugin-directory/values.yaml @@ -15,7 +15,7 @@ databaseMigrations: client: image: repository: ghcr.io/openhands/plugin-directory-client - tag: "1.2.0" + tag: "1.2.0-r1@sha256:8d74aa59e423d50aaa8bb4558a4aab8325463de7bccb761f10ed55c823358aff" resources: requests: memory: 256Mi @@ -29,7 +29,7 @@ server: repository: ghcr.io/openhands/plugin-directory-server # You must use a stable, semver tag. Do not use sha-based tags. # If you are hotfixing, you MUST create a patch release and use the semver tag. - tag: "1.2.0" + tag: "1.2.0-r1@sha256:bf35b82bdcdcf37abba673ef5b40bdbed22ccc3af67b4793c7bcb21fdf11aa4d" resources: requests: memory: 256Mi diff --git a/charts/openhands/charts/runtime-api/values.yaml b/charts/openhands/charts/runtime-api/values.yaml index 632ba0d0b..a03dd7ede 100644 --- a/charts/openhands/charts/runtime-api/values.yaml +++ b/charts/openhands/charts/runtime-api/values.yaml @@ -2,7 +2,7 @@ image: repository: ghcr.io/openhands/runtime-api # You must use a stable, semver tag. Do not use sha-based tags. # If you are hotfixing, you MUST create a patch release and use the semver tag. - tag: 0.10.0 + tag: "0.10.0-r1@sha256:cdb63c3fca733796d1f1b846fcafc3eafa574969f547c15f9bcb75d32c8ede27" pullPolicy: Always nameOverride: "" @@ -358,7 +358,7 @@ global: # global wins; this default only applies when rendering the subchart alone. agentServerImage: repository: ghcr.io/openhands/agent-server - tag: 1.49.5-python + tag: "1.49.5-r1-python@sha256:5f2919fbfc33934c023092926fc79a5da9acecc809d5773e582b44b8093d8d3f" security: # This allows using the bitnamilegacy image repo. # See: https://github.com/bitnami/containers/issues/83267 diff --git a/charts/openhands/values.yaml b/charts/openhands/values.yaml index 80c62edb6..26877fcd5 100644 --- a/charts/openhands/values.yaml +++ b/charts/openhands/values.yaml @@ -12,7 +12,7 @@ image: repository: ghcr.io/openhands/enterprise-server # You must use a stable, semver tag. Do not use sha-based tags. # If you are hotfixing, you MUST create a patch release and use the semver tag. - tag: 1.64.0 + tag: "1.64.0-r1@sha256:6c137216f1c6afe1d560300e92990a52050064a1358472c314285ae8e0bf8307" autoscaling: enabled: false @@ -1129,12 +1129,12 @@ plugin-directory: client: image: repository: ghcr.io/openhands/plugin-directory-client - # tag: set via helm args or override + tag: "1.2.0-r1@sha256:8d74aa59e423d50aaa8bb4558a4aab8325463de7bccb761f10ed55c823358aff" server: image: repository: ghcr.io/openhands/plugin-directory-server - # tag: set via helm args or override + tag: "1.2.0-r1@sha256:bf35b82bdcdcf37abba673ef5b40bdbed22ccc3af67b4793c7bcb21fdf11aa4d" imagePullSecrets: [] @@ -1212,7 +1212,7 @@ automation: image: repository: ghcr.io/openhands/automation - # tag: set via helm args or override + tag: "1.14.0-r1@sha256:6c2c8bd220c92d6fc2c981a361b52e74207578a16ebacd6ac54fce82c47a6001" imagePullSecrets: [] @@ -1401,7 +1401,7 @@ global: # either of those for per-use exceptions; set it here to move them together. agentServerImage: repository: ghcr.io/openhands/agent-server - tag: 1.49.5-python + tag: "1.49.5-r1-python@sha256:5f2919fbfc33934c023092926fc79a5da9acecc809d5773e582b44b8093d8d3f" security: # This allows using the bitnamilegacy image repo. # See: https://github.com/bitnami/containers/issues/83267 @@ -1630,7 +1630,7 @@ agent-canvas: image: repository: ghcr.io/openhands/agent-canvas - # tag: supplied at deploy time via the OpenHands deploy workflow. + tag: "1.23.0-r1@sha256:7f024e6802eaa0e7ca54b8f6134b57941bf370436b22f9d61e13488cf267da5a" ingress: enabled: false From f96b3ef169dc335d6591e5ac01c965a0e14648ca Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:31:44 -0600 Subject: [PATCH 05/13] fix(infra): bump cert-manager chart to 1.20.4 --- charts/infra/Chart.lock | 6 +++--- charts/infra/Chart.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/infra/Chart.lock b/charts/infra/Chart.lock index 1414afebe..70f2ab4a4 100644 --- a/charts/infra/Chart.lock +++ b/charts/infra/Chart.lock @@ -1,12 +1,12 @@ dependencies: - name: cert-manager repository: oci://quay.io/jetstack/charts - version: 1.20.2 + version: 1.20.4 - name: trust-manager repository: oci://quay.io/jetstack/charts version: 0.22.1 - name: crd-check repository: oci://ghcr.io/openhands/helm-charts version: 0.1.0 -digest: sha256:ee6c9e0ba7c097cc59f0dc12409169a11831b548283b77ec7f8f90a94869ebf5 -generated: "2026-05-27T10:31:04.277099-04:00" +digest: sha256:e7419549335a41e224763cb379806d3c8482a4f84de46fa18aaa3ec2a63837e3 +generated: "2026-10-10T08:31:38.51937-06:00" diff --git a/charts/infra/Chart.yaml b/charts/infra/Chart.yaml index 0372f1b8b..45634f496 100644 --- a/charts/infra/Chart.yaml +++ b/charts/infra/Chart.yaml @@ -8,7 +8,7 @@ maintainers: - name: all-hands-ai dependencies: - name: cert-manager - version: 1.20.2 + version: 1.20.4 repository: oci://quay.io/jetstack/charts condition: cert-manager.enabled - name: trust-manager From c6681a9fb92f6109b949f50d432ebd7e4f1d2cf7 Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:31:59 -0600 Subject: [PATCH 06/13] fix(infra): rebuild trust-pkg default package image at 20230311-deb12u1.7 --- charts/infra/values.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/charts/infra/values.yaml b/charts/infra/values.yaml index 574dc5e25..4dec8d234 100644 --- a/charts/infra/values.yaml +++ b/charts/infra/values.yaml @@ -48,6 +48,9 @@ trust-manager: app: trust: namespace: cert-manager + # Chart default is :20230311-deb12u1.6; .7 is a rebuild of the same CA data. + defaultPackageImage: + tag: "20230311-deb12u1.7" resources: requests: cpu: 10m From a9d208bd065bdf3a545348238a80966c97341e0e Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:32:03 -0600 Subject: [PATCH 07/13] fix(openhands): bump TLS preflight probe image to alpine/openssl 3.5.9 --- charts/openhands/templates/troubleshoot/_tls-hostname.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/openhands/templates/troubleshoot/_tls-hostname.tpl b/charts/openhands/templates/troubleshoot/_tls-hostname.tpl index 53679d427..33c76788a 100644 --- a/charts/openhands/templates/troubleshoot/_tls-hostname.tpl +++ b/charts/openhands/templates/troubleshoot/_tls-hostname.tpl @@ -51,7 +51,7 @@ analyticsHost: {{ $lamFrontIng.hostname | default "" | quote }} routingMode: {{ $rtApiEnv.RUNTIME_ROUTING_MODE | default "" | quote }} rtSeparator: {{ $rtApiEnv.RUNTIME_URL_SEPARATOR | default "." | quote }} analyticsEnabled: {{ $lam.enabled | default false }} -probeImage: {{ printf "%s/docker.io/alpine/openssl:3.5.6" (trimSuffix "/ghcr.io/openhands/enterprise-server" $repo) | quote }} +probeImage: {{ printf "%s/docker.io/alpine/openssl:3.5.9" (trimSuffix "/ghcr.io/openhands/enterprise-server" $repo) | quote }} {{- end -}} {{- define "troubleshoot.collectors.tlsHostname" -}} From 608bd276e5cc740372ea78d5856e0bad35913617 Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:28:42 -0600 Subject: [PATCH 08/13] fix(openhands): bump rancher/kubectl to v1.33.13 --- charts/crd-check/templates/_hook.tpl | 2 +- charts/infra/values.yaml | 2 +- charts/openhands/values.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/crd-check/templates/_hook.tpl b/charts/crd-check/templates/_hook.tpl index d28562478..38ad1f7dc 100644 --- a/charts/crd-check/templates/_hook.tpl +++ b/charts/crd-check/templates/_hook.tpl @@ -17,7 +17,7 @@ Consumers must define a `crdCheck` block in their own values.yaml, e.g.: crds: [] image: repository: docker.io/rancher/kubectl - tag: v1.33.0 + tag: v1.33.13 pullPolicy: IfNotPresent imagePullSecrets: [] resources: diff --git a/charts/infra/values.yaml b/charts/infra/values.yaml index 4dec8d234..80a86827c 100644 --- a/charts/infra/values.yaml +++ b/charts/infra/values.yaml @@ -72,7 +72,7 @@ crdCheck: enabled: false image: repository: docker.io/rancher/kubectl - tag: v1.33.0 + tag: v1.33.13 pullPolicy: IfNotPresent timeout: 120s backoffLimit: 6 diff --git a/charts/openhands/values.yaml b/charts/openhands/values.yaml index 26877fcd5..11f3b69a2 100644 --- a/charts/openhands/values.yaml +++ b/charts/openhands/values.yaml @@ -1466,7 +1466,7 @@ crdCheck: enabled: false image: repository: docker.io/rancher/kubectl - tag: v1.33.0 + tag: v1.33.13 pullPolicy: IfNotPresent timeout: 120s backoffLimit: 6 From fb69b8f8765d4833cc593ba37531f5cd8e8b1bcc Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:44:41 -0600 Subject: [PATCH 09/13] fix(openhands): bump litellm-database to 1.100.5 --- charts/openhands/README.md | 2 +- charts/openhands/values.yaml | 2 +- scripts/test_litellm_budget_cache.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/openhands/README.md b/charts/openhands/README.md index a779e77f1..e896340a2 100644 --- a/charts/openhands/README.md +++ b/charts/openhands/README.md @@ -703,7 +703,7 @@ Note: This will not delete any PVCs or secrets created. You'll need to delete th ### Budget policy changes -The bundled LiteLLM proxy uses unmodified 1.100.1 pinned by digest and +The bundled LiteLLM proxy uses unmodified 1.100.5 pinned by digest and `litellm-helm.proxy_config.general_settings.user_api_key_cache_ttl: 0`. Both are required for a budget change (including disabling a user's limit) to affect the next request using an existing key. Older proxies can keep enforcing diff --git a/charts/openhands/values.yaml b/charts/openhands/values.yaml index 11f3b69a2..0c0cd8fff 100644 --- a/charts/openhands/values.yaml +++ b/charts/openhands/values.yaml @@ -691,7 +691,7 @@ litellm-helm: # (BerriAI/litellm#33424, released in v1.94.0), which addresses the gradual # per-worker memory growth seen on 1.93.0. image: - tag: "1.100.1@sha256:fc44cf7f72786e636dc4dc1032b4e431818abfec9d54b8e04284fdea7ef03e2a" + tag: "1.100.5@sha256:65cdef1d78a9a966dfa6797951ea01602826430b6978bc9fa3957da6913dcc7f" masterkeySecretName: lite-llm-api-key masterkeySecretKey: lite-llm-api-key environmentSecrets: [litellm-env-secrets] diff --git a/scripts/test_litellm_budget_cache.py b/scripts/test_litellm_budget_cache.py index 15afa3a73..791e2f4ac 100644 --- a/scripts/test_litellm_budget_cache.py +++ b/scripts/test_litellm_budget_cache.py @@ -17,7 +17,7 @@ def test_helm_and_replicated_disable_stale_authorization_cache(): documents = yaml.safe_load_all((ROOT / "replicated/openhands.yaml").read_text()) chart = next(doc for doc in documents if doc and doc.get("kind") == "HelmChart") assert values["litellm-helm"]["image"]["tag"] == ( - "1.100.1@sha256:fc44cf7f72786e636dc4dc1032b4e431818abfec9d54b8e04284fdea7ef03e2a" + "1.100.5@sha256:65cdef1d78a9a966dfa6797951ea01602826430b6978bc9fa3957da6913dcc7f" ) assert "tag" not in chart["spec"]["values"]["litellm-helm"]["image"] for config in [values, chart["spec"]["values"]]: From eb6a7b6b9afcc811c8b09591abb3e1413be524d4 Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:52:14 -0600 Subject: [PATCH 10/13] fix(openhands): bump Bitnami postgresql and redis image tags --- charts/openhands/values.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/charts/openhands/values.yaml b/charts/openhands/values.yaml index 0c0cd8fff..91bc173ed 100644 --- a/charts/openhands/values.yaml +++ b/charts/openhands/values.yaml @@ -828,6 +828,8 @@ postgresql: enabled: true image: repository: bitnamilegacy/postgresql + # Same app version as chart 15.5.38's default (16.4.0), later OS-package rebuild. + tag: 16.4.0-debian-12-r28 auth: username: postgres existingSecret: postgres-password @@ -865,6 +867,8 @@ redis: enabled: true image: repository: bitnamilegacy/redis + # Patch bump over chart 20.3.0's default (7.4.1); 7.4.3 fixes CVE-2025-21605. + tag: 7.4.3-debian-12-r0 architecture: standalone auth: enabled: true From a554877014d05bc983badccda29d9fb305f44f5e Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:45:11 -0600 Subject: [PATCH 11/13] fix(openhands): pin the postgres client image used by init containers and jobs Every wait-for-db, create-db and create-db-user container hardcoded either bitnamilegacy/postgresql:latest or postgres:14. All but Keycloak's bypassed the Replicated proxy and the airgap registry rewrite, and :latest was unpinned. Route all of them through global.postgresClientImage, pinned by digest to postgres:16.15-alpine, and mirror it in the online and local-registry Replicated values. Keycloak's wait-for-db keeps uid 1001, which the Bitnami image used to supply. --- .../automation/templates/deployment.yaml | 4 +- .../openhands/charts/automation/values.yaml | 5 ++ .../templates/deployment.yaml | 4 +- .../charts/integrations-hub/values.yaml | 5 ++ .../templates/_init-containers.yaml | 4 +- .../charts/plugin-directory/values.yaml | 5 ++ .../templates/_init-containers.yaml | 4 +- .../templates/create-db-user-job.yaml | 2 +- .../openhands/charts/runtime-api/values.yaml | 5 ++ .../openhands/templates/_init-containers.yaml | 4 +- charts/openhands/values.yaml | 17 ++-- replicated/openhands.yaml | 9 +- scripts/test_postgres_client_image.py | 90 +++++++++++++++++++ 13 files changed, 136 insertions(+), 22 deletions(-) create mode 100644 scripts/test_postgres_client_image.py diff --git a/charts/openhands/charts/automation/templates/deployment.yaml b/charts/openhands/charts/automation/templates/deployment.yaml index 513565478..c0d3bedcb 100644 --- a/charts/openhands/charts/automation/templates/deployment.yaml +++ b/charts/openhands/charts/automation/templates/deployment.yaml @@ -47,7 +47,7 @@ spec: {{- if .Values.database.createDatabaseUser }} # Create automation database and user in an existing PostgreSQL instance - name: create-db-user - image: postgres:14 + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" env: - name: PGPASSWORD valueFrom: @@ -124,7 +124,7 @@ spec: {{- else if .Values.postgresql.enabled }} # Wait for the automation's own PostgreSQL subchart to be ready - name: wait-for-postgres - image: bitnamilegacy/postgresql:latest + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" command: ['sh', '-c'] args: - | diff --git a/charts/openhands/charts/automation/values.yaml b/charts/openhands/charts/automation/values.yaml index eab5422a3..7d96e3a73 100644 --- a/charts/openhands/charts/automation/values.yaml +++ b/charts/openhands/charts/automation/values.yaml @@ -207,6 +207,11 @@ postgresql: enabled: false global: + # psql/pg_isready image for the database init containers and jobs. The openhands + # umbrella's global wins; this default only applies when rendering the subchart alone. + postgresClientImage: + repository: docker.io/library/postgres + tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea security: # This allows using the bitnamilegacy image repo allowInsecureImages: true diff --git a/charts/openhands/charts/integrations-hub/templates/deployment.yaml b/charts/openhands/charts/integrations-hub/templates/deployment.yaml index 15a510ff1..a2f4d91d3 100644 --- a/charts/openhands/charts/integrations-hub/templates/deployment.yaml +++ b/charts/openhands/charts/integrations-hub/templates/deployment.yaml @@ -37,7 +37,7 @@ spec: # Create database and user in PostgreSQL. Disable this when the database # and user are provisioned outside the chart. - name: create-db-user - image: postgres:14 + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" env: - name: PGPASSWORD valueFrom: @@ -109,7 +109,7 @@ spec: {{- else if .Values.postgresql.enabled }} # Wait for the service's own PostgreSQL subchart to be ready - name: wait-for-postgres - image: bitnamilegacy/postgresql:latest + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" command: ['sh', '-c'] args: - | diff --git a/charts/openhands/charts/integrations-hub/values.yaml b/charts/openhands/charts/integrations-hub/values.yaml index d248b13a9..8007b8821 100644 --- a/charts/openhands/charts/integrations-hub/values.yaml +++ b/charts/openhands/charts/integrations-hub/values.yaml @@ -171,6 +171,11 @@ postgresql: enabled: false global: + # psql/pg_isready image for the database init containers and jobs. The openhands + # umbrella's global wins; this default only applies when rendering the subchart alone. + postgresClientImage: + repository: docker.io/library/postgres + tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea security: # This allows using the bitnamilegacy image repo allowInsecureImages: true diff --git a/charts/openhands/charts/plugin-directory/templates/_init-containers.yaml b/charts/openhands/charts/plugin-directory/templates/_init-containers.yaml index ba5a108ee..facb0911a 100644 --- a/charts/openhands/charts/plugin-directory/templates/_init-containers.yaml +++ b/charts/openhands/charts/plugin-directory/templates/_init-containers.yaml @@ -1,7 +1,7 @@ {{- define "plugin-directory.dbInitContainers" }} {{- if .Values.databaseMigrations.waitForDatabase }} - name: wait-for-db - image: "bitnamilegacy/postgresql:latest" + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" command: ['sh', '-c'] args: - | @@ -16,7 +16,7 @@ {{- end }} {{- if .Values.databaseMigrations.createDatabases }} - name: create-db - image: "bitnamilegacy/postgresql:latest" + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" command: ['sh', '-c'] args: - | diff --git a/charts/openhands/charts/plugin-directory/values.yaml b/charts/openhands/charts/plugin-directory/values.yaml index 41c582bf2..4712da7b5 100644 --- a/charts/openhands/charts/plugin-directory/values.yaml +++ b/charts/openhands/charts/plugin-directory/values.yaml @@ -160,6 +160,11 @@ datadog: env: {} global: + # psql/pg_isready image for the database init containers and jobs. The openhands + # umbrella's global wins; this default only applies when rendering the subchart alone. + postgresClientImage: + repository: docker.io/library/postgres + tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea scheduling: # Affinity applied to this chart's pods when `affinity` above is empty. The # openhands umbrella sets this once for every chart it owns; this default diff --git a/charts/openhands/charts/runtime-api/templates/_init-containers.yaml b/charts/openhands/charts/runtime-api/templates/_init-containers.yaml index b0354175d..ccbbb17f2 100644 --- a/charts/openhands/charts/runtime-api/templates/_init-containers.yaml +++ b/charts/openhands/charts/runtime-api/templates/_init-containers.yaml @@ -1,7 +1,7 @@ {{- define "runtime-api.dbInitContainers" }} {{- if .Values.databaseMigrations.waitForDatabase }} - name: wait-for-db - image: "bitnamilegacy/postgresql:latest" + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" command: ['sh', '-c'] args: - | @@ -18,7 +18,7 @@ {{- end }} {{- if .Values.databaseMigrations.createDatabases }} - name: create-db - image: "bitnamilegacy/postgresql:latest" + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" command: ['sh', '-c'] args: - | diff --git a/charts/openhands/charts/runtime-api/templates/create-db-user-job.yaml b/charts/openhands/charts/runtime-api/templates/create-db-user-job.yaml index 46d90e560..dc888f53f 100644 --- a/charts/openhands/charts/runtime-api/templates/create-db-user-job.yaml +++ b/charts/openhands/charts/runtime-api/templates/create-db-user-job.yaml @@ -22,7 +22,7 @@ spec: {{- end }} containers: - name: create-user - image: postgres:14 + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" env: - name: PGPASSWORD valueFrom: diff --git a/charts/openhands/charts/runtime-api/values.yaml b/charts/openhands/charts/runtime-api/values.yaml index a03dd7ede..e5502cf46 100644 --- a/charts/openhands/charts/runtime-api/values.yaml +++ b/charts/openhands/charts/runtime-api/values.yaml @@ -353,6 +353,11 @@ replicated: enabled: false global: + # psql/pg_isready image for the database init containers and jobs. The openhands + # umbrella's global wins; this default only applies when rendering the subchart alone. + postgresClientImage: + repository: docker.io/library/postgres + tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea # Canonical agent-server image. Defaults any warm-runtime configsByName entry # that omits its own `image`. In the openhands umbrella the parent chart's # global wins; this default only applies when rendering the subchart alone. diff --git a/charts/openhands/templates/_init-containers.yaml b/charts/openhands/templates/_init-containers.yaml index fcb308a26..a8fe51c93 100644 --- a/charts/openhands/templates/_init-containers.yaml +++ b/charts/openhands/templates/_init-containers.yaml @@ -1,7 +1,7 @@ {{- define "openhands.dbInitContainers" }} {{- if .Values.databaseMigrations.waitForDatabase }} - name: wait-for-db - image: "bitnamilegacy/postgresql:latest" + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" command: ['sh', '-c'] args: - | @@ -18,7 +18,7 @@ {{- end }} {{- if .Values.databaseMigrations.createDatabases }} - name: create-db - image: "bitnamilegacy/postgresql:latest" + image: "{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}" command: ['sh', '-c'] args: - | diff --git a/charts/openhands/values.yaml b/charts/openhands/values.yaml index 91bc173ed..e98891417 100644 --- a/charts/openhands/values.yaml +++ b/charts/openhands/values.yaml @@ -537,15 +537,14 @@ keycloak: # this is evaluated in the Keycloak subchart context at render time. - name: KC_DB_URL_PROPERTIES value: 'sslmode={{ .Values.externalDatabase.sslMode | default "prefer" }}' - waitForDb: - image: "bitnamilegacy/postgresql:latest" initContainers: - name: wait-for-db - # The Bitnami Keycloak subchart renders initContainers through common.tplvalues.render, - # so this template expression is evaluated at deploy time rather than being treated as - # a literal string. This lets us override just the image (e.g. for Replicated proxy) - # without duplicating the entire init container. - image: '{{ .Values.waitForDb.image }}' + # Rendered through common.tplvalues.render, so this resolves against the shared global. + image: '{{ .Values.global.postgresClientImage.repository }}:{{ .Values.global.postgresClientImage.tag }}' + # The client image defaults to root; keep the uid the Bitnami image ran this as. + securityContext: + runAsUser: 1001 + runAsNonRoot: true command: ['sh', '-c'] args: - | @@ -1400,6 +1399,10 @@ replicated: postgresDatabase: "" global: + # psql/pg_isready image for the database init containers and jobs. + postgresClientImage: + repository: docker.io/library/postgres + tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea # Canonical agent-server image. Defaults the runtime image (runtime.image) and # any warm-runtime configsByName entry that omits its own `image`. Override # either of those for per-use exceptions; set it here to move them together. diff --git a/replicated/openhands.yaml b/replicated/openhands.yaml index e1b549db1..daaf31471 100644 --- a/replicated/openhands.yaml +++ b/replicated/openhands.yaml @@ -21,6 +21,9 @@ spec: # global.agentServerImage. agentServerImage: repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/agent-server' + # Tag pinned in the chart. + postgresClientImage: + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/library/postgres' # Runtime (agent-server sandbox) env vars. The chart serialises this map # into OH_AGENT_SERVER_ENV and mirrors it into every warm-runtime entry's # env (runtime-api claims warm pods by exact env match, so a key here @@ -173,8 +176,6 @@ spec: keycloakConfigCli: image: repository: 'proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/keycloak-config-cli' - waitForDb: - image: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/bitnamilegacy/postgresql:latest' # caBundle wiring: mount the trust-manager Bundle ConfigMap and point # Keycloak's truststore at the merged PEM. Repeats the chart's default # KC_* env vars because helm value merging replaces arrays — adding @@ -781,6 +782,8 @@ spec: # warmRuntimes default entry both inherit this. Tag pinned in the chart. agentServerImage: repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/agent-server' + postgresClientImage: + repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/postgres' image: repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/deploy' keycloak: @@ -789,8 +792,6 @@ spec: keycloakConfigCli: image: repository: '{{repl LocalRegistryNamespace }}/keycloak-config-cli' - waitForDb: - image: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/postgresql:latest' postgresql: image: repository: '{{repl LocalRegistryNamespace }}/postgresql' diff --git a/scripts/test_postgres_client_image.py b/scripts/test_postgres_client_image.py new file mode 100644 index 000000000..4a9d59037 --- /dev/null +++ b/scripts/test_postgres_client_image.py @@ -0,0 +1,90 @@ +"""Every psql/pg_isready container must use the pinned global.postgresClientImage, mirrored in each mode.""" + +import subprocess +from pathlib import Path + +import pytest +import yaml + +ROOT = Path(__file__).resolve().parents[1] +CHART = ROOT / "charts/openhands" +APP, HOST, NS = "test-app", "registry.test", "test-ns" +# Turn on every site that runs the client, including the non-default branches. +SITE_VALUES = [ + { + "databaseMigrations": {"createDatabases": True}, + "keycloak": {"enabled": True}, + "runtime-api": { + "databaseMigrations": {"createDatabases": True}, + "database": {"create": True, "host": "db", "user": "postgres", "name": "rt", "new_user": "rt_user"}, + }, + "plugin-directory": {"enabled": True, "databaseMigrations": {"createDatabases": True}}, + "automation": {"enabled": True, "database": {"createDatabaseUser": True}}, + "integrations-hub": {"enabled": True, "database": {"host": "db", "createDatabaseUser": True}}, + }, + { + "automation": {"enabled": True, "database": {"createDatabaseUser": False}, "postgresql": {"enabled": True}}, + "integrations-hub": {"enabled": True, "database": {"host": "db", "createDatabaseUser": False}, "postgresql": {"enabled": True}}, + }, +] + + +def chart_default(): + return yaml.safe_load((CHART / "values.yaml").read_text())["global"]["postgresClientImage"] + + +def replicated_repository(mode): + spec = yaml.safe_load((ROOT / "replicated/openhands.yaml").read_text())["spec"] + if mode == "online": + values = spec["values"] + else: + values = next(b for b in spec["optionalValues"] if "HasLocalRegistry" in b["when"])["values"] + repo = values["global"]["postgresClientImage"]["repository"] + for source, target in { + '{{repl LicenseFieldValue "appSlug"}}': APP, + "{{repl LocalRegistryHost }}": HOST, + "{{repl LocalRegistryNamespace }}": NS, + }.items(): + repo = repo.replace(source, target) + return repo + + +def client_images(rendered): + images = [] + for doc in yaml.safe_load_all(rendered): + if not doc: + continue + spec = doc.get("spec", {}) + pod = spec.get("template", {}).get("spec") or spec.get("jobTemplate", {}).get("spec", {}).get("template", {}).get("spec") + for c in (pod or {}).get("initContainers", []) + (pod or {}).get("containers", []): + script = " ".join((c.get("command") or []) + (c.get("args") or [])) + if "psql" in script or "pg_isready" in script: + images.append((doc["metadata"]["name"], c["name"], c["image"])) + return images + + +def test_chart_default_is_digest_pinned(): + assert "@sha256:" in chart_default()["tag"] + + +@pytest.mark.parametrize("mode", ["online", "airgap"]) +@pytest.mark.parametrize("sites", range(len(SITE_VALUES))) +def test_every_client_container_uses_the_mirrored_image(mode, sites, tmp_path): + default = chart_default() + expected_repo = { + "online": f"images.r9.all-hands.dev/proxy/{APP}/{default['repository']}", + "airgap": f"{HOST}/{NS}/{default['repository'].rsplit('/', 1)[-1]}", + }[mode] + assert replicated_repository(mode) == expected_repo + values = dict(SITE_VALUES[sites], **{"global": {"postgresClientImage": {"repository": expected_repo}}}) + values_path = tmp_path / "values.yaml" + values_path.write_text(yaml.safe_dump(values)) + rendered = subprocess.run( + ["helm", "template", "openhands", str(CHART), "-f", str(values_path)], + check=True, + capture_output=True, + text=True, + ).stdout + images = client_images(rendered) + assert len(images) >= 5 + assert all(image == f"{expected_repo}:{default['tag']}" for _, _, image in images), images From ce65a45492163772917e9a702f6d5d68e19275a9 Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 08:46:27 -0600 Subject: [PATCH 12/13] fix(openhands): [optional] use alpine/psql for the postgres client image Optional on top of the previous commit: drop it to stay on the Docker Official postgres:16.15-alpine image. postgres:16.15-alpine still reports 1 CRITICAL and 24 HIGH fixable findings, all in the Go stdlib of its gosu binary, which none of these containers run. alpine/psql 18.6 ships only the client tools and scans clean (0 CRITICAL/HIGH). psql 18 supports servers back to 9.2, and the image runs every site's command with output identical to the old images against PostgreSQL 13, 16 and 18. --- charts/openhands/charts/automation/values.yaml | 4 ++-- charts/openhands/charts/integrations-hub/values.yaml | 4 ++-- charts/openhands/charts/plugin-directory/values.yaml | 4 ++-- charts/openhands/charts/runtime-api/values.yaml | 4 ++-- charts/openhands/values.yaml | 4 ++-- replicated/openhands.yaml | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/charts/openhands/charts/automation/values.yaml b/charts/openhands/charts/automation/values.yaml index 7d96e3a73..82805d077 100644 --- a/charts/openhands/charts/automation/values.yaml +++ b/charts/openhands/charts/automation/values.yaml @@ -210,8 +210,8 @@ global: # psql/pg_isready image for the database init containers and jobs. The openhands # umbrella's global wins; this default only applies when rendering the subchart alone. postgresClientImage: - repository: docker.io/library/postgres - tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea + repository: docker.io/alpine/psql + tag: 18.6@sha256:08f354a83552fcefa508116268463b371717577fe49d3fcb7b82cf8d2be464b8 security: # This allows using the bitnamilegacy image repo allowInsecureImages: true diff --git a/charts/openhands/charts/integrations-hub/values.yaml b/charts/openhands/charts/integrations-hub/values.yaml index 8007b8821..0d872f013 100644 --- a/charts/openhands/charts/integrations-hub/values.yaml +++ b/charts/openhands/charts/integrations-hub/values.yaml @@ -174,8 +174,8 @@ global: # psql/pg_isready image for the database init containers and jobs. The openhands # umbrella's global wins; this default only applies when rendering the subchart alone. postgresClientImage: - repository: docker.io/library/postgres - tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea + repository: docker.io/alpine/psql + tag: 18.6@sha256:08f354a83552fcefa508116268463b371717577fe49d3fcb7b82cf8d2be464b8 security: # This allows using the bitnamilegacy image repo allowInsecureImages: true diff --git a/charts/openhands/charts/plugin-directory/values.yaml b/charts/openhands/charts/plugin-directory/values.yaml index 4712da7b5..96ac73ebd 100644 --- a/charts/openhands/charts/plugin-directory/values.yaml +++ b/charts/openhands/charts/plugin-directory/values.yaml @@ -163,8 +163,8 @@ global: # psql/pg_isready image for the database init containers and jobs. The openhands # umbrella's global wins; this default only applies when rendering the subchart alone. postgresClientImage: - repository: docker.io/library/postgres - tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea + repository: docker.io/alpine/psql + tag: 18.6@sha256:08f354a83552fcefa508116268463b371717577fe49d3fcb7b82cf8d2be464b8 scheduling: # Affinity applied to this chart's pods when `affinity` above is empty. The # openhands umbrella sets this once for every chart it owns; this default diff --git a/charts/openhands/charts/runtime-api/values.yaml b/charts/openhands/charts/runtime-api/values.yaml index e5502cf46..eb44f2fdb 100644 --- a/charts/openhands/charts/runtime-api/values.yaml +++ b/charts/openhands/charts/runtime-api/values.yaml @@ -356,8 +356,8 @@ global: # psql/pg_isready image for the database init containers and jobs. The openhands # umbrella's global wins; this default only applies when rendering the subchart alone. postgresClientImage: - repository: docker.io/library/postgres - tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea + repository: docker.io/alpine/psql + tag: 18.6@sha256:08f354a83552fcefa508116268463b371717577fe49d3fcb7b82cf8d2be464b8 # Canonical agent-server image. Defaults any warm-runtime configsByName entry # that omits its own `image`. In the openhands umbrella the parent chart's # global wins; this default only applies when rendering the subchart alone. diff --git a/charts/openhands/values.yaml b/charts/openhands/values.yaml index e98891417..511059344 100644 --- a/charts/openhands/values.yaml +++ b/charts/openhands/values.yaml @@ -1401,8 +1401,8 @@ replicated: global: # psql/pg_isready image for the database init containers and jobs. postgresClientImage: - repository: docker.io/library/postgres - tag: 16.15-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea + repository: docker.io/alpine/psql + tag: 18.6@sha256:08f354a83552fcefa508116268463b371717577fe49d3fcb7b82cf8d2be464b8 # Canonical agent-server image. Defaults the runtime image (runtime.image) and # any warm-runtime configsByName entry that omits its own `image`. Override # either of those for per-use exceptions; set it here to move them together. diff --git a/replicated/openhands.yaml b/replicated/openhands.yaml index daaf31471..1ba9c7812 100644 --- a/replicated/openhands.yaml +++ b/replicated/openhands.yaml @@ -23,7 +23,7 @@ spec: repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/ghcr.io/openhands/agent-server' # Tag pinned in the chart. postgresClientImage: - repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/library/postgres' + repository: 'images.r9.all-hands.dev/proxy/{{repl LicenseFieldValue "appSlug"}}/docker.io/alpine/psql' # Runtime (agent-server sandbox) env vars. The chart serialises this map # into OH_AGENT_SERVER_ENV and mirrors it into every warm-runtime entry's # env (runtime-api claims warm pods by exact env match, so a key here @@ -783,7 +783,7 @@ spec: agentServerImage: repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/agent-server' postgresClientImage: - repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/postgres' + repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/psql' image: repository: '{{repl LocalRegistryHost }}/{{repl LocalRegistryNamespace }}/deploy' keycloak: From cf82b5cb4fa29eb967debfb14d9a0aae2a69c262 Mon Sep 17 00:00:00 2001 From: dylan-openhands Date: Sat, 10 Oct 2026 09:16:32 -0600 Subject: [PATCH 13/13] ci: keep image-loader and crd-check on their release tags Changing either chart makes release-please propose a release of it on release/0.71. The sync check now reads 1.49.5-r1-python as 1.49.5-python, so image-loader can stay on the release tag, as it did for 0.71.2. The crd-check edit was a doc comment (the chart is consumed as OCI 0.1.0). --- charts/crd-check/templates/_hook.tpl | 2 +- charts/image-loader/values.yaml | 2 +- scripts/check_agent_server_sync.py | 7 ++++--- scripts/test_check_agent_server_sync.py | 11 +++++++++++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/charts/crd-check/templates/_hook.tpl b/charts/crd-check/templates/_hook.tpl index 38ad1f7dc..d28562478 100644 --- a/charts/crd-check/templates/_hook.tpl +++ b/charts/crd-check/templates/_hook.tpl @@ -17,7 +17,7 @@ Consumers must define a `crdCheck` block in their own values.yaml, e.g.: crds: [] image: repository: docker.io/rancher/kubectl - tag: v1.33.13 + tag: v1.33.0 pullPolicy: IfNotPresent imagePullSecrets: [] resources: diff --git a/charts/image-loader/values.yaml b/charts/image-loader/values.yaml index 8e20ed6df..cdebee6c1 100644 --- a/charts/image-loader/values.yaml +++ b/charts/image-loader/values.yaml @@ -1,7 +1,7 @@ # Agent-server image the loader pre-pulls onto nodes; keep tag in sync with the sandbox runtime. image: repository: ghcr.io/openhands/agent-server - tag: "1.49.5-r1-python@sha256:5f2919fbfc33934c023092926fc79a5da9acecc809d5773e582b44b8093d8d3f" + tag: 1.49.5-python pullPolicy: Always resources: diff --git a/scripts/check_agent_server_sync.py b/scripts/check_agent_server_sync.py index e9e7a23a8..0b057c077 100644 --- a/scripts/check_agent_server_sync.py +++ b/scripts/check_agent_server_sync.py @@ -65,8 +65,9 @@ # no tag to look up on the remote -- the commit itself is the ref. _SHA_TAG_RE = re.compile(r"^sha-(?P[0-9a-f]{7,40})$") -# Rebuilds of a release (`1.64.0-patched@sha256:...`, `1.64.0-r1`) carry the release they rebuild. -_PATCHED_SUFFIX_RE = re.compile(r"(?:-(?:patched|r\d+))?(?:@sha256:[0-9a-f]{64})?$") +# Rebuilds of a release (`1.64.0-patched@sha256:...`, `1.64.0-r1`, `1.49.5-r1-python`) carry the release they rebuild. +_PATCHED_SUFFIX_RE = re.compile(r"(?:-patched)?(?:@sha256:[0-9a-f]{64})?$") +_REBUILD_RE = re.compile(r"^(?P[^-@]+)-r\d+(?=-|@|$)") # `openhands-agent-server[extra]==1.43.1 ; python_version >= "3.12"` _REQUIREMENT_RE = re.compile( @@ -136,7 +137,7 @@ def read_pin(repo_root: Path, pin: Pin) -> str: def release_tag(tag: str) -> str: """Strip a ``-patched``/``-rN`` rebuild suffix and digest pin, leaving the release tag.""" - return _PATCHED_SUFFIX_RE.sub("", tag, count=1) + return _PATCHED_SUFFIX_RE.sub("", _REBUILD_RE.sub(r"\g", tag, count=1), count=1) def split_variant(tag: str) -> tuple[str, str | None]: diff --git a/scripts/test_check_agent_server_sync.py b/scripts/test_check_agent_server_sync.py index 95daad72a..66333e82c 100644 --- a/scripts/test_check_agent_server_sync.py +++ b/scripts/test_check_agent_server_sync.py @@ -157,6 +157,17 @@ def test_r1_hotfix_pins_resolve_to_the_release_they_rebuild(tmp_path, fake_remot assert "git/ref/tags/1.56.0" in fake_remote["calls"] +def test_r1_pins_agree_with_an_image_loader_left_on_the_release_tag(tmp_path, fake_remote): + digest = "@sha256:" + "d" * 64 + write_charts(tmp_path, f"1.56.0-r1{digest}", f"1.43.1-r1-python{digest}") + loader = AGENT_SERVER_PINS[-1] + document = yaml.safe_load((tmp_path / loader.path).read_text()) + document["image"]["tag"] = "1.43.1-python" + (tmp_path / loader.path).write_text(yaml.safe_dump(document)) + + assert run_check(tmp_path) + + def test_plain_r1_enterprise_tag_resolves_to_the_release(tmp_path, fake_remote): write_charts(tmp_path, "1.56.0-r1", "1.43.1-r1-python")