Skip to content

fix: 14 small triaged issues (OIDC/security hardening, loaders, logging, flaky test) - #491

Merged
EnjoyBacon7 merged 11 commits into
mainfrom
fix/triage-quick-fixes
Jun 15, 2026
Merged

fix: 14 small triaged issues (OIDC/security hardening, loaders, logging, flaky test)#491
EnjoyBacon7 merged 11 commits into
mainfrom
fix/triage-quick-fixes

Conversation

@EnjoyBacon7

@EnjoyBacon7 EnjoyBacon7 commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

What this does

Fixes a batch of small, self-contained issues found during the recent open-issue triage. Each change is under 20 lines. Grouped by area below.

Auth and OIDC

Indexing and loaders

API and deploy

Tests

Testing

  • uv run pytest openrag/ → 386 passed, 5 skipped
  • uv run ruff check openrag/ and ruff format --check openrag/ → clean

Fixes #360, fixes #483, fixes #386, fixes #485, fixes #361, fixes #376, fixes #121, fixes #477, fixes #487, fixes #363, fixes #481, fixes #488, fixes #426.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@EnjoyBacon7, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 3 minutes and 11 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dd3ba7a1-1cfe-472f-b6c2-df6121b4adaf

📥 Commits

Reviewing files that changed from the base of the PR and between 5233ca5 and 9a73200.

📒 Files selected for processing (13)
  • ansible/ansible.cfg
  • ansible/playbooks/openrag.yml
  • docs/assets/compose_linux_gpu.yaml
  • openrag/components/auth/oidc_client.py
  • openrag/components/indexer/loaders/CustomDocLoader.py
  • openrag/components/indexer/utils/text_sanitizer.py
  • openrag/components/indexer/vectordb/utils.py
  • openrag/models/user.py
  • openrag/routers/auth.py
  • openrag/routers/indexer.py
  • openrag/routers/openai.py
  • openrag/routers/search.py
  • tests/api_tests/test_indexer.py
📝 Walkthrough

Walkthrough

This PR applies a batch of security hardening fixes and bug corrections: OIDC token validation gains azp and sub binding checks; redirect sanitization blocks backslashes and control characters; admin token rotation is stabilized; OIDC sessions are revoked on API token rotation; deployment configs tighten SSH host key checking, .env permissions, and Ray dashboard exposure. Bug fixes cover multi-page document loading, empty LLM streams, search query logging, and a flaky test.

Changes

Security Hardening and Bug Fixes

Layer / File(s) Summary
OIDC azp claim and userinfo sub binding validation
openrag/components/auth/oidc_client.py, openrag/routers/auth.py
azp == client_id check added for multi-audience tokens in both _verify_id_token and verify_logout_token; OIDC callback aborts with 400 when userinfo.sub does not match the ID token sub.
OIDC redirect URL sanitization hardening
openrag/routers/auth.py
_sanitize_next_url rejects values containing backslashes or control characters, falling back to /.
Admin token preservation and OIDC session revocation on token rotation
openrag/components/indexer/vectordb/utils.py
_ensure_admin_user preserves the stored token when AUTH_TOKEN is absent; regenerate_user_token calls new revoke_oidc_sessions_by_user_id to bulk-revoke active OIDC sessions after API token rotation.
UserBase external_user_id empty-string normalization
openrag/models/user.py
Field validator converts empty/whitespace external_user_id to None before DB insertion to prevent unique index collisions.
source_file_id validation in copy endpoint
openrag/routers/indexer.py
Imports is_file_id_valid, removes the dead FORBIDDEN_CHARS_IN_FILE_ID constant, and returns HTTP 400 when source_file_id fails allowlist validation.
Prompt-control token neutralizer colon-variant defanging
openrag/components/indexer/utils/text_sanitizer.py
_INJECT_SOURCE_BLOCK_RE extended to capture an optional trailing colon; substitution lambda removes the colon so the downstream answer-tag parser cannot match the colon-bearing form.
CustomDocLoader multi-page text accumulation fix
openrag/components/indexer/loaders/CustomDocLoader.py
aload_document now appends (+=) each page's content instead of overwriting, preserving all pages in the returned Document.
Empty upstream LLM stream 502 handling
openrag/routers/openai.py
Non-streaming /chat/completions and /completions paths catch StopAsyncIteration on the first __anext__() call and raise HTTP 502 "Empty response from upstream LLM".
Ansible and Docker Compose deployment hardening
ansible/ansible.cfg, ansible/playbooks/openrag.yml, docs/assets/compose_linux_gpu.yaml
host_key_checking enabled, SSH args set to accept-new, .env mode set to 0600, uv installer pinned to 0.5.11, Ray dashboard port bound to 127.0.0.1 only.
Search router query text replaced with length in logs
openrag/routers/search.py
All three search endpoints replace query=search_params.text with query_len=len(search_params.text) in logger.bind().
Flaky cancel-task test fixed with polling loop
tests/api_tests/test_indexer.py
test_cancel_increments_total_cancelled polls /queue/info until total_cancelled increments rather than reading immediately after the cancel call.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • linagora/openrag#400: Directly addresses the same CustomDocLoader multi-page overwrite bug fixed here by changing s = to s +=.
  • linagora/openrag#405: Implements the same OIDC multi-audience azp == client_id hardening in _verify_id_token that this PR extends to also cover verify_logout_token.

Poem

🐇 Hop, hop, security seams all sewed tight,
Backslash redirects vanquished in the night,
Admin tokens preserved, OIDC sessions swept clean,
Ray dashboard hidden — no hacker convene!
All pages of documents finally read,
Empty LLM streams get a 502 instead. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: 14 small triaged issues (OIDC/security hardening, loaders, logging, flaky test)' accurately summarizes the main purpose: bundling fixes for 14 self-contained triaged issues spanning OIDC/security, data loaders, logging, and test reliability improvements.
Linked Issues check ✅ Passed The PR comprehensively addresses all 14 linked issues: OIDC/userinfo validation (#360, #483, #386, #485), admin token rotation (#361), file-id validation and Ray dashboard binding (#477), prompt-control neutralizer (#487), Ansible hardening (#488), search logging (#481), external_user_id uniqueness (#121), empty LLM streams (#363), multi-page loader (#376), and flaky test (#426).
Out of Scope Changes check ✅ Passed All changes are directly scoped to the 14 linked issues; no extraneous modifications to unrelated functionality detected across the 14 modified files.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/triage-quick-fixes

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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
openrag/routers/indexer.py (1)

410-425: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Wrap the copy actor call with the centralized timeout helper.

This endpoint still awaits indexer.copy_file.remote(...) directly, so a stalled Ray call can hang request handling and bypass the standardized cancellation/error path.

Suggested patch
-    await indexer.copy_file.remote(file_id=source_file_id, metadata=metadata, partition=source_partition, user=user)
+    await call_ray_actor_with_timeout(
+        indexer.copy_file.remote(
+            file_id=source_file_id,
+            metadata=metadata,
+            partition=source_partition,
+            user=user,
+        ),
+        timeout=VECTORDB_TIMEOUT,
+        task_description=f"copy_file({source_partition}:{source_file_id}->{partition}:{file_id})",
+    )

As per coding guidelines, “Use the centralized call_ray_actor_with_timeout() utility from openrag/components/ray_utils for all Ray actor method calls, which handles timeout, cancellation, and error management.”

🤖 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 `@openrag/routers/indexer.py` around lines 410 - 425, The direct await of
indexer.copy_file.remote() bypasses the standardized timeout and error handling
mechanisms. Replace the direct await call to indexer.copy_file.remote() with a
call to the centralized call_ray_actor_with_timeout() utility function from
openrag/components/ray_utils, passing the appropriate parameters (actor method,
timeout value, and any required arguments) to ensure consistent timeout
management, cancellation handling, and error management across all Ray actor
calls.

Source: Coding guidelines

🤖 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 `@ansible/ansible.cfg`:
- Line 10: Remove the `-o UserKnownHostsFile=/dev/null` parameter from the
ssh_args configuration line in ansible.cfg. This parameter discards host keys
after each connection, preventing SSH from validating host key changes across
sessions and eliminating MITM detection. Keep the other ssh_args options like
ControlMaster, ControlPersist, and StrictHostKeyChecking intact, allowing SSH to
use its default known_hosts location for proper host key validation.

In `@ansible/playbooks/openrag.yml`:
- Around line 127-130: The shell task using curl piped to sh does not enable
pipefail, which means if curl fails to download the installation script, the
failure will be masked and the task will appear successful. Modify the shell
task by adding an executable parameter to use bash instead of the default POSIX
sh, and add set -o pipefail to the shell command itself (or use the args option
to set it) so that if curl fails, the entire pipeline fails and the task
properly reports the error. This ensures the system does not enter an
inconsistent state when the uv installation fails.

In `@tests/api_tests/test_indexer.py`:
- Around line 787-799: The final assertion in the polling loop uses strict
equality `assert cancelled_after == cancelled_before + 1` which is overly strict
for an asynchronous shared counter. The loop correctly waits for the counter to
increment by at least one using `>=`, but the final assertion should also use
`>=` instead of `==` to account for the possibility that another cancellation
increment might occur during the same polling window. Change the final assertion
to check that `cancelled_after >= cancelled_before + 1` to prevent test
flakiness.

---

Outside diff comments:
In `@openrag/routers/indexer.py`:
- Around line 410-425: The direct await of indexer.copy_file.remote() bypasses
the standardized timeout and error handling mechanisms. Replace the direct await
call to indexer.copy_file.remote() with a call to the centralized
call_ray_actor_with_timeout() utility function from
openrag/components/ray_utils, passing the appropriate parameters (actor method,
timeout value, and any required arguments) to ensure consistent timeout
management, cancellation handling, and error management across all Ray actor
calls.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e3c12dcf-5822-4117-838b-6431f0c35795

📥 Commits

Reviewing files that changed from the base of the PR and between 217a883 and 5233ca5.

📒 Files selected for processing (13)
  • ansible/ansible.cfg
  • ansible/playbooks/openrag.yml
  • docs/assets/compose_linux_gpu.yaml
  • openrag/components/auth/oidc_client.py
  • openrag/components/indexer/loaders/CustomDocLoader.py
  • openrag/components/indexer/utils/text_sanitizer.py
  • openrag/components/indexer/vectordb/utils.py
  • openrag/models/user.py
  • openrag/routers/auth.py
  • openrag/routers/indexer.py
  • openrag/routers/openai.py
  • openrag/routers/search.py
  • tests/api_tests/test_indexer.py

Comment thread ansible/ansible.cfg Outdated
Comment thread ansible/playbooks/openrag.yml Outdated
Comment thread tests/api_tests/test_indexer.py
@EnjoyBacon7
EnjoyBacon7 force-pushed the fix/triage-quick-fixes branch from b911d68 to 9a73200 Compare June 15, 2026 16:10
@EnjoyBacon7

Copy link
Copy Markdown
Collaborator Author

CodeRabbit review addressed:

  • 3 inline comments fixed and folded into their commits: dropped UserKnownHostsFile=/dev/null so accept-new actually validates host keys; ran the uv install under /bin/bash with set -euo pipefail; relaxed the cancel-counter assertion to >= (shared async counter). See thread replies.
  • Possibly-related PRs fix(loaders): accumulate all pages in CustomDocLoader (#376) #400 / fix(oidc): require azp == client_id on multi-audience ID tokens (#385) #405: both merged into refactor/hexagonal, not main. main still carries both bugs (CustomDocLoader still overwrites pages; no azp check), so the changes here are the equivalent fixes for main and will reconcile trivially when the refactor lands.
  • Docstring Coverage warning (42.86%): left as-is. The shortfall is in pre-existing functions in the touched files; adding docstrings there would be outside the scope of these fixes (which the Out-of-Scope check otherwise passed).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment