test(net): pin that get_scrubbed keeps the vendor key out of errors (#1398)

- the message and args are masked; no request, response or chained original travels with the error; a passthrough status is returned
This commit is contained in:
Yijia-Xiao
2026-09-24 18:45:44 +00:00
parent f9d6495dca
commit 05878c96a8
+65
View File
@@ -0,0 +1,65 @@
"""``get_scrubbed``: the vendor key must not survive into an error.
FRED and Alpha Vantage authenticate with a query parameter, so requests quotes
the key back in the text of HTTP, connection and timeout errors, and in the
``request`` and ``response`` it attaches (#1324).
"""
from unittest import mock
import pytest
import requests
from tradingagents.dataflows.net import get_scrubbed
# A fabricated value in the shape of a FRED key.
_KEY = "deadbeefdeadbeefdeadbeefdeadbeef"
_LEAK = (
"HTTPSConnectionPool(host='api.stlouisfed.org', port=443): Max retries "
f"exceeded with url: /fred/series?series_id=DGS10&api_key={_KEY}&file_type=json"
)
def _response(status_code):
response = mock.Mock(spec=requests.Response)
response.status_code = status_code
response.raise_for_status.side_effect = requests.HTTPError(_LEAK) if status_code >= 400 else None
return response
def _call(**kwargs):
return get_scrubbed("https://api.stlouisfed.org/fred/series",
params={"api_key": _KEY}, timeout=5, secret=_KEY, **kwargs)
@pytest.mark.unit
@pytest.mark.parametrize("failure", [
{"side_effect": requests.ConnectionError(_LEAK)},
{"return_value": _response(500)},
], ids=["transport", "status"])
def test_the_key_is_masked_in_the_error(failure):
with mock.patch.object(requests, "get", **failure), pytest.raises(requests.RequestException) as caught:
_call()
assert _KEY not in str(caught.value) and _KEY not in repr(caught.value.args)
assert "api_key=***" in str(caught.value)
@pytest.mark.unit
def test_nothing_that_holds_the_url_travels_with_the_error():
"""The request, the response and a chained original each carry the full URL."""
leaky = requests.ConnectionError(_LEAK)
leaky.request = mock.Mock(url=f"https://x.invalid/?api_key={_KEY}")
leaky.response = mock.Mock(url=f"https://x.invalid/?api_key={_KEY}")
with mock.patch.object(requests, "get", side_effect=leaky), pytest.raises(requests.ConnectionError) as caught:
_call()
error = caught.value
assert error.request is None and error.response is None
assert error.__cause__ is None and error.__context__ is None
@pytest.mark.unit
def test_a_passthrough_status_is_returned_for_the_caller():
response = _response(400)
with mock.patch.object(requests, "get", return_value=response):
assert _call(passthrough=(400,)) is response
response.raise_for_status.assert_not_called()