fix(client,version): add timeout to all requests.get calls - #106
fix(client,version): add timeout to all requests.get calls#106mmclinton wants to merge 2 commits into
Conversation
All HTTP requests, the API client and the import-time PyPI version check, were made without a timeout. A hung TCP connection would block indefinitely with no recovery. - Add timeout param (default 30s) to GridStatusClient constructor; Timeout exceptions feed into the existing retry logic automatically - Add timeout=3 to the PyPI version check and swallow network errors silently since the check is non-critical
|
Quick clarification on the failing This failure is the one genuinely introduced by this PR. In requests.get("https://pypi.org/pypi/gridstatusio/json", timeout=3)but the test in mock_get.assert_called_once_with("https://pypi.org/pypi/gridstatusio/json")which produces: The fix is simply to update the assertion to include the new mock_get.assert_called_once_with(
"https://pypi.org/pypi/gridstatusio/json",
timeout=3,
)I'll push this update shortly. (Side note: the remaining |
the previous commit added a 3s timeout to the pypi version-check request, but the mock assertion still expected the old single-arg call signature. update the assertion so the test reflects the new network-call contract.
|
I updated the assertion to reflect the new network-call contract. Tests should no longer fail in this regard. The only fails now are secret-gated assertions — |
Summary
This PR fixes two
requests.get()calls that had no timeout set, found via static analysis with Bandit (rule B113:request_without_timeout, CWE-400).Issues
1. API requests can hang indefinitely (
gs_client.py)_get_with_retry()callsrequests.get()with no timeout. If a TCP connection is established but the server stalls, the call blocks forever, there is no OS-level default.requests.exceptions.Timeoutis already listed inRETRIABLE_EXCEPTIONS, but it is only raised when a timeout is actually set, so the existing retry logic never fires in this scenario. A caller's process can hang permanently with no recovery path.2. Import-time PyPI version check can also hang (
version.py)check_for_update()is called onimport gridstatusio. The underlyingrequests.get("https://pypi.org/pypi/gridstatusio/json")had no timeout, so a slow or unreachable PyPI could make the library unimportable until the OS TCP timeout fires (potentially several minutes).GSIO_SKIP_VERSION_CHECKexists as an escape hatch, but a user hitting this cold won't know to use it.Changes
GridStatusClientgains atimeoutparameter (default30.0seconds) passed directly torequests.get(). The default can be overridden at construction time; set a lower value for latency-sensitive pipelines orNoneto restore the previous unbounded behavior.timeout=3. Network errors are now swallowed silently since the check is informational only.Validation
bandit -r gridstatusio/ -llreports no issues after these changes (previously two medium-severity findings).timeoutdefault of 30s is well above normal API response times.