Skip to content

v0.2.2

Choose a tag to compare

@dbowm91 dbowm91 released this 02 Oct 11:07

EggFetch v0.2.2

EggFetch 0.2.2 publishes the M007 native transport failure classifier as the coordinated release. It is a patch release under the pre-1.0 compatibility policy: public Rust, Python, C, CLI, and HTTPX APIs, the feature graph and defaults, Rust MSRV (1.89), and dependency policy are unchanged apart from the additive Rust error-domain API below.

Added

  • eggfetch-core: native transport failure classification. Error gains one additive method, transport_failure_kind(), returning Option<TransportFailureKind> for the new #[non_exhaustive] enum TransportFailureKind::{Connect, Tls, Protocol, Cancelled}; None means the typed evidence does not prove a category.

    use eggfetch_core::error::{Error, TransportFailureKind};
    
    match err.transport_failure_kind() {
        Some(TransportFailureKind::Tls) => { /* TLS config/handshake/verification */ }
        Some(TransportFailureKind::Connect) => { /* connection establishment */ }
        Some(TransportFailureKind::Protocol) => { /* HTTP framing / premature body */ }
        Some(TransportFailureKind::Cancelled) => { /* cancelled before completion */ }
        _ => { /* unknown, or a future variant */ }
    }

    This is a Rust core surface only. The Python, CLI, FFI, and Node adapters did not gain an equivalent classifier API; use the existing per-adapter error surfaces there.

    The Error enum itself is unchanged — no new variants, no #[non_exhaustive], unchanged kind() tokens and Display. The classifier is diagnostic only and does not imply retryability: RetryPolicy::is_error_retryable() is unchanged and never consults it.

Fixed

Correctness and security hardening from the internal audit that landed after 0.2.1, plus one build fix found by the release gate itself:

  • Core — timeout arithmetic saturates instead of panicking on huge finite values; CONNECT target formatting rejects /, ?, #, and @ in the authority; low-level transport retry is limited to connect-level failures plus stale-pool cancellations; proxy configuration fails closed on a missing host; an empty CA directory fails closed for the ca_certificate (replace) variant; SOCKS deadline overflow is treated as an already-expired Total timeout; Content-Length conflicts are rejected; cross-origin Referer/Origin stripping, proxy-auth conflict handling, redirect SNI/pinning retention, and Total-wins-tie deadline breaking are enforced.
  • Redaction — proxy_rejection_body redacts credential-looking text on token boundaries, the redact helper always truncates at ?/#, TransportHints Debug logs target length only, and the HTTPX cookie __repr__ redacts values.
  • Python — ssl.SSLContext translation rejects security-semantic OP_UNSAFE_LEGACY_RENEGOTIATION, OP_LEGACY_SERVER_CONNECT, OP_NO_TICKET, and OP_NO_RENEGOTIATION; websocket failures raised by native eggfetch errors are translated to WebSocketNetworkError; async streaming iterators spawn on the client runtime handle like sync iterators; non-coroutine async trace callbacks are rejected with TypeError before dispatch.
  • CLI — --no-follow now parses (overrides_with instead of conflicts_with); JSON and NDJSON redirect URLs are routed through safe_url_for_display so userinfo, query, and fragment are stripped.
  • FFI — out-pointers are nulled on allocation failure, the tracking pointer is cleared before Box::from_raw so a panic fallback cannot double-free, the builder is restored on Err, and the bounded C-string scan no longer uses the signed-only cast_unsigned() conversion that made eggfetch-ffi fail to compile on targets where c_char is u8 (aarch64 Linux and other unsigned-c_char targets).
  • Node — header and body FFI failures propagate as napi::Error instead of a silent skip or empty body.

Packages

The PyPI release contains 18 wheels for CPython 3.10–3.15 across Linux x86_64, macOS arm64, and Windows x86_64, plus one source distribution. Python 3.15 has no stable interpreter yet, so the 3.15 wheels were built against CPython 3.15.0-rc.2 on all three platforms; that matrix row will resolve a stable 3.15.x automatically once 3.15.0 final ships.

Verification

Released from signed tag v0.2.2 on commit 015a56d7ec3edf186eec8ebccff01cbf5584274e, with Tier 1, Tier 2 (including the Rust 1.89.0 MSRV matrix, the six-profile public API oracle, and 223 semver checks), Tier 3, and a live security preflight green on that exact candidate, plus a build-only 19-distribution wheel rehearsal on the same commit.

See the changelog for full detail.