Skip to content

Commit a3a8ee7

Browse files
Pass --force-refresh to CLI auth token command
Pass --force-refresh to the Databricks CLI auth token command when the CLI supports it (>= v0.296.0), bypassing the CLI's internal token cache. The SDK manages its own token caching. When the SDK considers its token stale and shells out to `databricks auth token`, the CLI may return a cached token that is about to expire from the SDK's perspective. The --force-refresh flag guarantees a freshly minted token. With the version detection infrastructure from the parent commit, adding --force-refresh is a one-constant, one-if change. See: databricks/cli#4767
1 parent 1dc0960 commit a3a8ee7

3 files changed

Lines changed: 108 additions & 1 deletion

File tree

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
### Internal Changes
1717
* Detect Databricks CLI version at init time via `databricks version`, enabling version-gated flag support without additional subprocess calls.
1818
* Validate Databricks CLI configuration at `DatabricksCliTokenSource.__init__` time. Misconfiguration (missing profile and host, or `--profile`-unsupported CLI without a host fallback) now surfaces as `IOError` synchronously from construction rather than lazily from the first `refresh()` call. The exception type matches the previous `refresh()`-time behaviour, so callers who already catch `IOError` are unaffected.
19+
* Pass `--force-refresh` to Databricks CLI `auth token` command so the SDK always receives a freshly minted token instead of a potentially stale one from the CLI's internal cache.
1920

2021
### API Changes
2122
* Add [w.temporary_volume_credentials](https://databricks-sdk-py.readthedocs.io/en/latest/workspace/catalog/temporary_volume_credentials.html) workspace-level service.

databricks/sdk/credentials_provider.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,9 @@ def _validate_token_scopes(self, token: oauth.Token):
10431043
# --profile support added in CLI v0.207.1: https://github.com/databricks/cli/pull/855
10441044
_CLI_VERSION_FOR_PROFILE = CliVersion(0, 207, 1)
10451045

1046+
# --force-refresh support added in CLI v0.296.0: https://github.com/databricks/cli/pull/4767
1047+
_CLI_VERSION_FOR_FORCE_REFRESH = CliVersion(0, 296, 0)
1048+
10461049
@staticmethod
10471050
def _parse_cli_version(output: str) -> CliVersion:
10481051
"""Parse the JSON output of `databricks version --output json`.
@@ -1095,7 +1098,34 @@ def _resolve_cli_command(cli_path: str, cfg: "Config") -> List[str]:
10951098

10961099
@staticmethod
10971100
def _build_cli_command(cli_path: str, cfg: "Config", version: CliVersion) -> List[str]:
1098-
"""Build the `auth token` command.
1101+
"""Build the full CLI command, including capability-gated flags.
1102+
1103+
Delegates the profile/host decision to _build_core_cli_command and
1104+
appends --force-refresh when supported.
1105+
"""
1106+
cmd = DatabricksCliTokenSource._build_core_cli_command(cli_path, cfg, version)
1107+
if version >= DatabricksCliTokenSource._CLI_VERSION_FOR_FORCE_REFRESH:
1108+
cmd.append("--force-refresh")
1109+
elif version == CliVersion() or version.is_default_dev_build:
1110+
# Detection failed or no version metadata — we can't prove the CLI
1111+
# lacks --force-refresh, just failed to confirm it. Upstream has
1112+
# already logged the underlying cause, so use softer wording.
1113+
logger.warning(
1114+
f"Could not confirm --force-refresh support for Databricks CLI {version} "
1115+
f"(requires >= {DatabricksCliTokenSource._CLI_VERSION_FOR_FORCE_REFRESH}). "
1116+
"The CLI's token cache may provide stale tokens."
1117+
)
1118+
else:
1119+
logger.warning(
1120+
f"Databricks CLI {version} does not support --force-refresh "
1121+
f"(requires >= {DatabricksCliTokenSource._CLI_VERSION_FOR_FORCE_REFRESH}). "
1122+
"The CLI's token cache may provide stale tokens."
1123+
)
1124+
return cmd
1125+
1126+
@staticmethod
1127+
def _build_core_cli_command(cli_path: str, cfg: "Config", version: CliVersion) -> List[str]:
1128+
"""Build the base `auth token` command without capability-gated flags.
10991129
11001130
Falls back to --host when --profile is either not configured or not
11011131
supported by the installed CLI. Raises IOError describing which

tests/test_credentials_provider.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,48 @@ def _make_cfg(*, profile=None, host=None, account_id=None):
451451
_CV(0, 0, 0),
452452
[_CLI, "auth", "token", "--host", _HOST],
453453
),
454+
(
455+
"host with force-refresh",
456+
_make_cfg(host=_HOST),
457+
_CV(0, 296, 0),
458+
[_CLI, "auth", "token", "--host", _HOST, "--force-refresh"],
459+
),
460+
(
461+
"account host with force-refresh",
462+
_make_cfg(host=_ACCT_HOST, account_id="acct-123"),
463+
_CV(0, 296, 0),
464+
[_CLI, "auth", "token", "--host", _ACCT_HOST, "--account-id", "acct-123", "--force-refresh"],
465+
),
466+
(
467+
"profile with force-refresh",
468+
_make_cfg(profile="my-profile", host=_HOST),
469+
_CV(0, 296, 0),
470+
[_CLI, "auth", "token", "--profile", "my-profile", "--force-refresh"],
471+
),
472+
(
473+
"profile supports profile but not force-refresh",
474+
_make_cfg(profile="my-profile", host=_HOST),
475+
_CV(0, 207, 1),
476+
[_CLI, "auth", "token", "--profile", "my-profile"],
477+
),
478+
(
479+
"profile-only with force-refresh",
480+
_make_cfg(profile="my-profile"),
481+
_CV(0, 296, 0),
482+
[_CLI, "auth", "token", "--profile", "my-profile", "--force-refresh"],
483+
),
484+
(
485+
"unknown version, host only, no force-refresh",
486+
_make_cfg(host=_HOST),
487+
_CV(),
488+
[_CLI, "auth", "token", "--host", _HOST],
489+
),
490+
(
491+
"dev-build version, host only, no force-refresh",
492+
_make_cfg(host=_HOST),
493+
_CV(0, 0, 0),
494+
[_CLI, "auth", "token", "--host", _HOST],
495+
),
454496
],
455497
)
456498
def test_build_cli_command(name, cfg, version, expected):
@@ -576,6 +618,40 @@ def test_resolve_cli_command_new_cli_uses_profile(mocker):
576618
assert cmd == [_CLI, "auth", "token", "--profile", "my-profile"]
577619

578620

621+
def test_build_cli_command_force_refresh_unsupported_logs_warning(caplog):
622+
import logging
623+
624+
cfg = _make_cfg(host=_HOST)
625+
with caplog.at_level(logging.WARNING, logger="databricks.sdk.credentials_provider"):
626+
credentials_provider.DatabricksCliTokenSource._build_cli_command(_CLI, cfg, _CV(0, 295, 0))
627+
assert any(
628+
"does not support --force-refresh" in rec.message and rec.levelname == "WARNING" for rec in caplog.records
629+
)
630+
631+
632+
@pytest.mark.parametrize(
633+
"version",
634+
[
635+
# Detection failed: we don't actually know the CLI lacks --force-refresh.
636+
_CV(),
637+
# Default dev build: no version metadata injected, same story.
638+
_CV(0, 0, 0),
639+
],
640+
)
641+
def test_build_cli_command_unconfirmed_force_refresh_softens_warning(caplog, version):
642+
import logging
643+
644+
cfg = _make_cfg(host=_HOST)
645+
with caplog.at_level(logging.WARNING, logger="databricks.sdk.credentials_provider"):
646+
credentials_provider.DatabricksCliTokenSource._build_cli_command(_CLI, cfg, version)
647+
# Softer phrasing for states where --force-refresh support wasn't proven absent.
648+
assert any(
649+
"Could not confirm --force-refresh support" in rec.message and rec.levelname == "WARNING"
650+
for rec in caplog.records
651+
)
652+
assert not any("does not support --force-refresh" in rec.message for rec in caplog.records)
653+
654+
579655
# Tests for cloud-agnostic hosts and removed cloud checks
580656
class TestCloudAgnosticHosts:
581657
"""Tests that credential providers work with cloud-agnostic hosts after removing is_azure/is_gcp checks."""

0 commit comments

Comments
 (0)