cli/pkg/cmd/auth/gitcredential/helper_test.go
Mislav Marohnić 6701b526d1 Fix authenticating git operations after auth login --with-token
After completing the interactive `gh auth login` flow, the `hosts.yml`
config file will have been populated with both `oauth_token` and `user`
properties for the GitHub host. However, after `auth login --with-token`
only the `oauth_token` is persisted but no username.

This fixes `auth git-credential` behavior so it allows authentication
even if the `user` property is missing. It's entirely optional to send a
proper username for git authentication, since GitHub seems to ignore the
actual value sent and just focuses on the token itself.
2022-02-09 00:10:10 +01:00

235 lines
5.2 KiB
Go

package login
import (
"fmt"
"testing"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/v2/pkg/iostreams"
)
// why not just use the config stub argh
type tinyConfig map[string]string
func (c tinyConfig) GetWithSource(host, key string) (string, string, error) {
return c[fmt.Sprintf("%s:%s", host, key)], c["_source"], nil
}
func Test_helperRun(t *testing.T) {
tests := []struct {
name string
opts CredentialOptions
input string
wantStdout string
wantStderr string
wantErr bool
}{
{
name: "host only, credentials found",
opts: CredentialOptions{
Operation: "get",
Config: func() (config, error) {
return tinyConfig{
"_source": "/Users/monalisa/.config/gh/hosts.yml",
"example.com:user": "monalisa",
"example.com:oauth_token": "OTOKEN",
}, nil
},
},
input: heredoc.Doc(`
protocol=https
host=example.com
`),
wantErr: false,
wantStdout: heredoc.Doc(`
protocol=https
host=example.com
username=monalisa
password=OTOKEN
`),
wantStderr: "",
},
{
name: "host plus user",
opts: CredentialOptions{
Operation: "get",
Config: func() (config, error) {
return tinyConfig{
"_source": "/Users/monalisa/.config/gh/hosts.yml",
"example.com:user": "monalisa",
"example.com:oauth_token": "OTOKEN",
}, nil
},
},
input: heredoc.Doc(`
protocol=https
host=example.com
username=monalisa
`),
wantErr: false,
wantStdout: heredoc.Doc(`
protocol=https
host=example.com
username=monalisa
password=OTOKEN
`),
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{
Operation: "get",
Config: func() (config, error) {
return tinyConfig{
"_source": "/Users/monalisa/.config/gh/hosts.yml",
"example.com:user": "monalisa",
"example.com:oauth_token": "OTOKEN",
}, nil
},
},
input: heredoc.Doc(`
url=https://monalisa@example.com
`),
wantErr: false,
wantStdout: heredoc.Doc(`
protocol=https
host=example.com
username=monalisa
password=OTOKEN
`),
wantStderr: "",
},
{
name: "host only, no credentials found",
opts: CredentialOptions{
Operation: "get",
Config: func() (config, error) {
return tinyConfig{
"_source": "/Users/monalisa/.config/gh/hosts.yml",
"example.com:user": "monalisa",
}, nil
},
},
input: heredoc.Doc(`
protocol=https
host=example.com
`),
wantErr: true,
wantStdout: "",
wantStderr: "",
},
{
name: "user mismatch",
opts: CredentialOptions{
Operation: "get",
Config: func() (config, error) {
return tinyConfig{
"_source": "/Users/monalisa/.config/gh/hosts.yml",
"example.com:user": "monalisa",
"example.com:oauth_token": "OTOKEN",
}, nil
},
},
input: heredoc.Doc(`
protocol=https
host=example.com
username=hubot
`),
wantErr: true,
wantStdout: "",
wantStderr: "",
},
{
name: "no username configured",
opts: CredentialOptions{
Operation: "get",
Config: func() (config, error) {
return tinyConfig{
"_source": "/Users/monalisa/.config/gh/hosts.yml",
"example.com:oauth_token": "OTOKEN",
}, nil
},
},
input: heredoc.Doc(`
protocol=https
host=example.com
`),
wantErr: false,
wantStdout: heredoc.Doc(`
protocol=https
host=example.com
username=x-access-token
password=OTOKEN
`),
wantStderr: "",
},
{
name: "token from env",
opts: CredentialOptions{
Operation: "get",
Config: func() (config, error) {
return tinyConfig{
"_source": "GITHUB_ENTERPRISE_TOKEN",
"example.com:oauth_token": "OTOKEN",
}, nil
},
},
input: heredoc.Doc(`
protocol=https
host=example.com
username=hubot
`),
wantErr: false,
wantStdout: heredoc.Doc(`
protocol=https
host=example.com
username=x-access-token
password=OTOKEN
`),
wantStderr: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
io, stdin, stdout, stderr := iostreams.Test()
fmt.Fprint(stdin, tt.input)
opts := &tt.opts
opts.IO = io
if err := helperRun(opts); (err != nil) != tt.wantErr {
t.Fatalf("helperRun() error = %v, wantErr %v", err, tt.wantErr)
}
if tt.wantStdout != stdout.String() {
t.Errorf("stdout: got %q, wants %q", stdout.String(), tt.wantStdout)
}
if tt.wantStderr != stderr.String() {
t.Errorf("stderr: got %q, wants %q", stderr.String(), tt.wantStderr)
}
})
}
}