pull/32243/merge
Simone Tollardo 3 days ago committed by GitHub
commit c30bb8a16b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -47,6 +47,11 @@ type Dependency struct {
ImportValues []any `json:"import-values,omitempty" yaml:"import-values,omitempty"`
// Alias usable alias to be used for the chart
Alias string `json:"alias,omitempty" yaml:"alias,omitempty"`
// Digest is the SHA256 hash of the dependency chart archive (sha256:...).
//
// This field is populated in Chart.lock to record the exact tarball bytes
// that were downloaded. It is omitted from Chart.yaml dependency entries.
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
}
// Validate checks for common problems with the dependency datastructure in
@ -75,7 +80,10 @@ func (d *Dependency) Validate() error {
type Lock struct {
// Generated is the date the lock file was last generated.
Generated time.Time `json:"generated"`
// Digest is a hash of the dependencies in Chart.yaml.
// Digest is a hash of Chart.yaml dependency constraints and the resolved
// lock metadata (name, version, repository). It detects drift between
// Chart.yaml and Chart.lock. Per-dependency tarball content is tracked
// separately via Dependency.Digest.
Digest string `json:"digest"`
// Dependencies is the list of dependencies that this lock file has locked.
Dependencies []*Dependency `json:"dependencies"`

@ -209,9 +209,13 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
// HashReq generates a hash of the dependencies.
//
// This should be used only to compare against another hash generated by this
// function.
// function. Per-dependency content digests are excluded; the top-level lock
// digest tracks Chart.yaml constraints and resolved metadata only.
func HashReq(req, lock []*chart.Dependency) (string, error) {
data, err := json.Marshal([2][]*chart.Dependency{req, lock})
data, err := json.Marshal([2][]*chart.Dependency{
dependenciesForMetadataHash(req),
dependenciesForMetadataHash(lock),
})
if err != nil {
return "", err
}
@ -219,6 +223,23 @@ func HashReq(req, lock []*chart.Dependency) (string, error) {
return "sha256:" + s, err
}
// dependenciesForMetadataHash returns a copy of deps with content digests cleared.
func dependenciesForMetadataHash(deps []*chart.Dependency) []*chart.Dependency {
if len(deps) == 0 {
return nil
}
out := make([]*chart.Dependency, len(deps))
for i, d := range deps {
if d == nil {
continue
}
cp := *d
cp.Digest = ""
out[i] = &cp
}
return out
}
// HashV2Req generates a hash of requirements generated in Helm v2.
//
// This should be used only to compare against another hash generated by the

@ -297,3 +297,21 @@ func TestGetLocalPath(t *testing.T) {
})
}
}
func TestHashReqIgnoresContentDigest(t *testing.T) {
req := []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "http://localhost:8879/charts"},
}
lockWithout := []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "http://localhost:8879/charts"},
}
lockWith := []*chart.Dependency{
{Name: "alpine", Version: "0.1.0", Repository: "http://localhost:8879/charts", Digest: "sha256:abc123"},
}
h1, err := HashReq(req, lockWithout)
require.NoError(t, err)
h2, err := HashReq(req, lockWith)
require.NoError(t, err)
assert.Equal(t, h1, h2)
}

@ -47,6 +47,11 @@ type Dependency struct {
ImportValues []any `json:"import-values,omitempty" yaml:"import-values,omitempty"`
// Alias usable alias to be used for the chart
Alias string `json:"alias,omitempty" yaml:"alias,omitempty"`
// Digest is the SHA256 hash of the dependency chart archive (sha256:...).
//
// This field is populated in Chart.lock to record the exact tarball bytes
// that were downloaded. It is omitted from Chart.yaml dependency entries.
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
}
// Validate checks for common problems with the dependency datastructure in
@ -75,7 +80,10 @@ func (d *Dependency) Validate() error {
type Lock struct {
// Generated is the date the lock file was last generated.
Generated time.Time `json:"generated"`
// Digest is a hash of the dependencies in Chart.yaml.
// Digest is a hash of Chart.yaml dependency constraints and the resolved
// lock metadata (name, version, repository). It detects drift between
// Chart.yaml and Chart.lock. Per-dependency tarball content is tracked
// separately via Dependency.Digest.
Digest string `json:"digest"`
// Dependencies is the list of dependencies that this lock file has locked.
Dependencies []*Dependency `json:"dependencies"`

@ -85,6 +85,10 @@ type ChartDownloader struct {
// Cache specifies the cache implementation to use.
Cache Cache
// ExpectedDigest is the digest from the repository index or OCI reference.
// When set, downloaded content is compared and a warning is emitted on mismatch.
ExpectedDigest string
}
// DownloadTo retrieves a chart. Depending on the settings, it may also download a provenance file.
@ -152,6 +156,10 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
if err != nil {
return "", nil, err
}
if err := verifyDownloadedDigest(c.Out, ref, c.ExpectedDigest, hash, data); err != nil {
return "", nil, err
}
}
name := filepath.Base(u.Path)
@ -592,6 +600,27 @@ func loadRepoConfig(file string) (*repo.File, error) {
return r, nil
}
// verifyDownloadedDigest compares downloaded chart bytes against the digest from
// the repository index or OCI reference. A mismatch emits a warning to out.
func verifyDownloadedDigest(out io.Writer, ref, expectedDigest, resolvedDigest string, data *bytes.Buffer) error {
digest := expectedDigest
if digest == "" {
digest = resolvedDigest
}
if digest == "" || data == nil {
return nil
}
computed, err := provenance.Digest(bytes.NewReader(data.Bytes()))
if err != nil {
return err
}
if !digestEqual(digest, computed) {
fmt.Fprintf(out, "WARNING: digest mismatch for %s: repository index has sha256:%s, downloaded content has sha256:%s\n",
ref, stripDigestAlgorithm(digest), computed)
}
return nil
}
// stripDigestAlgorithm removes the algorithm prefix (e.g., "sha256:") from a digest string.
// If no prefix is present, the original string is returned unchanged.
func stripDigestAlgorithm(digest string) string {

@ -0,0 +1,95 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package downloader
import (
"fmt"
"strings"
chart "helm.sh/helm/v4/pkg/chart/v2"
"helm.sh/helm/v4/pkg/provenance"
)
// formatDigest returns a digest string in the canonical sha256: form.
func formatDigest(hex string) string {
if hex == "" {
return ""
}
if strings.HasPrefix(hex, "sha256:") {
return hex
}
return "sha256:" + hex
}
// digestEqual compares two digests regardless of sha256: prefix.
func digestEqual(a, b string) bool {
if a == "" || b == "" {
return a == b
}
return stripDigestAlgorithm(a) == stripDigestAlgorithm(b)
}
// digestFile computes the SHA256 digest of a chart archive file.
func digestFile(path string) (string, error) {
hex, err := provenance.DigestFile(path)
if err != nil {
return "", err
}
return formatDigest(hex), nil
}
// recordDependencyDigest computes and stores the tarball digest on a lock dependency entry.
func recordDependencyDigest(dep *chart.Dependency, tarballPath string) error {
digest, err := digestFile(tarballPath)
if err != nil {
return err
}
if dep.Digest != "" && !digestEqual(dep.Digest, digest) {
return fmt.Errorf("chart.lock digest mismatch for %s-%s: expected %s, got %s", dep.Name, dep.Version, formatDigest(dep.Digest), digest)
}
dep.Digest = digest
return nil
}
// lockNeedsWrite reports whether the new lock differs from the old lock in metadata
// or per-dependency content digests.
func lockNeedsWrite(old, updated *chart.Lock) bool {
if old == nil {
return true
}
if old.Digest != updated.Digest {
return true
}
return !dependencyDigestsEqual(old.Dependencies, updated.Dependencies)
}
func dependencyDigestsEqual(a, b []*chart.Dependency) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] == nil || b[i] == nil {
if a[i] != b[i] {
return false
}
continue
}
if a[i].Name != b[i].Name || !digestEqual(a[i].Digest, b[i].Digest) {
return false
}
}
return true
}

@ -0,0 +1,322 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package downloader
import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/yaml"
"helm.sh/helm/v4/internal/resolver"
chart "helm.sh/helm/v4/pkg/chart/v2"
"helm.sh/helm/v4/pkg/chart/v2/loader"
chartutil "helm.sh/helm/v4/pkg/chart/v2/util"
"helm.sh/helm/v4/pkg/getter"
"helm.sh/helm/v4/pkg/provenance"
"helm.sh/helm/v4/pkg/repo/v1/repotest"
)
func setupDigestTestManager(t *testing.T, chartPath string, srv *repotest.Server) (*Manager, *bytes.Buffer) {
t.Helper()
out := bytes.NewBuffer(nil)
contentCache := t.TempDir()
m := &Manager{
ChartPath: chartPath,
Out: out,
Getters: getter.Providers{{Schemes: []string{"http", "https"}, New: getter.NewHTTPGetter}},
RepositoryConfig: filepath.Join(srv.Root(), "repositories.yaml"),
RepositoryCache: srv.Root(),
ContentCache: contentCache,
}
return m, out
}
func setupParentChart(t *testing.T, srv *repotest.Server, dep *chart.Dependency) (string, *chart.Chart) {
t.Helper()
dir := func(p ...string) string {
return filepath.Join(append([]string{srv.Root()}, p...)...)
}
parent := &chart.Chart{
Metadata: &chart.Metadata{
Name: "parent",
Version: "0.1.0",
APIVersion: "v2",
Dependencies: []*chart.Dependency{dep},
},
}
require.NoError(t, chartutil.SaveDir(parent, dir()))
return dir("parent"), parent
}
func TestContentDigestUpdateOnRepublish(t *testing.T) {
srv := repotest.NewTempServer(t, repotest.WithChartSourceGlob("testdata/local-subchart-0.1.0.tgz"))
defer srv.Stop()
require.NoError(t, srv.LinkIndices())
parentPath, _ := setupParentChart(t, srv, &chart.Dependency{
Name: "local-subchart",
Version: "0.1.0",
Repository: srv.URL(),
})
m, _ := setupDigestTestManager(t, parentPath, srv)
require.NoError(t, m.Update())
lockData, err := os.ReadFile(filepath.Join(parentPath, "Chart.lock"))
require.NoError(t, err)
var lock1 chart.Lock
require.NoError(t, yaml.Unmarshal(lockData, &lock1))
firstDigest := lock1.Dependencies[0].Digest
require.NotEmpty(t, firstDigest)
assert.True(t, strings.HasPrefix(firstDigest, "sha256:"))
// Republish same version with different chart bytes.
sub, err := loader.LoadDir(filepath.Join("testdata", "local-subchart"))
require.NoError(t, err)
sub.Metadata.Description = "modified content"
_, err = chartutil.Save(sub, srv.Root())
require.NoError(t, err)
require.NoError(t, srv.CreateIndex())
require.NoError(t, m.Update())
lockData, err = os.ReadFile(filepath.Join(parentPath, "Chart.lock"))
require.NoError(t, err)
var lock2 chart.Lock
require.NoError(t, yaml.Unmarshal(lockData, &lock2))
secondDigest := lock2.Dependencies[0].Digest
require.NotEmpty(t, secondDigest)
assert.NotEqual(t, firstDigest, secondDigest)
assert.Equal(t, lock1.Digest, lock2.Digest, "metadata digest should be unchanged when version pin is exact")
}
func TestContentDigestStableOnSameBytes(t *testing.T) {
srv := repotest.NewTempServer(t, repotest.WithChartSourceGlob("testdata/local-subchart-0.1.0.tgz"))
defer srv.Stop()
require.NoError(t, srv.LinkIndices())
parentPath, _ := setupParentChart(t, srv, &chart.Dependency{
Name: "local-subchart",
Version: "0.1.0",
Repository: srv.URL(),
})
m, _ := setupDigestTestManager(t, parentPath, srv)
require.NoError(t, m.Update())
lockBefore, err := os.ReadFile(filepath.Join(parentPath, "Chart.lock"))
require.NoError(t, err)
require.NoError(t, m.Update())
lockAfter, err := os.ReadFile(filepath.Join(parentPath, "Chart.lock"))
require.NoError(t, err)
assert.Equal(t, string(lockBefore), string(lockAfter))
}
func TestBuildDigestMismatch(t *testing.T) {
srv := repotest.NewTempServer(t, repotest.WithChartSourceGlob("testdata/local-subchart-0.1.0.tgz"))
defer srv.Stop()
require.NoError(t, srv.LinkIndices())
parentPath, _ := setupParentChart(t, srv, &chart.Dependency{
Name: "local-subchart",
Version: "0.1.0",
Repository: srv.URL(),
})
m, _ := setupDigestTestManager(t, parentPath, srv)
require.NoError(t, m.Update())
sub, err := loader.LoadDir(filepath.Join("testdata", "local-subchart"))
require.NoError(t, err)
sub.Metadata.Description = "tampered upstream content"
_, err = chartutil.Save(sub, srv.Root())
require.NoError(t, err)
require.NoError(t, srv.CreateIndex())
err = m.Build()
require.Error(t, err)
assert.Contains(t, err.Error(), "chart.lock digest mismatch for local-subchart-0.1.0")
}
func TestLegacyLockWithoutDigest(t *testing.T) {
srv := repotest.NewTempServer(t, repotest.WithChartSourceGlob("testdata/local-subchart-0.1.0.tgz"))
defer srv.Stop()
require.NoError(t, srv.LinkIndices())
parentPath, parent := setupParentChart(t, srv, &chart.Dependency{
Name: "local-subchart",
Version: "0.1.0",
Repository: srv.URL(),
})
legacyLock := &chart.Lock{
Generated: time.Now(),
Dependencies: []*chart.Dependency{{
Name: "local-subchart",
Version: "0.1.0",
Repository: srv.URL(),
}},
}
digest, err := resolver.HashReq(parent.Metadata.Dependencies, legacyLock.Dependencies)
require.NoError(t, err)
legacyLock.Digest = digest
lockData, err := yaml.Marshal(legacyLock)
require.NoError(t, err)
require.NoError(t, os.WriteFile(filepath.Join(parentPath, "Chart.lock"), lockData, 0644))
m, _ := setupDigestTestManager(t, parentPath, srv)
require.NoError(t, m.Build())
require.NoError(t, m.Update())
lockData, err = os.ReadFile(filepath.Join(parentPath, "Chart.lock"))
require.NoError(t, err)
var updated chart.Lock
require.NoError(t, yaml.Unmarshal(lockData, &updated))
require.NotEmpty(t, updated.Dependencies[0].Digest)
}
func TestIndexDigestMismatchWarning(t *testing.T) {
srv := repotest.NewTempServer(t, repotest.WithChartSourceGlob("testdata/local-subchart-0.1.0.tgz"))
defer srv.Stop()
require.NoError(t, srv.LinkIndices())
depArchive := filepath.Join(srv.Root(), "local-subchart-0.1.0.tgz")
realDigest, err := provenance.DigestFile(depArchive)
require.NoError(t, err)
dest := t.TempDir()
contentCache := t.TempDir()
out := bytes.NewBuffer(nil)
dl := ChartDownloader{
Out: out,
RepositoryConfig: filepath.Join(srv.Root(), "repositories.yaml"),
RepositoryCache: srv.Root(),
ContentCache: contentCache,
Getters: getter.Providers{{Schemes: []string{"http", "https"}, New: getter.NewHTTPGetter}},
ExpectedDigest: strings.Repeat("a", len(realDigest)),
}
_, _, err = dl.DownloadTo(srv.URL()+"/local-subchart-0.1.0.tgz", "0.1.0", dest)
require.NoError(t, err)
assert.Contains(t, out.String(), "WARNING: digest mismatch")
}
func TestSemverRangeRecordsContentDigest(t *testing.T) {
srv := repotest.NewTempServer(t, repotest.WithChartSourceGlob("testdata/local-subchart-0.1.0.tgz"))
defer srv.Stop()
sub, err := loader.LoadDir(filepath.Join("testdata", "local-subchart"))
require.NoError(t, err)
sub.Metadata.Version = "0.2.0"
_, err = chartutil.Save(sub, srv.Root())
require.NoError(t, err)
require.NoError(t, srv.CreateIndex())
require.NoError(t, srv.LinkIndices())
parentPath, _ := setupParentChart(t, srv, &chart.Dependency{
Name: "local-subchart",
Version: ">=0.1.0",
Repository: srv.URL(),
})
m, _ := setupDigestTestManager(t, parentPath, srv)
require.NoError(t, m.Update())
lockData, err := os.ReadFile(filepath.Join(parentPath, "Chart.lock"))
require.NoError(t, err)
var lock chart.Lock
require.NoError(t, yaml.Unmarshal(lockData, &lock))
require.Len(t, lock.Dependencies, 1)
assert.Equal(t, "0.2.0", lock.Dependencies[0].Version)
require.NotEmpty(t, lock.Dependencies[0].Digest)
tgzPath := filepath.Join(parentPath, "charts", "local-subchart-0.2.0.tgz")
require.FileExists(t, tgzPath)
got, err := provenance.DigestFile(tgzPath)
require.NoError(t, err)
assert.Equal(t, "sha256:"+got, lock.Dependencies[0].Digest)
}
func TestLockNeedsWrite(t *testing.T) {
metaDigest := "sha256:abc"
old := &chart.Lock{
Digest: metaDigest,
Dependencies: []*chart.Dependency{{
Name: "foo",
Version: "1.0.0",
Digest: "sha256:111",
}},
}
same := &chart.Lock{
Digest: metaDigest,
Dependencies: []*chart.Dependency{{
Name: "foo",
Version: "1.0.0",
Digest: "sha256:111",
}},
}
changedContent := &chart.Lock{
Digest: metaDigest,
Dependencies: []*chart.Dependency{{
Name: "foo",
Version: "1.0.0",
Digest: "sha256:222",
}},
}
assert.False(t, lockNeedsWrite(old, same))
assert.True(t, lockNeedsWrite(old, changedContent))
assert.True(t, lockNeedsWrite(nil, same))
withNil := &chart.Lock{
Digest: metaDigest,
Dependencies: []*chart.Dependency{
nil,
{Name: "foo", Version: "1.0.0", Digest: "sha256:111"},
},
}
assert.True(t, lockNeedsWrite(old, withNil))
assert.True(t, dependencyDigestsEqual(withNil.Dependencies, withNil.Dependencies))
}
func TestLoadLockWithDigestField(t *testing.T) {
srv := repotest.NewTempServer(t, repotest.WithChartSourceGlob("testdata/local-subchart-0.1.0.tgz"))
defer srv.Stop()
require.NoError(t, srv.LinkIndices())
parentPath, _ := setupParentChart(t, srv, &chart.Dependency{
Name: "local-subchart",
Version: "0.1.0",
Repository: srv.URL(),
})
m, _ := setupDigestTestManager(t, parentPath, srv)
require.NoError(t, m.Update())
c, err := loader.LoadDir(parentPath)
require.NoError(t, err)
require.NotNil(t, c.Lock)
require.NotEmpty(t, c.Lock.Dependencies[0].Digest)
}

@ -211,9 +211,8 @@ func (m *Manager) Update() error {
}
lock.Digest = newDigest
// If the lock file hasn't changed, don't write a new one.
oldLock := c.Lock
if oldLock != nil && oldLock.Digest == lock.Digest {
// Rewrite the lock when metadata or per-dependency content digests changed.
if !lockNeedsWrite(c.Lock, lock) {
return nil
}
@ -273,6 +272,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
fmt.Fprintf(m.Out, "Saving %d charts\n", len(deps))
var saveError error
churls := make(map[string]struct{})
churlFiles := make(map[string]string)
for _, dep := range deps {
// No repository means the chart is in charts directory
if dep.Repository == "" {
@ -310,12 +310,17 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
break
}
dep.Version = ver
tgzPath := filepath.Join(tmpPath, fmt.Sprintf("%s-%s.tgz", dep.Name, ver))
if err := recordDependencyDigest(dep, tgzPath); err != nil {
saveError = err
break
}
continue
}
// Any failure to resolve/download a chart should fail:
// https://github.com/helm/helm/issues/1439
churl, username, password, insecureSkipTLSVerify, passCredentialsAll, caFile, certFile, keyFile, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos)
churl, username, password, insecureSkipTLSVerify, passCredentialsAll, caFile, certFile, keyFile, indexDigest, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos)
if err != nil {
saveError = fmt.Errorf("could not find %s: %w", churl, err)
break
@ -323,6 +328,12 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
if _, ok := churls[churl]; ok {
fmt.Fprintf(m.Out, "Already downloaded %s from repo %s\n", dep.Name, dep.Repository)
if tgzPath, ok := churlFiles[churl]; ok {
if err := recordDependencyDigest(dep, tgzPath); err != nil {
saveError = err
break
}
}
continue
}
@ -343,6 +354,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
getter.WithInsecureSkipVerifyTLS(insecureSkipTLSVerify),
getter.WithTLSClientConfig(certFile, keyFile, caFile),
},
ExpectedDigest: indexDigest,
}
version := ""
@ -356,12 +368,19 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
getter.WithTagName(version))
}
if _, _, err = dl.DownloadTo(churl, version, tmpPath); err != nil {
destfile, _, err := dl.DownloadTo(churl, version, tmpPath)
if err != nil {
saveError = fmt.Errorf("could not download %s: %w", churl, err)
break
}
if err := recordDependencyDigest(dep, destfile); err != nil {
saveError = err
break
}
churls[churl] = struct{}{}
churlFiles[churl] = destfile
}
// TODO: this should probably be refactored to be a []error, so we can capture and provide more information rather than "last error wins".
@ -722,9 +741,9 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error {
// repoURL is the repository to search
//
// If it finds a URL that is "relative", it will prepend the repoURL.
func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, insecureSkipTLSVerify, passCredentialsAll bool, caFile, certFile, keyFile string, err error) {
func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, insecureSkipTLSVerify, passCredentialsAll bool, caFile, certFile, keyFile, indexDigest string, err error) {
if registry.IsOCI(repoURL) {
return fmt.Sprintf("%s/%s:%s", repoURL, name, version), "", "", false, false, "", "", "", nil
return fmt.Sprintf("%s/%s:%s", repoURL, name, version), "", "", false, false, "", "", "", "", nil
}
for _, cr := range repos {
@ -744,6 +763,7 @@ func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*
//nolint:nakedret
return
}
indexDigest = ve.Digest
url, err = repo.ResolveReferenceURL(repoURL, ve.URLs[0])
if err != nil {
//nolint:nakedret
@ -762,10 +782,10 @@ func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*
}
url, err = repo.FindChartInRepoURL(repoURL, name, m.Getters, repo.WithChartVersion(version), repo.WithClientTLS(certFile, keyFile, caFile))
if err == nil {
return url, username, password, false, false, "", "", "", err
return url, username, password, false, false, "", "", "", "", err
}
err = fmt.Errorf("chart %s not found in %s: %w", name, repoURL, err)
return url, username, password, false, false, "", "", "", err
return url, username, password, false, false, "", "", "", "", err
}
// findEntryByName finds an entry in the chart repository whose name matches the given name.

@ -71,7 +71,7 @@ func TestFindChartURL(t *testing.T) {
version := "0.1.0"
repoURL := "http://example.com/charts"
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err := m.findChartURL(name, version, repoURL, repos)
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, _, err := m.findChartURL(name, version, repoURL, repos)
if err != nil {
t.Fatal(err)
}
@ -96,7 +96,7 @@ func TestFindChartURL(t *testing.T) {
version = "1.2.3"
repoURL = "https://example-https-insecureskiptlsverify.com"
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err = m.findChartURL(name, version, repoURL, repos)
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, _, err = m.findChartURL(name, version, repoURL, repos)
if err != nil {
t.Fatal(err)
}
@ -121,7 +121,7 @@ func TestFindChartURL(t *testing.T) {
version = "1.2.3"
repoURL = "http://example.com/helm"
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err = m.findChartURL(name, version, repoURL, repos)
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, _, err = m.findChartURL(name, version, repoURL, repos)
if err != nil {
t.Fatal(err)
}

Loading…
Cancel
Save