diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index ce39d58..88e02c2 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -3,6 +3,7 @@ package auth import ( + "fmt" "os" "os/exec" "strconv" @@ -148,8 +149,15 @@ func defaultHost(cfg *config.Config) (string, string) { return github, defaultSource } +// TenancyHost is the domain name of a tenancy GitHub instance. +const tenancyHost = "ghe.com" + func isEnterprise(host string) bool { - return host != github && host != localhost + return host != github && host != localhost && !isTenancy(host) +} + +func isTenancy(host string) bool { + return strings.HasSuffix(host, "."+tenancyHost) } func normalizeHostname(host string) string { @@ -160,5 +168,21 @@ func normalizeHostname(host string) string { if strings.HasSuffix(hostname, "."+localhost) { return localhost } + // This has been copied over from the cli/cli NormalizeHostname function + // to ensure compatible behaviour but we don't fully understand when or + // why it would be useful here. We can't see what harm will come of + // duplicating the logic. + if before, found := cutSuffix(hostname, "."+tenancyHost); found { + idx := strings.LastIndex(before, ".") + return fmt.Sprintf("%s.%s", before[idx+1:], tenancyHost) + } return hostname } + +// Backport strings.CutSuffix from Go 1.20. +func cutSuffix(s, suffix string) (string, bool) { + if !strings.HasSuffix(s, suffix) { + return s, false + } + return s[:len(s)-len(suffix)], true +} diff --git a/pkg/auth/auth_test.go b/pkg/auth/auth_test.go index 5c18112..a0bb59d 100644 --- a/pkg/auth/auth_test.go +++ b/pkg/auth/auth_test.go @@ -84,6 +84,30 @@ func TestTokenForHost(t *testing.T) { wantToken: "yyyyyyyyyyyyyyyyyyyy", wantSource: "oauth_token", }, + { + name: "token for tenant with GH_TOKEN, GITHUB_TOKEN, and config token", + host: "tenant.ghe.com", + ghToken: "GH_TOKEN", + githubToken: "GITHUB_TOKEN", + config: testHostsConfig(), + wantToken: "GH_TOKEN", + wantSource: "GH_TOKEN", + }, + { + name: "token for tenant with GITHUB_TOKEN, and config token", + host: "tenant.ghe.com", + githubToken: "GITHUB_TOKEN", + config: testHostsConfig(), + wantToken: "GITHUB_TOKEN", + wantSource: "GITHUB_TOKEN", + }, + { + name: "token for tenant with config token", + host: "tenant.ghe.com", + config: testHostsConfig(), + wantToken: "zzzzzzzzzzzzzzzzzzzz", + wantSource: "oauth_token", + }, } for _, tt := range tests { @@ -171,7 +195,7 @@ func TestKnownHosts(t *testing.T) { { name: "includes authenticated hosts", config: testHostsConfig(), - wantHosts: []string{"github.com", "enterprise.com"}, + wantHosts: []string{"github.com", "enterprise.com", "tenant.ghe.com"}, }, { name: "includes default host if environment auth token", @@ -184,7 +208,7 @@ func TestKnownHosts(t *testing.T) { config: testHostsConfig(), ghHost: "test.com", ghToken: "TOKEN", - wantHosts: []string{"test.com", "github.com", "enterprise.com"}, + wantHosts: []string{"test.com", "github.com", "enterprise.com", "tenant.ghe.com"}, }, } @@ -223,6 +247,11 @@ func TestIsEnterprise(t *testing.T) { host: "mygithub.com", wantOut: true, }, + { + name: "tenant", + host: "tenant.ghe.com", + wantOut: false, + }, } for _, tt := range tests { @@ -259,6 +288,16 @@ func TestNormalizeHostname(t *testing.T) { host: "mygithub.com", wantHost: "mygithub.com", }, + { + name: "bare tenant", + host: "tenant.ghe.com", + wantHost: "tenant.ghe.com", + }, + { + name: "subdomained tenant", + host: "api.tenant.ghe.com", + wantHost: "tenant.ghe.com", + }, } for _, tt := range tests { @@ -296,6 +335,10 @@ hosts: user: user2 oauth_token: yyyyyyyyyyyyyyyyyyyy git_protocol: https + tenant.ghe.com: + user: user3 + oauth_token: zzzzzzzzzzzzzzzzzzzz + git_protocol: https ` return config.ReadFromString(data) }