|
| 1 | +# httpware 0.11.0 — deep-audit hardening (security + correctness) |
| 2 | + |
| 3 | +**Minor release. Additive only — no breaking changes.** |
| 4 | + |
| 5 | +This release ships the full remediation of the 2026-06-14 full-codebase deep |
| 6 | +audit: 35 confirmed findings closed across security, correctness, public API, |
| 7 | +test quality, and documentation. |
| 8 | + |
| 9 | +## New public names |
| 10 | + |
| 11 | +```python |
| 12 | +from httpware import ResponseTooLargeError |
| 13 | +``` |
| 14 | + |
| 15 | +`AsyncClient` / `Client` gain an opt-in `max_error_body_bytes: int | None = None`. |
| 16 | + |
| 17 | +## Security hardening |
| 18 | + |
| 19 | +- **URL secret redaction.** Request URLs that reach logs, OpenTelemetry span |
| 20 | + events, and `StatusError` messages/`repr` are now sanitized: `user:pass@` |
| 21 | + userinfo is stripped and the values of known-sensitive query/fragment |
| 22 | + parameters (`api_key`, `access_token`, `token`, `secret`, `password`, …) are |
| 23 | + masked with `REDACTED`. Redaction is centralized at the `_emit_event` |
| 24 | + emission boundary, so every resilience event is covered and a future event |
| 25 | + cannot reintroduce the leak. Non-secret URLs are byte-identical to before. |
| 26 | +- **Bounded error bodies.** With `max_error_body_bytes` set, `stream()` raises |
| 27 | + the new `ResponseTooLargeError` on a 4xx/5xx whose declared `Content-Length` |
| 28 | + exceeds the cap, *before* reading the body. Default (`None`) is unchanged. |
| 29 | + A chunked error body with no declared length is still read — a hard mid-read |
| 30 | + cap would require httpx2 private API; that deeper bound is tracked as |
| 31 | + deferred work. |
| 32 | +- **Documented trust boundaries.** `trust_env=True` proxy inheritance and the |
| 33 | + fact that `exc.response.request` exposes `Authorization`/`Cookie` headers are |
| 34 | + now called out in `architecture/`. |
| 35 | + |
| 36 | +## Correctness fixes |
| 37 | + |
| 38 | +- **RetryBudget no longer spends a token on a `Retry-After` give-up.** When a |
| 39 | + server's `Retry-After` exceeds `max_delay`, the give-up check now runs before |
| 40 | + `budget.try_withdraw()`, so a `Retry-After` flood can't drain shared-budget |
| 41 | + capacity for unrelated requests (sync and async). |
| 42 | +- **Hostile headers no longer crash the retry loop.** A `Retry-After` of a few |
| 43 | + hundred digits raised `OverflowError`; `_parse_retry_after` now degrades it |
| 44 | + to "no hint". `full_jitter_delay` likewise no longer raises at very large |
| 45 | + attempt indices — it clamps to `max_delay` as documented. |
| 46 | +- **Decoder/extras robustness.** The pydantic import is fully guarded so the |
| 47 | + decoder module loads without the extra (the friendly `ImportError` is the |
| 48 | + real fail-fast path), and `msgspec`'s internal type walk raises a friendly |
| 49 | + `ImportError` rather than `NameError` when the extra is absent. |
| 50 | +- **`AsyncClient` streaming-body detection** now recognizes non-replayable sync |
| 51 | + iterables explicitly instead of relying on an undocumented httpx2 detail. |
| 52 | +- **URL sanitizer** no longer emits a malformed `http:///path` for the |
| 53 | + credentials-but-no-host edge case. |
| 54 | + |
| 55 | +## Public API |
| 56 | + |
| 57 | +- `httpware.middleware` now defines `__all__`, so `from httpware.middleware |
| 58 | + import *` no longer leaks `httpx2`, typing helpers, or submodules. |
| 59 | + |
| 60 | +## Quality |
| 61 | + |
| 62 | +- Test suite hardened: closed coverage gaps (sync terminal mapping, the |
| 63 | + `CookieConflict` branch, `TimeoutError` tripping the circuit breaker, the |
| 64 | + three never-constructed status errors), added sync/async parity mirrors and |
| 65 | + `Client` overload typing tests, replaced a flaky `time.sleep`-based bulkhead |
| 66 | + test with a deterministic barrier, and pinned a budget-test clock. |
| 67 | +- Documentation accuracy fixes across `architecture/` and the docs site. |
| 68 | + |
| 69 | +## Shipped via |
| 70 | + |
| 71 | +PRs #62 (pydantic isolation), #63 (security cluster), #64 (correctness + |
| 72 | +public API), #65 (test quality), #66 (docs). See |
| 73 | +[`planning/audits/2026-06-14-deep-audit.md`](../audits/2026-06-14-deep-audit.md) |
| 74 | +for the full audit. |
0 commit comments