Skip to content

[CFX-6319] Actionable recovery path and --timeout on a login timeout - #915

Open
chasdr wants to merge 9 commits into
mainfrom
chas/CFX-6319-timeout-recovery
Open

[CFX-6319] Actionable recovery path and --timeout on a login timeout#915
chasdr wants to merge 9 commits into
mainfrom
chas/CFX-6319-timeout-recovery

Conversation

@chasdr

@chasdr chasdr commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

When dr auth login never gets a browser callback, it sat out the 5-minute timeout and printed a bare Go error with no next step. The usual cause is a recoverable browser-side sign-in error that clears on a retry, so the user was left stuck. This adds an actionable recovery block on timeout, plus a --timeout flag to shorten or extend the wait behind a slow identity provider.

Notes for review

The wait now wraps a new ErrLoginTimedOut sentinel instead of context.DeadlineExceeded. Both callers, dr auth login and the implicit login in EnsureAuthenticated, detect it and print the help to stderr, so --output-format json still leaves stdout clean. Only a timeout prints the help.

The 5-minute hang itself traces to a cross-team OIDC issue (PLT-23376); this is the CLI-side half, useful either way.

Output

Before, the whole message on timeout:

ERROR Failed to retrieve API key. error="timed out after 5m0s waiting for browser authorization: context deadline exceeded"

After (--timeout 2s against a dead endpoint, help to stderr):

$ dr auth login https://nonexistent.invalid --no-browser --timeout 2s
❌ No authorization came back from the browser.

If your browser showed a sign-in error, click through it and run login again.
The sign-in often completes on the second attempt:
  dr auth login

To skip the browser, set both and try again:
  export DATAROBOT_ENDPOINT=https://app.datarobot.com
  export DATAROBOT_API_TOKEN=<token from Developer Tools>

Technical Changes

  • internal/auth/browserflow.go: ErrLoginTimedOut sentinel, FprintLoginTimeoutHelp, LoginOptions.Timeout applied in runLoginWithFlow.
  • internal/auth/auth.go: the implicit login in EnsureAuthenticated prints the help on timeout.
  • cmd/auth/login/cmd.go: --timeout flag; on timeout prints the help and exits quiet, not the raw error.
  • docs: the recovery output and --timeout in the auth command and development docs.
  • 5 tests: the sentinel, the help render, --timeout honored, the implicit path prints help, the flag contract.

Breakdown

  • code: +48 / -4
  • tests: +94 / -1
  • docs: +28 / -1

Note

Low Risk
Changes are limited to login wait UX, error messaging, and an optional timeout flag; credential storage and callback security behavior are unchanged.

Overview
Browser login no longer ends with a raw Go deadline error when the callback never arrives. BrowserFlow.Wait now returns ErrLoginTimedOut, and dr auth login, EnsureAuthenticated, and the setup wizard show recovery guidance (retry dr auth login or use DATAROBOT_ENDPOINT / DATAROBOT_API_TOKEN) via FprintLoginTimeoutHelp or a dedicated wizard message.

dr auth login adds --timeout (default still 5m when unset) with rejection of negative values; timeouts exit with cli.ErrSilent after printing help on stderr. LoginOptions.Timeout applies the override in runLoginWithFlow. The setup errMsg type gains Unwrap so errors.Is can detect timeouts through bubbletea. Docs and tests cover the flag, help output, and timeout paths.

Reviewed by Cursor Bugbot for commit 1d8447d. Configure here.

Wait wraps ErrLoginTimedOut on the deadline. Both callers (dr auth login
and EnsureAuthenticated's implicit login) print FprintLoginTimeoutHelp to
stderr instead of the bare Go timeout string: retry, since a sign-in error
often clears on the second attempt, or set the DATAROBOT_ENDPOINT and
DATAROBOT_API_TOKEN pair to skip the browser.

--timeout overrides the 5m default for a slow identity provider where a
cold SSO sign-in with MFA needs longer.
@datarobot-pr-review-router

Copy link
Copy Markdown

🎫 Jira: CFX-6319 — Auth error "do not have access to this application" is not actionable — no recovery path shown

@chasdr
chasdr marked this pull request as ready for review September 11, 2026 16:05
@chasdr
chasdr requested a review from a team as a code owner September 11, 2026 16:05
@chasdr
chasdr requested a lite review from Copilot and removed request for a team September 11, 2026 16:05
@github-actions github-actions Bot added the go Pull requests that update go code label Sep 11, 2026
cursor[bot]

This comment was marked as resolved.

This comment was marked as resolved.

- FprintLoginTimeoutHelp renders the endpoint the user was logging into
  instead of a hardcoded app.datarobot.com, which pointed EU, JP, and
  on-prem users at the US instance. Reworded so the env-pair line no longer
  implies dr auth login itself skips the browser (it always opens it); the
  pair authenticates the CLI for the commands that run behind the gate.
- Reject a negative --timeout instead of silently falling back to 5m, so a
  typo does not look like a hang.
- Command-level tests for the timeout branch (help to stderr, cli.ErrSilent)
  and the negative-timeout rejection.

This comment was marked as resolved.

cursor[bot]

This comment was marked as resolved.

The env-pair recovery lines printed bash `export`, which is invalid in
PowerShell and cmd.exe. On Windows the help now prints the
`$env:NAME="value"` form, matching how FprintUnsetTokenInstructions
already handles the platform split.

Also: require.ErrorIs before the follow-up assertion (testifylint).
@chasdr
chasdr requested a lite review from Copilot September 11, 2026 16:31
@chasdr

This comment was marked as resolved.

cursor[bot]

This comment was marked as resolved.

This comment was marked as resolved.

Wait has a third consumer, the template setup login model, which rendered
the error verbatim. It now shows a retry/env-pair line on ErrLoginTimedOut,
and that branch takes precedence so a timeout replaces the stale "browser
opening" hint instead of hiding behind it.

Also reworded the Wait error so it no longer repeats the sentinel text.
cursor[bot]

This comment was marked as resolved.

This comment was marked as resolved.

errMsg embedded error without an Unwrap method, so errors.Is against
ErrLoginTimedOut was always false and the friendly timeout line added last
round never showed. Add Unwrap plus a View test that pins the branch.
@chasdr
chasdr requested a lite review from Copilot September 11, 2026 17:08
cursor[bot]

This comment was marked as resolved.

This comment was marked as resolved.

The env-pair recovery lines interpolated the user-configured endpoint into
a copy-paste command unquoted, so a shell metacharacter in the value would
execute when pasted. Single-quote it per shell, matching how dr auth export
already quotes with posixQuote.
cursor[bot]

This comment was marked as resolved.

This comment was marked as resolved.

… command

The env-pair recovery lines printed an exact export command that was wrong
three ways: DATAROBOT_ENDPOINT dropped the /api/v2 path that GetBaseURL
strips (so it would fail verification), the token placeholder's angle
brackets broke a verbatim paste, and the value needed per-shell quoting.
Naming the two variables in prose is correct on every shell and removes the
GOOS branch, the quote helpers, and the endpoint argument.
@chasdr
chasdr requested a lite review from Copilot September 11, 2026 17:37
@chasdr

chasdr commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 1d8447d. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved validation-order, shell-guidance, endpoint-documentation, and comment-completion findings remain.

Review details

Suppressed comments (4)

cmd/auth/login/cmd.go:89

  • This validation runs only after SetURLToConfig, GetBaseURLOrAsk, and config.GetAPIKey(context.Background()). With a stored token or an unreachable configured endpoint, a negative duration can trigger config/API work (or report that error) before the invalid flag is rejected. Read and validate --timeout at the start of RunE, before any URL or credential work.
	timeout, _ := cmd.Flags().GetDuration("timeout")
	if timeout < 0 {
		log.Errorf("--timeout must be zero or positive, got %s", timeout)

		cmd.SilenceUsage = true

		return cli.ErrSilent
	}

cmd/auth/login/cmd.go:98

  • This newly added comment ends with the incomplete fragment “the help block is.” Please complete the sentence so the rationale is readable.
		// The bare timeout error is a Go string with no next step; the help block is.

docs/commands/auth.md:117

  • These instructions omit the API endpoint format. Environment credential verification uses the value verbatim and appends /version/, while dr auth export emits the canonical /api/v2 endpoint; using the base URL shown in the PR's recovery example will probe the wrong path. Include /api/v2 in the example or direct users to the canonical export output.
Or set the DATAROBOT_ENDPOINT and DATAROBOT_API_TOKEN environment variables
(from Developer Tools) to authenticate without the browser.

internal/auth/browserflow.go:179

  • On the timeout path this only names the two variables; it does not provide the shell-specific copy/paste statements promised by the PR's recovery output (including PowerShell/Windows syntax). The existing auth export guidance already handles Bash, PowerShell, and cmd forms, so users—especially on Windows—still have to invent the recovery command here. Add shell-aware examples or a shared formatter.
	fmt.Fprintln(w, base.Render("Or set the DATAROBOT_ENDPOINT and DATAROBOT_API_TOKEN environment variables"))
	fmt.Fprintln(w, base.Render("(from Developer Tools) to authenticate without the browser."))
  • Files reviewed: 10/10 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@datarobot-pr-review-router

Copy link
Copy Markdown

Code Ownership

Cli Maintainers

  • cmd/auth/login/cmd.go
  • cmd/auth/login/cmd_test.go
  • cmd/templates/setup/loginModel.go
  • cmd/templates/setup/loginModel_test.go
  • docs/commands/auth.md
  • docs/development/authentication.md
  • internal/auth/auth.go
  • internal/auth/auth_test.go
  • internal/auth/browserflow.go
  • internal/auth/browserflow_test.go

Review requested from the teams above. Labels will be removed automatically upon approval.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants