From 19ad8037ce0b7efa369394063acd2331ea78176d Mon Sep 17 00:00:00 2001 From: rootp1 Date: Wed, 8 Jul 2026 13:13:34 +0530 Subject: [PATCH] Use password-stdin in Kubernetes Helm provider Signed-off-by: rootp1 --- .../plugin/kubernetes/provider/helm.go | 14 ++-- .../plugin/kubernetes/provider/helm_test.go | 66 +++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/pkg/app/pipedv1/plugin/kubernetes/provider/helm.go b/pkg/app/pipedv1/plugin/kubernetes/provider/helm.go index c0e5612c71..8f0b7ce98a 100644 --- a/pkg/app/pipedv1/plugin/kubernetes/provider/helm.go +++ b/pkg/app/pipedv1/plugin/kubernetes/provider/helm.go @@ -55,13 +55,13 @@ func (h *Helm) LoginToOCIRegistry(ctx context.Context, address, username, passwo "login", "-u", username, - "-p", - password, + "--password-stdin", address, } var stderr bytes.Buffer cmd := exec.CommandContext(ctx, h.execPath, args...) + cmd.Stdin = strings.NewReader(password) cmd.Stderr = &stderr h.logger.Info("login to oci registry", zap.String("address", address)) @@ -138,10 +138,16 @@ func (h *Helm) AddRepository(ctx context.Context, repo config.HelmChartRepositor if repo.Insecure { args = append(args, "--insecure-skip-tls-verify") } - if repo.Username != "" || repo.Password != "" { - args = append(args, "--username", repo.Username, "--password", repo.Password) + if repo.Username != "" { + args = append(args, "--username", repo.Username) + } + if repo.Password != "" { + args = append(args, "--password-stdin") } cmd := exec.CommandContext(ctx, h.execPath, args...) + if repo.Password != "" { + cmd.Stdin = strings.NewReader(repo.Password) + } out, err := cmd.CombinedOutput() if err != nil { h.logger.Error("failed to add chart repository", zap.String("name", repo.Name), zap.Error(err)) diff --git a/pkg/app/pipedv1/plugin/kubernetes/provider/helm_test.go b/pkg/app/pipedv1/plugin/kubernetes/provider/helm_test.go index 21a9b4ae7f..71880097db 100644 --- a/pkg/app/pipedv1/plugin/kubernetes/provider/helm_test.go +++ b/pkg/app/pipedv1/plugin/kubernetes/provider/helm_test.go @@ -16,6 +16,8 @@ package provider import ( "context" + "os" + "path/filepath" "strings" "testing" @@ -25,6 +27,7 @@ import ( "github.com/pipe-cd/piped-plugin-sdk-go/toolregistry/toolregistrytest" + "github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes/config" "github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes/toolregistry" ) @@ -84,6 +87,43 @@ func TestTemplateLocalChart_WithNamespace(t *testing.T) { } } +func TestLoginToOCIRegistry_PasswordUsesStdin(t *testing.T) { + t.Parallel() + + execPath, argsPath, stdinPath := newFakeHelm(t) + helm := NewHelm(execPath, zaptest.NewLogger(t)) + + err := helm.LoginToOCIRegistry(t.Context(), "ghcr.io", "test-user", "super-secret") + require.NoError(t, err) + + args := readFakeHelmOutput(t, argsPath) + assert.NotContains(t, args, "super-secret") + assert.Contains(t, args, "--password-stdin") + assert.Equal(t, "super-secret", strings.TrimSpace(readFakeHelmOutput(t, stdinPath))) +} + +func TestAddRepository_PasswordUsesStdin(t *testing.T) { + t.Parallel() + + execPath, argsPath, stdinPath := newFakeHelm(t) + helm := NewHelm(execPath, zaptest.NewLogger(t)) + + err := helm.AddRepository(t.Context(), config.HelmChartRepository{ + Name: "test-repo", + Address: "https://example.com/charts", + Username: "test-user", + Password: "super-secret", + }) + require.NoError(t, err) + + args := readFakeHelmOutput(t, argsPath) + assert.NotContains(t, args, "super-secret") + assert.Contains(t, args, "--username") + assert.Contains(t, args, "test-user") + assert.Contains(t, args, "--password-stdin") + assert.Equal(t, "super-secret", strings.TrimSpace(readFakeHelmOutput(t, stdinPath))) +} + func TestVerifyHelmValueFilePath(t *testing.T) { t.Parallel() @@ -210,3 +250,29 @@ func TestTemplateRemoteChart(t *testing.T) { require.Equal(t, "testapp-helloworld", name) } } + +func newFakeHelm(t *testing.T) (execPath, argsPath, stdinPath string) { + t.Helper() + + dir := t.TempDir() + argsPath = filepath.Join(dir, "args.txt") + stdinPath = filepath.Join(dir, "stdin.txt") + execPath = filepath.Join(dir, "helm") + + script := strings.Join([]string{ + "#!/bin/sh", + "printf '%s\\n' \"$@\" > \"" + argsPath + "\"", + "cat > \"" + stdinPath + "\"", + }, "\n") + + require.NoError(t, os.WriteFile(execPath, []byte(script), 0o755)) + return execPath, argsPath, stdinPath +} + +func readFakeHelmOutput(t *testing.T, path string) string { + t.Helper() + + data, err := os.ReadFile(path) + require.NoError(t, err) + return string(data) +}