Skip to content

Commit c27c163

Browse files
lesnik512claude
andcommitted
chore(release): 0.11.0 — deep-audit hardening
Add 0.11.0 release notes (security redaction, bounded error bodies + ResponseTooLargeError, correctness fixes, middleware __all__, test/doc quality — the full 2026-06-14 deep-audit remediation, #62#66). Reset the static pyproject version to the placeholder "0": releases are tag-driven (publish.yml runs `uv version $GITHUB_REF_NAME` from the tag), so the field was stale at 0.3.0 against the 0.10.1 release history. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7d779ea commit c27c163

2 files changed

Lines changed: 75 additions & 1 deletion

File tree

planning/releases/0.11.0.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ classifiers = [
2626
"Topic :: Internet :: WWW/HTTP",
2727
"Framework :: AsyncIO",
2828
]
29-
version = "0.3.0"
29+
version = "0"
3030
dependencies = [
3131
"httpx2>=2.0.0,<3.0",
3232
]

0 commit comments

Comments
 (0)