Skip to content

Commit 7dd6d46

Browse files
CBP-18409 using the new git-credential-cloudbees (#25)
* use git-credential-cloudbees * update command * add logs * for ssh using existing code * Revert "add logs" This reverts commit 13dfb69. * fix review suggestions * refactor credentials helper logic * use CommandContext for child process * update tests * restore original .gitconfig after tests * mock loadConfig in test * fix nil pointer in tests * logs to debug ci test failures * more logs * debug env * remove existing pathenv in tests * commenting tests * trigger workflow * debug: log command * trigger workflow * use correct args for git-credential-cloudbees * remove debug logs * trigger workflow
1 parent a16efa2 commit 7dd6d46

File tree

3 files changed

+193
-23
lines changed

3 files changed

+193
-23
lines changed

internal/configuration/config.go

Lines changed: 78 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import (
99
"fmt"
1010
"io"
1111
"os"
12+
"os/exec"
1213
"path/filepath"
1314
"regexp"
1415
"sort"
1516
"strings"
1617

18+
"github.com/cloudbees-io/configure-git-global-credentials/internal"
1719
"github.com/go-git/go-git/v5/config"
1820
format "github.com/go-git/go-git/v5/plumbing/format/config"
1921
"github.com/go-git/go-git/v5/plumbing/transport"
@@ -46,7 +48,12 @@ type Config struct {
4648
GitLabServerURL string `mapstructure:"gitlab-server-url"`
4749
}
4850

49-
func loadConfig(scope config.Scope) (_ *format.Config, _ string, retErr error) {
51+
const (
52+
tokenEnv = "CLOUDBEES_API_TOKEN"
53+
cbGitCredentialsHelperPath = "git-credential-cloudbees"
54+
)
55+
56+
var loadConfig = func(scope config.Scope) (_ *format.Config, _ string, retErr error) {
5057
paths, err := config.Paths(scope)
5158
if err != nil {
5259
return nil, "", err
@@ -153,6 +160,15 @@ func (c *Config) Apply(ctx context.Context) error {
153160
return err
154161
}
155162

163+
gitCredCloudbeesExists := true
164+
cbGitCredentialsHelperPath, err := exec.LookPath(cbGitCredentialsHelperPath)
165+
if err != nil {
166+
internal.Debug("Could not find git-credential-cloudbees on the path, falling back to old-style helper")
167+
gitCredCloudbeesExists = false
168+
} else {
169+
internal.Debug("Found git-credential-cloudbees on the path at %s", cbGitCredentialsHelperPath)
170+
}
171+
156172
homePath := os.Getenv("HOME")
157173
actionPath := filepath.Join(homePath, ".cloudbees-configure-git-global-credentials", c.uniqueId())
158174
if err := os.MkdirAll(actionPath, os.ModePerm); err != nil {
@@ -164,35 +180,44 @@ func (c *Config) Apply(ctx context.Context) error {
164180
var helperConfigFile string
165181

166182
if !c.ssh() {
167-
fmt.Println("🔄 Installing credentials helper ...")
183+
if !gitCredCloudbeesExists {
184+
fmt.Println("🔄 Installing credentials helper ...")
168185

169-
self, err := os.Executable()
170-
if err != nil {
171-
return err
172-
}
186+
self, err := os.Executable()
187+
if err != nil {
188+
return err
189+
}
173190

174-
helperExecutable := filepath.Join(actionPath, "git-credential-helper")
175-
if a, err := filepath.Abs(helperExecutable); err != nil {
176-
helperExecutable = a
177-
}
191+
helperExecutable := filepath.Join(actionPath, "git-credential-helper")
192+
if a, err := filepath.Abs(helperExecutable); err != nil {
193+
helperExecutable = a
194+
}
178195

179-
err = copyFileHelper(helperExecutable, self)
180-
if err != nil {
181-
return err
182-
}
196+
err = copyFileHelper(helperExecutable, self)
197+
if err != nil {
198+
return err
199+
}
183200

184-
fmt.Println("✅ Credentials helper installed")
201+
fmt.Println("✅ Credentials helper installed")
185202

186-
helperConfig = &format.Config{}
187-
helperConfigFile = helperExecutable + ".cfg"
188-
helper = fmt.Sprintf("%s credential-helper --config-file %s", helperExecutable, helperConfigFile)
203+
helperConfig = &format.Config{}
204+
helperConfigFile = helperExecutable + ".cfg"
205+
helper = fmt.Sprintf("%s credential-helper --config-file %s", helperExecutable, helperConfigFile)
189206

190-
if _, err := os.Stat(helperConfigFile); err != nil {
191-
b, err := os.ReadFile(helperConfigFile)
192-
if err == nil {
193-
// make best effort to merge existing, if it fails we will overwrite the whole
194-
_ = format.NewDecoder(bytes.NewReader(b)).Decode(helperConfig)
207+
if _, err := os.Stat(helperConfigFile); err != nil {
208+
b, err := os.ReadFile(helperConfigFile)
209+
if err == nil {
210+
// make best effort to merge existing, if it fails we will overwrite the whole
211+
_ = format.NewDecoder(bytes.NewReader(b)).Decode(helperConfig)
212+
}
195213
}
214+
} else {
215+
filterUrl := make([]string, 0, len(aliases))
216+
for url := range aliases {
217+
filterUrl = append(filterUrl, url)
218+
}
219+
220+
return invokeGitCredentialsHelper(ctx, cbGitCredentialsHelperPath, cfgPath, c.CloudBeesApiURL, c.CloudBeesApiToken, filterUrl)
196221
}
197222
} else {
198223
// check if the SSH key looks to be a base64 encoded private key that the user forgot to decode
@@ -308,6 +333,36 @@ func (c *Config) Apply(ctx context.Context) error {
308333
return nil
309334
}
310335

336+
var invokeGitCredentialsHelper = func(ctx context.Context, path, gitConfigPath, cloudbeesApiURL, cloudbeesApiToken string, filterGitUrls []string) error {
337+
338+
homeDir, err := os.UserHomeDir()
339+
if err != nil {
340+
return err
341+
}
342+
helperConfig := filepath.Join(homeDir, ".git-credential-cloudbees-config")
343+
344+
filterUrlArgs := []string{}
345+
346+
filterUrlArgs = append(filterUrlArgs, "init")
347+
filterUrlArgs = append(filterUrlArgs, "--config", helperConfig)
348+
filterUrlArgs = append(filterUrlArgs, "--cloudbees-api-token-env-var", tokenEnv)
349+
filterUrlArgs = append(filterUrlArgs, "--cloudbees-api-url", cloudbeesApiURL)
350+
filterUrlArgs = append(filterUrlArgs, "--git-config-file-path", gitConfigPath)
351+
for _, filterGitUrl := range filterGitUrls {
352+
filterUrlArgs = append(filterUrlArgs, "--filter-git-urls", filterGitUrl)
353+
}
354+
cmd := exec.CommandContext(ctx, path, filterUrlArgs...)
355+
356+
cmd.Stdout = os.Stdout
357+
cmd.Stderr = os.Stderr
358+
359+
internal.Debug("%s", cmd.String())
360+
361+
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=%s", tokenEnv, cloudbeesApiToken))
362+
363+
return cmd.Run()
364+
}
365+
311366
func (c *Config) providerUsername() string {
312367
switch c.Provider {
313368
case "github":

internal/configuration/config_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
package configuration
22

33
import (
4+
"bytes"
5+
"context"
6+
"os"
7+
"path/filepath"
48
"testing"
59

10+
"github.com/go-git/go-git/v5/config"
11+
format "github.com/go-git/go-git/v5/plumbing/format/config"
12+
"github.com/stretchr/testify/assert"
613
"github.com/stretchr/testify/require"
714
)
815

@@ -603,3 +610,99 @@ func TestConfig_insteadOfURLs(t *testing.T) {
603610
})
604611
}
605612
}
613+
614+
func TestConfig_Apply_Scenarios(t *testing.T) {
615+
originalCfg, _, err := loadConfig(config.GlobalScope)
616+
require.NoError(t, err)
617+
tests := []struct {
618+
name string
619+
config Config
620+
setupCredentialsHelper bool
621+
}{
622+
{
623+
name: "with credentials helper",
624+
config: Config{
625+
Repositories: "user/repo",
626+
Provider: "github",
627+
},
628+
setupCredentialsHelper: true,
629+
},
630+
{
631+
name: "without credentials helper",
632+
config: Config{
633+
Repositories: "user/repo",
634+
Provider: "github",
635+
},
636+
setupCredentialsHelper: false,
637+
},
638+
{
639+
name: "with credentials helper and ssh",
640+
config: Config{
641+
Repositories: "user/repo",
642+
Provider: "github",
643+
SshKey: `-----BEGIN OPENSSH PRIVATE KEY-----
644+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
645+
QyNTUxOQAAACB5tesp0633JJ+Q2hfpUXljwtBX263Tq9ENr76NdZ9e3wAAAKAFw5AuBcOQ
646+
LgAAAAtzc2gtZWQyNTUxOQAAACB5tesp0633JJ+Q2hfpUXljwtBX263Tq9ENr76NdZ9e3w
647+
AAAEApe1n3xwD4plUvs5E82QSBggtUz1M6HiiaVEYWp7ybpnm16ynTrfckn5DaF+lReWPC
648+
0FfbrdOr0Q2vvo11n17fAAAAFnlvdXJfZW1haWxAZXhhbXBsZS5jb20BAgMEBQYH
649+
-----END OPENSSH PRIVATE KEY-----
650+
`,
651+
},
652+
setupCredentialsHelper: true,
653+
},
654+
}
655+
656+
for _, tt := range tests {
657+
t.Run(tt.name, func(t *testing.T) {
658+
// Reset the credentials helper invocation flag
659+
gitCredentialsHelperInvoked := false
660+
661+
// mock credentials helper function
662+
invokeGitCredentialsHelper = func(ctx context.Context, path, gitConfigPath, cloudbeesApiURL, cloudbeesApiToken string, filterGitUrls []string) error {
663+
gitCredentialsHelperInvoked = true
664+
return nil
665+
}
666+
667+
// mock loadConfig helper function
668+
loadConfig = func(scope config.Scope) (_ *format.Config, _ string, retErr error) {
669+
670+
tempGitConfig := filepath.Join(t.TempDir(), ".gitconfig")
671+
672+
var b bytes.Buffer
673+
err = format.NewEncoder(&b).Encode(originalCfg)
674+
require.NoError(t, err)
675+
676+
err = os.WriteFile(tempGitConfig, b.Bytes(), 0666)
677+
require.NoError(t, err)
678+
679+
return originalCfg, tempGitConfig, nil
680+
}
681+
682+
if tt.setupCredentialsHelper {
683+
helperBinary(t)
684+
}
685+
686+
// Execute the Apply method
687+
err := tt.config.Apply(context.Background())
688+
assert.NoError(t, err)
689+
690+
if tt.config.ssh() {
691+
assert.Equal(t, false, gitCredentialsHelperInvoked)
692+
} else {
693+
assert.Equal(t, tt.setupCredentialsHelper, gitCredentialsHelperInvoked)
694+
}
695+
696+
})
697+
}
698+
}
699+
700+
func helperBinary(t *testing.T) {
701+
binPath := filepath.Join(t.TempDir(), cbGitCredentialsHelperPath)
702+
err := os.WriteFile(binPath, []byte("dummy git credential helper"), 0500)
703+
require.NoError(t, err)
704+
705+
err = os.Setenv("PATH", filepath.Dir(binPath))
706+
require.NoError(t, err)
707+
708+
}

internal/util.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package internal
2+
3+
import (
4+
"fmt"
5+
"os"
6+
)
7+
8+
func Debug(msg string, args ...any) {
9+
if os.Getenv("RUNNER_DEBUG") == "1" {
10+
fmt.Println("##[debug]" + fmt.Sprintf(msg, args...))
11+
}
12+
}

0 commit comments

Comments
 (0)