Repository navigation
feat(transport,auth): http2 extra, per-request headers, Retry-After date, header scrubbing, passphrase support - #233
Conversation
Code Review — PR #233Wave 2-B is solid overall: the changes are surgical, well-tested, and address real gaps. A few issues worth addressing before merge, ranging from a meaningful semantic bug to minor style nits. OverviewSix targeted improvements bundled together:
IssuesMedium — documentation contradicts implementation
The implementation does the opposite — a user-supplied filter (callable or iterable) fully replaces the default. The test even documents this explicitly: # … and the default Set-Cookie scrubbing did NOT apply (user took over).
assert headers.get("set-cookie") == "should-be-kept-when-filter-is-overridden"This is fine as a design choice, but the word "extend" is wrong and will mislead anyone who wants to add a header to the deny-list while keeping the defaults. Either:
The current UX footgun: a user passing Medium — async transport has no test coverage for the new features
Minimum additions needed:
Minor / StyleInternal ticket references in source code ( # P1.6: canonicalize trailing slash BEFORE both signing and httpx call
# P1.5 default response-header scrubbing:Per the project's own CLAUDE.md: "Don't reference the current task, fix, or callers… those belong in the PR description and rot as the codebase evolves." P1.1/P1.5/P1.6 mean nothing to a future reader. The explanatory text after the label is valuable — keep that, drop the label.
Uses def test_from_key_path_with_passphrase_succeeds(
self, rsa_private_key: rsa.RSAPrivateKey, tmp_path: Path
) -> None:
encrypted = self._encrypted_pem(rsa_private_key, b"pw")
key_file = tmp_path / "key.pem"
key_file.write_bytes(encrypted)
auth = KalshiAuth.from_key_path("k", key_file, password="pw")
assert auth.key_id == "k"Local imports in
Duplicated comment in async transport ( The sync version has the full three-line comment; the async version has only the single-line form. Either use the same comment or omit both per CLAUDE.md's "no obvious comments" rule. Correctness / Security ✓
Test Coverage — OverallComprehensive. The trailing-slash test re-derives the signed message and cryptographically verifies the signature against the canonicalized path — that's the right level of rigor for a signing invariant. The HTTP-date Retry-After tests cover future/past/garbage cases cleanly. The two gaps (async transport tests, "extend vs replace" documentation) are the main things to address before this is merge-ready. |
Code Review — Wave 2-B Transport/Auth Polish + Passphrase SupportOverall this is a solid, well-structured PR. The implementation is correct, the security model is sound, and the test suite is thorough. A few issues worth addressing before merge. OverviewSix focused improvements: passphrase-protected PEM support, HTTP-date Issues1.
|
…ate, header scrubbing, passphrase support - pyproject http2 extra; KalshiConfig.__post_init__ validates h2 availability when http2=True. - _base_client request(): optional per-request extra_headers (auth headers still win). - _map_error: Retry-After HTTP-date form parsed via email.utils.parsedate_to_datetime, capped at retry_max_delay. - RecordingTransport: response header scrubbing (Set-Cookie / Authorization / X-Kalshi-*-id|key|account|user filtered by default; user-overridable via response_header_filter callable or iterable deny-list). - auth.py: trailing-slash path canonicalization at transport boundary (sync+async); KalshiAuth.from_pem/from_key_path/from_env/try_from_env accept optional password (str/bytes/callable). KALSHI_PRIVATE_KEY_PASSPHRASE env var. Existing TypeError message now points at password= kwarg and env var alongside the openssl recipe. - docs/configuration.md: correct extra_headers override claim; http2 install recipe references the new [http2] extra and the fail-fast check. - docs/authentication.md: passphrase usage examples (str / bytes / callable / env var). Closes #217, Closes #220 Refs #224
…P-date parsing Pre-existing test_429_retry_after_http_date_falls_back_to_backoff asserted old behavior (HTTP-date unparseable → backoff fallback). With P1.3 the date is parsed via email.utils.parsedate_to_datetime and capped at retry_max_delay. Renamed + updated to test_429_retry_after_http_date_parsed_and_capped to mirror the sync sibling test.
07888ad to
d5392aa
Compare
Code Review — PR #233Wave 2-B audit polish. Overall this is solid work with good test coverage. I found one substantive bug, one style issue that will likely fail OverviewSix P1 polish items plus passphrase support:
All six features have corresponding tests and updated docs. Substantive Issue
ResponseHeaderFilter = Callable[[str, str], bool] | Iterable[str] | NoneA plain Consider adding a guard at the top of if isinstance(response_header_filter, str):
raise TypeError(
"response_header_filter must be a callable or an iterable of header names, "
"not a plain str — did you mean [response_header_filter]?"
)mypy may not catch this at call-site because Style Issue (will likely fail ruff)Missing blank lines before assert cfg.ws_json_dumps is json.dumps
class TestHttp2ImportCheck: # ← no blank linesPEP 8 / ruff E302 requires two blank lines before a top-level class definition. Minor Observations
return bool(_DEFAULT_SCRUB_RE.match(name))
Unreachable if path != "/" and path.endswith("/"):
path = path.rstrip("/") or "/"The Duplicated test comment — # Predicate was called for every response header.
# Predicate was called for every response header (httpx lowercases).The same comment appears twice consecutively. Looks like a copy-paste artifact. What's Well Done
VerdictOne bug fix needed ( |
Wave 2-B of audit umbrella. 6 P1 polish items + passphrase support.
Changes
extra_headersplumbing, Retry-After HTTP-date parsing, RecordingTransport response-header scrubbing (Set-Cookie / Authorization / X-Kalshi-*-id|key|account|user), trailing-slash signing canonicalization at the transport boundary,docs/configuration.mdextra_headers override claim corrected.KalshiAuth.from_pem/from_key_path/from_env/try_from_envaccept optionalpassword(str/bytes/callable).KALSHI_PRIVATE_KEY_PASSPHRASEenv var. Users no longer need to write plaintext keys to disk.Closes #217, Closes #220
Refs #224