Skip to content

Commit 9abf3e3

Browse files
committed
propagate debug mode
1 parent 88f1047 commit 9abf3e3

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

databricks/sdk/_base_client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ def __init__(
9999
# Default to 60 seconds
100100
self._http_timeout_seconds = http_timeout_seconds or 60
101101

102-
self._error_parser = _Parser(extra_error_customizers=extra_error_customizers)
102+
self._error_parser = _Parser(
103+
extra_error_customizers=extra_error_customizers,
104+
debug_headers=debug_headers,
105+
)
103106

104107
def _authenticate(self, r: requests.PreparedRequest) -> requests.PreparedRequest:
105108
if self._header_factory:

databricks/sdk/errors/parser.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@
3131
]
3232

3333

34-
def _unknown_error(response: requests.Response) -> str:
34+
def _unknown_error(response: requests.Response, debug_headers: bool = False) -> str:
3535
"""A standard error message that can be shown when an API response cannot be parsed.
3636
3737
This error message includes a link to the issue tracker for the SDK for users to report the issue to us.
38+
39+
:param response: The response object from the API request.
40+
:param debug_headers: Whether to include headers in the request log. Defaults to False for security.
3841
"""
39-
request_log = RoundTrip(response, debug_headers=True, debug_truncate_bytes=10 * 1024).generate()
42+
request_log = RoundTrip(response, debug_headers=debug_headers, debug_truncate_bytes=10 * 1024).generate()
4043
return (
4144
"This is likely a bug in the Databricks SDK for Python or the underlying "
4245
"API. Please report this issue with the following debugging information to the SDK issue tracker at "
@@ -56,11 +59,13 @@ def __init__(
5659
self,
5760
extra_error_parsers: List[_ErrorDeserializer] = [],
5861
extra_error_customizers: List[_ErrorCustomizer] = [],
62+
debug_headers: bool = False,
5963
):
6064
self._error_parsers = _error_deserializers + (extra_error_parsers if extra_error_parsers is not None else [])
6165
self._error_customizers = _error_customizers + (
6266
extra_error_customizers if extra_error_customizers is not None else []
6367
)
68+
self._debug_headers = debug_headers
6469

6570
def get_api_error(self, response: requests.Response) -> Optional[DatabricksError]:
6671
"""
@@ -84,7 +89,7 @@ def get_api_error(self, response: requests.Response) -> Optional[DatabricksError
8489
)
8590
return _error_mapper(
8691
response,
87-
{"message": "unable to parse response. " + _unknown_error(response)},
92+
{"message": "unable to parse response. " + _unknown_error(response, self._debug_headers)},
8893
)
8994

9095
# Private link failures happen via a redirect to the login page. From a requests-perspective, the request

tests/test_errors.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,3 +371,47 @@ def test_get_api_error(test_case: TestCase):
371371
assert isinstance(e.value, test_case.want_err_type)
372372
assert str(e.value) == test_case.want_message
373373
assert e.value.get_error_details() == test_case.want_details
374+
375+
376+
def test_debug_headers_disabled_by_default():
377+
"""Test that debug_headers=False by default does not leak sensitive headers in unparseable errors."""
378+
# Create a response with Authorization header that cannot be parsed
379+
resp = requests.Response()
380+
resp.status_code = 400
381+
resp.reason = "Bad Request"
382+
resp.request = requests.Request("POST", "https://databricks.com/api/2.0/sql/statements").prepare()
383+
resp.request.headers["Authorization"] = "Bearer secret-token-12345"
384+
resp.request.headers["X-Databricks-Azure-SP-Management-Token"] = "secret-azure-token-67890"
385+
resp._content = b"unparseable response"
386+
387+
parser = errors._Parser(debug_headers=False)
388+
error = parser.get_api_error(resp)
389+
390+
error_message = str(error)
391+
# Verify that sensitive tokens are NOT in the error message
392+
assert "secret-token-12345" not in error_message
393+
assert "secret-azure-token-67890" not in error_message
394+
assert "Authorization" not in error_message
395+
assert "X-Databricks-Azure-SP-Management-Token" not in error_message
396+
397+
398+
def test_debug_headers_enabled_shows_headers():
399+
"""Test that debug_headers=True includes headers in unparseable error messages."""
400+
# Create a response with Authorization header that cannot be parsed
401+
resp = requests.Response()
402+
resp.status_code = 400
403+
resp.reason = "Bad Request"
404+
resp.request = requests.Request("POST", "https://databricks.com/api/2.0/sql/statements").prepare()
405+
resp.request.headers["Authorization"] = "Bearer debug-token-12345"
406+
resp.request.headers["X-Databricks-Azure-SP-Management-Token"] = "debug-azure-token-67890"
407+
resp._content = b"unparseable response"
408+
409+
parser = errors._Parser(debug_headers=True)
410+
error = parser.get_api_error(resp)
411+
412+
error_message = str(error)
413+
# Verify that headers ARE included when explicitly enabled
414+
assert "Authorization" in error_message
415+
assert "debug-token-12345" in error_message
416+
assert "X-Databricks-Azure-SP-Management-Token" in error_message
417+
assert "debug-azure-token-67890" in error_message

0 commit comments

Comments
 (0)