Split `helm_import_repository` into different rules per source type
Right now, helm_import_repository supports three different use cases:
- Downloading a chart from the specified HTTP URL
- Finding a chart in a HTTP repository
- Note that
index.yamlmay provide aoci://URL here
- Note that
- Downloading a chart from an OCI registry
Two issues discovered here:
-
No support for specifying by digest instead of version tag for OCI URLs:
oci://registry-1.docker.io/bitnamicharts/grafana@sha256:015f66a231a809557ab368d903f6762ba31ba2f7b3d0f890445be6e8f213cff1This is not valid in
helmthough,helmrequires specifying tag in the URL or setting the--versionflag. -
Can't always determine version from URL:
aws-cluster-autoscaler-1.2.3-rc.tgzis a possible chart package file name (Ref: https://helm.sh/docs/chart_best_practices/conventions/#chart-names), but there's no clear way to separate the version (1.2.3-rc) from the name ofaws-cluster-autoscaler.
I propose splitting helm_import_repository into three different rules:
helm_import_urlto import a chart from a HTTP URLhelm_import_repositoryto import a chart from a HTTP repository by finding it inindex.yamlhelm_import_registryto import a chart from an OCI registry.
Splitting into separate rules will make it easier to manage the code and avoid the issues mentioned earlier.
Unfortunately, this would be a breaking change for current users. @abrisco, thoughts?
Maybe some history will help reveal a path forward:
The original design of helm_import_repository was to support users specifying chart names, versions, and repositories, just as they would outside of Bazel, to fetch a dependency. Though, in the spirit of Bazel's determinism, the rule would recommend adding the sha256 checksum and url of the chart file so the dependency would be reproducible. I felt like this was low friction to new adopters familiar with helm and unfamiliar with Bazel and that Bazel would encourage modifying the repository rule instantiation to be reproducible. If oci registries don't support the same behavior, I would split oci logic into another rule and still aim to allow users to take the same info they might add to their chart.yaml files and add them to MODULE.bazel.
That being said though, I've not been a new user in a while so perhaps the UX I thought was cool was actually bad. Does that flavored history help in any way? 😅
Working/thinking through this more, I think it makes sense to split into two rules:
-
helm_import_urlto import from a HTTP or OCI URL, which would be similar tohelm_importfor importing a local chart package. With the sha256 sum, this would be deterministic and preferred. -
helm_import_repositoryto look up a chart from a HTTP repository, given the repository, chart name, and chart version. Maybe this should never be deterministic and recommend adoptinghelm_import_url, which would be deterministic given URL and sha256 sum.
Looking at the Bazel documentation for repository rules, they should only be returning the parameters that make the rule reproducible.
So I think for importing from a repository, the repository name, chart name, and version are enough to make it reproducible, but the rule still should accept a checksum. It shouldn't return the sum since we can't use that to locate the chart.
For importing from a OCI registry, you can specify a container digest, which is a sha256 sum, but it is from the entire container image and the chart layer (the .tgz file) has its sum that should be verified against.
Also, one thing that might be leading to some confusion is the _repository suffix is a pattern I've been using for all repository rules (I forget where I adopted that from). Maybe it'd be better to call it helm_repository_import and helm_url_import?
I think sticking with helm_import_url would be better since this alphabetically sorts with the other helm_import rules.
I can't find any reference recommending that repository rules end with _repository. I was thinking here that it was referring to importing from a Helm chart repository, and not that the rule itself was a Bazel repository rule.
If we really wanted to have parity with Helm though, we would use helm pull inside of the import rules. This is done in https://github.com/bazel-contrib/rules_jvm_external/tree/master which calls external programs to pull JARs.
I've taken a look at other repository_rule use cases for fetching external user-specified dependencies (compared to downloading tools like maven or helm) in https://github.com/bazel-contrib/rules_oci/blob/1605dcde9b30cb64528a0d1cce7144c9f63cc82a/oci/private/pull.bzl and https://github.com/bazel-contrib/rules_python/blob/fe45faabeb3dceab8766fb1a67131ec0cc1135dc/python/private/pypi/pip_repository.bzl#L73 and they don't return anything from their rules, so I think the import rules here should be updated to resolve https://github.com/abrisco/rules_helm/issues/189.
Another reason to use helm pull instead of the Bazel downloader for pulling charts is to let Helm handle authentication, like how real Helm is used to push charts in https://github.com/abrisco/rules_helm/blob/main/helm/private/registrar/registrar.go.
https://github.com/abrisco/rules_helm/pull/197/commits/4bca75577a30c74e55d071253751161b92e18228
I just wanted to share that the first issue raised:
No support for specifying by digest instead of version tag for OCI URLs:
oci://registry-1.docker.io/bitnamicharts/grafana@sha256:015f66a231a809557ab368d903f6762ba31ba2f7b3d0f890445be6e8f213cff1
This is not valid in helm though, helm requires specifying tag in the URL or setting the --version flag.
is not an issue in the upcoming Helm v4 release. It is definitely still an issue when using older versions though!
Enhanced OCI Support
Install charts by digest for better supply chain security. For example, helm install myapp oci://registry.example.com/charts/app@sha256:abc123.... Charts with non-matching digests are not installed.