helm / helm/helm

`helm pull --verify` fails on a correctly signed chart when the repository name differs from the chart name

Open
#32,546 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
30.2k
Forks
7.8k
Avg merge
20h 58m
Merged PRs (30d)
36

Description

### What happened?

A chart signed at package time cannot be verified when it is pulled from a repository named after something else:

```console
$ helm pull oci://localhost:5099/charts/foo:0.1.0 --plain-http --verify --keyring "$GNUPGHOME/pubring.gpg"
Pulled: localhost:5099/charts/foo:0.1.0
Digest: sha256:278e1cd2439aee3d07a559f29921859d355fe03cd6f304a45babbd05c19e020c
Error: provenance does not contain a SHA for a file named "foo-0.1.0.tgz"
```

The same chart, the same signature, pulled from the repository named after the chart, verifies:

```console
$ helm pull oci://localhost:5099/charts/bar:0.1.0 --plain-http --verify --keyring "$GNUPGHOME/pubring.gpg"
Signed by: Helm Repro
Using Key With Fingerprint: D99616A6EF85B14F28E76DE19E0766A448857C16
Chart Hash Verified: sha256:ecd61ca508db32cb765021964651a22eec5ce33dbefe8c8eb934853f1b25edd1
```

Nothing about the chart differs between the two runs. What differs is the name the archive is checked under. `pkg/downloader/chart_downloader.go:156-159` builds that name from the reference, `filepath.Base(u.Path)` plus the tag, and `:311-320` derives it the same way for verification. `pkg/provenance/sign.go:266` then looks the archive up in the signed manifest by that name. The manifest was written by `helm package` and names the chart, so the lookup asks for a file it does not describe. The comment above the verification code already records the assumption this rests on.

`helm pull` without `--verify` handles the mismatch fine, so nothing else in the pull notices it. A repository can also hold several charts under one index, and only one of them can be named after the repository.

#32529 reports the same mismatch from another side, `helm dependency update` followed by `helm lint`, and HIP helm/community#443 proposes a way to express both identities for dependencies. Both are about dependency declarations and neither covers this path. Verification needs no new field and no change in semantics; it needs the name the archive is checked under to be the name the signature was made over.

### What did you expect to happen?

A chart that was signed and arrives intact to verify wherever it is published from.

### How can we reproduce it (as minimally and precisely as possible)?

```console
$ export GNUPGHOME=$(mktemp -d)
$ gpg --batch --pinentry-mode loopback --passphrase '' \
--quick-generate-key 'Helm Repro ' rsa2048 sign 1d
$ gpg --export-secret-keys > "$GNUPGHOME/secring.gpg"
$ gpg --export > "$GNUPGHOME/pubring.gpg"

$ docker run -d --rm -p 5099:5000 registry:2.8.3
$ helm create bar
$ helm package --sign --key 'Helm Repro' --keyring "$GNUPGHOME/secring.gpg" bar
$ helm push bar-0.1.0.tgz oci://localhost:5099/charts --plain-http

$ oras cp --from-plain-http --to-plain-http \
localhost:5099/charts/bar:0.1.0 localhost:5099/charts/foo:0.1.0

$ helm pull oci://localhost:5099/charts/bar:0.1.0 --plain-http --verify --keyring "$GNUPGHOME/pubring.gpg"
Chart Hash Verified: sha256:ecd61ca508db32cb765021964651a22eec5ce33dbefe8c8eb934853f1b25edd1

$ helm pull oci://localhost:5099/charts/foo:0.1.0 --plain-http --verify --keyring "$GNUPGHOME/pubring.gpg"
Error: provenance does not contain a SHA for a file named "foo-0.1.0.tgz"
```

The copy step only moves the artifact to a second repository; the chart, its layers and its provenance are byte for byte the ones that were pushed.

### Helm version

```console
$ helm version
version.BuildInfo{Version:"v4.2.3", GitCommit:"43e8b7feece8beb0fcba47059ec9b522fd929a64", GitTreeState:"clean", GoVersion:"go1.26.5", KubeClientVersion:"v1.36"}
```

The download path is unchanged on `main`.

### Kubernetes version

Not involved, the failure is in the downloader before any cluster is contacted.

Contributor guide

Open the contributing guide

Research direction

Start with pkg/downloader/chart_downloader.go at lines 156-159 and 311-320, then read the manifest lookup in pkg/provenance/sign.go:266. Reproduce the signed-chart pull using the commands in the issue and trace the archive name used for verification. Done means the copied chart verifies under a repository name different from its chart name without changing signature semantics.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli, security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.