Skip to content

Add helm_oci_manifest so rules_img's multi_deploy can push a chart - #305

Draft
rdark wants to merge 1 commit into
periareon:mainfrom
rdark:richard/pla-2603-helm-deploy-multi-deploy
Draft

rdark wants to merge 1 commit into
periareon:mainfrom
rdark:richard/pla-2603-helm-deploy-multi-deploy

Conversation

@rdark

@rdark rdark commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Closes #276.

multi_deploy pushes many images from one bazel run (concurrently in later versions), but each chart still needs its own bazel run of helm_push. helm_push cannot provide DeployInfo, because DeployInfo describes an image push or load, not a command to run. This PR describes the chart as the OCI artifact helm push creates, and lets rules_img push that.

Digest
The pushed manifest is byte-identical to the one helm push creates.

Usage

load("@rules_helm//helm:defs.bzl", "helm_chart")
load("@rules_helm//helm:rules_img.bzl", "helm_oci_manifest")
load("@rules_img//img:multi_deploy.bzl", "multi_deploy")

helm_chart(name = "chart")

# Describes the push; it is not runnable on its own.
helm_oci_manifest(name = "chart_oci_manifest", chart = ":chart", registry_url = "oci://registry.example.com/charts")

# `bazel run :deploy` pushes the chart. Image push targets can go in the same list.
multi_deploy(name = "deploy", operations = [":chart_oci_manifest"])

The target is an image_manifest with the Helm config media type, the chart .tgz as its only layer, the annotations helm push writes, and an image_push_spec for <registry_url>/<chart name>:<chart version> (+ in the version becomes _, as Helm does). It is built from rules_img's public rules only. helm_chart does not create it; it is opt-in through the new helm/rules_img.bzl.

Not supported, and documented in the macro: push_cmd and plugins such as cm-push, HELM_REGISTRY_USERNAME/HELM_REGISTRY_PASSWORD login (credentials come from rules_img's Docker config and credential helpers), include_images, and charts from helm_import (their metadata has no created value).

Two issues a user might otherwise hit: rules_img expands Go templates in annotation values, so {{ in chart metadata is escaped; and the manifest sets soci = "disabled", since a SOCI index would add an annotation helm push does not write.

Dependency change

rules_img is now a non-dev dependency at 0.3.18. 0.3.14 is the first version that reads annotations_file as a JSON object with values verbatim; earlier versions split KEY=VALUE lines and trim them. 0.3.18 adds multi_deploy --sink, which the offline test uses, so it is also the version this repository tests. omit_platform (0.3.21) is not needed: it changes only the manifest descriptor, and the pushed bytes on 0.3.23 are identical with and without it.

This has a cost for consumers who never load helm/rules_img.bzl. In a throwaway consumer module with one helm_chart, built from an empty repository cache, the change added rules_img+ (about 0.9 MB of source), hermetic_launcher+ (128 KB) and the img_toolchain hub repo (20 KB) to the fetched repositories, because both modules register toolchains. No img tool binaries were fetched. Module resolution also raises rules_img to at least 0.3.18, bazel_features to 1.47.0 and package_metadata to 0.0.10.

Moving to 0.3.17 or later broke tests/with_image_deps_img on Linux, because img_pull started making :image an alias. Base PR #304 fixes that.

Implementation

The chart-reading and annotation code moves out of oci_digest.go into helm/private/oci_digest/ociartifact, unchanged. oci_digest keeps its output (the simple and created digest goldens pass unchanged), and a new oci_parts tool writes the config blob, annotations, tag and destination for rules_img.

Testing

  • tests/helm_oci_manifest runs each multi_deploy with --sink oci:<dir>, offline, and checks the Helm config and layer media types, that the layer is the chart .tgz, that the config blob and manifest equal goldens from a real helm push, that the manifest is that manifest plus the top-level mediaType and nothing else (the check that flips when the field can be omitted), that the rest matches helm_oci_digest, the reference for a trailing-slash registry_url and for registry_url_file, a {{ description and a + version. It also passes with SOCI forced on.
  • Go unit tests for ociartifact and oci_parts.
  • bazel test //... and --config=strict on macOS with Bazel 9.3.0 and 7.7.1: 66 pass, 3 skipped (the Linux-only with_image_deps_img tests).
  • By hand: pushed to a local registry from a fresh output base (same digests as above); helm pull, helm show chart and helm template accept the charts with Helm 3.16.3 and 4.2.0, and the pulled .tgz is byte-identical to the built one.
  • Not run: Linux and Windows CI (I built with_image_deps_img for linux_arm64 and checked its patterns by hand, but did not run the tests), Helm 3.17.3, Flux pulling a chart, and registries that need credentials.

@rdark
rdark marked this pull request as ready for review October 19, 2026 15:32
@rdark
rdark force-pushed the richard/pla-2603-helm-deploy-multi-deploy branch 2 times, most recently from c286b80 to ab3e11c Compare October 20, 2026 07:46
@rdark rdark changed the title Add helm_deploy so rules_img's multi_deploy can push a chart Add helm_oci_manifest so rules_img's multi_deploy can push a chart Oct 20, 2026
@rdark

rdark commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

CI failures are 429's from ECR

`helm_push` cannot provide `DeployInfo`, so a chart could not be one of a
`multi_deploy`'s operations. `helm_oci_manifest` in the new
helm/rules_img.bzl describes the chart as the OCI artifact `helm push`
creates: an `image_manifest` with the Helm config media type, the chart
.tgz as its only layer, the annotations `helm push` writes, and a push
spec for `<registry_url>/<chart name>:<chart version>`.

The pushed manifest differs from the `helm push` one only by the
top-level `mediaType` that rules_img always writes, so its digest differs
from `helm_oci_digest`'s.

Move the chart-reading and annotation code from oci_digest into a shared
ociartifact package, add an oci_parts tool for the rules_img inputs, and
make rules_img a non-dev dependency at 0.3.18.
@rdark
rdark marked this pull request as draft October 24, 2026 16:59
@rdark
rdark force-pushed the richard/pla-2603-helm-deploy-multi-deploy branch from ab3e11c to 197c5e9 Compare October 24, 2026 16:59
@rdark

rdark commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

@abrisco I moved back into draft status - I think it would be better to wait on a rules_img release with rules_img#805 in, then we have byte-identical manifests from day 1. Will move back out of draft when that happens

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Include rules_img's DeployInfo provider on helm_push targets

1 participant