Skip to content

Prevent push cmd failure in 3.18 by handling version tag resolution in ORAS memory store #30894

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 23, 2025

Conversation

benoittgt
Copy link
Contributor

@benoittgt benoittgt commented May 21, 2025

What this PR does / why we need it:

Fix: #30881

Initial work for dev-v3 in #30889 (comment) but as requested by @gjenkins8, we should backport after on v3. :)

The issue is:

  • The newReference() function transforms version tags by replacing + with _ for OCI compatibility (as we can see in the output message)
  • But the code was using the original ref (with +) for TagBytes()
  • Then it tries to find the tagged reference using parsedRef.String() (with _)
  • This mismatch causes the Resolve method to fail with "not found"
  • By using parsedRef.String() consistently in both places, the references will match and the lookup will succeed.

I extracted the TagBytes function to improve testability. Push() includes several external calls that are hard to mock, so isolating this logic makes testing more manageable.

The patch could be summarized as:

- oras.TagBytes(ctx, memoryStore, ocispec.MediaTypeImageManifest, manifestData, ref)
+ oras.TagBytes(ctx, memoryStore, ocispec.MediaTypeImageManifest, manifestData, parsedRef.String())

The initial regression is something that was missed in 5a7046b#diff-acbc1e889c3e91003a88f18e21c3073b64937801b20f663fcf2601540b9e3cdaR709

Before :

» ../../helm/bin/helm push ./test-0.0.0-snapshot+dirty.tgz oci://ghcr.io/benoittgt/helm-charts/test --debug
Error: failed to perform "Resolve" on source: ghcr.io/benoittgt/helm-charts/test/test:0.0.0-snapshot_dirty: not found
helm.go:92: 2025-05-21 16:41:49.581662 +0200 CEST m=+0.041508960 [debug] failed to perform "Resolve" on source: ghcr.io/benoittgt/helm-charts/test/test:0.0.0-snapshot_dirty: not found

After :

» ../../helm/bin/helm push ./test-0.0.0-snapshot+dirty.tgz oci://ghcr.io/benoittgt/helm-charts/test --debug
Pushed: ghcr.io/benoittgt/helm-charts/test/test:0.0.0-snapshot_dirty
Digest: sha256:680f23c71cb6727ae8845daf01f019dc11bdac4b652289c9a970b270c56ba79d
ghcr.io/benoittgt/helm-charts/test/test:0.0.0-snapshot_dirty contains an underscore.

OCI artifact references (e.g. tags) do not support the plus sign (+). To support
storing semantic versions, Helm adopts the convention of changing plus (+) to
an underscore (_) in chart version tags when pushing to a registry and back to
a plus (+) when pulling from a registry.

Special notes for your reviewer:

If applicable:

  • this PR contains user facing changes (the docs needed label should be applied if so)
  • this PR contains unit tests
  • this PR has been tested for backwards compatibility (it will be backported)

- The newReference() function transforms version tags by replacing + with _ for OCI compatibility
- But the code was using the original ref (with +) for TagBytes()
- Then it tries to find the tagged reference using parsedRef.String() (with _)
- This mismatch causes the Resolve method to fail with "not found"
- By using parsedRef.String() consistently in both places, the references will match and the lookup will succeed.

I extracted the TagBytes function to improve testability.
Push() includes several external calls that are hard to mock,
so isolating this logic makes testing more manageable.

Close: helm#30881
Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>
@pull-request-size pull-request-size bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label May 21, 2025
@benoittgt benoittgt marked this pull request as ready for review May 21, 2025 19:40
Copy link
Contributor

@TerryHowe TerryHowe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to remove the unused parsedRef

@@ -685,19 +685,9 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu
})

ociAnnotations := generateOCIAnnotations(meta, operation.creationTime)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the parsedRef, err := newReference(ref) above should be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I get it. The parsedRef is used here ? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 611. It won't let me comment up there

Copy link
Contributor Author

@benoittgt benoittgt May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that what you had in mind? f939f61

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeh, that works

}

return oras.TagBytes(ctx, memoryStore, ocispec.MediaTypeImageManifest,
manifestData, parsedRef.String())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only actual change here I think, using parsedRef.String() instead of ref although the tests are nice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. I should have specified it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified it's this.

- oras.TagBytes(ctx, memoryStore, ocispec.MediaTypeImageManifest, manifestData, ref)
+ oras.TagBytes(ctx, memoryStore, ocispec.MediaTypeImageManifest, manifestData, parsedRef.String())

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeh, this PR could in theory be just that one line change the way I read it.

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>
@benoittgt benoittgt requested a review from TerryHowe May 23, 2025 09:51
Copy link
Contributor

@TerryHowe TerryHowe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@@ -685,19 +685,9 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu
})

ociAnnotations := generateOCIAnnotations(meta, operation.creationTime)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeh, that works

@robertsirc robertsirc added the Needs v3 backport Label PRs for v4/main, which are still applicable to v3 so need a separate backport PR label May 23, 2025
Copy link
Collaborator

@mattfarina mattfarina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Also manually tested.

Copy link
Member

@robertsirc robertsirc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@robertsirc robertsirc merged commit 52dddba into helm:main May 23, 2025
5 checks passed
@benoittgt benoittgt deleted the fix-#30881-main branch May 26, 2025 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs v3 backport Label PRs for v4/main, which are still applicable to v3 so need a separate backport PR size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

helm push error 3.18.0
4 participants