Skip to content

Commit 6bbf406

Browse files
Pass --force-refresh to Databricks CLI auth token command
The SDK manages its own token caching via `CachedTokenSource`. When the SDK shells out to `databricks auth token`, the CLI may return a token from *its* own cache that is about to expire (or has already expired from the SDK's perspective), producing unnecessary refresh failures and retry loops. The CLI added `--force-refresh` in v0.296.0 (databricks/cli#4767) to let callers bypass its cache. With the version-detection infrastructure from the parent PR already in place, opting in is a one-constant, one-branch change: * Introduce `CLI_VERSION_FOR_FORCE_REFRESH = v0.296.0`. * Split `buildCliCommand` into the existing profile/host decision (now `buildCoreCliCommand`) and a thin wrapper that appends `--force-refresh` when supported and otherwise logs a precise warning. Future capability-gated flags slot into the same wrapper. Mirrors: * databricks/databricks-sdk-go#1628 * databricks/databricks-sdk-py#1378 Co-authored-by: Isaac
1 parent fdd7383 commit 6bbf406

3 files changed

Lines changed: 66 additions & 9 deletions

File tree

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@
1515

1616
### Internal Changes
1717
* Detect Databricks CLI version at init time via `databricks version --output json`, enabling version-gated flag support. Successful detections are cached per CLI path; subprocess failures fall back to the most conservative command and are retried on the next call.
18+
* Pass `--force-refresh` to Databricks CLI `auth token` command (when the installed CLI is >= v0.296.0) so the SDK always receives a freshly minted token instead of a potentially stale one from the CLI's internal cache.
1819

1920
### API Changes

databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksCliCredentialsProvider.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ public class DatabricksCliCredentialsProvider implements CredentialsProvider {
3535
// --profile support added in CLI v0.207.1: https://github.com/databricks/cli/pull/855
3636
static final DatabricksCliVersion CLI_VERSION_FOR_PROFILE = new DatabricksCliVersion(0, 207, 1);
3737

38+
// --force-refresh support added in CLI v0.296.0: https://github.com/databricks/cli/pull/4767
39+
static final DatabricksCliVersion CLI_VERSION_FOR_FORCE_REFRESH =
40+
new DatabricksCliVersion(0, 296, 0);
41+
3842
// 5-second cap on `databricks version` so a hung CLI (slow first-run scan, antivirus, blocked
3943
// stdin) does not wedge SDK init indefinitely.
4044
private static final long VERSION_PROBE_TIMEOUT_SECONDS = 5;
@@ -161,13 +165,42 @@ List<String> resolveCliCommand(String cliPath, DatabricksConfig config) {
161165
}
162166

163167
/**
164-
* Builds the {@code auth token} command for the given CLI version.
168+
* Builds the full {@code auth token} command, including capability-gated flags.
165169
*
166-
* <p>Falls back to {@code --host} when {@code --profile} is either not configured or not
167-
* supported by the installed CLI.
170+
* <p>Delegates the profile/host decision to {@link #buildCoreCliCommand} and appends {@code
171+
* --force-refresh} when the installed CLI supports it.
168172
*/
169173
List<String> buildCliCommand(
170174
String cliPath, DatabricksConfig config, DatabricksCliVersion version) {
175+
List<String> cmd = buildCoreCliCommand(cliPath, config, version);
176+
if (version.atLeast(CLI_VERSION_FOR_FORCE_REFRESH)) {
177+
cmd.add("--force-refresh");
178+
} else if (version.isDefaultDevBuild()) {
179+
// Dev build — the dev-build INFO emitted by buildCoreCliCommand already explained why
180+
// feature detection is disabled; no per-flag noise needed here.
181+
} else if (version.equals(DatabricksCliVersion.UNKNOWN)) {
182+
// We didn't actually prove the CLI lacks --force-refresh; we just failed to confirm it.
183+
LOG.warn(
184+
"Could not confirm --force-refresh support for Databricks CLI {} (requires >= {}). "
185+
+ "The CLI's token cache may provide stale tokens.",
186+
version,
187+
CLI_VERSION_FOR_FORCE_REFRESH);
188+
} else {
189+
LOG.warn(
190+
"Databricks CLI {} does not support --force-refresh (requires >= {}). "
191+
+ "The CLI's token cache may provide stale tokens.",
192+
version,
193+
CLI_VERSION_FOR_FORCE_REFRESH);
194+
}
195+
return cmd;
196+
}
197+
198+
/**
199+
* Builds the base {@code auth token} command without capability-gated flags. Falls back to {@code
200+
* --host} when {@code --profile} is either not configured or not supported by the installed CLI.
201+
*/
202+
List<String> buildCoreCliCommand(
203+
String cliPath, DatabricksConfig config, DatabricksCliVersion version) {
171204
if (config.getProfile() == null) {
172205
return buildHostArgs(cliPath, config);
173206
}

databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksCliCredentialsProviderTest.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,33 +112,56 @@ void testBuildCliCommand_ProfileWithNullHost_ThrowsClearError() {
112112
private static Stream<Arguments> buildCliCommandCases() {
113113
return Stream.of(
114114
Arguments.of(
115-
"host only — old CLI",
115+
"host only — old CLI, no force-refresh",
116116
new DatabricksConfig().setHost(HOST),
117117
new DatabricksCliVersion(0, 200, 0),
118118
Arrays.asList(CLI_PATH, "auth", "token", "--host", HOST)),
119119
Arguments.of(
120-
"account host — old CLI",
120+
"host only — new CLI, with force-refresh",
121+
new DatabricksConfig().setHost(HOST),
122+
DatabricksCliCredentialsProvider.CLI_VERSION_FOR_FORCE_REFRESH,
123+
Arrays.asList(CLI_PATH, "auth", "token", "--host", HOST, "--force-refresh")),
124+
Arguments.of(
125+
"account host — old CLI, no force-refresh",
121126
new DatabricksConfig().setHost(ACCOUNT_HOST).setAccountId(ACCOUNT_ID),
122127
new DatabricksCliVersion(0, 200, 0),
123128
Arrays.asList(
124129
CLI_PATH, "auth", "token", "--host", ACCOUNT_HOST, "--account-id", ACCOUNT_ID)),
125130
Arguments.of(
126-
"profile with new CLI — uses --profile",
131+
"account host — new CLI, with force-refresh",
132+
new DatabricksConfig().setHost(ACCOUNT_HOST).setAccountId(ACCOUNT_ID),
133+
DatabricksCliCredentialsProvider.CLI_VERSION_FOR_FORCE_REFRESH,
134+
Arrays.asList(
135+
CLI_PATH,
136+
"auth",
137+
"token",
138+
"--host",
139+
ACCOUNT_HOST,
140+
"--account-id",
141+
ACCOUNT_ID,
142+
"--force-refresh")),
143+
Arguments.of(
144+
"profile with profile-supporting CLI — uses --profile, no force-refresh",
127145
new DatabricksConfig().setProfile(PROFILE).setHost(HOST),
128146
DatabricksCliCredentialsProvider.CLI_VERSION_FOR_PROFILE,
129147
Arrays.asList(CLI_PATH, "auth", "token", "--profile", PROFILE)),
130148
Arguments.of(
131-
"profile with old CLI — falls back to --host",
149+
"profile with newest CLI — uses --profile and --force-refresh",
150+
new DatabricksConfig().setProfile(PROFILE).setHost(HOST),
151+
DatabricksCliCredentialsProvider.CLI_VERSION_FOR_FORCE_REFRESH,
152+
Arrays.asList(CLI_PATH, "auth", "token", "--profile", PROFILE, "--force-refresh")),
153+
Arguments.of(
154+
"profile with old CLI — falls back to --host, no force-refresh",
132155
new DatabricksConfig().setProfile(PROFILE).setHost(HOST),
133156
new DatabricksCliVersion(0, 207, 0),
134157
Arrays.asList(CLI_PATH, "auth", "token", "--host", HOST)),
135158
Arguments.of(
136-
"unknown version — falls back to --host",
159+
"unknown version — falls back to --host, no force-refresh",
137160
new DatabricksConfig().setProfile(PROFILE).setHost(HOST),
138161
DatabricksCliVersion.UNKNOWN,
139162
Arrays.asList(CLI_PATH, "auth", "token", "--host", HOST)),
140163
Arguments.of(
141-
"dev build — falls back to --host",
164+
"dev build — falls back to --host, no force-refresh",
142165
new DatabricksConfig().setProfile(PROFILE).setHost(HOST),
143166
new DatabricksCliVersion(0, 0, 0),
144167
Arrays.asList(CLI_PATH, "auth", "token", "--host", HOST)));

0 commit comments

Comments
 (0)