fix: make ORAS reference private

Signed-off-by: Terry Howe <terrylhowe@gmail.com>
pull/12690/head
Terry Howe 11 months ago
parent aca7e8d775
commit d2b94f6200

@ -23,7 +23,6 @@ import (
"path/filepath"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/pkg/errors"
"helm.sh/helm/v3/internal/fileutil"
@ -141,71 +140,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
@ -228,7 +162,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)

@ -22,6 +22,7 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strings"
@ -319,7 +320,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
}
@ -351,7 +352,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
}
@ -535,7 +536,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
}
@ -594,12 +595,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
@ -630,7 +631,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")
}
@ -705,7 +706,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
}
@ -713,7 +714,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
}
@ -721,3 +722,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…
Cancel
Save