mirror of
https://github.com/helm/helm.git
synced 2026-05-28 04:35:48 -04:00
fix: make ORAS reference private
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
(cherry picked from commit d2b94f6200)
This commit is contained in:
parent
aba95b9cb4
commit
949b2e6040
4 changed files with 101 additions and 100 deletions
|
|
@ -23,7 +23,6 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/internal/fileutil"
|
||||
|
|
@ -143,71 +142,6 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
|
|||
return destfile, ver, nil
|
||||
}
|
||||
|
||||
func (c *ChartDownloader) getOciURI(ref, version string, u *url.URL) (*url.URL, error) {
|
||||
var tag string
|
||||
|
||||
registryReference, err := registry.NewReference(u.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if version == "" {
|
||||
// Use OCI URI tag as default
|
||||
version = registryReference.Tag
|
||||
} else {
|
||||
if registryReference.Tag != "" && registryReference.Tag != version {
|
||||
return nil, errors.Errorf("chart reference and version mismatch: %s is not %s", version, registryReference.Tag)
|
||||
}
|
||||
}
|
||||
|
||||
if registryReference.Digest != "" {
|
||||
if registryReference.Tag == "" {
|
||||
// Install by digest only
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// Validate the tag if it was specified
|
||||
path := registryReference.Registry + "/" + registryReference.Repository + ":" + registryReference.Tag
|
||||
desc, err := c.RegistryClient.Resolve(path)
|
||||
if err != nil {
|
||||
// The resource does not have to be tagged when digest is specified
|
||||
return u, nil
|
||||
}
|
||||
if desc != nil && desc.Digest.String() != registryReference.Digest {
|
||||
return nil, errors.Errorf("chart reference digest mismatch: %s is not %s", desc.Digest.String(), registryReference.Digest)
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// Evaluate whether an explicit version has been provided. Otherwise, determine version to use
|
||||
_, errSemVer := semver.NewVersion(version)
|
||||
if errSemVer == nil {
|
||||
tag = version
|
||||
} else {
|
||||
// Retrieve list of repository tags
|
||||
tags, err := c.RegistryClient.Tags(strings.TrimPrefix(ref, fmt.Sprintf("%s://", registry.OCIScheme)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(tags) == 0 {
|
||||
return nil, errors.Errorf("Unable to locate any tags in provided repository: %s", ref)
|
||||
}
|
||||
|
||||
// Determine if version provided
|
||||
// If empty, try to get the highest available tag
|
||||
// If exact version, try to find it
|
||||
// If semver constraint string, try to find a match
|
||||
tag, err = registry.GetTagMatchingVersionOrConstraint(tags, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
u.Path = fmt.Sprintf("%s/%s:%s", registryReference.Registry, registryReference.Repository, tag)
|
||||
|
||||
return u, err
|
||||
}
|
||||
|
||||
// ResolveChartVersion resolves a chart reference to a URL.
|
||||
//
|
||||
// It returns the URL and sets the ChartDownloader's Options that can fetch
|
||||
|
|
@ -230,7 +164,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
|
|||
}
|
||||
|
||||
if registry.IsOCI(u.String()) {
|
||||
return c.getOciURI(ref, version, u)
|
||||
return c.RegistryClient.ValidateReference(ref, version, u)
|
||||
}
|
||||
|
||||
rf, err := loadRepoConfig(c.RepositoryConfig)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
|
|
@ -377,7 +378,7 @@ type (
|
|||
|
||||
// Pull downloads a chart from a registry
|
||||
func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) {
|
||||
parsedRef, err := NewReference(ref)
|
||||
parsedRef, err := newReference(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -409,7 +410,7 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) {
|
|||
}
|
||||
|
||||
var descriptors, layers []ocispec.Descriptor
|
||||
remotesResolver, err := c.resolver(parsedRef.OrasReference)
|
||||
remotesResolver, err := c.resolver(parsedRef.orasReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -593,7 +594,7 @@ type (
|
|||
|
||||
// Push uploads a chart to a registry.
|
||||
func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResult, error) {
|
||||
parsedRef, err := NewReference(ref)
|
||||
parsedRef, err := newReference(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -652,12 +653,12 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu
|
|||
return nil, err
|
||||
}
|
||||
|
||||
remotesResolver, err := c.resolver(parsedRef.OrasReference)
|
||||
remotesResolver, err := c.resolver(parsedRef.orasReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
registryStore := content.Registry{Resolver: remotesResolver}
|
||||
_, err = oras.Copy(ctx(c.out, c.debug), memoryStore, parsedRef.OrasReference.String(), registryStore, "",
|
||||
_, err = oras.Copy(ctx(c.out, c.debug), memoryStore, parsedRef.orasReference.String(), registryStore, "",
|
||||
oras.WithNameValidation(nil))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -688,7 +689,7 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu
|
|||
}
|
||||
fmt.Fprintf(c.out, "Pushed: %s\n", result.Ref)
|
||||
fmt.Fprintf(c.out, "Digest: %s\n", result.Manifest.Digest)
|
||||
if strings.Contains(parsedRef.OrasReference.Reference, "_") {
|
||||
if strings.Contains(parsedRef.orasReference.Reference, "_") {
|
||||
fmt.Fprintf(c.out, "%s contains an underscore.\n", result.Ref)
|
||||
fmt.Fprint(c.out, registryUnderscoreMessage+"\n")
|
||||
}
|
||||
|
|
@ -763,7 +764,7 @@ func (c *Client) Tags(ref string) ([]string, error) {
|
|||
// Resolve a reference to a descriptor.
|
||||
func (c *Client) Resolve(ref string) (*ocispec.Descriptor, error) {
|
||||
ctx := context.Background()
|
||||
parsedRef, err := NewReference(ref)
|
||||
parsedRef, err := newReference(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -771,7 +772,7 @@ func (c *Client) Resolve(ref string) (*ocispec.Descriptor, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
remotesResolver, err := c.resolver(parsedRef.OrasReference)
|
||||
remotesResolver, err := c.resolver(parsedRef.orasReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -779,3 +780,69 @@ func (c *Client) Resolve(ref string) (*ocispec.Descriptor, error) {
|
|||
_, desc, err := remotesResolver.Resolve(ctx, ref)
|
||||
return &desc, err
|
||||
}
|
||||
|
||||
// ValidateReference for path and version
|
||||
func (c *Client) ValidateReference(ref, version string, u *url.URL) (*url.URL, error) {
|
||||
var tag string
|
||||
|
||||
registryReference, err := newReference(u.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if version == "" {
|
||||
// Use OCI URI tag as default
|
||||
version = registryReference.Tag
|
||||
} else {
|
||||
if registryReference.Tag != "" && registryReference.Tag != version {
|
||||
return nil, errors.Errorf("chart reference and version mismatch: %s is not %s", version, registryReference.Tag)
|
||||
}
|
||||
}
|
||||
|
||||
if registryReference.Digest != "" {
|
||||
if registryReference.Tag == "" {
|
||||
// Install by digest only
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// Validate the tag if it was specified
|
||||
path := registryReference.Registry + "/" + registryReference.Repository + ":" + registryReference.Tag
|
||||
desc, err := c.Resolve(path)
|
||||
if err != nil {
|
||||
// The resource does not have to be tagged when digest is specified
|
||||
return u, nil
|
||||
}
|
||||
if desc != nil && desc.Digest.String() != registryReference.Digest {
|
||||
return nil, errors.Errorf("chart reference digest mismatch: %s is not %s", desc.Digest.String(), registryReference.Digest)
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// Evaluate whether an explicit version has been provided. Otherwise, determine version to use
|
||||
_, errSemVer := semver.NewVersion(version)
|
||||
if errSemVer == nil {
|
||||
tag = version
|
||||
} else {
|
||||
// Retrieve list of repository tags
|
||||
tags, err := c.Tags(strings.TrimPrefix(ref, fmt.Sprintf("%s://", OCIScheme)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(tags) == 0 {
|
||||
return nil, errors.Errorf("Unable to locate any tags in provided repository: %s", ref)
|
||||
}
|
||||
|
||||
// Determine if version provided
|
||||
// If empty, try to get the highest available tag
|
||||
// If exact version, try to find it
|
||||
// If semver constraint string, try to find a match
|
||||
tag, err = GetTagMatchingVersionOrConstraint(tags, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
u.Path = fmt.Sprintf("%s/%s:%s", registryReference.Registry, registryReference.Repository, tag)
|
||||
|
||||
return u, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,19 +22,19 @@ import (
|
|||
orasregistry "oras.land/oras-go/pkg/registry"
|
||||
)
|
||||
|
||||
type Reference struct {
|
||||
OrasReference orasregistry.Reference
|
||||
type reference struct {
|
||||
orasReference orasregistry.Reference
|
||||
Registry string
|
||||
Repository string
|
||||
Tag string
|
||||
Digest string
|
||||
}
|
||||
|
||||
// NewReference will parse and validate the reference, and clean tags when
|
||||
// newReference will parse and validate the reference, and clean tags when
|
||||
// applicable tags are only cleaned when plus (+) signs are present, and are
|
||||
// converted to underscores (_) before pushing
|
||||
// See https://github.com/helm/helm/issues/10166
|
||||
func NewReference(raw string) (result Reference, err error) {
|
||||
func newReference(raw string) (result reference, err error) {
|
||||
// Remove oci:// prefix if it is there
|
||||
raw = strings.TrimPrefix(raw, OCIScheme+"://")
|
||||
|
||||
|
|
@ -60,19 +60,19 @@ func NewReference(raw string) (result Reference, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
result.OrasReference, err = orasregistry.ParseReference(raw)
|
||||
result.orasReference, err = orasregistry.ParseReference(raw)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.Registry = result.OrasReference.Registry
|
||||
result.Repository = result.OrasReference.Repository
|
||||
result.Tag = result.OrasReference.Reference
|
||||
result.Registry = result.orasReference.Registry
|
||||
result.Repository = result.orasReference.Repository
|
||||
result.Tag = result.orasReference.Reference
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Reference) String() string {
|
||||
func (r *reference) String() string {
|
||||
if r.Tag == "" {
|
||||
return r.OrasReference.String() + "@" + r.Digest
|
||||
return r.orasReference.String() + "@" + r.Digest
|
||||
}
|
||||
return r.OrasReference.String()
|
||||
return r.orasReference.String()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,15 +18,15 @@ package registry
|
|||
|
||||
import "testing"
|
||||
|
||||
func verify(t *testing.T, actual Reference, registry, repository, tag, digest string) {
|
||||
if registry != actual.OrasReference.Registry {
|
||||
t.Errorf("Oras Reference registry expected %v actual %v", registry, actual.Registry)
|
||||
func verify(t *testing.T, actual reference, registry, repository, tag, digest string) {
|
||||
if registry != actual.orasReference.Registry {
|
||||
t.Errorf("Oras reference registry expected %v actual %v", registry, actual.Registry)
|
||||
}
|
||||
if repository != actual.OrasReference.Repository {
|
||||
t.Errorf("Oras Reference repository expected %v actual %v", repository, actual.Repository)
|
||||
if repository != actual.orasReference.Repository {
|
||||
t.Errorf("Oras reference repository expected %v actual %v", repository, actual.Repository)
|
||||
}
|
||||
if tag != actual.OrasReference.Reference {
|
||||
t.Errorf("Oras Reference reference expected %v actual %v", tag, actual.Tag)
|
||||
if tag != actual.orasReference.Reference {
|
||||
t.Errorf("Oras reference reference expected %v actual %v", tag, actual.Tag)
|
||||
}
|
||||
if registry != actual.Registry {
|
||||
t.Errorf("Registry expected %v actual %v", registry, actual.Registry)
|
||||
|
|
@ -55,43 +55,43 @@ func verify(t *testing.T, actual Reference, registry, repository, tag, digest st
|
|||
}
|
||||
|
||||
func TestNewReference(t *testing.T) {
|
||||
actual, err := NewReference("registry.example.com/repository:1.0@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888")
|
||||
actual, err := newReference("registry.example.com/repository:1.0@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
verify(t, actual, "registry.example.com", "repository", "1.0", "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888")
|
||||
|
||||
actual, err = NewReference("oci://registry.example.com/repository:1.0@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888")
|
||||
actual, err = newReference("oci://registry.example.com/repository:1.0@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
verify(t, actual, "registry.example.com", "repository", "1.0", "sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888")
|
||||
|
||||
actual, err = NewReference("a/b:1@c")
|
||||
actual, err = newReference("a/b:1@c")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
verify(t, actual, "a", "b", "1", "c")
|
||||
|
||||
actual, err = NewReference("a/b:@")
|
||||
actual, err = newReference("a/b:@")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
verify(t, actual, "a", "b", "", "")
|
||||
|
||||
actual, err = NewReference("registry.example.com/repository:1.0+001")
|
||||
actual, err = newReference("registry.example.com/repository:1.0+001")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
verify(t, actual, "registry.example.com", "repository", "1.0_001", "")
|
||||
|
||||
actual, err = NewReference("thing:1.0")
|
||||
actual, err = newReference("thing:1.0")
|
||||
if err == nil {
|
||||
t.Errorf("Expect error error %v", err)
|
||||
}
|
||||
verify(t, actual, "", "", "", "")
|
||||
|
||||
actual, err = NewReference("registry.example.com/the/repository@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888")
|
||||
actual, err = newReference("registry.example.com/the/repository@sha256:c6841b3a895f1444a6738b5d04564a57e860ce42f8519c3be807fb6d9bee7888")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue