diff --git a/internal/ghinstance/host.go b/internal/ghinstance/host.go index 146a94e77..b96852a4d 100644 --- a/internal/ghinstance/host.go +++ b/internal/ghinstance/host.go @@ -72,13 +72,23 @@ func RESTPrefix(hostname string) string { } func GistPrefix(hostname string) string { + prefix := "https://" + + if strings.EqualFold(hostname, localhost) { + prefix = "http://" + } + + return prefix + GistHost(hostname) +} + +func GistHost(hostname string) string { if IsEnterprise(hostname) { - return fmt.Sprintf("https://%s/gist/", hostname) + return fmt.Sprintf("%s/gist/", hostname) } if strings.EqualFold(hostname, localhost) { - return fmt.Sprintf("http://%s/gist/", hostname) + return fmt.Sprintf("%s/gist/", hostname) } - return fmt.Sprintf("https://gist.%s/", hostname) + return fmt.Sprintf("gist.%s/", hostname) } func HostPrefix(hostname string) string { diff --git a/pkg/cmd/auth/gitcredential/helper.go b/pkg/cmd/auth/gitcredential/helper.go index 8d1ab7ff3..117584b34 100644 --- a/pkg/cmd/auth/gitcredential/helper.go +++ b/pkg/cmd/auth/gitcredential/helper.go @@ -100,12 +100,18 @@ func helperRun(opts *CredentialOptions) error { return err } + lookupHost := wants["host"] var gotUser string - gotToken, source, _ := cfg.GetWithSource(wants["host"], "oauth_token") + gotToken, source, _ := cfg.GetWithSource(lookupHost, "oauth_token") + if gotToken == "" && strings.HasPrefix(lookupHost, "gist.") { + lookupHost = strings.TrimPrefix(lookupHost, "gist.") + gotToken, source, _ = cfg.GetWithSource(lookupHost, "oauth_token") + } + if strings.HasSuffix(source, "_TOKEN") { gotUser = tokenUser } else { - gotUser, _, _ = cfg.GetWithSource(wants["host"], "user") + gotUser, _, _ = cfg.GetWithSource(lookupHost, "user") } if gotUser == "" || gotToken == "" { diff --git a/pkg/cmd/auth/gitcredential/helper_test.go b/pkg/cmd/auth/gitcredential/helper_test.go index 7e30ec495..c06d6877f 100644 --- a/pkg/cmd/auth/gitcredential/helper_test.go +++ b/pkg/cmd/auth/gitcredential/helper_test.go @@ -74,6 +74,32 @@ func Test_helperRun(t *testing.T) { `), wantStderr: "", }, + { + name: "gist host", + opts: CredentialOptions{ + Operation: "get", + Config: func() (config, error) { + return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", + "github.com:user": "monalisa", + "github.com:oauth_token": "OTOKEN", + }, nil + }, + }, + input: heredoc.Doc(` + protocol=https + host=gist.github.com + username=monalisa + `), + wantErr: false, + wantStdout: heredoc.Doc(` + protocol=https + host=gist.github.com + username=monalisa + password=OTOKEN + `), + wantStderr: "", + }, { name: "url input", opts: CredentialOptions{ diff --git a/pkg/cmd/auth/shared/git_credential.go b/pkg/cmd/auth/shared/git_credential.go index 9e47bcc7e..fb8ba31c2 100644 --- a/pkg/cmd/auth/shared/git_credential.go +++ b/pkg/cmd/auth/shared/git_credential.go @@ -63,25 +63,46 @@ func (flow *GitCredentialFlow) Setup(hostname, username, authToken string) error func (flow *GitCredentialFlow) gitCredentialSetup(hostname, username, password string) error { if flow.helper == "" { - // first use a blank value to indicate to git we want to sever the chain of credential helpers - preConfigureCmd, err := git.GitCommand("config", "--global", "--replace-all", gitCredentialHelperKey(hostname), "") - if err != nil { - return err - } - if err = run.PrepareCmd(preConfigureCmd).Run(); err != nil { - return err + credHelperKeys := []string{ + gitCredentialHelperKey(hostname), } - // use GitHub CLI as a credential helper (for this host only) - configureCmd, err := git.GitCommand( - "config", "--global", "--add", - gitCredentialHelperKey(hostname), - fmt.Sprintf("!%s auth git-credential", shellQuote(flow.Executable)), - ) - if err != nil { - return err + gistHost := strings.TrimSuffix(ghinstance.GistHost(hostname), "/") + if strings.HasPrefix(gistHost, "gist.") { + credHelperKeys = append(credHelperKeys, gitCredentialHelperKey(gistHost)) } - return run.PrepareCmd(configureCmd).Run() + + var configErr error + + for _, credHelperKey := range credHelperKeys { + if configErr != nil { + break + } + // first use a blank value to indicate to git we want to sever the chain of credential helpers + preConfigureCmd, err := git.GitCommand("config", "--global", "--replace-all", credHelperKey, "") + if err != nil { + configErr = err + break + } + if err = run.PrepareCmd(preConfigureCmd).Run(); err != nil { + configErr = err + break + } + + // second configure the actual helper for this host + configureCmd, err := git.GitCommand( + "config", "--global", "--add", + credHelperKey, + fmt.Sprintf("!%s auth git-credential", shellQuote(flow.Executable)), + ) + if err != nil { + configErr = err + } else { + configErr = run.PrepareCmd(configureCmd).Run() + } + } + + return configErr } // clear previous cached credentials @@ -121,7 +142,8 @@ func (flow *GitCredentialFlow) gitCredentialSetup(hostname, username, password s } func gitCredentialHelperKey(hostname string) string { - return fmt.Sprintf("credential.%s.helper", strings.TrimSuffix(ghinstance.HostPrefix(hostname), "/")) + host := strings.TrimSuffix(ghinstance.HostPrefix(hostname), "/") + return fmt.Sprintf("credential.%s.helper", host) } func gitCredentialHelper(hostname string) (helper string, err error) { diff --git a/pkg/cmd/auth/shared/git_credential_test.go b/pkg/cmd/auth/shared/git_credential_test.go index dfdb72db9..fe674e1d7 100644 --- a/pkg/cmd/auth/shared/git_credential_test.go +++ b/pkg/cmd/auth/shared/git_credential_test.go @@ -22,7 +22,54 @@ func TestGitCredentialSetup_configureExisting(t *testing.T) { } } -func TestGitCredentialSetup_setOurs(t *testing.T) { +func TestGitCredentialsSetup_setOurs_GH(t *testing.T) { + cs, restoreRun := run.Stub() + defer restoreRun(t) + cs.Register(`git config --global --replace-all credential\.`, 0, "", func(args []string) { + if key := args[len(args)-2]; key != "credential.https://github.com.helper" { + t.Errorf("git config key was %q", key) + } + if val := args[len(args)-1]; val != "" { + t.Errorf("global credential helper configured to %q", val) + } + }) + cs.Register(`git config --global --add credential\.`, 0, "", func(args []string) { + if key := args[len(args)-2]; key != "credential.https://github.com.helper" { + t.Errorf("git config key was %q", key) + } + if val := args[len(args)-1]; val != "!/path/to/gh auth git-credential" { + t.Errorf("global credential helper configured to %q", val) + } + }) + cs.Register(`git config --global --replace-all credential\.`, 0, "", func(args []string) { + if key := args[len(args)-2]; key != "credential.https://gist.github.com.helper" { + t.Errorf("git config key was %q", key) + } + if val := args[len(args)-1]; val != "" { + t.Errorf("global credential helper configured to %q", val) + } + }) + cs.Register(`git config --global --add credential\.`, 0, "", func(args []string) { + if key := args[len(args)-2]; key != "credential.https://gist.github.com.helper" { + t.Errorf("git config key was %q", key) + } + if val := args[len(args)-1]; val != "!/path/to/gh auth git-credential" { + t.Errorf("global credential helper configured to %q", val) + } + }) + + f := GitCredentialFlow{ + Executable: "/path/to/gh", + helper: "", + } + + if err := f.gitCredentialSetup("github.com", "monalisa", "PASSWD"); err != nil { + t.Errorf("GitCredentialSetup() error = %v", err) + } + +} + +func TestGitCredentialSetup_setOurs_nonGH(t *testing.T) { cs, restoreRun := run.Stub() defer restoreRun(t) cs.Register(`git config --global --replace-all credential\.`, 0, "", func(args []string) {