helm / helm/helm

registry.Client.Tags returns normalized semver strings, not the registry's actual tags

Open
#32,582 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?

`registry.Client.Tags` returns *normalized* semver strings rather than the tag strings as they exist in the registry. The returned value is `tv.String()`:

https://github.com/helm/helm/blob/main/pkg/registry/client.go#L817

Since these values are fed straight back into a pull reference (`findChartURL` builds `oci://repo/name:version` from the resolved version, [manager.go#L726](https://github.com/helm/helm/blob/main/pkg/downloader/manager.go#L726)), any tag whose normalized form differs from its stored form can be *resolved* but not *pulled*.

The clearest case is the underscore convention from #10166. `Tags` converts `_` back to `+` before parsing:

https://github.com/helm/helm/blob/main/pkg/registry/client.go#L799

```go
tagVersion, err := semver.StrictNewVersion(strings.ReplaceAll(tag, "_", "+"))
```

…but the conversion is one-directional. A chart stored under tag `1.1.17_meta` is returned as `1.1.17+meta`, which is not a legal OCI tag and does not exist in the registry.

Related: `StrictNewVersion` silently drops tags it cannot parse — `v1.1.17` and `1.1` are both rejected with no log line — so a chart can be invisible to `helm dep update` with no diagnostic at all. Whether `v`-prefixed tags *should* be accepted is a separate design question, but if they are accepted, the original tag string has to be preserved or the pull will 404 for the same reason.

### What did you expect to happen?

`Tags` returns tag strings that can actually be used as OCI references — i.e. the original tag as stored in the registry — while still sorting by semver precedence. Tags that are skipped are logged at debug level rather than dropped silently.

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

1. Push a chart to an OCI registry under tag `1.1.17_meta` (the `_` form Helm itself documents for build metadata, per #10166).
2. Reference it from a parent chart with a constraint:
```yaml
dependencies:
- name: my-subchart
repository: "oci://my-registry"
version: "1.x.x"
```
3. `helm dep update` resolves the version to `1.1.17+meta` and then fails to pull it — that tag does not exist in the registry.

Suggested fix: carry the original tag alongside the parsed version inside `Tags` (e.g. sort a `[]struct{orig string; v *semver.Version}` and return `orig`), so sorting stays semver-correct but the returned strings remain valid references. Note `Tags` is exported v4 API, so the return *shape* shouldn't change — only the strings it contains.

Found while investigating #32581.

### Helm version

```console
main @ d62bee21c (v4.2.4+)
```

### Kubernetes version

Unrelated

Contributor guide

Open the contributing guide

Research direction

Read pkg/registry/client.go around Tags and pkg/downloader/manager.go around findChartURL, then trace how resolved versions become OCI references. Preserve each registry tag for returned references while retaining semver ordering, and add debug logging for skipped tags; verify that the underscore-form tag resolves and can be pulled.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.