fix(net): bounded request time, curl size and time caps, lock waits, sane prices

From the full-repo Codex audit:
- MSN and Yahoo clients set connect and body timeouts but none for the
  response headers, so a server that stalled before answering hung the
  call; four such calls take every MCP call slot. Add a 30 s overall
  deadline. Every curl-impersonate run gets --max-time 600 and a 256 MiB
  --max-filesize, and output above that is rejected (curl cannot cap a
  response without a length); the Yahoo cookie fetch gets --max-time.
- Ownership commands blocked on the database lock without limit, so a
  long sync or import, or a stuck process, held MCP call slots
  indefinitely. Wait up to 30 s, then fail with a "busy, try again" error.
- A price of 1e20 saturated `as i64` and the change subtraction then
  overflowed. Prices that are not finite, negative, or above 1e12 IDR are
  treated as missing, and a quote's own price as an error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
This commit is contained in:
hermes 2026-10-17 04:28:30 +00:00
commit 66207d24b6
6 changed files with 144 additions and 34 deletions

View file

@ -97,8 +97,19 @@ pub fn run_owned_with_fallback(
Err(last_error.expect("at least one profile was tried"))
}
/// Every curl run gives up after this long, so a stalled server cannot hang
/// a command or an MCP call.
const MAX_TIME_SECS: &str = "600";
/// Largest response kept in memory (IDX report files are a few MB).
const MAX_RESPONSE_BYTES: usize = 256 * 1024 * 1024;
fn run_binary(stage: &str, binary: &str, args: &[String]) -> Result<Output, IdxError> {
let output = Command::new(binary).args(args).output().map_err(|e| {
let max_filesize = MAX_RESPONSE_BYTES.to_string();
let output = Command::new(binary)
.args(["--max-time", MAX_TIME_SECS, "--max-filesize", max_filesize.as_str()])
.args(args)
.output()
.map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
return IdxError::Http(format!(
"curl-impersonate binary '{binary}' not found; set {OVERRIDE_ENV} or install nixpkgs#curl-impersonate-chrome"
@ -107,6 +118,12 @@ fn run_binary(stage: &str, binary: &str, args: &[String]) -> Result<Output, IdxE
IdxError::Http(format!("failed to run {binary} for {stage}: {e}"))
})?;
// --max-filesize cannot stop a response without a length; check here too.
if output.stdout.len() > MAX_RESPONSE_BYTES {
return Err(IdxError::Http(format!(
"{stage} response exceeds {MAX_RESPONSE_BYTES} bytes"
)));
}
if output.status.success() {
return Ok(output);
}