diff --git a/pkg/docker/login.go b/pkg/docker/login.go index 2110224a06..2e52528076 100644 --- a/pkg/docker/login.go +++ b/pkg/docker/login.go @@ -45,7 +45,8 @@ func saveAuthToCredentialsStore(ctx context.Context, credsStore string, registry } cmd := exec.CommandContext(ctx, binary, "store") //nolint:gosec // G702: binary is from Docker config, not user input cmd.Env = os.Environ() - cmd.Stderr = os.Stderr + var stderr strings.Builder + cmd.Stderr = &stderr stdin, err := cmd.StdinPipe() if err != nil { return fmt.Errorf("Failed to connect stdin to %s: %w", binary, err) @@ -61,6 +62,13 @@ func saveAuthToCredentialsStore(ctx context.Context, credsStore string, registry return fmt.Errorf("Failed to close stdin to %s: %w", binary, err) } if err := cmd.Wait(); err != nil { + output := strings.TrimSpace(stderr.String()) + if strings.Contains(strings.ToLower(output), "pass not initialized") { + return fmt.Errorf("failed to store Docker credentials because `pass` is not initialized; create a GPG key with `gpg --generate-key`, initialize the password store with `pass init `, then run `cog login` again") + } + if output != "" { + return fmt.Errorf("Failed to run %s: %s", binary, output) + } return fmt.Errorf("Failed to run %s: %w", binary, err) } return nil diff --git a/pkg/docker/login_test.go b/pkg/docker/login_test.go new file mode 100644 index 0000000000..fbd527a837 --- /dev/null +++ b/pkg/docker/login_test.go @@ -0,0 +1,34 @@ +package docker + +import ( + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSaveAuthToCredentialsStorePassNotInitialized(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("test credential helper is a shell script") + } + + binDir := t.TempDir() + helperPath := filepath.Join(binDir, "docker-credential-test") + helper := `#!/bin/sh +cat >/dev/null +echo "pass not initialized: exit status 1" >&2 +exit 1 +` + require.NoError(t, os.WriteFile(helperPath, []byte(helper), 0o755)) + t.Setenv("PATH", binDir+string(os.PathListSeparator)+os.Getenv("PATH")) + + err := saveAuthToCredentialsStore(t.Context(), "test", "r8.im", "test-user", "secret-token") + require.Error(t, err) + assert.Contains(t, err.Error(), "`pass` is not initialized") + assert.Contains(t, err.Error(), "gpg --generate-key") + assert.Contains(t, err.Error(), "pass init ") + assert.NotContains(t, err.Error(), "secret-token") +}