feat(search): add Querit provider#2753
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Querit as a new web search provider across backend (tool, config, RPC), frontend (types, UI), translations, tests, and environment documentation. ChangesQuerit Search Engine Integration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
src/openhuman/tools/schemas.rs (1)
678-682: ⚡ Quick winAdd an explicit error log before returning Querit execution failures.
tool.execute(args)failures are returned to caller, but this branch doesn’t emit a corresponding diagnostics log event with the existing[rpc][tools.querit_search]prefix.Proposed patch
- let result = tool - .execute(args) - .await - .map_err(|e| format!("querit search failed: {e:#}"))?; + let result = tool.execute(args).await.map_err(|e| { + tracing::warn!( + query_len = query.chars().count(), + max_results, + error = %e, + "[rpc][tools.querit_search] failed" + ); + format!("querit search failed: {e:#}") + })?;As per coding guidelines, "Log entry/exit, branches, external calls, retries/timeouts, state transitions, and errors with verbose diagnostics using stable grep-friendly prefixes and correlation fields".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/openhuman/tools/schemas.rs` around lines 678 - 682, The map_err on tool.execute(args) should log the error with the stable grep-friendly prefix before returning; capture the error from tool.execute(args) in the closure, emit an error diagnostics log event using the existing logging facility with the prefix "[rpc][tools.querit_search]" (include correlation/context fields used in this module), then return the formatted error string as before — locate the map_err around tool.execute(args) and replace the inline map_err with a closure that logs the error and then produces the same formatted error.app/src/lib/i18n/en.ts (1)
639-639: 💤 Low valueQuerit placeholder could show an API key pattern.
The Querit placeholder is generic (
'Querit API key') while Parallel and Brave show actual key prefixes (pk_...,BSA...). If Querit keys follow a recognizable pattern, showing it here would improve UX consistency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/lib/i18n/en.ts` at line 639, Update the translation entry for 'settings.search.placeholderQuerit' so the placeholder shows the Querit API key prefix/pattern (e.g., change from 'Querit API key' to something like 'qr_...' or the actual Querit prefix if you have it) to match the UX of other providers; update the value in en.ts and mirror the change in any other locale files where 'settings.search.placeholderQuerit' appears.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/openhuman/config/ops.rs`:
- Around line 410-412: The docstring for SearchSettingsPatch.engine is
inaccurate: runtime validation in apply_search_settings rejects empty or unknown
engine values rather than falling back to "managed"; update the comment on the
pub engine: Option<String> field (SearchSettingsPatch.engine) to state that
empty or unrecognized values are rejected by apply_search_settings and must be
one of the allowed engines ("managed" | "parallel" | "brave" | "querit"), so
documentation matches runtime behavior.
In `@src/openhuman/config/schema/load.rs`:
- Around line 1481-1485: The Querit API key loaded into search.querit.api_key is
missing from the secret encryption/decryption paths; update both
decrypt_config_secrets and encrypt_config_secrets to include the same config
path that targets search.querit.api_key so it is processed when secrets.encrypt
is true (i.e., add the search.querit.api_key entry to whatever list/paths those
functions iterate over or the match arms that handle secret fields).
In `@src/openhuman/integrations/querit.rs`:
- Around line 481-486: The code logs raw upstream response body via body_text →
detail (via utf8_safe_prefix_at_byte_boundary) in the tracing::warn call; change
this to never log verbatim body content — instead sanitize or redact sensitive
data before logging: capture the response length and status, compute a safe
summary (e.g., fixed placeholder like "<redacted>" or a digest/hex of the first
N bytes) and log that along with status; update the code around
resp.text().await.unwrap_or_default(), utf8_safe_prefix_at_byte_boundary, and
the tracing::warn call to use the sanitized summary rather than the raw detail.
---
Nitpick comments:
In `@app/src/lib/i18n/en.ts`:
- Line 639: Update the translation entry for 'settings.search.placeholderQuerit'
so the placeholder shows the Querit API key prefix/pattern (e.g., change from
'Querit API key' to something like 'qr_...' or the actual Querit prefix if you
have it) to match the UX of other providers; update the value in en.ts and
mirror the change in any other locale files where
'settings.search.placeholderQuerit' appears.
In `@src/openhuman/tools/schemas.rs`:
- Around line 678-682: The map_err on tool.execute(args) should log the error
with the stable grep-friendly prefix before returning; capture the error from
tool.execute(args) in the closure, emit an error diagnostics log event using the
existing logging facility with the prefix "[rpc][tools.querit_search]" (include
correlation/context fields used in this module), then return the formatted error
string as before — locate the map_err around tool.execute(args) and replace the
inline map_err with a closure that logs the error and then produces the same
formatted error.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 007c883b-6c12-467c-8976-26395abb6d85
📒 Files selected for processing (29)
.env.exampleapp/src/components/settings/panels/SearchPanel.tsxapp/src/lib/i18n/chunks/ar-1.tsapp/src/lib/i18n/chunks/bn-1.tsapp/src/lib/i18n/chunks/de-1.tsapp/src/lib/i18n/chunks/en-1.tsapp/src/lib/i18n/chunks/es-1.tsapp/src/lib/i18n/chunks/fr-1.tsapp/src/lib/i18n/chunks/hi-1.tsapp/src/lib/i18n/chunks/id-1.tsapp/src/lib/i18n/chunks/it-1.tsapp/src/lib/i18n/chunks/ko-1.tsapp/src/lib/i18n/chunks/pt-1.tsapp/src/lib/i18n/chunks/ru-1.tsapp/src/lib/i18n/chunks/zh-CN-1.tsapp/src/lib/i18n/en.tsapp/src/lib/i18n/zh-CN.tsapp/src/utils/tauriCommands/config.tssrc/openhuman/config/mod.rssrc/openhuman/config/ops.rssrc/openhuman/config/schema/load.rssrc/openhuman/config/schema/mod.rssrc/openhuman/config/schema/tools.rssrc/openhuman/config/schemas.rssrc/openhuman/integrations/mod.rssrc/openhuman/integrations/querit.rssrc/openhuman/tools/ops.rssrc/openhuman/tools/ops_tests.rssrc/openhuman/tools/schemas.rs
graycyrus
left a comment
There was a problem hiding this comment.
Summary
This PR adds Querit as a new web search engine provider. The integration is well-structured and follows existing patterns, but two critical security issues need fixing:
- Missing secret encryption for Querit API key — When secrets.encrypt = true, the Querit key is loaded from env but NOT included in encrypt/decrypt paths, leaving it in plaintext.
- Error responses can leak sensitive data — Querit error bodies are included in error messages. If Querit echoes queries or context, they'll be exposed.
The docs issue CodeRabbit flagged has been corrected in this PR. Once the two security issues are fixed, this is ready to go.
CI Status
PR Submission Checklist is failing. Most other checks pass or are pending.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/components/settings/panels/SearchPanel.test.tsx`:
- Around line 58-62: The test helper keyEditor should stop using DOM class-based
scoping (closest('.rounded-xl')); update keyEditor to locate the control
container via accessible queries instead (e.g., find the element by
role/aria-label/aria-labelledby or a grouping with an accessible name that
matches the label) and then call within(...) on that accessible container;
modify the keyEditor function to use screen.getByRole/getByLabelText/getByText
combined with role-based ancestor selection (accessible name) instead of
closest('.rounded-xl') so tests rely on behavior/semantics not CSS.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 82980c57-0f1a-461f-ab09-c329c8c8262e
📒 Files selected for processing (26)
.env.exampleapp/src/components/settings/panels/SearchPanel.test.tsxapp/src/components/settings/panels/SearchPanel.tsxapp/src/lib/i18n/chunks/ar-1.tsapp/src/lib/i18n/chunks/bn-1.tsapp/src/lib/i18n/chunks/de-1.tsapp/src/lib/i18n/chunks/en-1.tsapp/src/lib/i18n/chunks/es-1.tsapp/src/lib/i18n/chunks/fr-1.tsapp/src/lib/i18n/chunks/hi-1.tsapp/src/lib/i18n/chunks/id-1.tsapp/src/lib/i18n/chunks/it-1.tsapp/src/lib/i18n/chunks/ko-1.tsapp/src/lib/i18n/chunks/pt-1.tsapp/src/lib/i18n/chunks/ru-1.tsapp/src/lib/i18n/chunks/zh-CN-1.tsapp/src/lib/i18n/en.tsapp/src/utils/tauriCommands/config.tssrc/openhuman/config/mod.rssrc/openhuman/config/ops.rssrc/openhuman/config/schema/load.rssrc/openhuman/config/schema/tools.rssrc/openhuman/config/schemas.rssrc/openhuman/integrations/querit.rssrc/openhuman/tools/ops.rssrc/openhuman/tools/ops_tests.rs
✅ Files skipped from review due to trivial changes (10)
- src/openhuman/config/mod.rs
- app/src/lib/i18n/chunks/fr-1.ts
- app/src/lib/i18n/chunks/zh-CN-1.ts
- app/src/lib/i18n/chunks/pt-1.ts
- app/src/lib/i18n/chunks/it-1.ts
- app/src/lib/i18n/chunks/bn-1.ts
- .env.example
- app/src/lib/i18n/chunks/ar-1.ts
- app/src/lib/i18n/chunks/en-1.ts
- app/src/lib/i18n/en.ts
🚧 Files skipped from review as they are similar to previous changes (14)
- app/src/lib/i18n/chunks/ru-1.ts
- app/src/lib/i18n/chunks/hi-1.ts
- app/src/utils/tauriCommands/config.ts
- app/src/lib/i18n/chunks/es-1.ts
- src/openhuman/tools/ops_tests.rs
- app/src/lib/i18n/chunks/id-1.ts
- src/openhuman/config/schema/load.rs
- app/src/components/settings/panels/SearchPanel.tsx
- src/openhuman/config/schemas.rs
- app/src/lib/i18n/chunks/ko-1.ts
- app/src/lib/i18n/chunks/de-1.ts
- src/openhuman/config/ops.rs
- src/openhuman/tools/ops.rs
- src/openhuman/config/schema/tools.rs
|
@MurphyZzzzz unresolved review feedback — please address before we review. |
|
Unresolved review feedback from coderabbitai[bot] — please address before we review. |
graycyrus
left a comment
There was a problem hiding this comment.
All prior security issues fixed:
- Querit API key now included in both decrypt_config_secrets and encrypt_config_secrets paths — properly encrypted when secrets.encrypt=true.
- Error response bodies no longer leaked in error messages — now a generic status-only message, plus test coverage verifying responses don't expose sensitive data.
CI is 100% green across all checks (build, coverage, E2E, tests). Code quality looks solid.
Ready to merge.
There was a problem hiding this comment.
LGTM as 2nd maintainer pass. @graycyrus's 2 security blockers (encrypt/decrypt path inclusion + HTTP body leak) are both verified fixed; CodeRabbit iterated to APPROVED; CI all green; tests + precedent solid.
Verified independently
- Encrypt/decrypt —
search.querit.api_keyincluded in bothdecrypt_config_secrets(load.rs:461-465) andencrypt_config_secrets(load.rs:574-578), mirroringparallel/bravesibling pattern. Plaintext keys persisted undersecrets.encrypt=truenow encrypted asenc2:. - HTTP body leak — non-2xx path bails with status only (
querit.rs:487); body only used forbody_lenintracing::warn!. Negative testtest_execute_non_success_status_does_not_expose_response_bodyasserts a deliberately-sensitive mock body never reaches the error message. - Query log redaction —
tracing::debug!(query_len = query.chars().count(), max_results, ...)logs length only, never query content. Matches the redact-paths/IDs hygiene applied across the codebase. - Module registration —
integrations/mod.rsaddspub mod querit;+ re-exportsQueritSearchTool. Standard. - Tool registration — gated on
SearchEngine::Querit(tools/ops.rs:452-470), registers BOTHweb_search_toolANDquerit_search. Matches sibling-engine pattern. - Engine enum extension —
apply_search_settingsvalidates"managed" | "parallel" | "brave" | "querit"(ops.rs:1015), rejects unknowns. Public read-API exposesquerit_configured: boolonly, never the key. max_results.clamp(1, 20)— defensive.- 12 unit tests in
querit.rscovering request shaping, response parsing, missing-key behavior, error-body redaction. - i18n — 13 locales touched (
en+ 12 chunk-1 files), mechanical placeholder-copy per CLAUDE.md rules. - PR template adherence — body has all 6 required headings; N/A items correctly use
- [x] N/A: reason(avoids the trap from PR #2851).
Residual nit (NOT blocking, just flagging for awareness)
querit.rs:495-498 app-level error path bails with search_resp.error_msg interpolated. Different code path from the HTTP-non-2xx fix. If Querit's error_msg ever echoes user query/context back (typical of validation errors), it'd leak. The HTTP path is safe; the app-level path inherits Querit's discipline. Optional follow-up: add a sibling negative test feeding a mock query-echoing error_msg, or replace the interpolation with a generic string. Either fine — depends on Querit's actual error_msg behavior.
Ready to ship.
|
I've resolved the merge conflicts and pushed the updated branch. Could you please take another look when you have a chance? @graycyrus @oxoxDev |
|
Code looks great — both security issues are fixed and fully verified by me and oxoxDev. However, the Rust Core Coverage job is failing. That needs to be resolved before I can approve. Let me know what the coverage issue is and we can get this across the line! |
This looks like an unrelated flaky Rust test in the coverage job. I reproduced the focused test locally and it passed. Could someone with Actions permissions please re-run the failed job? @graycyrus |
The failing coverage job is not failing because of diff coverage or the Querit changes directly. The command
Failure path:
Relevant code path:
I pulled the latest PR branch locally and ran the focused test:
It passed locally, which supports that this is a randomness-triggered flake rather than a deterministic Querit regression. |
graycyrus
left a comment
There was a problem hiding this comment.
All prior security issues resolved + latest commit adds even more redaction. Code is excellent.
What's fixed since last review:
- New commit (18c36f3) further hardens error redaction: application-level Querit errors now only expose error_code, not error_msg (with a comprehensive test to prevent regression).
- All HTTP and application-level error paths now safe from data exposure.
- Secret encryption/decryption paths all correct.
Status:
- CodeRabbit: APPROVED ✓
- Code quality: Excellent ✓
- Security audit: Clean ✓
- All review threads: Resolved ✓
- Blocker: Many CI checks still PENDING (not failed, just not complete yet).
I'll APPROVE as soon as CI completes. Code is ready—just waiting on the test suite to finish running.
|
I don't have permission to re-run the upstream GitHub Actions job. |
yes. i'll watch this and if it passes, will merge. thanks brother |
graycyrus
left a comment
There was a problem hiding this comment.
looks good! code is excellent, all prior security fixes in place, and CodeRabbit already approved. CI still has a few jobs pending (core smoke test, Rust coverage, E2E, Windows tests), but no failures so far.
once those complete green, this is ready to roll. nice work on the Querit integration—the error redaction hardening and secret encryption handling are solid.
Summary
POST https://api.querit.ai/v1/search..env.example.querit_searchandweb_search_toolwhen Querit is the active configured engine.Problem
OpenHuman currently supports managed search and several BYO search providers, but not Querit. Users with a Querit API key cannot configure OpenHuman to use Querit for direct web search, including site, time range, country, and language filters.
Solution
This PR adds a Querit integration that follows the official Querit POST API shape and the local
querit-web-searchskill behavior. The implementation reuses the existing unified search engine settings model by storing Querit credentials undersearch.queritwith the sameSearchEngineCredentialsstructure used by other BYO engines.Important choices:
SearchConfiginstead of adding a separate top-level config block.count/filtersand OpenHuman-friendly aliases such asmax_results,include_domains,time_range,countries, andlanguages.Submission Checklist
## Related— N/A: no matrix feature IDs changed.Closes #NNNin the## Relatedsection — no issue provided.Impact
Adds a new optional BYO search provider. Existing managed, Parallel, Brave, Seltz, and SearXNG paths are preserved.
Runtime impact:
web_search_toolandquerit_searchonly whensearch.engine = "querit"and a Querit key is configured.Security:
Related
AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
codex/querit-search94bf886b347189f368b82f3a9d2dadd6669d2ea5Validation Run
pnpm --filter openhuman-app format:checkpnpm typecheckGGML_NATIVE=OFF cargo test --manifest-path Cargo.toml querit --libcargo fmt --manifest-path Cargo.toml --check; focused Rust tests passed.cmakeand documented below.Validation Blocked
command:pnpm rust:check/ pre-push hookcargo check --manifest-path app/src-tauri/Cargo.tomlerror:failed to execute command: No such file or directory (os error 2); is cmake not installed?impact:Local Tauri cargo check could not complete in this environment. Querit core tests, TypeScript typecheck, formatting checks, and manual local RPC smoke validation passed.Behavior Changes
Parity Contract
effective_engine()key-gated fallback pattern; without a Querit key, search falls back to Managed instead of registering unusable tools.Duplicate / Superseded PR Handling
Summary by CodeRabbit
New Features
Documentation
Localization
Tests