From f71752423efb09a0426b6cef6b549dd7f96fda8f Mon Sep 17 00:00:00 2001 From: Alex Eftimie Date: Thu, 17 Nov 2022 04:04:57 +0100 Subject: [PATCH] fix(helm): login OCI Helm dependencies correctly Signed-off-by: Alex Eftimie --- reposerver/repository/repository.go | 46 ++++++++++------- reposerver/repository/repository_test.go | 49 +++++++++++++------ .../testdata/oci-dependencies/Chart.yaml | 6 +++ 3 files changed, 67 insertions(+), 34 deletions(-) create mode 100644 reposerver/repository/testdata/oci-dependencies/Chart.yaml diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 8b31f660f78c7..67fc7b8a2eedb 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -819,6 +819,32 @@ func runHelmBuild(appPath string, h helm.Helm) error { return os.WriteFile(markerFile, []byte("marker"), 0644) } +func populateRequestRepos(appPath string, q *apiclient.ManifestRequest) error { + repos, err := getHelmDependencyRepos(appPath) + if err != nil { + return err + } + + for _, r := range repos { + if !repoExists(r.Repo, q.Repos) { + repositoryCredential := getRepoCredential(q.HelmRepoCreds, r.Repo) + if repositoryCredential != nil { + if repositoryCredential.EnableOCI { + r.Repo = strings.TrimPrefix(r.Repo, ociPrefix) + } + r.EnableOCI = repositoryCredential.EnableOCI + r.Password = repositoryCredential.Password + r.Username = repositoryCredential.Username + r.SSHPrivateKey = repositoryCredential.SSHPrivateKey + r.TLSClientCertData = repositoryCredential.TLSClientCertData + r.TLSClientCertKey = repositoryCredential.TLSClientCertKey + } + q.Repos = append(q.Repos, r) + } + } + return nil +} + func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclient.ManifestRequest, isLocal bool) ([]*unstructured.Unstructured, error) { concurrencyAllowed := isConcurrencyAllowed(appPath) if !concurrencyAllowed { @@ -915,24 +941,8 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie templateOpts.SetString[i] = env.Envsubst(j) } - repos, err := getHelmDependencyRepos(appPath) - if err != nil { - return nil, err - } - - for _, r := range repos { - if !repoExists(r.Repo, q.Repos) { - repositoryCredential := getRepoCredential(q.HelmRepoCreds, r.Repo) - if repositoryCredential != nil { - r.EnableOCI = repositoryCredential.EnableOCI - r.Password = repositoryCredential.Password - r.Username = repositoryCredential.Username - r.SSHPrivateKey = repositoryCredential.SSHPrivateKey - r.TLSClientCertData = repositoryCredential.TLSClientCertData - r.TLSClientCertKey = repositoryCredential.TLSClientCertKey - } - q.Repos = append(q.Repos, r) - } + if err := populateRequestRepos(appPath, q); err != nil { + return nil, fmt.Errorf("failed parsing dependencies: %v", err) } var proxy string diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go index d8cbab3cda6e5..ef1d4a2ed766a 100644 --- a/reposerver/repository/repository_test.go +++ b/reposerver/repository/repository_test.go @@ -47,14 +47,14 @@ gpg: using RSA key 4AEE18F83AFDEB23 gpg: Good signature from "GitHub (web-flow commit signing) " [ultimate] ` -type clientFunc func(*gitmocks.Client) +type clientFunc func(*gitmocks.Client, *helmmocks.Client) func newServiceWithMocks(root string, signed bool) (*Service, *gitmocks.Client) { root, err := filepath.Abs(root) if err != nil { panic(err) } - return newServiceWithOpt(func(gitClient *gitmocks.Client) { + return newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client) { gitClient.On("Init").Return(nil) gitClient.On("Fetch", mock.Anything).Return(nil) gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil) @@ -66,31 +66,32 @@ func newServiceWithMocks(root string, signed bool) (*Service, *gitmocks.Client) } else { gitClient.On("VerifyCommitSignature", mock.Anything).Return("", nil) } + + chart := "my-chart" + oobChart := "out-of-bounds-chart" + version := "1.1.0" + helmClient.On("GetIndex", true).Return(&helm.Index{Entries: map[string]helm.Entries{ + chart: {{Version: "1.0.0"}, {Version: version}}, + oobChart: {{Version: "1.0.0"}, {Version: version}}, + }}, nil) + helmClient.On("ExtractChart", chart, version).Return("./testdata/my-chart", io.NopCloser, nil) + helmClient.On("ExtractChart", oobChart, version).Return("./testdata2/out-of-bounds-chart", io.NopCloser, nil) + helmClient.On("CleanChartCache", chart, version).Return(nil) + helmClient.On("CleanChartCache", oobChart, version).Return(nil) + helmClient.On("DependencyBuild").Return(nil) }, root) } func newServiceWithOpt(cf clientFunc, root string) (*Service, *gitmocks.Client) { helmClient := &helmmocks.Client{} gitClient := &gitmocks.Client{} - cf(gitClient) + cf(gitClient, helmClient) service := NewService(metrics.NewMetricsServer(), cache.NewCache( cacheutil.NewCache(cacheutil.NewInMemoryCache(1*time.Minute)), 1*time.Minute, 1*time.Minute, ), RepoServerInitConstants{ParallelismLimit: 1}, argo.NewResourceTracking(), &git.NoopCredsStore{}, root) - chart := "my-chart" - oobChart := "out-of-bounds-chart" - version := "1.1.0" - helmClient.On("GetIndex", true).Return(&helm.Index{Entries: map[string]helm.Entries{ - chart: {{Version: "1.0.0"}, {Version: version}}, - oobChart: {{Version: "1.0.0"}, {Version: version}}, - }}, nil) - helmClient.On("ExtractChart", chart, version).Return("./testdata/my-chart", io.NopCloser, nil) - helmClient.On("ExtractChart", oobChart, version).Return("./testdata2/out-of-bounds-chart", io.NopCloser, nil) - helmClient.On("CleanChartCache", chart, version).Return(nil) - helmClient.On("CleanChartCache", oobChart, version).Return(nil) - service.newGitClient = func(rawRepoURL string, root string, creds git.Creds, insecure bool, enableLfs bool, prosy string, opts ...git.ClientOpts) (client git.Client, e error) { return gitClient, nil } @@ -121,7 +122,7 @@ func newServiceWithCommitSHA(root, revision string) *Service { revisionErr = errors.New("not a commit SHA") } - service, gitClient := newServiceWithOpt(func(gitClient *gitmocks.Client) { + service, gitClient := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client) { gitClient.On("Init").Return(nil) gitClient.On("Fetch", mock.Anything).Return(nil) gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil) @@ -1190,6 +1191,7 @@ func TestListApps(t *testing.T) { "kustomization_yml": "Kustomize", "my-chart": "Helm", "my-chart-2": "Helm", + "oci-dependencies": "Helm", "out-of-bounds-values-file-link": "Helm", "values-files": "Helm", } @@ -2519,3 +2521,18 @@ func Test_populateHelmAppDetails_values_symlinks(t *testing.T) { assert.Empty(t, res.Helm.Parameters) }) } + +func TestOCIDependencies(t *testing.T) { + src := argoappv1.ApplicationSource{Path: "."} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, HelmRepoCreds: []*argoappv1.RepoCreds{ + {URL: "example.com", Username: "test", Password: "test", EnableOCI: true}, + }} + + err := populateRequestRepos("./testdata/oci-dependencies", &q) + assert.Nil(t, err) + + assert.Equal(t, len(q.Repos), 1) + assert.Equal(t, q.Repos[0].Username, "test") + assert.Equal(t, q.Repos[0].EnableOCI, true) + assert.Equal(t, q.Repos[0].Repo, "example.com") +} diff --git a/reposerver/repository/testdata/oci-dependencies/Chart.yaml b/reposerver/repository/testdata/oci-dependencies/Chart.yaml new file mode 100644 index 0000000000000..3b39781ed6257 --- /dev/null +++ b/reposerver/repository/testdata/oci-dependencies/Chart.yaml @@ -0,0 +1,6 @@ +name: my-chart +version: 1.1.0 +dependencies: +- name: my-dependency + repository: oci://example.com + version: '*' \ No newline at end of file