pull/9760/merge
Andreas Karis 2 months ago committed by GitHub
commit cf647cb43b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -18,6 +18,7 @@ package action
import ( import (
"fmt" "fmt"
"log/slog"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -73,6 +74,23 @@ func (p *Pull) SetRegistryClient(client *registry.Client) {
func (p *Pull) Run(chartRef string) (string, error) { func (p *Pull) Run(chartRef string) (string, error) {
var out strings.Builder var out strings.Builder
// If the repository URL is set via CLI (--repo), but neither a username nor
// password are set for a pull request, check if the repository credentials
// are already stored in helm's repository config.
if p.RepoURL != "" {
if p.Username == "" && p.Password == "" {
f, err := repo.LoadFile(p.Settings.RepositoryConfig)
if err != nil {
return out.String(), err
}
if repoEntry := f.GetByURL(p.RepoURL); repoEntry != nil {
slog.Info("Using credentials from repository config")
p.Username = repoEntry.Username
p.Password = repoEntry.Password
}
}
}
c := downloader.ChartDownloader{ c := downloader.ChartDownloader{
Out: &out, Out: &out,
Keyring: p.Keyring, Keyring: p.Keyring,
@ -113,7 +131,6 @@ func (p *Pull) Run(chartRef string) (string, error) {
} }
defer os.RemoveAll(dest) defer os.RemoveAll(dest)
} }
if p.RepoURL != "" { if p.RepoURL != "" {
chartURL, err := repo.FindChartInRepoURL( chartURL, err := repo.FindChartInRepoURL(
p.RepoURL, p.RepoURL,

@ -393,3 +393,72 @@ func TestPullFileCompletion(t *testing.T) {
checkFileCompletion(t, "pull", false) checkFileCompletion(t, "pull", false)
checkFileCompletion(t, "pull repo/chart", false) checkFileCompletion(t, "pull repo/chart", false)
} }
func TestPullWithCredentialsFromExistingRepository(t *testing.T) {
srv := repotest.NewTempServer(
t,
repotest.WithChartSourceGlob("testdata/testcharts/*.tgz"),
repotest.WithMiddleware(repotest.BasicAuthMiddleware(t)),
)
defer srv.Stop()
srv2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir(srv.Root())).ServeHTTP(w, r)
}))
defer srv2.Close()
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
// all flags will get "-d outdir" appended.
tests := []struct {
name string
args string
expectFile string
}{
{
name: "Chart fetch using repo URL",
expectFile: "./signtest-0.1.0.tgz",
args: "signtest --repo " + srv.URL() + " --username username --password password",
},
{
name: "Chart fetch using repo URL",
expectFile: "./signtest-0.1.0.tgz",
args: "signtest --repo " + srv.URL(),
},
}
outdir := t.TempDir()
repositoryConfig := filepath.Join(outdir, "repositories.yaml")
repositoryCache := outdir
registryConfig := filepath.Join(outdir, "config.json")
cmd := fmt.Sprintf("repo add test_repository %s --username %s --password %s "+
"--repository-config %s --repository-cache %s --registry-config %s",
srv.URL(), "username", "password", repositoryConfig, repositoryCache, registryConfig,
)
if _, _, err := executeActionCommand(cmd); err != nil {
t.Fatalf("got error in setup, error: %q", err)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := fmt.Sprintf("pull %s -d '%s' --repository-config %s --repository-cache %s --registry-config %s",
tt.args,
outdir,
repositoryConfig,
repositoryCache,
registryConfig,
)
_, _, err := executeActionCommand(cmd)
if err != nil {
t.Fatalf("%q reported error: %s", tt.name, err)
}
ef := filepath.Join(outdir, tt.expectFile)
if _, err := os.Stat(ef); err != nil {
t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err)
}
})
}
}

@ -18,7 +18,9 @@ package repo // import "helm.sh/helm/v4/pkg/repo"
import ( import (
"fmt" "fmt"
"net/url"
"os" "os"
"path"
"path/filepath" "path/filepath"
"time" "time"
@ -94,6 +96,38 @@ func (r *File) Get(name string) *Entry {
return nil return nil
} }
// compareURLs returns true if url1 and url2 can each be parsed, have the exact
// same scheme and host and the same cleaned path.
func compareURLs(url1, url2 string) bool {
parsed1, err := url.Parse(url1)
if err != nil {
return false
}
parsed2, err := url.Parse(url2)
if err != nil {
return false
}
if parsed1.Scheme != parsed2.Scheme {
return false
}
if parsed1.Host != parsed2.Host {
return false
}
return path.Clean(parsed1.Path) == path.Clean(parsed2.Path)
}
// GetByURL returns the first entry with the given URL if one exists, otherwise
// returns nil. For comparison, GetByURL tries to sanitize/standardize the URLs
// as much as possible.
func (r *File) GetByURL(url string) *Entry {
for _, entry := range r.Repositories {
if compareURLs(entry.URL, url) {
return entry
}
}
return nil
}
// Remove removes the entry from the list of repositories. // Remove removes the entry from the list of repositories.
func (r *File) Remove(name string) bool { func (r *File) Remove(name string) bool {
cp := []*Entry{} cp := []*Entry{}

@ -128,6 +128,49 @@ func TestRepoFile_Get(t *testing.T) {
} }
} }
func TestRepoFileGetByURL(t *testing.T) {
repo := NewFile()
repo.Add(
&Entry{
Name: "first",
URL: "https://example.com/first",
},
&Entry{
Name: "second1",
URL: "https://example.comm/second",
},
&Entry{
Name: "second2",
URL: "http://example.com/second",
},
&Entry{
Name: "second3",
URL: "https://example.com/second/////////",
},
&Entry{
Name: "third",
URL: "https://example.com/third",
},
)
url := "https://example.com/second"
entry := repo.GetByURL(url)
if entry == nil {
t.Fatalf("Expected repo entry %q to be found", url)
}
expected := "second3"
if entry.Name != expected {
t.Errorf("Expected repo Name to be %q but got %q", expected, entry.Name)
}
entry = repo.GetByURL("http://nonexistent.example.com/nonexistent")
if entry != nil {
t.Errorf("Got unexpected entry %+v", entry)
}
}
func TestRemoveRepository(t *testing.T) { func TestRemoveRepository(t *testing.T) {
sampleRepository := NewFile() sampleRepository := NewFile()
sampleRepository.Add( sampleRepository.Add(

Loading…
Cancel
Save