Skip to content

Commit 9cee127

Browse files
committed
Make secure token storage the default storage mode
U2M tokens for the databricks-cli auth type now write to the OS-native keyring by default. Users who need the previous file-backed cache can opt back via DATABRICKS_AUTH_STORAGE=plaintext or auth_storage = plaintext under [__settings__] in .databrickscfg; the env var takes precedence. The login-time keyring probe and fallback (already on main) activate with this change. Co-authored-by: Isaac
1 parent 6327c33 commit 9cee127

13 files changed

Lines changed: 55 additions & 47 deletions

File tree

NEXT_CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Notable Changes
66

7+
* Breaking change: U2M (`auth_type = databricks-cli`) tokens are now stored in the OS-native secure store by default (Keychain on macOS, Credential Manager on Windows, Secret Service on Linux) instead of `~/.databricks/token-cache.json`. After upgrading, run `databricks auth login` once per profile to re-authenticate; cached tokens from older versions are not migrated. To keep the previous file-backed storage, set `DATABRICKS_AUTH_STORAGE=plaintext` or add `auth_storage = plaintext` under `[__settings__]` in `~/.databrickscfg` (the env var takes precedence over the config setting), then re-run `databricks auth login`.
8+
79
### CLI
810

911
* 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.

acceptance/cmd/auth/describe/u2m-json-output/output.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
>>> [CLI] auth describe --profile u2m-profile --output json
33
Warn: [hostmetadata] failed to fetch host metadata for https://u2m-profile.databricks.test, will skip for 1m0s
44
{
5-
"mode": "plaintext",
6-
"location": "~/.databricks/token-cache.json",
5+
"mode": "secure",
6+
"location": "OS keyring (service: databricks-cli)",
77
"source": "default"
88
}

acceptance/cmd/auth/describe/u2m-plaintext-default/test.toml

Lines changed: 0 additions & 3 deletions
This file was deleted.

acceptance/cmd/auth/describe/u2m-plaintext-default/out.test.toml renamed to acceptance/cmd/auth/describe/u2m-secure-default/out.test.toml

File renamed without changes.

acceptance/cmd/auth/describe/u2m-plaintext-default/output.txt renamed to acceptance/cmd/auth/describe/u2m-secure-default/output.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11

22
>>> [CLI] auth describe --profile u2m-profile
33
Warn: [hostmetadata] failed to fetch host metadata for https://u2m-profile.databricks.test, will skip for 1m0s
4-
Unable to authenticate: error getting token: cache: token not found
5-
Token storage: plaintext, ~/.databricks/token-cache.json (from default)
4+
Unable to authenticate: error getting token: [KEYRING_LOOKUP_ERROR]
5+
Token storage: secure, OS keyring (service: databricks-cli) (from default)
66
-----
77
Current configuration:
88
✓ host: https://u2m-profile.databricks.test (from ./home/.databrickscfg config file)

acceptance/cmd/auth/describe/u2m-plaintext-default/script renamed to acceptance/cmd/auth/describe/u2m-secure-default/script

File renamed without changes.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Ignore = [
2+
"home"
3+
]
4+
5+
# Normalize the platform-specific keyring lookup error. macOS returns
6+
# cache.ErrNotFound for a clean miss; Linux without D-Bus returns a
7+
# backend-specific error. The point of this test is the resolved storage
8+
# mode, not the lookup outcome.
9+
[[Repls]]
10+
Old = 'Unable to authenticate: error getting token: .*'
11+
New = 'Unable to authenticate: error getting token: [KEYRING_LOOKUP_ERROR]'

acceptance/script.prepare

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# Force plaintext token storage so acceptance tests exercise the file-backed
2+
# cache rather than the OS keyring, which is not reliably reachable in CI.
3+
# Tests that want to exercise the secure path or the resolver default unset
4+
# or override this in their own script.prepare or script.
5+
export DATABRICKS_AUTH_STORAGE=plaintext
6+
17
errcode() {
28
# Temporarily disable 'set -e' to prevent the script from exiting on error
39
set +e

cmd/auth/describe_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -240,21 +240,21 @@ func TestResolveTokenStorageInfo(t *testing.T) {
240240
want: nil,
241241
},
242242
{
243-
name: "databricks-cli with default plaintext",
243+
name: "databricks-cli with default secure",
244244
authType: authTypeDatabricksCLI,
245245
want: &tokenStorageInfo{
246-
Mode: "plaintext",
247-
Location: plaintextLocation,
246+
Mode: "secure",
247+
Location: secureLocation,
248248
Source: "default",
249249
},
250250
},
251251
{
252-
name: "databricks-cli with secure from env",
252+
name: "databricks-cli with plaintext from env",
253253
authType: authTypeDatabricksCLI,
254-
envValue: "secure",
254+
envValue: "plaintext",
255255
want: &tokenStorageInfo{
256-
Mode: "secure",
257-
Location: secureLocation,
256+
Mode: "plaintext",
257+
Location: plaintextLocation,
258258
Source: "DATABRICKS_AUTH_STORAGE environment variable",
259259
},
260260
},

libs/auth/storage/cache.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,6 @@ func ResolveCache(ctx context.Context, override StorageMode) (cache.TokenCache,
5959
// The timeout is ambiguous (locked vs hung); a misdiagnosis fails
6060
// the final Store rather than silently downgrading to plaintext.
6161
//
62-
// Rules 1 and 2 are dormant today: the resolver default is plaintext, so
63-
// (mode=Secure, explicit=false) is unreachable. They activate when the
64-
// default flips to secure at GA.
65-
//
6662
// Login-specific. Read paths (auth token, bundle commands) keep the original
6763
// keyring error so they don't silently mint plaintext copies of tokens that
6864
// were stored in the keyring on another machine.
@@ -120,12 +116,6 @@ func resolveCacheForLoginWith(ctx context.Context, override StorageMode, f cache
120116
// resolved mode and whether the user explicitly asked for it. Split out so
121117
// tests can drive the (mode, explicit) input space directly without depending
122118
// on whatever the resolver's default mode happens to be at any point in time.
123-
//
124-
// Pin-on-success across modes (locking in the first working behavior to
125-
// insulate users from keyring flakiness) is intentionally not implemented
126-
// here. It lands at GA alongside the default flip; pinning before the
127-
// flip would freeze every default user into plaintext and make the flip a
128-
// no-op for them.
129119
func applyLoginFallback(ctx context.Context, mode StorageMode, explicit bool, f cacheFactories) (cache.TokenCache, StorageMode, error) {
130120
switch mode {
131121
case StorageModePlaintext:
@@ -168,11 +158,9 @@ func applyLoginFallback(ctx context.Context, mode StorageMode, explicit bool, f
168158
// in .databrickscfg so subsequent commands skip the (slow/blocking) keyring
169159
// probe and route straight to the file cache.
170160
//
171-
// Only called on the (mode=Secure, explicit=false) probe-failure branch. That
172-
// branch is unreachable today (resolver default is plaintext), so this is
173-
// dormant infrastructure: it activates when the default flips to secure
174-
// at GA and lets default-on-broken-keyring users avoid a 3s probe on every
175-
// command.
161+
// Only called on the (mode=Secure, explicit=false) probe-failure branch.
162+
// Persisting the fallback lets default-on-broken-keyring users avoid a 3s
163+
// probe on every command.
176164
func persistPlaintextFallback(ctx context.Context) error {
177165
configPath := env.Get(ctx, "DATABRICKS_CONFIG_FILE")
178166
return databrickscfg.SetConfiguredAuthStorage(ctx, string(StorageModePlaintext), configPath)

0 commit comments

Comments
 (0)