Skip to content

Commit 2647a9e

Browse files
committed
decide loginFlow based on config AuthMode
1 parent d87db35 commit 2647a9e

File tree

2 files changed

+54
-73
lines changed

2 files changed

+54
-73
lines changed

cmd/src/login.go

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ const (
103103
loginFlowValidate
104104
)
105105

106-
var loadStoredOAuthToken = oauth.LoadToken
107-
108106
func loginCmd(ctx context.Context, p loginParams) error {
109107
if p.cfg.ConfigFilePath != "" {
110108
fmt.Fprintln(p.out)
@@ -115,34 +113,25 @@ func loginCmd(ctx context.Context, p loginParams) error {
115113
return flow(ctx, p)
116114
}
117115

118-
// selectLoginFlow decides what login flow to run based on flags and config.
119-
func selectLoginFlow(ctx context.Context, p loginParams) (loginFlowKind, loginFlow) {
116+
// selectLoginFlow decides what login flow to run based on configigured AuthMode.
117+
func selectLoginFlow(_ context.Context, p loginParams) (loginFlowKind, loginFlow) {
120118
endpointArg := cleanEndpoint(p.endpoint)
121119

122120
if p.useOAuth {
123121
return loginFlowOAuth, runOAuthLogin
124122
}
125-
if !hasEffectiveAuth(ctx, p.cfg, endpointArg) {
126-
return loginFlowMissingAuth, runMissingAuthLogin
127-
}
128-
if endpointArg != p.cfg.Endpoint {
129-
return loginFlowEndpointConflict, runEndpointConflictLogin
130-
}
131-
return loginFlowValidate, runValidatedLogin
132-
}
133123

134-
// hasEffectiveAuth determines whether we have auth credentials to continue. It first checks for a resolved Access Token in
135-
// config, then it checks for a stored OAuth token.
136-
func hasEffectiveAuth(ctx context.Context, cfg *config, resolvedEndpoint string) bool {
137-
if cfg.AccessToken != "" {
138-
return true
139-
}
140-
141-
if _, err := loadStoredOAuthToken(ctx, resolvedEndpoint); err == nil {
142-
return true
124+
switch p.cfg.AuthMode() {
125+
case AuthModeOAuth:
126+
return loginFlowOAuth, runOAuthLogin
127+
case AuthModeAccessToken:
128+
if endpointArg != p.cfg.Endpoint {
129+
return loginFlowEndpointConflict, runEndpointConflictLogin
130+
}
131+
return loginFlowValidate, runValidatedLogin
132+
default:
133+
return loginFlowMissingAuth, runMissingAuthLogin
143134
}
144-
145-
return false
146135
}
147136

148137
func printLoginProblem(out io.Writer, problem string) {

cmd/src/login_test.go

Lines changed: 42 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/http/httptest"
1010
"strings"
1111
"testing"
12+
"time"
1213

1314
"github.com/sourcegraph/src-cli/internal/cmderrors"
1415
"github.com/sourcegraph/src-cli/internal/oauth"
@@ -18,51 +19,47 @@ func TestLogin(t *testing.T) {
1819
check := func(t *testing.T, cfg *config, endpointArg string) (output string, err error) {
1920
t.Helper()
2021

21-
restoreStoredOAuthLoader(t, func(context.Context, string) (*oauth.Token, error) {
22-
return nil, fmt.Errorf("not found")
23-
})
24-
2522
var out bytes.Buffer
2623
err = loginCmd(context.Background(), loginParams{
2724
cfg: cfg,
2825
client: cfg.apiClient(nil, io.Discard),
2926
endpoint: endpointArg,
3027
out: &out,
31-
oauthClient: oauth.NewClient(oauth.DefaultClientID),
28+
oauthClient: fakeOAuthClient{startErr: fmt.Errorf("oauth unavailable")},
3229
})
3330
return strings.TrimSpace(out.String()), err
3431
}
3532

3633
t.Run("different endpoint in config vs. arg", func(t *testing.T) {
3734
out, err := check(t, &config{Endpoint: "https://example.com"}, "https://sourcegraph.example.com")
38-
if err != cmderrors.ExitCode1 {
35+
if err == nil {
3936
t.Fatal(err)
4037
}
41-
wantOut := "❌ Problem: No access token is configured.\n\n🛠 To fix: Create an access token by going to https://sourcegraph.example.com/user/settings/tokens, then set the following environment variables in your terminal:\n\n export SRC_ENDPOINT=https://sourcegraph.example.com\n export SRC_ACCESS_TOKEN=(your access token)\n\n To verify that it's working, run the login command again.\n\n Alternatively, you can try logging in using OAuth by running: src login --oauth https://sourcegraph.example.com"
42-
if out != wantOut {
43-
t.Errorf("got output %q, want %q", out, wantOut)
38+
if !strings.Contains(out, "OAuth Device flow authentication failed:") {
39+
t.Errorf("got output %q, want oauth failure output", out)
4440
}
4541
})
4642

47-
t.Run("no access token", func(t *testing.T) {
43+
t.Run("no access token triggers oauth flow", func(t *testing.T) {
4844
out, err := check(t, &config{Endpoint: "https://example.com"}, "https://sourcegraph.example.com")
49-
if err != cmderrors.ExitCode1 {
45+
if err == nil {
5046
t.Fatal(err)
5147
}
52-
wantOut := "❌ Problem: No access token is configured.\n\n🛠 To fix: Create an access token by going to https://sourcegraph.example.com/user/settings/tokens, then set the following environment variables in your terminal:\n\n export SRC_ENDPOINT=https://sourcegraph.example.com\n export SRC_ACCESS_TOKEN=(your access token)\n\n To verify that it's working, run the login command again.\n\n Alternatively, you can try logging in using OAuth by running: src login --oauth https://sourcegraph.example.com"
53-
if out != wantOut {
54-
t.Errorf("got output %q, want %q", out, wantOut)
48+
if !strings.Contains(out, "OAuth Device flow authentication failed:") {
49+
t.Errorf("got output %q, want oauth failure output", out)
5550
}
5651
})
5752

5853
t.Run("warning when using config file", func(t *testing.T) {
5954
out, err := check(t, &config{Endpoint: "https://example.com", ConfigFilePath: "f"}, "https://example.com")
60-
if err != cmderrors.ExitCode1 {
55+
if err == nil {
6156
t.Fatal(err)
6257
}
63-
wantOut := "⚠️ Warning: Configuring src with a JSON file is deprecated. Please migrate to using the env vars SRC_ENDPOINT, SRC_ACCESS_TOKEN, and SRC_PROXY instead, and then remove f. See https://github.com/sourcegraph/src-cli#readme for more information.\n\n❌ Problem: No access token is configured.\n\n🛠 To fix: Create an access token by going to https://example.com/user/settings/tokens, then set the following environment variables in your terminal:\n\n export SRC_ENDPOINT=https://example.com\n export SRC_ACCESS_TOKEN=(your access token)\n\n To verify that it's working, run the login command again.\n\n Alternatively, you can try logging in using OAuth by running: src login --oauth https://example.com"
64-
if out != wantOut {
65-
t.Errorf("got output %q, want %q", out, wantOut)
58+
if !strings.Contains(out, "Configuring src with a JSON file is deprecated") {
59+
t.Errorf("got output %q, want deprecation warning", out)
60+
}
61+
if !strings.Contains(out, "OAuth Device flow authentication failed:") {
62+
t.Errorf("got output %q, want oauth failure output", out)
6663
}
6764
})
6865

@@ -103,11 +100,31 @@ func TestLogin(t *testing.T) {
103100
})
104101
}
105102

106-
func TestSelectLoginFlow(t *testing.T) {
107-
restoreStoredOAuthLoader(t, func(context.Context, string) (*oauth.Token, error) {
108-
return nil, fmt.Errorf("not found")
109-
})
103+
type fakeOAuthClient struct {
104+
startErr error
105+
}
106+
107+
func (f fakeOAuthClient) ClientID() string {
108+
return oauth.DefaultClientID
109+
}
110+
111+
func (f fakeOAuthClient) Discover(context.Context, string) (*oauth.OIDCConfiguration, error) {
112+
return nil, fmt.Errorf("unexpected call to Discover")
113+
}
114+
115+
func (f fakeOAuthClient) Start(context.Context, string, []string) (*oauth.DeviceAuthResponse, error) {
116+
return nil, f.startErr
117+
}
118+
119+
func (f fakeOAuthClient) Poll(context.Context, string, string, time.Duration, int) (*oauth.TokenResponse, error) {
120+
return nil, fmt.Errorf("unexpected call to Poll")
121+
}
122+
123+
func (f fakeOAuthClient) Refresh(context.Context, *oauth.Token) (*oauth.TokenResponse, error) {
124+
return nil, fmt.Errorf("unexpected call to Refresh")
125+
}
110126

127+
func TestSelectLoginFlow(t *testing.T) {
111128
t.Run("uses oauth flow when oauth flag is set", func(t *testing.T) {
112129
params := loginParams{
113130
cfg: &config{Endpoint: "https://example.com"},
@@ -120,14 +137,14 @@ func TestSelectLoginFlow(t *testing.T) {
120137
}
121138
})
122139

123-
t.Run("uses missing auth flow when auth is unavailable", func(t *testing.T) {
140+
t.Run("uses oauth flow when no access token is configured", func(t *testing.T) {
124141
params := loginParams{
125142
cfg: &config{Endpoint: "https://example.com"},
126143
endpoint: "https://sourcegraph.example.com",
127144
}
128145

129-
if got, _ := selectLoginFlow(context.Background(), params); got != loginFlowMissingAuth {
130-
t.Fatalf("flow = %v, want %v", got, loginFlowMissingAuth)
146+
if got, _ := selectLoginFlow(context.Background(), params); got != loginFlowOAuth {
147+
t.Fatalf("flow = %v, want %v", got, loginFlowOAuth)
131148
}
132149
})
133150

@@ -152,29 +169,4 @@ func TestSelectLoginFlow(t *testing.T) {
152169
t.Fatalf("flow = %v, want %v", got, loginFlowValidate)
153170
}
154171
})
155-
156-
t.Run("treats stored oauth as effective auth", func(t *testing.T) {
157-
restoreStoredOAuthLoader(t, func(context.Context, string) (*oauth.Token, error) {
158-
return &oauth.Token{AccessToken: "oauth-token"}, nil
159-
})
160-
161-
params := loginParams{
162-
cfg: &config{Endpoint: "https://example.com"},
163-
endpoint: "https://example.com",
164-
}
165-
166-
if got, _ := selectLoginFlow(context.Background(), params); got != loginFlowValidate {
167-
t.Fatalf("flow = %v, want %v", got, loginFlowValidate)
168-
}
169-
})
170-
}
171-
172-
func restoreStoredOAuthLoader(t *testing.T, loader func(context.Context, string) (*oauth.Token, error)) {
173-
t.Helper()
174-
175-
prev := loadStoredOAuthToken
176-
loadStoredOAuthToken = loader
177-
t.Cleanup(func() {
178-
loadStoredOAuthToken = prev
179-
})
180172
}

0 commit comments

Comments
 (0)