Skip to content

Commit baf88f0

Browse files
ai: apply changes for #932 (3 review threads)
Addresses: - #3858601138 at src/databricks/sql/backend/kernel/auth_bridge.py:468 - #3858601153 at src/databricks/sql/session.py:193 - #3858601164 at src/databricks/sql/client.py:234 Signed-off-by: peco-engineer-bot[bot] <peco-engineer-bot[bot]@users.noreply.github.com>
1 parent 0de2e82 commit baf88f0

4 files changed

Lines changed: 71 additions & 9 deletions

File tree

src/databricks/sql/backend/kernel/auth_bridge.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,14 @@ def kernel_auth_kwargs(
462462
"oauth_scopes": scopes if scopes is not None else list(PYSQL_OAUTH_SCOPES),
463463
# OAuth U2M token-cache enable/disable: when present in auth_options,
464464
# forward to the kernel as token_cache_enabled on the U2M branch.
465-
# Default disabled (bool(None) = False) for backward compatibility when
466-
# moving token persistence control to the kernel. This ensures callers
467-
# must opt-in to on-disk persistence rather than silently enabling it.
468-
"token_cache_enabled": bool(opts.get("oauth_token_cache_enabled")),
465+
# Default disabled for backward compatibility when moving token
466+
# persistence control to the kernel. This ensures callers must
467+
# opt-in to on-disk persistence rather than silently enabling it.
468+
# Coerced via _coerce_bool so a string DSN/env value like "False"
469+
# is not treated as truthy (bool("False") is True).
470+
"token_cache_enabled": _coerce_bool(
471+
opts.get("oauth_token_cache_enabled")
472+
),
469473
}
470474
if federation_client_id:
471475
kwargs["identity_federation_client_id"] = federation_client_id
@@ -519,6 +523,28 @@ def _coerce_redirect_port(redirect_port: Any) -> int:
519523
)
520524

521525

526+
def _coerce_bool(value: Any) -> bool:
527+
"""Coerce an opt-in boolean flag (e.g. ``oauth_token_cache_enabled``,
528+
which may arrive as a string from a DSN/env) to a ``bool``.
529+
530+
A plain ``bool(value)`` is wrong for string inputs: ``bool("False")`` is
531+
``True``, which would silently enable on-disk token persistence whenever
532+
the flag arrived as the string ``"False"``. Only genuinely truthy values
533+
enable the flag: real booleans, and the usual textual/numeric truthy
534+
spellings ("true"/"1"/"yes"/"on"). ``None`` (unset) and anything else
535+
disable it (opt-in default)."""
536+
if isinstance(value, bool):
537+
return value
538+
if value is None:
539+
return False
540+
if isinstance(value, str):
541+
return value.strip().lower() in ("true", "1", "yes", "on")
542+
if isinstance(value, (int, float)):
543+
return value != 0
544+
# Unknown types default to disabled rather than truthy-by-accident.
545+
return False
546+
547+
522548
def _normalize_scopes(scopes: Any) -> Optional[list]:
523549
"""Normalise an ``oauth_scopes`` value to a list of strings, or
524550
``None`` to let the kernel apply its defaults.

src/databricks/sql/client.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,13 @@ def read(self) -> Optional[OAuthToken]:
228228
:param oauth_token_cache_enabled: `bool | None`, optional (default is None)
229229
**Kernel-only, U2M-only.** Controls whether the kernel persists OAuth U2M
230230
refresh tokens to disk (AES-256 encrypted, at `~/.config/databricks-sql-kernel/oauth/`).
231-
When unset (None, the default), the kernel's own default behavior applies.
232-
When True, enables persistent on-disk token cache; when False, tokens are
233-
held in memory only and the user must re-authenticate when the process restarts.
231+
When unset (None, the default), the connector treats this as False and
232+
forwards `token_cache_enabled=False` to the kernel, so on-disk caching is
233+
disabled by default — matching the Thrift posture and avoiding silently
234+
writing tokens to disk. Callers must opt in explicitly to enable persistence.
235+
When True, enables persistent on-disk token cache; when False (or unset),
236+
tokens are held in memory only and the user must re-authenticate when the
237+
process restarts.
234238
Has no effect on Thrift or SEA backends, which maintain their own token
235239
lifecycle via `experimental_oauth_persistence`. This parameter is distinct
236240
from the Thrift-only `experimental_oauth_persistence` — this controls the

src/databricks/sql/session.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,12 @@ def _create_backend(
188188
),
189189
# OAuth U2M token-cache enable/disable: controls whether the kernel
190190
# persists U2M refresh tokens to disk (encrypted, at ~/.config/databricks-sql-kernel/oauth/).
191-
# Omitted ⇒ kernel default (enabled); False ⇒ in-memory only.
191+
# Coerced via _coerce_bool on the oauth-u2m branch, so omitted/None
192+
# ⇒ token_cache_enabled=False (disabled, in-memory only) — the
193+
# opt-in default that preserves backward compat when token
194+
# persistence moves to the kernel path; True ⇒ on-disk persistence.
192195
# This is forwarded to the kernel's pyo3 Session as token_cache_enabled
193-
# on the oauth-u2m auth branch only, ensuring backward compat when moved to the kernel path.
196+
# on the oauth-u2m auth branch only.
194197
"oauth_token_cache_enabled": kwargs.get("oauth_token_cache_enabled"),
195198
# Azure Entra SP credentials for the azure-sp-m2m path. The
196199
# kernel owns Azure resolution (endpoint/scope/tenant discovery),

tests/unit/test_kernel_auth_bridge.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,35 @@ def test_u2m_token_cache_enabled_true_forwarded(self):
620620
)
621621
assert kwargs["token_cache_enabled"] is True
622622

623+
@pytest.mark.parametrize(
624+
"raw_value",
625+
["False", "false", "0", "no", "off", "", " ", "nope"],
626+
)
627+
def test_u2m_token_cache_enabled_falsey_string_stays_false(self, raw_value):
628+
# A string DSN/env value that reads as falsey (e.g. "False") must NOT
629+
# enable on-disk persistence: bool("False") is True, so the flag is
630+
# coerced via _coerce_bool rather than bool().
631+
kwargs = kernel_auth_kwargs(
632+
_FakeOAuthProvider(),
633+
{
634+
"auth_type": "databricks-oauth",
635+
"oauth_token_cache_enabled": raw_value,
636+
},
637+
)
638+
assert kwargs["token_cache_enabled"] is False
639+
640+
@pytest.mark.parametrize("raw_value", ["True", "true", "1", "yes", "on"])
641+
def test_u2m_token_cache_enabled_truthy_string_enables(self, raw_value):
642+
# An explicit truthy string DSN/env value enables persistence.
643+
kwargs = kernel_auth_kwargs(
644+
_FakeOAuthProvider(),
645+
{
646+
"auth_type": "databricks-oauth",
647+
"oauth_token_cache_enabled": raw_value,
648+
},
649+
)
650+
assert kwargs["token_cache_enabled"] is True
651+
623652
@pytest.mark.parametrize("u2m_auth_type", ["databricks-oauth", "azure-oauth"])
624653
def test_u2m_token_cache_enabled_both_auth_types(self, u2m_auth_type):
625654
# token_cache_enabled applies to both databricks-oauth and azure-oauth U2M types.

0 commit comments

Comments
 (0)