Skip to content

fix: bound the last two unbounded operational curl calls - #6181

Closed
0xacee wants to merge 1 commit into
Osmantic:public-betafrom
0xacee:fix/curl-timeout-stragglers
Closed

0xacee wants to merge 1 commit into
Osmantic:public-betafrom
0xacee:fix/curl-timeout-stragglers

Conversation

@0xacee

@0xacee 0xacee commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Why this matters

ODS bounds essentially every operational curl call — preflight probes, health checks, downloads, update checks — except two stragglers:

  1. installers/phases/12-health.sh — after detecting Perplexica needs configuration, the phase fetches ${PERPLEXICA_URL}/api/config to learn provider UUIDs with no timeout, then pipes it into the config-push Python. A wedged Perplexica listener (container "Created", port mapped but app hung, firewall DROP) freezes install phase 12 indefinitely with the installer looking alive. The identical query 20 lines earlier in the same block already uses --max-time 5 — this site was simply missed.
  2. installers/macos/ods-macos.sh cmd_chat — the ./ods-macos.sh chat command POSTs to /v1/chat/completions unbounded. A stalled local inference server or unreachable cloud endpoint hangs the user's terminal forever; every other probe in the same file uses --max-time 10.

A peer that accepts TCP but never answers is precisely the failure mode --connect-timeout alone cannot catch — --max-time is required.

What changed

  • 12-health.sh: curl -sf --max-time 5 "${PERPLEXICA_URL}/api/config" — same bound as the sibling fetch above it.
  • ods-macos.sh: curl -sf --connect-timeout 5 --max-time 300 -X POST ... — generous ceiling for slow CPU/cloud inference; bounds hangs, not slow responses.

No behavior change when services respond normally; failures now surface through the existing error paths (PERPLEXICA_SETUP empty → auto-setup skipped, cmd_chat → "Chat request failed.").

Regression test

ods/tests/test-curl-timeout-stragglers.sh stubs curl on PATH: the stub records argv and sleeps 30 s when --max-time is absent. It then:

  • evals the real cmd_chat function body (extracted from ods-macos.sh) with stubbed ai/resolve_cli_llm_route — boundary-level proof the flags reach curl's argv;
  • extracts and executes each curl ... /api/config invocation line from 12-health.sh under the stub;
  • statically sweeps both files for any curl -… invocation lacking max-time/a bounds array.

Red on upstream/public-beta (15eb56fab): cmd_chat stalls → exit 124; the second /api/config fetch stalls → 124; sweep reports 1 unbounded call per file. 1 passed, 5 failed.
Green on this branch: 6 passed, 0 failed — and the already-bounded sibling fetch at :494 correctly passes, confirming the harness isn't tautological.

Validation

  • bash -n both files: clean
  • shellcheck -S error on both files + test: clean
  • git diff --check: clean

Overlap check

Searched open/closed PRs for 12-health, ods-macos curl, curl timeout install. Closed unmerged attempts (#435, #391) were broad sweeps abandoned long ago; #1229 (merged) bounded the STT preload only. My own #6180 covers the demo scripts — disjoint files. No open PR touches these two call sites.

Notes

  • Live end-to-end run against a real wedged Perplexica/cloud endpoint is pending CI/maintainer validation; the stub harness exercises the exact argv boundary curl sees.

Every operational curl call in the installer and CLI is bounded except
two stragglers:

- installers/phases/12-health.sh fetches Perplexica /api/config before
  pushing the provider config with no timeout — while the identical
  query 20 lines earlier already uses --max-time 5. A wedged Perplexica
  listener freezes phase 12 mid-install.
- installers/macos/ods-macos.sh cmd_chat POSTs chat completions with no
  bound, so a stalled local or cloud endpoint hangs the chat command
  forever.

Bound the config fetch with --max-time 5 (matching its sibling) and the
chat POST with --connect-timeout 5 --max-time 300 (generous ceiling for
slow inference; bounds hangs, not slow responses).

Regression test stubs curl to sleep 30s on any call lacking --max-time,
evals the real cmd_chat body and each extracted /api/config fetch line,
and statically sweeps both files: red on base (two 124 hangs + sweep
hits), green here.
@0xacee 0xacee closed this Oct 4, 2026
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.

1 participant