fix(search): resolvable searxng host in docker config + diagnostics (#90) - #93
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #90 (does not auto-close — leaving the issue open for maintainer review).
Root cause
config.docker.tomlshippedsearxng_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 referencedocker-compose.ymldefines no custom networks and nosearxng-internalalias; the sidecar is reachable only assearxng:8080. So the host never resolved and/v1/search(plus thecrw_searchMCP 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.Changes (per commit)
fix(search)— point the default atsearxng:8080; rewrite the comment for the opencore topology + theCRW_SEARCH__SEARXNG_URLoverride.test(search)— regression guard: parseconfig.docker.tomland 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-treetomlcrate, no compose-YAML parsing.feat(search)— diagnosability:target_unreachableerrors, origin-only sanitized (scheme://host[:port]) so a credentialed URL never leaks; alsoreqwest::Error::without_url()to strip the embedded request URL/healthzstartup reachability probesearch_disabled/target_unreachable/timeoutcontract in thecrw_searchtool descriptiondocs(docker)— repair the staledocker.md(it claimed "two services" with an obsolete compose snippet); add a Search (SearXNG) section (theSEARXNG_BASE_URLvssearxng_urldistinction, cold-start timing); reconcilemcp.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.docker_config_hosts(+ proven to fail when reverted tosearxng-internal), 6diagnosticstests (incl. credential-leak guards),map_search_error_transport_names_sanitized_host.docker compose exec searxng wget -qO- http://searxng:8080/healthz.Scope notes
[search]quality flags, or hidecrw_searchwhen search is down (contract stability).crw-mcpbinary (no backend) should advertisecrw_searchat all.