diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 3feb5b702..bc8ced3bc 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -21,6 +21,7 @@ import ( "net/url" "os" "path/filepath" + "regexp" "strings" "github.com/Masterminds/semver/v3" @@ -141,36 +142,41 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven return destfile, ver, nil } +var sha256re = regexp.MustCompile(`^sha256:[0-9a-fA-F]{64}$`) + func (c *ChartDownloader) getOciURI(ref, version string, u *url.URL) (*url.URL, error) { - var tag string var err error // Evaluate whether an explicit version has been provided. Otherwise, determine version to use - _, errSemVer := semver.NewVersion(version) - if errSemVer == nil { - tag = version + if sha256re.MatchString(version) { + u.Path = fmt.Sprintf("%s@%s", u.Path, 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) - } + var tag string + _, 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 + // 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", u.Path, tag) } - u.Path = fmt.Sprintf("%s:%s", u.Path, tag) - return u, err } @@ -182,7 +188,9 @@ func (c *ChartDownloader) getOciURI(ref, version string, u *url.URL) (*url.URL, // A reference may be an HTTP URL, an oci reference URL, a 'reponame/chartname' // reference, or a local path. // -// A version is a SemVer string (1.2.3-beta.1+f334a6789). +// A version is a SemVer string (1.2.3-beta.1+f334a6789) or a SHA256 digest of +// the chart's manifest +// (sha256:d234555386402a5867ef0169fefe5486858b6d8d209eaf32fd26d29b16807fd6). // // - For fully qualified URLs, the version will be ignored (since URLs aren't versioned) // - For a chart reference diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index f70a56422..6d1256efa 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -40,6 +40,7 @@ func TestResolveChartRef(t *testing.T) { {name: "full URL", ref: "http://example.com/foo-1.2.3.tgz", expect: "http://example.com/foo-1.2.3.tgz"}, {name: "full URL, HTTPS", ref: "https://example.com/foo-1.2.3.tgz", expect: "https://example.com/foo-1.2.3.tgz"}, {name: "full URL, with authentication", ref: "http://username:password@example.com/foo-1.2.3.tgz", expect: "http://username:password@example.com/foo-1.2.3.tgz"}, + {name: "full URL, with sha256", ref: "oci://example.com/foo/bar", version: "sha256:d234555386402a5867ef0169fefe5486858b6d8d209eaf32fd26d29b16807fd6", expect: "oci://example.com/foo/bar@sha256:d234555386402a5867ef0169fefe5486858b6d8d209eaf32fd26d29b16807fd6"}, {name: "reference, testing repo", ref: "testing/alpine", expect: "http://example.com/alpine-1.2.3.tgz"}, {name: "reference, version, testing repo", ref: "testing/alpine", version: "0.2.0", expect: "http://example.com/alpine-0.2.0.tgz"}, {name: "reference, version, malformed repo", ref: "malformed/alpine", version: "1.2.3", expect: "http://dl.example.com/alpine-1.2.3.tgz"},