Skip to content

fix(search): resolvable searxng host in docker config + diagnostics (#90) - #93

Merged
us merged 4 commits into
mainfrom
fix/searxng-default-host
Jun 5, 2026
Merged

fix(search): resolvable searxng host in docker config + diagnostics (#90)#93
us merged 4 commits into
mainfrom
fix/searxng-default-host

Conversation

@us

@us us commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Refs #90 (does not auto-close — leaving the issue open for maintainer review).

Root cause

config.docker.toml shipped searxng_url = "http://searxng-internal:8080" — a SaaS-only network alias introduced in #70 for the crw-saas dual-network topology (search_rpc + public_egress). The opencore reference docker-compose.yml defines no custom networks and no searxng-internal alias; the sidecar is reachable only as searxng:8080. So the host never resolved and /v1/search (plus the crw_search MCP tool) failed for every user of the reference stack. crw-saas is a separate repo with its own compose/config, so reverting the opencore default is safe.

Note: the issue's symptom report is slightly off — crw_search is always advertised in the MCP tool list, and the "Search is disabled" message only fires when searxng_url is unset. With searxng-internal set, the real failure is a DNS/transport error at call time. This PR fixes the host and the poor diagnosability around it.

Changes (per commit)

  • fix(search) — point the default at searxng:8080; rewrite the comment for the opencore topology + the CRW_SEARCH__SEARXNG_URL override.
  • test(search) — regression guard: parse config.docker.toml and assert every renderer/search host is a known compose service name (would have caught fix(search): point engine at searxng-internal alias (search_rpc-only) #70; bites on future drift). Uses the in-tree toml crate, no compose-YAML parsing.
  • feat(search) — diagnosability:
    • startup log of search state (disabled / enabled-but-unset / enabled) via a unit-tested helper
    • name the configured host in target_unreachable errors, origin-only sanitized (scheme://host[:port]) so a credentialed URL never leaks; also reqwest::Error::without_url() to strip the embedded request URL
    • optional non-fatal /healthz startup reachability probe
    • document the search_disabled / target_unreachable / timeout contract in the crw_search tool description
  • docs(docker) — repair the stale docker.md (it claimed "two services" with an obsolete compose snippet); add a Search (SearXNG) section (the SEARXNG_BASE_URL vs searxng_url distinction, cold-start timing); reconcile mcp.md's "crw_search = Cloud only" claim (a self-hosted server with SearXNG exposes it); regenerate the HTML mirror.

Verification

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace — all green.
  • New tests: docker_config_hosts (+ proven to fail when reverted to searxng-internal), 6 diagnostics tests (incl. credential-leak guards), map_search_error_transport_names_sanitized_host.
  • Manual smoke (from inside the compose network): docker compose exec searxng wget -qO- http://searxng:8080/healthz.

Scope notes

  • Did not add SaaS network machinery to the opencore compose, change the [search] quality flags, or hide crw_search when search is down (contract stability).
  • Deferred (separate issue): whether the standalone embedded crw-mcp binary (no backend) should advertise crw_search at all.

us added 4 commits June 5, 2026 12:17
config.docker.toml shipped `searxng_url = http://searxng-internal:8080`, a
SaaS-only network alias (added in #70) that has no service or alias on the
opencore single-bridge compose network. The host never resolved, so /v1/search
and the crw_search MCP tool failed for every user of the reference stack.

Point it at `searxng:8080` — the actual compose service name — and rewrite the
comment to describe the opencore topology and the CRW_SEARCH__SEARXNG_URL
override instead of the SaaS rationale.
Parses config.docker.toml and asserts every renderer/search host resolves to a
known docker-compose service name. This would have caught the SaaS-only
`searxng-internal` host that #70 leaked into the opencore default, and bites on
any future drift. Uses the in-tree toml crate (no compose YAML parsing).
Search failures were hard to diagnose: the tool is always advertised, the
'Search is disabled' message only fires when the URL is unset, and a
set-but-unreachable host surfaced an opaque transport error.

- log search state once at startup (disabled / enabled-but-unset / enabled),
  via a unit-tested helper in a new diagnostics module
- name the configured host in target_unreachable errors so operators see which
  host failed, sanitized to scheme://host[:port] so a credentialed searxng_url
  never leaks (also strip reqwest's embedded URL via without_url())
- optional non-fatal /healthz reachability probe at startup
- document the search_disabled / target_unreachable / timeout contract in the
  crw_search MCP tool description
docker.md claimed 'two services' and showed an obsolete compose snippet with no
searxng/chrome/stealth and a dead env var. Repair the service table and snippet
to match the shipped stack, add a Search (SearXNG) section covering searxng:8080,
the CRW_SEARCH__SEARXNG_URL override, the SEARXNG_BASE_URL vs searxng_url
distinction, and cold-start timing. Reconcile mcp.md's 'crw_search = Cloud only'
claim (a self-hosted server with SearXNG exposes it too). Cross-link from
search.md and self-hosting.md. Regenerated HTML mirror.
@us
us merged commit e79f0f4 into main Jun 5, 2026
1 check passed
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