Skip to content

Enforce Request Timeouts, Safe Transport Retries, Dependency Hardening, and Clean Lifecycle - #137

Open
mozluk wants to merge 2 commits into
Kalshi:mainfrom
mozluk:mozluk-patch-1
Open

mozluk wants to merge 2 commits into
Kalshi:mainfrom
mozluk:mozluk-patch-1

Conversation

@mozluk

@mozluk mozluk commented Sep 10, 2026

Copy link
Copy Markdown

Description

This pull request addresses reliability, security, and supply-chain findings identified in kalshi-starter-code-python during the workspace-wide security audit (K1–K5).

Previously, HTTP API requests were executed without socket timeouts, causing threads to block indefinitely on stalled connections. The client lacked connection pooling and safe transient retry handling, the rate limiter relied on non-monotonic wall-clock timestamps, and the success condition inadvertently treated HTTP 299 as a failure. Furthermore, dependencies contained 15 known vulnerabilities, and main.py executed network calls and private key reads at import time.

Key Changes & Remediations

1. Bounded HTTP Transport & Safe Retries (K1, K2 - clients.py)

  • Explicit Request Timeouts (K1): Defined DEFAULT_TIMEOUT = (5.0, 30.0) (connect, read) and routed it to all get(), post(), and delete() call sites to eliminate unbounded thread hangs.
  • Pooled Session with Method-Aware Retries (K2): Implemented a pooled requests.Session mounted with an HTTPAdapter configured for exponential backoff (total=3, backoff_factor=0.5). Restricted allowed_methods strictly to GET and DELETE—deliberately excluding POST to prevent duplicate order submissions upon network hiccups.
  • Accurate Status Evaluation (K2): Replaced range(200, 299) with 200 <= response.status_code < 300, properly recognizing HTTP 299 as a successful response.
  • Monotonic Rate Limiter (K2): Updated rate_limit() to use time.monotonic() instead of time.time(), sleeping only the remaining elapsed duration within the 100 ms window to prevent throughput degradation and immunity to clock drift.
  • Resource Cleanup (K2): Added close() and context manager support (__enter__ / __exit__) to ensure pooled sockets are released deterministically.

2. Exception Chaining & Idiomatic Defaults (K3 - clients.py)

  • Preserve Error Lineage: Narrowed exception handling during RSA-PSS signing to (ValueError, TypeError) and chained the original cause via raise ValueError(...) from exc.
  • Immutable Defaults: Replaced mutable default dictionary parameters (params={}) with None sentinels to prevent request parameter pollution across calls.

3. Supply-Chain Hardening (K4 - requirements.txt)

  • Resolved 15 Dependency Advisories: Raised pins to advisory-free versions according to pip-audit:
    • requests==2.33.0
    • cryptography==50.0.0
    • urllib3==2.7.0
    • python-dotenv==1.2.2
  • Removed Shadowed Package: Dropped the third-party datetime==5.5 package, preventing confusion with the standard library and shedding unused transitive dependencies (zope.interface).

4. Import Hygiene & Configuration Template (K5 - main.py, .env.example)

  • Eliminated Import-Time Side Effects: Wrapped credential loading and initial execution inside a clean main() routine behind if __name__ == "__main__":.
  • Documented Environment Contract: Added .env.example demonstrating the required DEMO_* and PROD_* configuration variables without checking in live credentials.

How to Review

  1. Inspect clients.py to confirm DEFAULT_TIMEOUT, requests.Session adapter constraints, and time.monotonic() in rate_limit().
  2. Inspect main.py to verify that module imports no longer trigger side effects.
  3. Review requirements.txt and verify that pip-audit -r requirements.txt reports zero vulnerabilities.

…g, and Clean Lifecycle

### Description
This pull request addresses reliability, security, and supply-chain findings identified in `kalshi-starter-code-python` during the workspace-wide security audit (**K1–K5**).

Previously, HTTP API requests were executed without socket timeouts, causing threads to block indefinitely on stalled connections. The client lacked connection pooling and safe transient retry handling, the rate limiter relied on non-monotonic wall-clock timestamps, and the success condition inadvertently treated HTTP 299 as a failure. Furthermore, dependencies contained 15 known vulnerabilities, and `main.py` executed network calls and private key reads at import time.

### Key Changes & Remediations

#### 1. Bounded HTTP Transport & Safe Retries (K1, K2 - `clients.py`)
* **Explicit Request Timeouts (K1):** Defined `DEFAULT_TIMEOUT = (5.0, 30.0)` (connect, read) and routed it to all `get()`, `post()`, and `delete()` call sites to eliminate unbounded thread hangs.
* **Pooled Session with Method-Aware Retries (K2):** Implemented a pooled `requests.Session` mounted with an `HTTPAdapter` configured for exponential backoff (`total=3`, `backoff_factor=0.5`). Restricted `allowed_methods` strictly to `GET` and `DELETE`—deliberately excluding `POST` to prevent duplicate order submissions upon network hiccups.
* **Accurate Status Evaluation (K2):** Replaced `range(200, 299)` with `200 <= response.status_code < 300`, properly recognizing HTTP 299 as a successful response.
* **Monotonic Rate Limiter (K2):** Updated `rate_limit()` to use `time.monotonic()` instead of `time.time()`, sleeping only the remaining elapsed duration within the 100 ms window to prevent throughput degradation and immunity to clock drift.
* **Resource Cleanup (K2):** Added `close()` and context manager support (`__enter__` / `__exit__`) to ensure pooled sockets are released deterministically.

#### 2. Exception Chaining & Idiomatic Defaults (K3 - `clients.py`)
* **Preserve Error Lineage:** Narrowed exception handling during RSA-PSS signing to `(ValueError, TypeError)` and chained the original cause via `raise ValueError(...) from exc`.
* **Immutable Defaults:** Replaced mutable default dictionary parameters (`params={}`) with `None` sentinels to prevent request parameter pollution across calls.

#### 3. Supply-Chain Hardening (K4 - `requirements.txt`)
* **Resolved 15 Dependency Advisories:** Raised pins to advisory-free versions according to `pip-audit`:
  * `requests==2.33.0`
  * `cryptography==50.0.0`
  * `urllib3==2.7.0`
  * `python-dotenv==1.2.2`
* **Removed Shadowed Package:** Dropped the third-party `datetime==5.5` package, preventing confusion with the standard library and shedding unused transitive dependencies (`zope.interface`).

#### 4. Import Hygiene & Configuration Template (K5 - `main.py`, `.env.example`)
* **Eliminated Import-Time Side Effects:** Wrapped credential loading and initial execution inside a clean `main()` routine behind `if __name__ == "__main__":`.
* **Documented Environment Contract:** Added `.env.example` demonstrating the required `DEMO_*` and `PROD_*` configuration variables without checking in live credentials.

### How to Review
1. Inspect `clients.py` to confirm `DEFAULT_TIMEOUT`, `requests.Session` adapter constraints, and `time.monotonic()` in `rate_limit()`.
2. Inspect `main.py` to verify that module imports no longer trigger side effects.
3. Review `requirements.txt` and verify that `pip-audit -r requirements.txt` reports zero vulnerabilities.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant