Skip to content

Mirror Helm charts - #606

Merged
andrew merged 2 commits into
git-pkgs:mainfrom
simonchrz:feat/mirror-helm
Oct 26, 2026
Merged

andrew merged 2 commits into
git-pkgs:mainfrom
simonchrz:feat/mirror-helm

Conversation

@simonchrz

Copy link
Copy Markdown
Contributor

Part of #414.

Mirroring pkg:helm/... failed with unsupported ecosystem. The Helm handler caches charts per configured repository, not per chart name, so the PURL namespace names the upstream.helm repository: pkg:helm/{repository}/{chart}@{version}. The purl spec defines no repository qualifier for helm (the purl library drops repository_url for it on purpose), so the namespace is the only place for it.

A release is mirrored the way handleChart would fetch it:

  • found in the repository's index.yaml through the handler's own index lookup (chartLookup, now also keyed by chart and version), read through the metadata cache under the handler's key;
  • fetched from the first URL the release lists, which is the one helm downloads;
  • checked against the index digest with GetOrFetchArtifactFromURLWithDigest, and cached as helm / repository / digest / filename, the key handleChart reads.

Since the index is cached too, helm repo add and helm pull work against the proxy with the repository down (with cache_metadata on, which proxy mirror always sets). Unversioned PURLs list every version in the index through the registries Helm client, pointed at the configured repository URL.

Refused, with a message saying why:

  • PURLs without a repository namespace;
  • repositories not in upstream.helm (the message lists the configured ones);
  • releases the index lists in an OCI registry: helm pulls those through /v2, so the error names the pkg:oci PURL that mirrors them as an image;
  • releases in cooldown, which the rewritten index doesn't list.

The mirror builds its own HelmHandler (Mirror.Charts), set by proxy mirror and the mirror API. To keep runMirror under the lint's maintainability limit, building the command's mirror moved into newCommandMirror. The shared test helper now sets CacheMetadata and passes its version lister to the PURL source, as proxy mirror does.

Tested through the mirror and then the Helm handler with the upstream closed: the index and the chart come from the cache (internal/server/mirror_helm_test.go), a digest mismatch is refused and leaves nothing to serve, and the refusals above. The tests fail without the change. Against https://charts.jetstack.io I mirrored pkg:helm/jetstack/cert-manager@v1.21.3, ran the proxy with HTTPS_PROXY pointing at a dead port, and helm pull jetstack/cert-manager --version v1.21.3 (alpine/helm 3.16.4) got the chart with the published digest; v1.21.2, not mirrored, failed with 502.

Mirroring pkg:helm PURLs failed with an unsupported ecosystem error. The
namespace now names the upstream.helm repository, as the Helm handler
caches charts per repository: pkg:helm/{repository}/{chart}@{version}.

The chart is found in the repository's index through the handler's own
index lookup, fetched from the first URL the release lists, as helm does,
checked against the listed digest and cached under the repository,
digest and filename the handler serves it from. The index goes through
the metadata cache, so helm finds the chart there while the repository is
down. Unversioned PURLs list every version in the index.

Charts without a repository, from an unconfigured one, or listed in an
OCI registry are refused; the last are pulled through /v2, and the error
names the pkg:oci PURL that mirrors them.
@andrew
andrew merged commit 61df321 into git-pkgs:main Oct 26, 2026
7 checks passed
@andrew andrew mentioned this pull request Oct 26, 2026
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.

2 participants