Skip to content

Commit 6327c33

Browse files
Honor [__settings__].default_profile in api, bundle, and auth token (#5214)
## Changes `[__settings__].default_profile` is a CLI-level fallback for the active profile that the SDK does not know about. Until now it was consulted only on the `MustWorkspaceClient` / `MustAccountClient` / `MustAnyClient` paths. Several command surfaces silently ignored it: - `databricks api {get,post,...}` built its own `*config.Config` and only honored `--profile`. - Bundle commands (`databricks bundle`, `databricks pipelines`) read the profile only from `--profile` / `DATABRICKS_CONFIG_PROFILE`. - `databricks auth token` (no positional, no flags, no env) jumped straight to the interactive picker. This PR promotes the resolution logic to `databrickscfg.ResolveDefaultProfile` and applies it from each affected command: - `cmd/api/api.go`: `--profile` flag → `DATABRICKS_CONFIG_PROFILE` env → `default_profile`, then hand off to the SDK. - `cmd/root/bundle.go` (`configureProfile`): falls back to `default_profile` only when the bundle declares no `workspace.host` and no `workspace.profile`. The host-empty guard preserves SDK host-based resolution when the bundle pins its own host. - `cmd/auth/token.go` (`resolveNoArgsToken`): inserts a Step 2.5 between the env-var check and the interactive picker. If the named profile doesn't exist, falls through to the picker (advisory, not fatal). ## Why Users reasonably expect "I set my default to `tmp` — every CLI invocation should default to `tmp`." The previous behavior was inconsistent across command surfaces and surprised users. The bundle host-empty guard is the only subtle bit worth flagging: applying `default_profile` before the SDK sees a bundle's pinned `workspace.host` could silently route the user to a profile pointing at a different host. The guard lets the existing multi-profile-match path (`resolveProfileAmbiguity`) handle host conflicts as before. ## Tests - `libs/databrickscfg/ops_test.go`: matrix tests for `ResolveDefaultProfile` (file present/absent, settings present/absent, parse error, reserved `__settings__` self-reference, default home-file lookup). - `cmd/root/bundle_test.go`: four `TestBundleConfigureWithDefaultProfile_*` unit tests covering the positive case, `--profile` override, `DATABRICKS_CONFIG_PROFILE` override, and the bundle-host-wins guard. - Acceptance tests: - `acceptance/cmd/api/default-profile/` - `acceptance/auth/bundle_default_profile/` (with a bundle-with-host sub-case) - `acceptance/cmd/auth/token/default-profile/` (with a missing-default fall-through case) Each new acceptance test covers the positive case (`default_profile` honored) and the negative case (`--profile` overrides). _This PR was written by Claude Code._
1 parent 9551b6b commit 6327c33

20 files changed

Lines changed: 482 additions & 12 deletions

File tree

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
### CLI
88

99
* Added `databricks aitools` command group for installing Databricks skills into your coding agents (Claude Code, Cursor, Codex CLI, OpenCode, GitHub Copilot, Antigravity). Skills are fetched from [github.com/databricks/databricks-agent-skills](https://github.com/databricks/databricks-agent-skills) and either symlinked into each agent's skills directory or copied into the current project. Use `databricks aitools install` to set up, `update` to pull newer versions, `list` to see what's available, and `uninstall` to remove them.
10+
* `[__settings__].default_profile` is now consulted as a fallback by `databricks api`, `databricks auth token`, and bundle commands when neither `--profile` nor `DATABRICKS_CONFIG_PROFILE` is set. `databricks auth token` continues to give precedence to `DATABRICKS_HOST` over `default_profile`. For bundle commands, `default_profile` only applies when the bundle does not pin its own `workspace.host`.
1011

1112
### Bundles
1213
* Make sure warnings asking for approval are understood by agents ([#5239](https://github.com/databricks/cli/pull/5239))
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
bundle:
2+
name: test-default-profile
3+
4+
# No workspace.host on purpose: this is the surface where
5+
# [__settings__].default_profile should be applied.

acceptance/auth/bundle_default_profile/out.test.toml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
=== Bundle without workspace.host: default_profile is honored
3+
4+
>>> [CLI] bundle validate -o json
5+
{
6+
"host": null,
7+
"profile": "default-target"
8+
}
9+
10+
=== --profile overrides default_profile (negative case)
11+
12+
>>> errcode [CLI] bundle validate -p other -o json
13+
Warn: [hostmetadata] failed to fetch host metadata for https://other.test, will skip for 1m0s
14+
Error: Get "https://other.test/api/2.0/preview/scim/v2/Me": (redacted)
15+
16+
17+
Exit code: 1
18+
{
19+
"host": null,
20+
"profile": "other"
21+
}
22+
23+
=== Bundle with workspace.host: default_profile is NOT applied
24+
25+
>>> errcode [CLI] bundle validate -o json
26+
Error: failed during request visitor: default auth: cannot configure default credentials, please check https://docs.databricks.com/en/dev-tools/auth.html#databricks-client-unified-authentication to configure credentials for your preferred authentication method. Config: host=[DATABRICKS_URL], workspace_id=[NUMID], databricks_cli_path=[CLI]. Env: DATABRICKS_CLI_PATH
27+
28+
29+
Exit code: 1
30+
{
31+
"host": "[DATABRICKS_URL]",
32+
"profile": null
33+
}
34+
35+
=== Bundle with workspace.profile: pinned profile wins over default_profile
36+
37+
>>> errcode [CLI] bundle validate -o json
38+
Error: failed during request visitor: default auth: cannot configure default credentials, please check https://docs.databricks.com/en/dev-tools/auth.html#databricks-client-unified-authentication to configure credentials for your preferred authentication method. Config: profile=other, databricks_cli_path=[CLI]. Env: DATABRICKS_CLI_PATH
39+
40+
41+
Exit code: 1
42+
{
43+
"host": null,
44+
"profile": "other"
45+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
sethome "./home"
2+
3+
# Save the test server host so we can pin a bundle-with-host variant below.
4+
host_value="$DATABRICKS_HOST"
5+
6+
cat > "./home/.databrickscfg" <<EOF
7+
[default-target]
8+
host = $DATABRICKS_HOST
9+
token = $DATABRICKS_TOKEN
10+
11+
[other]
12+
host = https://other.test
13+
token = other-token
14+
15+
[__settings__]
16+
default_profile = default-target
17+
EOF
18+
19+
unset DATABRICKS_HOST
20+
unset DATABRICKS_TOKEN
21+
unset DATABRICKS_CONFIG_PROFILE
22+
23+
title "Bundle without workspace.host: default_profile is honored\n"
24+
trace $CLI bundle validate -o json | jq '{host: .workspace.host, profile: .workspace.profile}'
25+
26+
title "--profile overrides default_profile (negative case)\n"
27+
trace errcode $CLI bundle validate -p other -o json | jq '{host: .workspace.host, profile: .workspace.profile}'
28+
29+
# Switch to a bundle that pins workspace.host. The default_profile guard in
30+
# configureProfile must NOT apply default_profile here, because that would
31+
# silently route the user to a profile pointing at a different host than the
32+
# bundle declares.
33+
mkdir -p ./bundle-with-host
34+
cat > ./bundle-with-host/databricks.yml <<EOF
35+
bundle:
36+
name: bundle-with-host
37+
38+
workspace:
39+
host: $host_value
40+
EOF
41+
42+
title "Bundle with workspace.host: default_profile is NOT applied\n"
43+
(cd ./bundle-with-host && trace errcode $CLI bundle validate -o json | jq '{host: .workspace.host, profile: .workspace.profile}')
44+
45+
# Switch to a bundle that pins workspace.profile but no host. The pinned
46+
# profile must win over default_profile — configureProfile's guard skips
47+
# default_profile when workspace.profile is already set.
48+
mkdir -p ./bundle-with-profile
49+
cat > ./bundle-with-profile/databricks.yml <<EOF
50+
bundle:
51+
name: bundle-with-profile
52+
53+
workspace:
54+
profile: other
55+
EOF
56+
57+
title "Bundle with workspace.profile: pinned profile wins over default_profile\n"
58+
(cd ./bundle-with-profile && trace errcode $CLI bundle validate -o json | jq '{host: .workspace.host, profile: .workspace.profile}')
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Ignore = [
2+
"home",
3+
".databricks",
4+
"bundle-with-host",
5+
"bundle-with-profile",
6+
]
7+
8+
# Negative case: -p other tries to reach a non-existing host. Redact the
9+
# OS-/network-dependent suffix so the test is stable across runners.
10+
[[Repls]]
11+
Old = 'Get "https://other.test/api/2.0/preview/scim/v2/Me": .*'
12+
New = 'Get "https://other.test/api/2.0/preview/scim/v2/Me": (redacted)'

acceptance/cmd/api/default-profile/out.test.toml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
=== default_profile is used when no --profile flag and no DATABRICKS_CONFIG_PROFILE
3+
4+
>>> [CLI] api get /api/2.0/clusters/list
5+
{}
6+
7+
>>> print_requests.py --get //api/2.0/clusters/list
8+
{
9+
"headers": {
10+
"Authorization": [
11+
"Bearer [DATABRICKS_TOKEN]"
12+
],
13+
"User-Agent": [
14+
"cli/[DEV_VERSION] databricks-sdk-go/[SDK_VERSION] go/[GO_VERSION] os/[OS] cmd/api_get cmd-exec-id/[UUID] interactive/none auth/pat"
15+
],
16+
"X-Databricks-Org-Id": [
17+
"[NUMID]"
18+
]
19+
},
20+
"method": "GET",
21+
"path": "/api/2.0/clusters/list"
22+
}
23+
24+
=== --profile overrides default_profile (negative case)
25+
Warn: [hostmetadata] failed to fetch host metadata for https://other.test, will skip for 1m0s
26+
Error: Get "https://other.test/api/2.0/clusters/list": (redacted)
27+
28+
Exit code: 1
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
sethome "./home"
2+
3+
# Two profiles plus an explicit default_profile pointing at the test server.
4+
# The 'other' profile points at an RFC 2606 reserved host so we can assert
5+
# that --profile overrides default_profile without making a real request.
6+
cat > "./home/.databrickscfg" <<EOF
7+
[default-target]
8+
host = $DATABRICKS_HOST
9+
token = $DATABRICKS_TOKEN
10+
11+
[other]
12+
host = https://other.test
13+
token = other-token
14+
15+
[__settings__]
16+
default_profile = default-target
17+
EOF
18+
19+
unset DATABRICKS_HOST
20+
unset DATABRICKS_TOKEN
21+
unset DATABRICKS_CONFIG_PROFILE
22+
23+
title "default_profile is used when no --profile flag and no DATABRICKS_CONFIG_PROFILE\n"
24+
MSYS_NO_PATHCONV=1 trace $CLI api get /api/2.0/clusters/list
25+
trace print_requests.py --get //api/2.0/clusters/list | contains.py "X-Databricks-Org-Id"
26+
27+
title "--profile overrides default_profile (negative case)\n"
28+
MSYS_NO_PATHCONV=1 errcode $CLI api get /api/2.0/clusters/list -p other 2>&1 | contains.py "other.test"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Ignore = [
2+
"home",
3+
]
4+
5+
# Redact the OS- and network-dependent suffix on the failed lookup so the
6+
# negative case (--profile overrides default_profile) is stable across
7+
# runners. We still assert the requested host appears in output.
8+
[[Repls]]
9+
Old = 'Get "https://other.test/api/2.0/clusters/list": .*'
10+
New = 'Get "https://other.test/api/2.0/clusters/list": (redacted)'

0 commit comments

Comments
 (0)