Commit 39891ac
Discovery-driven login with workspace selection for SPOG hosts (#4809)
## Why
SPOG (Single Pane of Glass) hosts use one URL for both account-level and
workspace-level APIs. The CLI's login flow doesn't call the
`.well-known/databricks-config` discovery endpoint, so it can't detect
SPOG hosts. This means `account_id` and `workspace_id` don't get
populated for SPOG profiles, and users of multi-workspace SPOG accounts
have no way to set `workspace_id` through the interactive login flow.
## Changes
The CLI now calls discovery during login to detect SPOG hosts and
auto-populate fields. Users can also paste browser URLs with query
params directly into `auth login`.
**Before:** SPOG hosts classified as regular workspace hosts. No
account_id/workspace_id discovery. Users must manually edit
`.databrickscfg`.
**Now:** Discovery runs automatically during login. SPOG fields are
populated from `.well-known/databricks-config`. Multi-workspace accounts
get an interactive workspace picker.
Concrete changes:
- **URL query param parsing** in `setHostAndAccountId()`: extracts `?o=`
(workspace_id) and `?a=` (account_id) from host URLs, strips query
params from host. Explicit flags take precedence over URL params.
- **Host metadata discovery**: calls `EnsureResolved()` with a temporary
config during login to fetch `.well-known/databricks-config`. Populates
account_id/workspace_id if not already set. Best-effort, never blocks
login on failure.
- **`ToOAuthArgument()` refactored**: routes OAuth flow based on
`DiscoveryURL` from `EnsureResolved()` instead of
`Experimental_IsUnifiedHost` flag. Account-scoped OIDC endpoints
(`/oidc/accounts/`) trigger unified OAuth. Classic workspace hosts are
never misrouted.
- **Profile matching simplified**: `MatchWorkspaceProfiles()` uses
`WorkspaceID != ""` presence. `MatchAccountProfiles()` uses `AccountID
!= "" && WorkspaceID == ""`. Both still handle legacy `IsUnifiedHost`
profiles.
- **Post-auth workspace selection**: for SPOG hosts with account_id but
no workspace_id, prompts user to select from `Workspaces.List()`.
Auto-selects single workspace. Capped at 50 entries. Skippable.
Non-interactive mode proceeds without selection.
- **Token path updated**: `loadToken()` uses workspace_id for
disambiguation when matching multi-workspace SPOG profiles.
**Note on discovery in `ToOAuthArgument()`:** This function now calls
`EnsureResolved()` on every invocation, which makes an unauthenticated
HTTP request to `{host}/.well-known/databricks-config`. This is a
deliberate tradeoff. The alternative was to persist additional state
(like `discovery_url` or `experimental_is_unified_host`) to
`.databrickscfg` so we could route the OAuth flow without a network
call. We chose not to do that because we want to move away from
persisting host-type markers to profiles and instead derive behavior
from the host at runtime. The added latency (~100ms per call) will be
addressed by a separate discovery caching PR that caches
`.well-known/databricks-config` responses with a 1-hour TTL, making
repeated calls essentially free.
Backward compatibility:
- Existing profiles with `experimental_is_unified_host = true` still
work (legacy fallback in `ToOAuthArgument()`)
- Classic `accounts.*` login flow unchanged
- Regular workspace login unchanged
- `--experimental-is-unified-host` flag preserved in re-auth error
messages
## Test plan
- [x] Table-driven tests for URL query param parsing (all param
combinations, explicit flag precedence, invalid URLs)
- [x] Discovery tests with mock HTTP server (SPOG host, classic
workspace host, discovery failure)
- [x] `ToOAuthArgument()` routing tests (SPOG -> unified, classic
workspace not misrouted, env var contamination prevented, legacy
IsUnifiedHost fallback)
- [x] Profile matching tests (all profile types: regular workspace,
regular account, SPOG workspace, SPOG account, legacy unified)
- [x] Token path profile disambiguation tests (workspace_id matching for
multi-workspace SPOG)
- [x] `IsAccountsHost()` helper tests
- [x] `make checks` passes
- [x] All existing auth tests pass
---------
Co-authored-by: Andrew Nester <andrew.nester.dev@gmail.com>1 parent 19f9dbe commit 39891ac
File tree
25 files changed
+801
-110
lines changed- acceptance/cmd/auth/login
- configure-serverless
- custom-config-file
- host-arg-overrides-profile
- host-from-profile
- nominal
- preserve-fields
- with-scopes
- cmd/auth
- testdata
- libs
- auth
- databrickscfg/profile
25 files changed
+801
-110
lines changedLines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
4 | 5 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
6 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
21 | | - | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
6 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
16 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
6 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
16 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
6 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
0 commit comments