ulysses/services/search
Ernest Hysa 5e9b415bd9
fix(search): pin httpx connection to resolved IP to block DNS rebinding (#704)
* fix(search): pin DNS-validated fetch connections

Rebase the DNS-rebinding SSRF fix onto current dev after search content moved behind the services.search.content canonical module.

Integrate the pinned httpcore NetworkBackend/BaseTransport approach with the current size-capped Client.stream fetch path, preserving Host/SNI semantics while forcing TCP connect to the already validated resolved IP.

Keep src.search.content as the compatibility wrapper and preserve existing OG-image http(s) behavior; this avoids reintroducing the unrelated scope changes that previously blocked review.

Add the explicit httpcore>=1.0,<2.0 requirement used by the public httpcore NetworkBackend and ConnectionPool APIs.

* test(search): restore and rebase DNS rebinding regressions

Keep the current security regression coverage that the stale PR branch had deleted, including auth-disabled localhost bypass and Ollama cookbook hardening tests.

Carry forward the DNS-rebinding coverage for private resolve blocking, pinned TCP connect behavior, Host header preservation, redirect revalidation, and the BaseTransport/public-httpcore static guard.

Update redirect tests to mock the current Client.stream-based capped fetch path rather than the older httpx.stream/get path.

* test(search): adapt size-cap fetch tests to pinned client stream

The DNS-rebinding repair moved _get_public_url from the module-level httpx.stream shortcut to httpx.Client(...).stream(...) so the fetch can use the pinned transport.

Keep the existing size-cap test fakes by routing Client.stream through the monkeypatched httpx.stream only when a test has installed that fake; otherwise fall back to a real Client.

This fixes the CI failures in tests/test_web_fetch_size_caps.py without touching unrelated upload-handler atomicity behavior, which is already flaky on clean origin/dev.

---------

Co-authored-by: Alexandre Teixeira <alexandremagteixeira@gmail.com>
2026-07-02 13:08:06 +01:00
..
__init__.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
analytics.py fix: search analytics FileHandler crashes on startup writing to read-only image layer (#2366) 2026-06-07 19:26:22 +02:00
cache.py fix(search): write cache under DATA_DIR, guard mkdir against read-only path (#3334) 2026-06-07 22:37:12 +01:00
content.py fix(search): pin httpx connection to resolved IP to block DNS rebinding (#704) 2026-07-02 13:08:06 +01:00
core.py fix: web search content blocks numbered by fetch completion order break citations (#1672) 2026-06-03 14:22:55 +09:00
providers.py refactor(search): centralize the web-scraping User-Agent into one constant (#4325) 2026-06-16 01:33:47 +00:00
query.py fix: _extract_entities crashes on a non-string query (#1724) 2026-06-03 13:30:28 +09:00
ranking.py Word-boundary match for snippet and subject-term ranking (#1473 follow-up) (#2556) 2026-06-05 08:04:31 +01:00
service.py fix: SearchService.search() calls comprehensive_web_search incorrectly (broken public API) (#1720) 2026-06-03 13:33:56 +09:00