Skip to content

feat: Add raw OpenSearch DSL search endpoint/tool/SDK, configurable search fuzziness - #2206

Open
edwinjosechittilappilly wants to merge 10 commits into
mainfrom
feat/raw-search-api-sdk
Open

feat: Add raw OpenSearch DSL search endpoint/tool/SDK, configurable search fuzziness#2206
edwinjosechittilappilly wants to merge 10 commits into
mainfrom
feat/raw-search-api-sdk

Conversation

@edwinjosechittilappilly

@edwinjosechittilappilly edwinjosechittilappilly commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Exposes the Langflow "OpenSearch (Multi-Model Multi-Embedding)" component's raw_search output as a first-class OpenRAG capability, with the same endpoint/tool/SDK surface openrag_search already has:

  • POST /v1/search/raw (src/api/v1/search.py) — runs a caller-supplied OpenSearch Query DSL (dict) or plain-text query through the caller's ACL-scoped OpenSearch client (session_manager.get_user_opensearch_client), so document-level ACLs still apply, unlike the Langflow component's admin-credentialed client. Supports filters/filter_id/limit/score_threshold, same as /v1/search.
  • SearchService.raw_search() (src/services/search_service.py) — the service-layer implementation; also extracts the filter-clause-building logic (previously duplicated twice in search_tool) into a shared _build_filter_clauses() helper.
  • sanitize_raw_search_response() (src/utils/opensearch_utils.py) — strips embedding-vector fields and fences chunk text with untrusted-content markers before returning raw hits, mirroring the Langflow component's own sanitization.
  • MCP tool openrag_raw_search (src/mcp_http/server.py) — auto-exposed from the new route via the existing COMPONENT_CUSTOMIZATIONS mechanism.
  • SDKsclient.search.raw_query(...) (Python) and client.search.rawQuery(...) (TypeScript), each with a RawSearchResponse model/type and integration test coverage.

Raw DSL execution was deliberately not added to the chat agent's autonomous tool registry (agentd's search_tool) — letting the LLM run arbitrary OpenSearch DSL mid-conversation is a materially larger attack surface than the semantic search it already has. This stays an explicit, API-key-gated capability only.

Also included: the hybrid search's keyword-match fuzziness (previously hardcoded to "AUTO:4,7" in SearchService.search_tool) is now an optional parameter threaded through search_tool/search(), /v1/search, and both SDKs — defaulting to "AUTO:4,7" to preserve existing behavior, but overridable (e.g. "AUTO:7,10", "0" for exact-only matching).

Test plan

  • python -m py_compile / ruff check on all touched Python files (one pre-existing unrelated F401 in sdks/python/openrag_sdk/search.py confirmed present on main before this change)
  • pytest tests/unit/test_search_service_exact_filter.py passes (validates the extracted _build_filter_clauses helper is behavior-preserving)
  • TypeScript SDK builds via tsup (JS/CJS output); .d.ts generation fails on a pre-existing tsconfig.json/installed-typescript-version mismatch unrelated to this change (confirmed via git stash)
  • vitest run tests/integration.test.ts collects all tests (37, up from 35) with no syntax errors
  • Integration tests (tests/integration/sdk/test_search.py::TestRawSearch, sdks/typescript/tests/integration.test.ts "Raw Search"/fuzziness cases) require a live OpenRAG instance — not run in this environment

Summary by CodeRabbit

  • New Features
    • Added raw search for OpenSearch DSL and text queries through the API, Python and TypeScript SDKs, and MCP tools.
    • Added filtering, result limits, score thresholds, and access-controlled results.
    • Added configurable search fuzziness, including exact-match support.
    • Raw results now remove embedding data and mark untrusted text content.
  • Bug Fixes
    • Improved validation and error handling for malformed, oversized, deeply nested, or unsafe queries.
  • Tests
    • Expanded coverage for raw queries, filtering, validation, fuzziness, limits, and response sanitization.

…earch fuzziness

Expose the Langflow OpenSearch (Multi-Model Multi-Embedding) component's
raw_search output as a first-class OpenRAG capability, matching the existing
openrag_search endpoint/tool/SDK surface:

- POST /v1/search/raw runs a caller-supplied OpenSearch Query DSL (or plain
  text) through the caller's ACL-scoped OpenSearch client, stripping
  embedding vectors and fencing chunk text before returning results.
- Exposed as the openrag_raw_search MCP tool.
- Added client.search.raw_query()/rawQuery() to the Python and TypeScript
  SDKs, with integration test coverage.
- Extracted the duplicated filter-clause-building logic in SearchService
  into a shared helper.

Also exposes the hybrid search's keyword-match fuzziness (previously
hardcoded to "AUTO:4,7") as an optional `fuzziness` parameter on
/v1/search, search_tool, and both SDKs, defaulting to "AUTO:4,7" to
preserve existing behavior.
@github-actions github-actions Bot added backend 🔷 Issues related to backend services (OpenSearch, Langflow, APIs) tests labels Aug 4, 2026
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The change adds configurable keyword fuzziness and authenticated raw OpenSearch queries. The API, search service, MCP interface, Python SDK, and TypeScript SDK support raw DSL or text queries with filters, limits, thresholds, typed responses, and response sanitization.

Changes

Search API and SDK enhancements

Layer / File(s) Summary
Search fuzziness propagation
src/auth_context.py, src/services/search_service.py, src/api/v1/search.py, sdks/python/openrag_sdk/search.py, sdks/typescript/src/search.ts, sdks/typescript/src/types.ts, src/mcp_http/server.py, tests/integration/sdk/test_search.py, sdks/typescript/tests/integration.test.ts
Standard search accepts configurable fuzziness with a default of "AUTO:7,10". The value passes through the API, context, service, SDK, MCP descriptions, and integration tests.
Raw search endpoint and service
src/services/search_service.py, src/utils/opensearch_utils.py, src/api/v1/search.py, src/app/routes/public_v1.py, src/mcp_http/server.py
The raw search route accepts DSL objects or text, validates query safety, applies filters and limits, executes authenticated queries, handles errors, and sanitizes returned sources.
SDK raw search contracts and clients
sdks/python/openrag_sdk/models.py, sdks/python/openrag_sdk/search.py, sdks/typescript/src/types.ts, sdks/typescript/src/search.ts
Python and TypeScript SDKs add raw query methods and typed raw response models.
Search integration validation
tests/integration/sdk/test_search.py, sdks/typescript/tests/integration.test.ts
Integration tests cover fuzziness, raw DSL and text queries, filtering, limits, sanitization, cleanup, whitespace validation, and malformed queries.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: phact

Sequence Diagram(s)

sequenceDiagram
  participant SearchClient
  participant SearchAPI
  participant SearchService
  participant OpenSearch

  SearchClient->>SearchAPI: POST /v1/search/raw
  SearchAPI->>SearchService: raw_search(query, filters, limit, score_threshold)
  SearchService->>OpenSearch: execute authenticated raw query
  OpenSearch-->>SearchService: raw response
  SearchService-->>SearchAPI: sanitized response
  SearchAPI-->>SearchClient: typed raw search response
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two main changes: raw OpenSearch DSL search and configurable search fuzziness.
Docstring Coverage ✅ Passed Docstring coverage is 97.06% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/raw-search-api-sdk

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@edwinjosechittilappilly edwinjosechittilappilly changed the title Add raw OpenSearch DSL search endpoint/tool/SDK, configurable search fuzziness feat: Add raw OpenSearch DSL search endpoint/tool/SDK, configurable search fuzziness Aug 4, 2026
Comment thread src/api/v1/search.py Fixed
Comment thread src/api/v1/search.py Fixed
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Aug 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 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 `@sdks/typescript/tests/integration.test.ts`:
- Around line 449-530: Update the “Raw Search” describe block to own its fixture
by adding a beforeAll that creates and ingests a document containing the
expected “orange kangaroos jumping” content before the tests run, and clean up
that document afterward using the block’s existing client APIs. In the filter
test’s finally block, retain document deletion and also remove tmpDir
recursively with force enabled via fs.rmSync.
- Around line 532-540: Update the malformed DSL assertion in the “should raise
an SDK error for a malformed DSL clause” test to expect ValidationError,
matching the SDK’s handling of 400 responses. Keep the existing whitespace-only
query assertion unchanged, and only assert the error message if the test must
distinguish malformed DSL validation.

In `@src/api/v1/search.py`:
- Around line 135-141: Harden the `/v1/search/raw` validation around
`body.query` before it reaches `raw_search()`: enforce an OpenSearch clause
allowlist or denylist, reject oversized or deeply nested query structures, and
apply limits for bucket, top, and other resource-intensive clauses. Preserve the
existing required-query and object/string type errors, and return a clear 400
response for disallowed or over-limit queries.

In `@src/app/routes/public_v1.py`:
- Around line 45-47: Update the add_api_route registration for
v1_search.raw_search_endpoint to declare an API-local success response model
describing the OpenSearch raw-search result shape, and pass that model via the
route’s response_model parameter so OpenAPI documents the endpoint contract.

In `@src/auth_context.py`:
- Line 7: Update the imports in auth_context.py to remove the unused and
deprecated Dict and Optional names, retaining only Any from typing to match the
file’s existing dict[str, Any] and str | None annotations.

In `@src/services/search_service.py`:
- Line 466: Validate SearchV1Body.fuzziness at the API boundary with a Pydantic
field validator, accepting only "0", "1", "2", "AUTO", or the documented
AUTO:<low>,<high> format and preserving None. Reject invalid values through
normal model validation so the endpoint returns status 400, while keeping the
existing fuzziness fallback and multi_match behavior unchanged.
- Around line 758-760: The raw_search authentication failure must use
exception-based signaling and consistent response validation across all affected
sites. In src/services/search_service.py lines 758-760, raise a dedicated
authentication exception instead of returning an error dict, and update the
synthetic empty-hits return at line 767 to preserve the OpenSearch response
shape. In src/api/v1/search.py line 179, catch that exception, return HTTP 401,
and validate results before constructing JSONResponse. In
sdks/typescript/src/search.ts lines 65-88, validate the parsed body has hits
before asserting RawSearchResponse and throw an SDK error when it is absent.
- Around line 762-793: Update the JSON parsing branch in raw_search so parsed
values are used as query_body only when json.loads returns a dict; for valid
JSON scalars or arrays, fall back to the existing keyword multi_match
construction using the stripped input. Preserve the current empty-string
handling and object-query behavior, ensuring later filter, size, and min_score
logic always receives a dictionary.

In `@tests/integration/sdk/test_search.py`:
- Around line 194-208: Update test_raw_query_with_filters_scopes_to_file to
assert that hits is non-empty immediately after extracting results.hits and
before iterating. Keep the existing per-hit filename assertion and cleanup
behavior unchanged; apply the equivalent non-empty assertion in the TypeScript
counterpart if it is part of this change.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a7aa7ad6-91ad-49e5-a8b4-0693ed2d701e

📥 Commits

Reviewing files that changed from the base of the PR and between 5b565bb and ec44424.

📒 Files selected for processing (12)
  • sdks/python/openrag_sdk/models.py
  • sdks/python/openrag_sdk/search.py
  • sdks/typescript/src/search.ts
  • sdks/typescript/src/types.ts
  • sdks/typescript/tests/integration.test.ts
  • src/api/v1/search.py
  • src/app/routes/public_v1.py
  • src/auth_context.py
  • src/mcp_http/server.py
  • src/services/search_service.py
  • src/utils/opensearch_utils.py
  • tests/integration/sdk/test_search.py

Comment thread sdks/typescript/tests/integration.test.ts
Comment thread sdks/typescript/tests/integration.test.ts
Comment thread src/api/v1/search.py
Comment thread src/app/routes/public_v1.py
Comment thread src/auth_context.py Outdated
Comment thread src/services/search_service.py
Comment thread src/services/search_service.py Outdated
Comment thread src/services/search_service.py
Comment thread tests/integration/sdk/test_search.py
…for agents

Changes the default keyword-match fuzziness from "AUTO:4,7" to "AUTO:7,10"
(fewer noisy fuzzy matches on shorter terms), and expands docs/comments
everywhere fuzziness is threaded through (auth_context, SearchService,
/v1/search, both SDKs) to spell out every accepted value and when to use
it. The openrag_search MCP tool description gets the most detail, since
that's what an LLM agent actually reads when deciding what to pass.
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Aug 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/services/search_service.py (2)

728-736: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reset omitted fuzziness before searching with a reused context.

_current_fuzziness persists per async context, so search() calls can leak one request’s custom fuzziness into a later omitted-fuzziness call. Always reset the context value or set it from config.settings before search_tool.

🤖 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/services/search_service.py` around lines 728 - 736, Update the search
flow before search_tool in search() to always reset the context fuzziness when
the request omits fuzziness, using the configured config.settings value;
preserve the explicit set_fuzziness behavior for provided values so reused async
contexts cannot retain a prior request’s custom setting.

804-808: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add an OpenSearch query timeout to raw DSL execution.

get_user_opensearch_client sets a 30s client transport timeout, but this raw search(...) call still does not limit server-side execution. Add a server-side timeout to the DSL or search params for expensive user DSL.

🤖 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/services/search_service.py` around lines 804 - 808, Update the raw DSL
execution in the search flow around the OpenSearch client search call to include
a 30-second server-side query timeout, using the DSL or search parameters
supported by the existing client. Preserve the current index, query body, and
terminate_after behavior while ensuring expensive user-supplied queries are
bounded independently of the transport timeout.
🤖 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.

Outside diff comments:
In `@src/services/search_service.py`:
- Around line 728-736: Update the search flow before search_tool in search() to
always reset the context fuzziness when the request omits fuzziness, using the
configured config.settings value; preserve the explicit set_fuzziness behavior
for provided values so reused async contexts cannot retain a prior request’s
custom setting.
- Around line 804-808: Update the raw DSL execution in the search flow around
the OpenSearch client search call to include a 30-second server-side query
timeout, using the DSL or search parameters supported by the existing client.
Preserve the current index, query body, and terminate_after behavior while
ensuring expensive user-supplied queries are bounded independently of the
transport timeout.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 30b6fc71-ecb5-4486-87f5-b88e016d1577

📥 Commits

Reviewing files that changed from the base of the PR and between ec44424 and 03f2baf.

📒 Files selected for processing (9)
  • sdks/python/openrag_sdk/search.py
  • sdks/typescript/src/search.ts
  • sdks/typescript/src/types.ts
  • sdks/typescript/tests/integration.test.ts
  • src/api/v1/search.py
  • src/auth_context.py
  • src/mcp_http/server.py
  • src/services/search_service.py
  • tests/integration/sdk/test_search.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • sdks/typescript/src/search.ts
  • sdks/python/openrag_sdk/search.py
  • sdks/typescript/src/types.ts
  • src/mcp_http/server.py
  • src/auth_context.py
  • src/api/v1/search.py
  • sdks/typescript/tests/integration.test.ts
  • tests/integration/sdk/test_search.py

CodeQL (information exposure through an exception):
- src/api/v1/search.py: search_endpoint and raw_search_endpoint no longer
  echo raw exception text to the client; details are logged server-side
  and a generic message is returned instead.

CodeRabbit correctness/security findings:
- search_service.raw_search: an unauthenticated call now raises
  SearchAuthenticationError instead of returning {"error": ...} with an
  implicit 200 (both SDKs previously had no way to detect this); the
  endpoint maps it to HTTP 401.
- search_service.raw_search: a JSON string query that parses to a scalar
  or array (not an object) no longer crashes attempting dict operations;
  it now falls back to the keyword-match path, same as non-JSON text.
- search_service.search: fuzziness is now always reset in the per-request
  context (via a shared DEFAULT_FUZZINESS constant) instead of only when
  provided, so a prior request's custom fuzziness can no longer leak into
  a later request that omits it on the same async context.
- SearchV1Body.fuzziness is now validated against the documented format
  ("0"/"1"/"2"/"AUTO"/"AUTO:<low>,<high>") at the API boundary, returning
  400 instead of a 500 from an unhandled OpenSearch parse error.
- raw_search now rejects scripted query clauses and oversized/deeply
  nested query bodies (RawSearchQueryError -> 400), and passes a
  server-side query timeout to OpenSearch. This is a scoped mitigation
  (script rejection + size/depth caps), not an exhaustive DSL allowlist.
- /v1/search/raw now declares a response_model so its OpenAPI schema
  documents the raw OpenSearch response shape.
- TypeScript SDK's rawQuery() validates the parsed response has `hits`
  before returning it, instead of silently exposing malformed responses
  to callers as a crash on first access.
- sdks/python/openrag_sdk/search.py: removed a pre-existing unused httpx
  import that was failing CI's ruff check on this PR (file is touched by
  this change, so the lint job runs against its full contents).

Test-hygiene fixes:
- TypeScript "Raw Search" tests now ingest and clean up their own fixture
  document instead of depending on document ingestion order from other
  describe blocks; the filter test's temp directory is now removed.
- Both SDKs' filter-scoped raw-search tests assert hits is non-empty
  before iterating, so a filter that wrongly excludes everything can no
  longer pass silently.
- TypeScript's malformed-DSL test now expects ValidationError (matching
  the SDK's actual 400 -> ValidationError mapping) instead of the
  looser OpenRAGError base class.

Verified locally: ruff check --no-fix, ruff format --check, and mypy all
pass on every changed Python file using CI's exact invocation; the
TypeScript SDK builds and typechecks cleanly (confirmed against
typescript@6.0.3, matching what CI resolves - the repo's committed
node_modules snapshot has a stale 5.9.3 that doesn't support this
tsconfig's ignoreDeprecations setting, a pre-existing, unrelated
environment issue).
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Aug 4, 2026
# Conflicts:
#	sdks/typescript/tests/integration.test.ts
#	tests/integration/sdk/test_search.py
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Aug 4, 2026
Comment thread src/api/v1/search.py Fixed
Comment thread src/api/v1/search.py Fixed
The previous CodeQL fix (str(e) -> generic message) only covered the
generic `except Exception` branch. It introduced two new instances of the
same taint pattern for the purpose-built SearchAuthenticationError and
RawSearchQueryError branches, each flagged as a fresh alert on this PR's
merge commit:

- SearchAuthenticationError's message is always the same literal
  ("Authentication required"), so it's now hardcoded directly instead of
  routed through str(e), eliminating the exception-derived taint flow
  entirely.
- RawSearchQueryError's message is dynamic but 100% developer-authored
  (validation reasons from _validate_raw_query_safety, e.g. "'size' must
  not exceed 1000") - never OpenSearch/driver internals. This is the
  genuinely-safe, user-facing validation message CodeRabbit asked for in
  the prior review round, so it's suppressed with the same lgtm[] +
  justification-comment convention already used elsewhere in this repo
  (src/utils/provider_health_cache.py) rather than discarded.
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Aug 4, 2026
Comment thread src/api/v1/search.py Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/services/search_service.py (1)

243-245: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the documented default fuzziness.

Both docstrings specify "AUTO:7,10". The PR contract preserves "AUTO:4,7". Update these values to match DEFAULT_FUZZINESS.

Proposed fix
-                            clause. See the openrag_search MCP tool description
-                            for accepted values. Defaults to "AUTO:7,10".
+                            clause. See the openrag_search MCP tool description
+                            for accepted values. Defaults to "AUTO:4,7".
...
-                values. Defaults to "AUTO:7,10" if not provided.
+                values. Defaults to "AUTO:4,7" if not provided.

Also applies to: 750-752

🤖 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/services/search_service.py` around lines 243 - 245, Update the fuzziness
defaults documented in both docstring locations for the relevant search service
method to `"AUTO:4,7"`, matching the `DEFAULT_FUZZINESS` contract; change
documentation only and leave runtime behavior unchanged.
🤖 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/api/v1/search.py`:
- Around line 217-225: Update the raw-search exception handler to classify
failures before selecting a response: preserve 401/403 responses for
authentication or access-denied errors, return 400 only for recognized request
or query-validation errors, and map unexpected OpenSearch service or network
failures to 500/502. Use the existing raw-search error handling symbols and keep
logging the original exception details.

---

Outside diff comments:
In `@src/services/search_service.py`:
- Around line 243-245: Update the fuzziness defaults documented in both
docstring locations for the relevant search service method to `"AUTO:4,7"`,
matching the `DEFAULT_FUZZINESS` contract; change documentation only and leave
runtime behavior unchanged.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b1f3c93-0324-4eb9-91d2-b452bff6a70a

📥 Commits

Reviewing files that changed from the base of the PR and between 03f2baf and f988f05.

📒 Files selected for processing (8)
  • sdks/python/openrag_sdk/search.py
  • sdks/typescript/src/search.ts
  • sdks/typescript/tests/integration.test.ts
  • src/api/v1/search.py
  • src/app/routes/public_v1.py
  • src/auth_context.py
  • src/services/search_service.py
  • tests/integration/sdk/test_search.py
💤 Files with no reviewable changes (1)
  • sdks/python/openrag_sdk/search.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/integration/sdk/test_search.py
  • src/auth_context.py
  • src/app/routes/public_v1.py
  • sdks/typescript/src/search.ts

Comment thread src/api/v1/search.py Outdated
@github-actions github-actions Bot removed the enhancement 🔵 New feature or request label Aug 4, 2026
@github-actions github-actions Bot added the enhancement 🔵 New feature or request label Aug 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sdks/typescript/tests/integration.test.ts (1)

644-660: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the temporary directory during cleanup.

tmpDir remains on the test runner after this test. Delete it even if client.documents.delete() fails.

Proposed cleanup
       } finally {
-        await client.documents.delete(filterDocName);
+        try {
+          await client.documents.delete(filterDocName);
+        } finally {
+          fs.rmSync(tmpDir, { recursive: true, force: true });
+        }
       }
🤖 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 `@sdks/typescript/tests/integration.test.ts` around lines 644 - 660, Update the
test cleanup in “should filter by a raw filters dict (data_sources)” so the
temporary directory identified by tmpDir is removed in the finally block, even
when client.documents.delete(filterDocName) fails. Ensure directory removal
still occurs if the document deletion throws.
🤖 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.

Outside diff comments:
In `@sdks/typescript/tests/integration.test.ts`:
- Around line 644-660: Update the test cleanup in “should filter by a raw
filters dict (data_sources)” so the temporary directory identified by tmpDir is
removed in the finally block, even when client.documents.delete(filterDocName)
fails. Ensure directory removal still occurs if the document deletion throws.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c7e2c95d-431f-42cf-a85f-39ccc47ff312

📥 Commits

Reviewing files that changed from the base of the PR and between f988f05 and b2f5b39.

📒 Files selected for processing (4)
  • sdks/typescript/src/types.ts
  • sdks/typescript/tests/integration.test.ts
  • src/api/v1/search.py
  • tests/integration/sdk/test_search.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • sdks/typescript/src/types.ts
  • tests/integration/sdk/test_search.py

…ss remaining CodeRabbit findings

The lgtm[py/stack-trace-exposure] suppression comment on RawSearchQueryError's
response didn't work - GitHub's code scanning flagged a fresh alert (#195) on
that exact line on the next push. Checked the repo's only other lgtm[] usage
(src/utils/provider_health_cache.py): its alert was dismissed manually by a
maintainer via the Security tab, not by the comment. The inline suppression
syntax isn't honored by this repo's code-scanning setup, so it can't be relied
on - dismissing alerts is a maintainer call, not something to route around.

Replaced it with a real fix: RawSearchQueryError now has three subclasses
(RawSearchScriptedQueryError, RawSearchQuerySizeError, RawSearchQueryDepthError),
one per _validate_raw_query_safety violation. raw_search_endpoint dispatches on
exception *type* through a fixed dict literal to pick the client-facing
message - it never reads the exception's message text, so there is no
exception-derived value flowing into the HTTP response for CodeQL to flag,
while callers still get a specific, useful error per violation kind instead of
one generic message.

Also addresses two more CodeRabbit findings from this round:
- raw_search_endpoint's final `except Exception` branch returned 400 for
  every unclassified failure, including genuine OpenSearch transport/service
  errors that aren't the caller's fault. Now returns 400 only for
  opensearchpy.RequestError (OpenSearch itself rejected the query DSL) and
  500 for anything else.
- TypeScript integration tests: both raw-search and hybrid-search "filter by
  data_sources" tests now remove their temp directory even if
  client.documents.delete() throws in the finally block, instead of leaking
  it on the test runner.

(The "fuzziness docstrings still say AUTO:7,10, should be AUTO:4,7" comment
from this same review round is stale - checked, all three docstrings already
correctly match DEFAULT_FUZZINESS = "AUTO:7,10"; not a real issue.)
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

React Doctor skipped this pull request — it changed no React files.

Reviewed by React Doctor for commit 991940d.

@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Aug 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/api/v1/search.py (1)

237-250: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use typed OpenSearch authorization exceptions.

Line 240 derives the HTTP status from str(e). If a RequestError includes rejected query text containing "access denied", this branch returns 403 before Line 242 returns 400. An authorization exception that does not contain either checked phrase returns 500 instead of 403.

Catch the opensearch-py authentication and authorization exception types before RequestError. Keep the catch-all branch for 500 responses.

Proposed fix
-from opensearchpy.exceptions import RequestError
+from opensearchpy.exceptions import (
+    AuthenticationException,
+    AuthorizationException,
+    RequestError,
+)
...
-    except Exception as e:
-        error_msg = str(e)
-        logger.error("Raw search failed", error=error_msg, user_id=user.user_id)
-        if "AuthenticationException" in error_msg or "access denied" in error_msg.lower():
-            return JSONResponse({"error": "Access denied"}, status_code=403)
-        if isinstance(e, RequestError):
+    except (AuthenticationException, AuthorizationException) as e:
+        logger.error("Raw search access denied", error=str(e), user_id=user.user_id)
+        return JSONResponse({"error": "Access denied"}, status_code=403)
+    except RequestError as e:
+        logger.error("Raw search query rejected", error=str(e), user_id=user.user_id)
         return JSONResponse(
             {
                 "error": "Raw search query was rejected by OpenSearch. Check server logs for details."
             },
             status_code=400,
         )
+    except Exception as e:
+        logger.error("Raw search failed", error=str(e), user_id=user.user_id)
+        return JSONResponse(
+            {"error": "Raw search failed. Check server logs for details."}, status_code=500
+        )
For opensearch-py 3.0.0, confirm which exported exceptions represent OpenSearch HTTP 401 and 403 responses. Confirm whether `AuthenticationException` and `AuthorizationException` are the correct types to catch before `RequestError`.
🤖 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/api/v1/search.py` around lines 237 - 250, Update the raw search exception
handling around the catch-all in the search handler to import and catch
opensearch-py’s AuthenticationException and AuthorizationException before
RequestError, returning 403 for either typed authorization failure. Remove the
message-based authorization checks so RequestError always reaches the existing
400 response, while retaining the catch-all path for 500 responses.
🤖 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.

Duplicate comments:
In `@src/api/v1/search.py`:
- Around line 237-250: Update the raw search exception handling around the
catch-all in the search handler to import and catch opensearch-py’s
AuthenticationException and AuthorizationException before RequestError,
returning 403 for either typed authorization failure. Remove the message-based
authorization checks so RequestError always reaches the existing 400 response,
while retaining the catch-all path for 500 responses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6f404f91-ea8e-4ab6-9e61-572f5972df62

📥 Commits

Reviewing files that changed from the base of the PR and between b2f5b39 and aad4381.

📒 Files selected for processing (3)
  • sdks/typescript/tests/integration.test.ts
  • src/api/v1/search.py
  • src/services/search_service.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • sdks/typescript/tests/integration.test.ts
  • src/services/search_service.py

… str(e)

Both search_endpoint and raw_search_endpoint decided between 403 and a
generic error status by checking whether "AuthenticationException" or
"access denied" appeared as a substring of str(e). This is fragile in
both directions: a RequestError whose rejected-query text happens to
contain "access denied" would be misclassified as 403 before reaching the
RequestError check, and a genuine typed authorization exception whose
message doesn't contain either literal substring would fall through to
the generic 500/400 branch instead of 403.

Both endpoints now catch opensearchpy's AuthenticationException and
AuthorizationException explicitly, ahead of RequestError and the generic
Exception catch-all, so classification is driven by the actual exception
type OpenSearch raised rather than pattern-matching its message text.
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Aug 4, 2026
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend 🔷 Issues related to backend services (OpenSearch, Langflow, APIs) enhancement 🔵 New feature or request tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants