From 9c30e5536cb4cb833d65444d5708813c2f23d059 Mon Sep 17 00:00:00 2001 From: Peter Guy Date: Mon, 16 Mar 2026 16:47:40 -0700 Subject: [PATCH 1/2] no longer accept the endpoint on the command line - require SSRC_ENDPOINT --- cmd/src/login.go | 57 ++++++++++++--------------------------- cmd/src/login_oauth.go | 2 +- cmd/src/login_test.go | 42 +++++++---------------------- cmd/src/login_validate.go | 7 ----- 4 files changed, 28 insertions(+), 80 deletions(-) diff --git a/cmd/src/login.go b/cmd/src/login.go index 60cc1698b6..153cd8143b 100644 --- a/cmd/src/login.go +++ b/cmd/src/login.go @@ -9,7 +9,6 @@ import ( "os" "github.com/sourcegraph/src-cli/internal/api" - "github.com/sourcegraph/src-cli/internal/cmderrors" "github.com/sourcegraph/src-cli/internal/oauth" ) @@ -22,53 +21,37 @@ Usage: Examples: - Authenticate to a Sourcegraph instance at https://sourcegraph.example.com: + Authenticate to a Sourcegraph instance specified in the SRC_ENDPOINT environment variable: - $ src login https://sourcegraph.example.com + $ src login - Authenticate to Sourcegraph.com: + Override the SRC_ENDPOINT environment variable: - $ src login https://sourcegraph.com + $ SRC_ENDPOINT=https://sourcegraph.example.com src login If no access token is configured, 'src login' uses OAuth device flow automatically: - $ src login https://sourcegraph.com + $ unset SRC_ENDPOINT + $ src login ` flagSet := flag.NewFlagSet("login", flag.ExitOnError) usageFunc := func() { fmt.Fprintln(flag.CommandLine.Output(), usage) - flagSet.PrintDefaults() } - var ( - apiFlags = api.NewFlags(flagSet) - ) - handler := func(args []string) error { if err := flagSet.Parse(args); err != nil { return err } - var loginEndpointURL *url.URL - if flagSet.NArg() >= 1 { - arg := flagSet.Arg(0) - u, err := parseEndpoint(arg) - if err != nil { - return cmderrors.Usage(fmt.Sprintf("invalid endpoint URL: %s", arg)) - } - loginEndpointURL = u - } - - client := cfg.apiClient(apiFlags, io.Discard) + client := cfg.apiClient(nil, io.Discard) return loginCmd(context.Background(), loginParams{ - cfg: cfg, - client: client, - out: os.Stdout, - apiFlags: apiFlags, - oauthClient: oauth.NewClient(oauth.DefaultClientID), - loginEndpointURL: loginEndpointURL, + cfg: cfg, + client: client, + out: os.Stdout, + oauthClient: oauth.NewClient(oauth.DefaultClientID), }) } @@ -80,12 +63,10 @@ Examples: } type loginParams struct { - cfg *config - client api.Client - out io.Writer - apiFlags *api.Flags - oauthClient oauth.Client - loginEndpointURL *url.URL + cfg *config + client api.Client + out io.Writer + oauthClient oauth.Client } type loginFlow func(context.Context, loginParams) error @@ -95,7 +76,6 @@ type loginFlowKind int const ( loginFlowOAuth loginFlowKind = iota loginFlowMissingAuth - loginFlowEndpointConflict loginFlowValidate ) @@ -111,9 +91,6 @@ func loginCmd(ctx context.Context, p loginParams) error { // selectLoginFlow decides what login flow to run based on configured AuthMode. func selectLoginFlow(p loginParams) (loginFlowKind, loginFlow) { - if p.loginEndpointURL != nil && p.loginEndpointURL.String() != p.cfg.endpointURL.String() { - return loginFlowEndpointConflict, runEndpointConflictLogin - } switch p.cfg.AuthMode() { case AuthModeOAuth: return loginFlowOAuth, runOAuthLogin @@ -136,6 +113,6 @@ func loginAccessTokenMessage(endpointURL *url.URL) string { To verify that it's working, run the login command again. - Alternatively, you can try logging in interactively by running: src login %s -`, endpointURL, endpointURL, endpointURL) + Alternatively, you can try logging in interactively by running: src login +`, endpointURL, endpointURL) } diff --git a/cmd/src/login_oauth.go b/cmd/src/login_oauth.go index 1e404d6447..d9e873bdf6 100644 --- a/cmd/src/login_oauth.go +++ b/cmd/src/login_oauth.go @@ -61,7 +61,7 @@ func newOAuthAPIClient(p loginParams, token *oauth.Token) api.Client { return api.NewClient(api.ClientOpts{ EndpointURL: p.cfg.endpointURL, AdditionalHeaders: p.cfg.additionalHeaders, - Flags: p.apiFlags, + Flags: nil, Out: p.out, ProxyURL: p.cfg.proxyURL, ProxyPath: p.cfg.proxyPath, diff --git a/cmd/src/login_test.go b/cmd/src/login_test.go index 85e79816b2..80c4184a36 100644 --- a/cmd/src/login_test.go +++ b/cmd/src/login_test.go @@ -26,33 +26,22 @@ func mustParseURL(t *testing.T, raw string) *url.URL { } func TestLogin(t *testing.T) { - check := func(t *testing.T, cfg *config, endpointArgURL *url.URL) (output string, err error) { + check := func(t *testing.T, cfg *config) (output string, err error) { t.Helper() var out bytes.Buffer err = loginCmd(context.Background(), loginParams{ - cfg: cfg, - client: cfg.apiClient(nil, io.Discard), - out: &out, - oauthClient: fakeOAuthClient{startErr: fmt.Errorf("oauth unavailable")}, - loginEndpointURL: endpointArgURL, + cfg: cfg, + client: cfg.apiClient(nil, io.Discard), + out: &out, + oauthClient: fakeOAuthClient{startErr: fmt.Errorf("oauth unavailable")}, }) return strings.TrimSpace(out.String()), err } - t.Run("different endpoint in config vs. arg", func(t *testing.T) { - out, err := check(t, &config{endpointURL: &url.URL{Scheme: "https", Host: "example.com"}}, &url.URL{Scheme: "https", Host: "sourcegraph.example.com"}) - if err == nil { - t.Fatal(err) - } - if !strings.Contains(out, "The configured endpoint is https://example.com, not https://sourcegraph.example.com.") { - t.Errorf("got output %q, want configured endpoint error", out) - } - }) - t.Run("no access token triggers oauth flow", func(t *testing.T) { u := &url.URL{Scheme: "https", Host: "example.com"} - out, err := check(t, &config{endpointURL: u}, u) + out, err := check(t, &config{endpointURL: u}) if err == nil { t.Fatal(err) } @@ -63,7 +52,7 @@ func TestLogin(t *testing.T) { t.Run("warning when using config file", func(t *testing.T) { endpoint := &url.URL{Scheme: "https", Host: "example.com"} - out, err := check(t, &config{endpointURL: endpoint, configFilePath: "f"}, endpoint) + out, err := check(t, &config{endpointURL: endpoint, configFilePath: "f"}) if err != cmderrors.ExitCode1 { t.Fatal(err) } @@ -82,11 +71,11 @@ func TestLogin(t *testing.T) { defer s.Close() u := mustParseURL(t, s.URL) - out, err := check(t, &config{endpointURL: u, accessToken: "x"}, u) + out, err := check(t, &config{endpointURL: u, accessToken: "x"}) if err != cmderrors.ExitCode1 { t.Fatal(err) } - wantOut := "āŒ Problem: Invalid access token.\n\nšŸ›  To fix: Create an access token by going to $ENDPOINT/user/settings/tokens, then set the following environment variables in your terminal:\n\n export SRC_ENDPOINT=$ENDPOINT\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 interactively by running: src login $ENDPOINT\n\n (If you need to supply custom HTTP request headers, see information about SRC_HEADER_* and SRC_HEADERS env vars at https://github.com/sourcegraph/src-cli/blob/main/AUTH_PROXY.md)" + wantOut := "āŒ Problem: Invalid access token.\n\nšŸ›  To fix: Create an access token by going to $ENDPOINT/user/settings/tokens, then set the following environment variables in your terminal:\n\n export SRC_ENDPOINT=$ENDPOINT\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 interactively by running: src login\n\n (If you need to supply custom HTTP request headers, see information about SRC_HEADER_* and SRC_HEADERS env vars at https://github.com/sourcegraph/src-cli/blob/main/AUTH_PROXY.md)" wantOut = strings.ReplaceAll(wantOut, "$ENDPOINT", s.URL) if out != wantOut { t.Errorf("got output %q, want %q", out, wantOut) @@ -100,7 +89,7 @@ func TestLogin(t *testing.T) { defer s.Close() u := mustParseURL(t, s.URL) - out, err := check(t, &config{endpointURL: u, accessToken: "x"}, u) + out, err := check(t, &config{endpointURL: u, accessToken: "x"}) if err != nil { t.Fatal(err) } @@ -192,17 +181,6 @@ func TestSelectLoginFlow(t *testing.T) { } }) - t.Run("uses endpoint conflict flow when auth exists for a different endpoint", func(t *testing.T) { - params := loginParams{ - cfg: &config{endpointURL: mustParseURL(t, "https://example.com"), accessToken: "x"}, - loginEndpointURL: mustParseURL(t, "https://sourcegraph.example.com"), - } - - if got, _ := selectLoginFlow(params); got != loginFlowEndpointConflict { - t.Fatalf("flow = %v, want %v", got, loginFlowEndpointConflict) - } - }) - t.Run("uses validation flow when auth exists for the selected endpoint", func(t *testing.T) { params := loginParams{ cfg: &config{endpointURL: mustParseURL(t, "https://example.com"), accessToken: "x"}, diff --git a/cmd/src/login_validate.go b/cmd/src/login_validate.go index 9aa65cdcef..4b373c6247 100644 --- a/cmd/src/login_validate.go +++ b/cmd/src/login_validate.go @@ -18,13 +18,6 @@ func runMissingAuthLogin(_ context.Context, p loginParams) error { return cmderrors.ExitCode1 } -func runEndpointConflictLogin(_ context.Context, p loginParams) error { - fmt.Fprintln(p.out) - printLoginProblem(p.out, fmt.Sprintf("The configured endpoint is %s, not %s.", p.cfg.endpointURL, p.loginEndpointURL)) - fmt.Fprintln(p.out, loginAccessTokenMessage(p.loginEndpointURL)) - return cmderrors.ExitCode1 -} - func runValidatedLogin(ctx context.Context, p loginParams) error { return validateCurrentUser(ctx, p.client, p.out, p.cfg.endpointURL) } From 77b5c9dc5b73e754c54802ff693c0bfe1361744f Mon Sep 17 00:00:00 2001 From: Peter Guy Date: Mon, 16 Mar 2026 20:48:35 -0700 Subject: [PATCH 2/2] return a usage error if the command-line is still used --- cmd/src/login.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/src/login.go b/cmd/src/login.go index 153cd8143b..2ab94c88eb 100644 --- a/cmd/src/login.go +++ b/cmd/src/login.go @@ -9,6 +9,7 @@ import ( "os" "github.com/sourcegraph/src-cli/internal/api" + "github.com/sourcegraph/src-cli/internal/cmderrors" "github.com/sourcegraph/src-cli/internal/oauth" ) @@ -45,6 +46,10 @@ Examples: return err } + if flagSet.NArg() > 0 { + return cmderrors.Usage("src login no longer accepts a URL argument; set SRC_ENDPOINT instead") + } + client := cfg.apiClient(nil, io.Discard) return loginCmd(context.Background(), loginParams{