Skip to content

fix: validate timeout_limit at the HTTP entry point instead of panicking on inf - #135

Merged
sahenjp merged 1 commit into
sahenjp:mainfrom
souta-lab:fix/a07-timeout-limit-validation
Nov 11, 2026
Merged

sahenjp merged 1 commit into
sahenjp:mainfrom
souta-lab:fix/a07-timeout-limit-validation

Conversation

@souta-lab

Copy link
Copy Markdown
Contributor

Summary

Validate the timeout_limit request parameter at the HTTP entry point and return 400 for invalid values, as prescribed by A07 in docs/AUDIT-2026-11-02.md. /search?q=rust&format=json&timeout_limit=inf previously panicked the request task in Duration::from_secs_f64.

Root cause

src/web/handlers.rs copied params.timeout_limit into the query unchecked, and src/aggregator.rs fed it to Duration::from_secs_f64 after only a .max(0.1) floor, which does not stop inf (or a finite value too large to represent as a Duration). The configured search.timeout_limit had no validation either, even though TOML can express inf.

Changes

  • src/web/handlers.rs: a supplied timeout_limit must be finite, greater than 0 and at most 60 seconds; anything else is a 400 (JSON error body for format=json, error page otherwise), following the existing language-parameter validation pattern.
  • src/aggregator.rs: the shared predicate is_valid_timeout_limit and the cap live next to SearchRequest. The deadline computation resolves the effective value through resolve_timeout_limit — an invalid override arriving through the library API, which bypasses the HTTP validation, falls back to the configured limit — and uses try_from_secs_f64, so this path can no longer panic.
  • src/settings.rs: search.timeout_limit is validated like fetch.timeout (finite, positive, representable), so a config file cannot smuggle inf in either.
  • Tests: the predicate (inf, -inf, NaN, zero, negative, over-cap, 1e300), the fallback resolution, and settings rejection via TOML using the same value set as the existing fetch.timeout test.

About the 60 second cap: the audit asks for a server limit but does not name a value. 60 seconds is 20x the 3.0 second default and matches the largest timeout already present in the settings (research/LLM timeouts, 60s). Happy to adjust if another value is preferred.

No dependencies or response fields change. Valid requests behave as before.

Verification

Linux x86_64, Rust 1.99.1:

  • New tests: 3 passed.
  • Live smoke test against the built server: timeout_limit=inf, nan, -5 and 3600 all return 400 ({"error":"timeout_limit must be a finite number of seconds greater than 0 and at most 60"} for JSON); timeout_limit=2.5 returns 200 and the server stays healthy afterwards.
  • cargo test --all-targets: 1110 passed, 1 failed. The failure is tests/pdf_pages.rs (Japanese PDF text extraction), which needs Poppler Japanese CMap data that is not installed in this sandbox; it fails identically on unmodified main and is unrelated to this change. Proxy environment variables were excluded from the test process for the loopback fixtures, as in fix: reject executable schemes in search results #52.
  • cargo fmt --all --check: passed.
  • cargo clippy --all-targets -- -D warnings: passed.

Limitations

Other platforms are left to CI. The library-API fallback does not apply the 60 second cap to a configured value (only the HTTP entry point enforces the cap); it only guarantees the deadline computation cannot panic.

Related

Addresses A07 in the existing audit.

AI assistance: implementation and tests.

@souta-lab
souta-lab requested a review from sahenjp as a code owner November 9, 2026 23:34
@sahenjp
sahenjp merged commit f318d72 into sahenjp:main Nov 11, 2026
14 checks passed
sahenjp pushed a commit that referenced this pull request Nov 11, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.31.2](v0.31.1...v0.31.2)
(2026-11-11)


### Bug Fixes

* parse the LLM query array as JSON instead of splitting on commas
([#134](#134))
([fee1a93](fee1a93))
* update rustix to 1.1.6 for RUSTSEC-2026-0486
([c07945e](c07945e))
* validate timeout_limit at the HTTP entry point instead of panicking on
inf ([#135](#135))
([f318d72](f318d72))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants