feat(helm): Support Bearer token auth when get chart

Signed-off-by: lemonli <liwenjun0323@gmail.com>
pull/8447/head
lemonli 5 years ago
parent 960b3b53c6
commit 01904fd06e

@ -56,6 +56,7 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download") f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download")
f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.StringVar(&c.Token, "token", "", "chart repository bearer token where to locate the requested chart")
} }
// bindOutputFlag will add the output flag to the given command and bind the // bindOutputFlag will add the output flag to the given command and bind the

@ -61,6 +61,8 @@ type repoAddOptions struct {
// Deprecated, but cannot be removed until Helm 4 // Deprecated, but cannot be removed until Helm 4
deprecatedNoUpdate bool deprecatedNoUpdate bool
tokenFromStdin bool
} }
func newRepoAddCmd(out io.Writer) *cobra.Command { func newRepoAddCmd(out io.Writer) *cobra.Command {
@ -76,7 +78,6 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
o.url = args[1] o.url = args[1]
o.repoFile = settings.RepositoryConfig o.repoFile = settings.RepositoryConfig
o.repoCache = settings.RepositoryCache o.repoCache = settings.RepositoryCache
return o.run(out) return o.run(out)
}, },
} }
@ -91,6 +92,7 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the repository") f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the repository")
f.BoolVar(&o.allowDeprecatedRepos, "allow-deprecated-repos", false, "by default, this command will not allow adding official repos that have been permanently deleted. This disables that behavior") f.BoolVar(&o.allowDeprecatedRepos, "allow-deprecated-repos", false, "by default, this command will not allow adding official repos that have been permanently deleted. This disables that behavior")
f.BoolVar(&o.tokenFromStdin, "token-stdin", false, "read chart repository bearer token from stdin")
return cmd return cmd
} }
@ -144,6 +146,16 @@ func (o *repoAddOptions) run(out io.Writer) error {
o.password = string(password) o.password = string(password)
} }
var token string
if o.tokenFromStdin {
tokenStdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
}
token = strings.TrimSuffix(string(tokenStdin), "\n")
token = strings.TrimSuffix(token, "\r")
}
c := repo.Entry{ c := repo.Entry{
Name: o.name, Name: o.name,
URL: o.url, URL: o.url,
@ -153,6 +165,7 @@ func (o *repoAddOptions) run(out io.Writer) error {
KeyFile: o.keyFile, KeyFile: o.keyFile,
CAFile: o.caFile, CAFile: o.caFile,
InsecureSkipTLSverify: o.insecureSkipTLSverify, InsecureSkipTLSverify: o.insecureSkipTLSverify,
Token: token,
} }
// If the repo exists do one of two things: // If the repo exists do one of two things:

@ -115,6 +115,7 @@ type ChartPathOptions struct {
Username string // --username Username string // --username
Verify bool // --verify Verify bool // --verify
Version string // --version Version string // --version
Token string // --token
} }
// NewInstall creates a new Install object with the given configuration. // NewInstall creates a new Install object with the given configuration.
@ -652,6 +653,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
getter.WithBasicAuth(c.Username, c.Password), getter.WithBasicAuth(c.Username, c.Password),
getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile), getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile),
getter.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify), getter.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify),
getter.WithBearerToken(c.Token),
}, },
RepositoryConfig: settings.RepositoryConfig, RepositoryConfig: settings.RepositoryConfig,
RepositoryCache: settings.RepositoryCache, RepositoryCache: settings.RepositoryCache,
@ -660,8 +662,15 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
dl.Verify = downloader.VerifyAlways dl.Verify = downloader.VerifyAlways
} }
if c.RepoURL != "" { if c.RepoURL != "" {
chartURL, err := repo.FindChartInAuthAndTLSRepoURL(c.RepoURL, c.Username, c.Password, name, version, chartURL, err := repo.FindChartInRepoURLWithAuth(
c.CertFile, c.KeyFile, c.CaFile, c.InsecureSkipTLSverify, getter.All(settings)) getter.All(settings),
repo.WithRepoURL(c.RepoURL),
repo.WithChartInfo(name, version),
repo.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile),
repo.WithBasicAuth(c.Username, c.Password),
repo.WithBearerToken(c.Token),
repo.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify),
)
if err != nil { if err != nil {
return "", err return "", err
} }

@ -65,6 +65,7 @@ func (p *Pull) Run(chartRef string) (string, error) {
getter.WithBasicAuth(p.Username, p.Password), getter.WithBasicAuth(p.Username, p.Password),
getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile), getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile),
getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify), getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify),
getter.WithBearerToken(p.Token),
}, },
RepositoryConfig: p.Settings.RepositoryConfig, RepositoryConfig: p.Settings.RepositoryConfig,
RepositoryCache: p.Settings.RepositoryCache, RepositoryCache: p.Settings.RepositoryCache,
@ -89,7 +90,15 @@ func (p *Pull) Run(chartRef string) (string, error) {
} }
if p.RepoURL != "" { if p.RepoURL != "" {
chartURL, err := repo.FindChartInAuthAndTLSRepoURL(p.RepoURL, p.Username, p.Password, chartRef, p.Version, p.CertFile, p.KeyFile, p.CaFile, p.InsecureSkipTLSverify, getter.All(p.Settings)) chartURL, err := repo.FindChartInRepoURLWithAuth(
getter.All(p.Settings),
repo.WithRepoURL(p.RepoURL),
repo.WithChartInfo(chartRef, p.Version),
repo.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile),
repo.WithBasicAuth(p.Username, p.Password),
repo.WithBearerToken(p.Token),
repo.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify),
)
if err != nil { if err != nil {
return out.String(), err return out.String(), err
} }

@ -191,6 +191,13 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
getter.WithBasicAuth(rc.Username, rc.Password), getter.WithBasicAuth(rc.Username, rc.Password),
) )
} }
if rc.Token != "" {
c.Options = append(
c.Options,
getter.WithBearerToken(rc.Token),
)
}
return u, nil return u, nil
} }
@ -220,6 +227,9 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
if r.Config.Username != "" && r.Config.Password != "" { if r.Config.Username != "" && r.Config.Password != "" {
c.Options = append(c.Options, getter.WithBasicAuth(r.Config.Username, r.Config.Password)) c.Options = append(c.Options, getter.WithBasicAuth(r.Config.Username, r.Config.Password))
} }
if r.Config.Token != "" {
c.Options = append(c.Options, getter.WithBearerToken(r.Config.Token))
}
} }
// Next, we need to load the index, and actually look up the chart. // Next, we need to load the index, and actually look up the chart.

@ -19,6 +19,7 @@ import (
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/internal/test/ensure"
@ -323,6 +324,63 @@ func TestDownloadTo_VerifyLater(t *testing.T) {
} }
} }
func TestDownloadTo_Token(t *testing.T) {
// Set up a fake repo with bearer auth enabled
srv, err := repotest.NewTempServerWithCleanup(t, "testdata/*.tgz*")
srv.Stop()
if err != nil {
t.Fatal(err)
}
srv.WithMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := strings.Split(r.Header.Get("Authorization"), "Bearer ")
if len(token) != 2 || strings.TrimSpace(token[1]) != "JWT" {
t.Errorf("Expected request to use bearer token and for token == 'JWT' got '%s'", token)
}
}))
srv.Start()
defer srv.Stop()
if err := srv.CreateIndex(); err != nil {
t.Fatal(err)
}
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
c := ChartDownloader{
Out: os.Stderr,
Verify: VerifyAlways,
Keyring: "testdata/helm-test-key.pub",
RepositoryConfig: repoConfig,
RepositoryCache: repoCache,
Getters: getter.All(&cli.EnvSettings{
RepositoryConfig: repoConfig,
RepositoryCache: repoCache,
}),
Options: []getter.Option{
getter.WithBearerToken("JWT"),
},
}
cname := "/signtest-0.1.0.tgz"
dest := srv.Root()
where, v, err := c.DownloadTo(srv.URL()+cname, "", dest)
if err != nil {
t.Fatal(err)
}
if expect := filepath.Join(dest, cname); where != expect {
t.Errorf("Expected download to %s, got %s", expect, where)
}
if v.FileHash == "" {
t.Error("File hash was empty, but verification is required.")
}
if _, err := os.Stat(filepath.Join(dest, cname)); err != nil {
t.Error(err)
}
}
func TestScanReposForURL(t *testing.T) { func TestScanReposForURL(t *testing.T) {
c := ChartDownloader{ c := ChartDownloader{
Out: os.Stderr, Out: os.Stderr,

@ -307,7 +307,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
// Any failure to resolve/download a chart should fail: // Any failure to resolve/download a chart should fail:
// https://github.com/helm/helm/issues/1439 // https://github.com/helm/helm/issues/1439
churl, username, password, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos) churl, username, password, token, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos)
if err != nil { if err != nil {
saveError = errors.Wrapf(err, "could not find %s", churl) saveError = errors.Wrapf(err, "could not find %s", churl)
break break
@ -329,6 +329,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
Getters: m.Getters, Getters: m.Getters,
Options: []getter.Option{ Options: []getter.Option{
getter.WithBasicAuth(username, password), getter.WithBasicAuth(username, password),
getter.WithBearerToken(token),
}, },
} }
@ -647,7 +648,7 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error {
// repoURL is the repository to search // repoURL is the repository to search
// //
// If it finds a URL that is "relative", it will prepend the repoURL. // 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, err error) { func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password, token string, err error) {
for _, cr := range repos { for _, cr := range repos {
if urlutil.Equal(repoURL, cr.Config.URL) { if urlutil.Equal(repoURL, cr.Config.URL) {
var entry repo.ChartVersions var entry repo.ChartVersions
@ -666,6 +667,7 @@ func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*
} }
username = cr.Config.Username username = cr.Config.Username
password = cr.Config.Password password = cr.Config.Password
token = cr.Config.Token
return return
} }
} }

@ -81,7 +81,7 @@ func TestFindChartURL(t *testing.T) {
version := "0.1.0" version := "0.1.0"
repoURL := "http://example.com/charts" repoURL := "http://example.com/charts"
churl, username, password, err := m.findChartURL(name, version, repoURL, repos) churl, username, password, token, err := m.findChartURL(name, version, repoURL, repos)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -94,6 +94,9 @@ func TestFindChartURL(t *testing.T) {
if password != "" { if password != "" {
t.Errorf("Unexpected password %q", password) t.Errorf("Unexpected password %q", password)
} }
if token != "" {
t.Errorf("Unexpected token %q", token)
}
} }
func TestGetRepoNames(t *testing.T) { func TestGetRepoNames(t *testing.T) {

@ -21,3 +21,6 @@ repositories:
certFile: "cert" certFile: "cert"
keyFile: "key" keyFile: "key"
caFile: "ca" caFile: "ca"
- name: testing-token
url: "http://example.com"
token: "JWT"

@ -0,0 +1,14 @@
apiVersion: v1
entries:
foo:
- name: foo
description: Foo Chart
home: https://helm.sh/helm
keywords: []
maintainers: []
sources:
- https://github.com/helm/charts
urls:
- http://example.com/foo-1.2.3.tgz
version: 1.2.3
checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d

@ -38,6 +38,7 @@ type options struct {
password string password string
userAgent string userAgent string
timeout time.Duration timeout time.Duration
token string
} }
// Option allows specifying various settings configurable by the user for overriding the defaults // Option allows specifying various settings configurable by the user for overriding the defaults
@ -83,6 +84,13 @@ func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
} }
} }
// WithBearerToken sets the request's Authorization header to use the provided token
func WithBearerToken(token string) Option {
return func(opts *options) {
opts.token = token
}
}
// WithTimeout sets the timeout for requests // WithTimeout sets the timeout for requests
func WithTimeout(timeout time.Duration) Option { func WithTimeout(timeout time.Duration) Option {
return func(opts *options) { return func(opts *options) {

@ -18,6 +18,7 @@ package getter
import ( import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"fmt"
"io" "io"
"net/http" "net/http"
@ -60,6 +61,10 @@ func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
req.SetBasicAuth(g.opts.username, g.opts.password) req.SetBasicAuth(g.opts.username, g.opts.password)
} }
if g.opts.token != "" {
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", g.opts.token))
}
client, err := g.httpClient() client, err := g.httpClient()
if err != nil { if err != nil {
return nil, err return nil, err

@ -58,6 +58,7 @@ func TestHTTPGetter(t *testing.T) {
WithTLSClientConfig(pub, priv, ca), WithTLSClientConfig(pub, priv, ca),
WithInsecureSkipVerifyTLS(insecure), WithInsecureSkipVerifyTLS(insecure),
WithTimeout(timeout), WithTimeout(timeout),
WithBearerToken("JWT"),
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -100,6 +101,10 @@ func TestHTTPGetter(t *testing.T) {
t.Errorf("Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout) t.Errorf("Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout)
} }
if hg.opts.token != "JWT" {
t.Errorf("Expected NewHTTPGetter to contain %s as the token, got %s", "JWT", hg.opts.token)
}
// Test if setting insecureSkipVerifyTLS is being passed to the ops // Test if setting insecureSkipVerifyTLS is being passed to the ops
insecure = true insecure = true
@ -259,6 +264,64 @@ func TestDownloadInsecureSkipTLSVerify(t *testing.T) {
} }
func TestDownloadToken(t *testing.T) {
expect := "Call me Ishmael"
expectedUserAgent := "I am Groot"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defaultUserAgent := "Helm/" + strings.TrimPrefix(version.GetVersion(), "v")
if r.UserAgent() != defaultUserAgent {
t.Errorf("Expected '%s', got '%s'", defaultUserAgent, r.UserAgent())
}
fmt.Fprint(w, expect)
}))
defer srv.Close()
g, err := All(cli.New()).ByScheme("http")
if err != nil {
t.Fatal(err)
}
got, err := g.Get(srv.URL, WithURL(srv.URL))
if err != nil {
t.Fatal(err)
}
if got.String() != expect {
t.Errorf("Expected %q, got %q", expect, got.String())
}
// test with http server
tokenSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := strings.Split(r.Header.Get("Authorization"), "Bearer ")
if len(token) != 2 || strings.TrimSpace(token[1]) != "JWT" {
t.Errorf("Expected request to use bearer token and for token == 'JWT' got '%s'", token)
}
if r.UserAgent() != expectedUserAgent {
t.Errorf("Expected '%s', got '%s'", expectedUserAgent, r.UserAgent())
}
fmt.Fprint(w, expect)
}))
defer tokenSrv.Close()
u, _ := url.ParseRequestURI(tokenSrv.URL)
httpgetter, err := NewHTTPGetter(
WithURL(u.String()),
WithBearerToken("JWT"),
WithUserAgent(expectedUserAgent),
)
if err != nil {
t.Fatal(err)
}
got, err = httpgetter.Get(u.String())
if err != nil {
t.Fatal(err)
}
if got.String() != expect {
t.Errorf("Expected %q, got %q", expect, got.String())
}
}
func TestHTTPGetterTarDownload(t *testing.T) { func TestHTTPGetterTarDownload(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
f, _ := os.Open("testdata/empty-0.0.1.tgz") f, _ := os.Open("testdata/empty-0.0.1.tgz")

@ -48,6 +48,7 @@ type Entry struct {
KeyFile string `json:"keyFile"` KeyFile string `json:"keyFile"`
CAFile string `json:"caFile"` CAFile string `json:"caFile"`
InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"` InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"`
Token string `json:"token"`
} }
// ChartRepository represents a chart repository // ChartRepository represents a chart repository
@ -59,6 +60,70 @@ type ChartRepository struct {
CachePath string CachePath string
} }
// options are generic parameters to be provided to find chart.
type options struct {
chartName string
chartVersion string
repoURL string
certFile string
keyFile string
caFile string
username string
password string
token string
insecureSkipTLSverify bool
}
// Option allows specifying various settings configurable by the user for overriding the defaults
// used when performing find chart.
type Option func(*options)
// WithChartInfo informs the chart info.
func WithChartInfo(chartName, chartVersion string) Option {
return func(opts *options) {
opts.chartName = chartName
opts.chartVersion = chartVersion
}
}
// WithRepoURL informs the repo url that will be used when find chart.
func WithRepoURL(url string) Option {
return func(opts *options) {
opts.repoURL = url
}
}
// WithBasicAuth sets the request's Authorization header to use the provided credentials
func WithBasicAuth(username, password string) Option {
return func(opts *options) {
opts.username = username
opts.password = password
}
}
// WithTLSClientConfig sets the client auth with the provided credentials.
func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
return func(opts *options) {
opts.certFile = certFile
opts.keyFile = keyFile
opts.caFile = caFile
}
}
// WithBearerToken sets the request's Authorization header to use the provided token
func WithBearerToken(token string) Option {
return func(opts *options) {
opts.token = token
}
}
// WithInsecureSkipVerifyTLS determines if a TLS Certificate will be checked
func WithInsecureSkipVerifyTLS(insecureSkipTLSverify bool) Option {
return func(opts *options) {
opts.insecureSkipTLSverify = insecureSkipTLSverify
}
}
// NewChartRepository constructs ChartRepository // NewChartRepository constructs ChartRepository
func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) { func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) {
u, err := url.Parse(cfg.URL) u, err := url.Parse(cfg.URL)
@ -127,6 +192,7 @@ func (r *ChartRepository) DownloadIndexFile() (string, error) {
getter.WithInsecureSkipVerifyTLS(r.Config.InsecureSkipTLSverify), getter.WithInsecureSkipVerifyTLS(r.Config.InsecureSkipTLSverify),
getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile), getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile),
getter.WithBasicAuth(r.Config.Username, r.Config.Password), getter.WithBasicAuth(r.Config.Username, r.Config.Password),
getter.WithBearerToken(r.Config.Token),
) )
if err != nil { if err != nil {
return "", err return "", err
@ -198,14 +264,33 @@ func (r *ChartRepository) generateIndex() error {
// FindChartInRepoURL finds chart in chart repository pointed by repoURL // FindChartInRepoURL finds chart in chart repository pointed by repoURL
// without adding repo to repositories // without adding repo to repositories
func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
return FindChartInAuthRepoURL(repoURL, "", "", chartName, chartVersion, certFile, keyFile, caFile, getters) return FindChartInRepoURLWithAuth(
getters,
WithRepoURL(repoURL),
WithChartInfo(chartName, chartVersion),
WithTLSClientConfig(certFile, keyFile, caFile),
)
} }
// FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL // FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL
// without adding repo to repositories, like FindChartInRepoURL, // without adding repo to repositories, like FindChartInRepoURL,
// but it also receives credentials for the chart repository. // but it also receives credentials for the chart repository.
// Deprecated: this function is deprecated and will be removed in Helm 4, please use FindChartInRepoURLWithAuth instead.
func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
return FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile, false, getters) return findChartInAuthRepoURL(
getters,
WithRepoURL(repoURL),
WithChartInfo(chartName, chartVersion),
WithBasicAuth(username, password),
WithTLSClientConfig(certFile, keyFile, caFile),
)
}
// FindChartInRepoURLWithAuth finds chart in chart repository pointed by repoURL
// without adding repo to repositories, like FindChartInRepoURL,
// but it also receives credentials for the chart repository.
func FindChartInRepoURLWithAuth(getters getter.Providers, opts ...Option) (string, error) {
return findChartInAuthRepoURL(getters, opts...)
} }
// FindChartInAuthAndTLSRepoURL finds chart in chart repository pointed by repoURL // FindChartInAuthAndTLSRepoURL finds chart in chart repository pointed by repoURL
@ -213,21 +298,37 @@ func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion
// but it also receives credentials and TLS verify flag for the chart repository. // but it also receives credentials and TLS verify flag for the chart repository.
// TODO Helm 4, FindChartInAuthAndTLSRepoURL should be integrated into FindChartInAuthRepoURL. // TODO Helm 4, FindChartInAuthAndTLSRepoURL should be integrated into FindChartInAuthRepoURL.
func FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, insecureSkipTLSverify bool, getters getter.Providers) (string, error) { func FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, insecureSkipTLSverify bool, getters getter.Providers) (string, error) {
return findChartInAuthRepoURL(
getters,
WithRepoURL(repoURL),
WithChartInfo(chartName, chartVersion),
WithBasicAuth(username, password),
WithTLSClientConfig(certFile, keyFile, caFile),
WithInsecureSkipVerifyTLS(insecureSkipTLSverify),
)
}
func findChartInAuthRepoURL(getters getter.Providers, opts ...Option) (string, error) {
// Download and write the index file to a temporary location // Download and write the index file to a temporary location
buf := make([]byte, 20) buf := make([]byte, 20)
rand.Read(buf) rand.Read(buf)
name := strings.ReplaceAll(base64.StdEncoding.EncodeToString(buf), "/", "-") name := strings.ReplaceAll(base64.StdEncoding.EncodeToString(buf), "/", "-")
repoOpts := options{}
for _, opt := range opts {
opt(&repoOpts)
}
c := Entry{ c := Entry{
URL: repoURL,
Username: username,
Password: password,
CertFile: certFile,
KeyFile: keyFile,
CAFile: caFile,
Name: name, Name: name,
InsecureSkipTLSverify: insecureSkipTLSverify, URL: repoOpts.repoURL,
Username: repoOpts.username,
Password: repoOpts.password,
CertFile: repoOpts.certFile,
KeyFile: repoOpts.keyFile,
CAFile: repoOpts.caFile,
Token: repoOpts.token,
InsecureSkipTLSverify: repoOpts.insecureSkipTLSverify,
} }
r, err := NewChartRepository(&c, getters) r, err := NewChartRepository(&c, getters)
if err != nil { if err != nil {
@ -235,7 +336,7 @@ func FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartV
} }
idx, err := r.DownloadIndexFile() idx, err := r.DownloadIndexFile()
if err != nil { if err != nil {
return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", repoURL) return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", repoOpts.repoURL)
} }
// Read the index file for the repository to get chart information and return chart URL // Read the index file for the repository to get chart information and return chart URL
@ -244,13 +345,13 @@ func FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartV
return "", err return "", err
} }
errMsg := fmt.Sprintf("chart %q", chartName) errMsg := fmt.Sprintf("chart %q", repoOpts.chartName)
if chartVersion != "" { if repoOpts.chartVersion != "" {
errMsg = fmt.Sprintf("%s version %q", errMsg, chartVersion) errMsg = fmt.Sprintf("%s version %q", errMsg, repoOpts.chartVersion)
} }
cv, err := repoIndex.Get(chartName, chartVersion) cv, err := repoIndex.Get(repoOpts.chartName, repoOpts.chartVersion)
if err != nil { if err != nil {
return "", errors.Errorf("%s not found in %s repository", errMsg, repoURL) return "", errors.Errorf("%s not found in %s repository", errMsg, repoOpts.repoURL)
} }
if len(cv.URLs) == 0 { if len(cv.URLs) == 0 {
@ -259,7 +360,7 @@ func FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartV
chartURL := cv.URLs[0] chartURL := cv.URLs[0]
absoluteChartURL, err := ResolveReferenceURL(repoURL, chartURL) absoluteChartURL, err := ResolveReferenceURL(repoOpts.repoURL, chartURL)
if err != nil { if err != nil {
return "", errors.Wrap(err, "failed to make chart URL absolute") return "", errors.Wrap(err, "failed to make chart URL absolute")
} }

Loading…
Cancel
Save