Skip to content

feat: add connectors permissions for Saas#1782

Merged
Wallgau merged 11 commits into
mainfrom
feat/rbac-connector-access-v2
Jun 9, 2026
Merged

feat: add connectors permissions for Saas#1782
Wallgau merged 11 commits into
mainfrom
feat/rbac-connector-access-v2

Conversation

@Wallgau

@Wallgau Wallgau commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Introduce admin Connectors Permission settings (cloud-only) backed by workspace_config, enforce availability on connector APIs and OAuth init, and sync the new connectors:manage:access permission at startup without an Alembic migration. OSS/dev OSS brand bypasses policy; add dev role toggle and brand-aware proxy headers for local RBAC testing.

Screen.Recording.2026-06-05.at.5.13.10.PM.mov

Summary by CodeRabbit

  • New Features

    • Added developer role-switching capability for local testing environments (when dev mode is enabled)
    • Added connector access management tab in Settings to configure workspace connector availability
    • Enhanced role-based permission system for granular connector access control
  • Documentation

    • Updated configuration guide with new development-mode settings for role toggle and connector policy enforcement

Introduce admin Connectors Permission settings (cloud-only) backed by
workspace_config, enforce availability on connector APIs and OAuth init,
and sync the new connectors:manage:access permission at startup without
an Alembic migration. OSS/dev OSS brand bypasses policy; add dev role
toggle and brand-aware proxy headers for local RBAC testing.
@github-actions github-actions Bot added frontend 🟨 Issues related to the UI/UX backend 🔷 Issues related to backend services (OpenSearch, Langflow, APIs) tests enhancement 🔵 New feature or request labels Jun 5, 2026
@coderabbitai

coderabbitai Bot commented Jun 5, 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

This PR integrates workspace connector-access policy enforcement and dev-role switching across backend and frontend. It adds environment toggles and cloud-context determination, enforces workspace connector availability via database policy checks in API handlers, provides admin UI to manage connector access per workspace, and enables developers to switch roles locally for testing. Frontend contexts and permission evaluation were refactored to support SaaS policy gating.

Changes

Connector policy, settings access, and dev-role controls

Layer / File(s) Summary
Policy flags and RBAC catalog foundation
.env.example, src/config/settings.py, src/db/seed.py, src/db/migrations_runtime.py, tests/unit/db/migrations/test_rbac_catalog_sync.py, tests/unit/services/test_rbac_service.py
Dev-only toggles OPENRAG_DEV_ROLE_TOGGLE and OPENRAG_DEV_CONNECTOR_POLICY are added; is_cloud_context() combines IBM auth, SaaS mode, and the connector policy toggle; RBAC catalog sync runs per-boot with connectors:manage:access permission; startup migration validates idempotent sync behavior and permission grant to admin.
Connector-access policy service
src/services/connector_access_service.py
Service loads/persists workspace connector access map, provides governable type list, validates type membership, enforces cloud-context-only policy, and filters connector metadata by enabled state.
Backend API endpoint enforcement
src/api/auth.py, src/api/connectors.py, src/app/routes/internal.py
All connector operations and auth_init now accept session dependency; request-time policy checks return 403 JSON when connector type is blocked; connector-type lists for sync operations are filtered by policy; routes /connectors/user-access GET/PUT for access management.
Connector-access enforcement tests
tests/unit/api/test_auth_init_connector_access.py, tests/unit/api/test_connectors_connector_access.py, tests/unit/services/test_connector_access_service.py
Unit tests validate service persistence/filtering, policy gating by run-mode/auth flags, and endpoint 403 short-circuit behavior when connector types are disabled.
Dev-role switching service and API
src/services/dev_role_toggle.py, src/api/users.py, src/dependencies.py, tests/unit/services/test_dev_role_toggle.py
Service swaps user built-in role membership; /me/dev-role endpoint returns updated roles and permissions; /me response adds cloud_context field; JWT role sync is bypassed when dev-role toggle is enabled; test coverage validates role replacement semantics.
Frontend brand and policy core
frontend/lib/brand.ts
New module exports Brand type, cloud classification, SaaS policy context helper, connector visibility rules, and RBAC settings tab gating predicates.
Auth and brand context updates
frontend/contexts/auth-context.tsx, frontend/contexts/brand-context.tsx, frontend/hooks/use-permissions.ts
Auth context adds cloudContext and permissionsResolved fields; brand context uses centralized helpers to compute effective brand; permission checks delegate to RBAC-aware hasRbacPermission; new useSettingsTabAccess hook builds settings access context from auth/brand state.
Connector query keys and mutations
frontend/app/api/queries/useGetConnectorsQuery.ts, frontend/app/api/mutations/useConnectConnectorMutation.ts, frontend/app/api/mutations/useDisconnectConnectorMutation.ts
Connector query key now includes cloud brand; workspace-policy filtering uses stored access map; mutations standardized to use shared snapshot/restore/update helpers; user-access query/mutation added for connector management API.
Settings tabs and connector-access UI
frontend/app/settings/[tab]/page.tsx, frontend/app/settings/_components/settings-nav.tsx, frontend/app/settings/_components/connector-access-section.tsx, frontend/app/settings/_components/connector-cards.tsx
New connector-access settings tab added; authorization switches to shared RBAC predicates; ConnectorAccessSection implements draft state, save flow, loading/error/retry; connector cards rendering aligns with SaaS policy context.
Dev-role toggle UI
frontend/components/dev-role-toggle.tsx, frontend/components/header.tsx
New DevRoleToggle component posts to /api/users/me/dev-role, refreshes permissions, invalidates connector caches, and triggers router refresh; header conditionally renders it under dev theme.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

  • langflow-ai/openrag#1579: Both PRs touch the connector "browse connection files" flow: the referenced PR wires an internal route to connectors.browse_connection_files, while this PR updates the handler to enforce workspace connector access policy.
  • langflow-ai/openrag#1631: Both PRs modify frontend settings tab RBAC gating—the referenced PR removes role UI, while this PR adds the connector-access tab and updates permission-context gating logic.

Suggested reviewers

  • lucaseduoli
  • edwinjosechittilappilly
  • phact
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.46% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add connectors permissions for Saas' directly describes the main change: introducing connector permissions functionality for the SaaS deployment mode. It is specific, concise, and accurately reflects the changeset's primary objective.
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.

✏️ 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 feat/rbac-connector-access-v2

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.

@github-actions github-actions Bot removed the enhancement 🔵 New feature or request label Jun 5, 2026
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Jun 5, 2026
Comment thread src/api/auth.py Fixed
@Wallgau Wallgau changed the title feat: add SaaS workspace connector permissions with RBAC gates feat: add connectors permissions for Saas Jun 5, 2026
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Jun 5, 2026
@Wallgau Wallgau changed the title feat: add connectors permissions for Saas feat: add connectors permissions for Saas Jun 5, 2026
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Jun 5, 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: 4

Caution

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

⚠️ Outside diff range comments (1)
src/api/auth.py (1)

1-26: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix import ordering and unused import to unblock Ruff/mypy CI.

Current import layout triggers E402, and typing.Optional is unused (F401). This is currently failing pipeline checks.

Suggested fix
-from typing import Optional
-
-from fastapi import Depends, HTTPException, Request
-from fastapi.responses import JSONResponse
-
-from utils.logging_config import get_logger
-from utils.telemetry import Category, MessageId, TelemetryClient
-from utils.version_utils import OPENRAG_VERSION
-
-logger = get_logger(__name__)
-
-from pydantic import BaseModel
-from sqlalchemy.ext.asyncio import AsyncSession
-
-from dependencies import (
+from fastapi import Depends, HTTPException, Request
+from fastapi.responses import JSONResponse
+from pydantic import BaseModel
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from dependencies import (
     get_auth_service,
     get_current_user,
     get_db_session,
     get_optional_user,
 )
 from services.connector_access_service import (
     CONNECTOR_TYPES,
     is_connector_access_policy_enforced,
     is_connector_allowed_for_request,
 )
 from session_manager import User
+from utils.logging_config import get_logger
+from utils.telemetry import Category, MessageId, TelemetryClient
+from utils.version_utils import OPENRAG_VERSION
+
+logger = get_logger(__name__)
🤖 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/auth.py` around lines 1 - 26, Reorder and clean up imports in auth
module to satisfy linters: remove the unused typing.Optional import and reorder
imports so standard library imports come first, then third-party (fastapi,
pydantic, sqlalchemy), then local project imports; ensure symbols referenced
like get_logger, OPENRAG_VERSION, BaseModel, AsyncSession, get_auth_service,
get_current_user, get_db_session, get_optional_user, CONNECTOR_TYPES,
is_connector_access_policy_enforced, is_connector_allowed_for_request, and User
remain correctly imported after the reorder to avoid E402/F401 errors.
🧹 Nitpick comments (3)
frontend/components/dev-role-toggle.tsx (1)

63-68: 💤 Low value

Consider parallelizing independent invalidations.

The invalidateQueries calls (lines 64 and 66) are independent and could run concurrently. While the current sequential approach is safe, wrapping them in Promise.all would improve perceived responsiveness.

⚡ Proposed refactor
 onSuccess: async (data) => {
   await refreshPermissions();
-  await queryClient.invalidateQueries({ queryKey: ["connectors"] });
-  await queryClient.invalidateQueries({
-    queryKey: ["connector-user-access"],
-  });
+  await Promise.all([
+    queryClient.invalidateQueries({ queryKey: ["connectors"] }),
+    queryClient.invalidateQueries({ queryKey: ["connector-user-access"] }),
+  ]);
   router.refresh();
🤖 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 `@frontend/components/dev-role-toggle.tsx` around lines 63 - 68, The two
independent calls to queryClient.invalidateQueries for queryKey ["connectors"]
and ["connector-user-access"] should run in parallel to reduce latency: replace
the sequential awaits with a single await
Promise.all([queryClient.invalidateQueries({ queryKey: ["connectors"] }),
queryClient.invalidateQueries({ queryKey: ["connector-user-access"] })]) while
keeping refreshPermissions awaited before and router.refresh() after,
referencing refreshPermissions, queryClient.invalidateQueries and router.refresh
to locate the changes.
src/api/users.py (1)

129-167: ⚡ Quick win

Add an explicit response model for POST /users/me/dev-role.

This endpoint returns structured JSON but doesn’t declare response_model, so schema drift won’t be caught and docs are less reliable.

Suggested refactor
+class DevRoleResponse(BaseModel):
+    roles: list[str]
+    role: str
+    permissions: list[str]
+
-@router.post("/me/dev-role")
+@router.post("/me/dev-role", response_model=DevRoleResponse)
 async def set_my_dev_role(
@@
-    return JSONResponse(
-        {
-            "roles": roles,
-            "role": body.role,
-            "permissions": sorted(perms),
-        }
-    )
+    return DevRoleResponse(
+        roles=roles,
+        role=body.role,
+        permissions=sorted(perms),
+    )

As per coding guidelines, src/api/**/*.py routes should verify response model typing.

🤖 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/users.py` around lines 129 - 167, The endpoint set_my_dev_role should
declare an explicit Pydantic response model to keep OpenAPI/docs and schema
validation correct: create a response model (e.g., DevRoleResponse) with fields
roles: List[str], role: str, permissions: List[str] and add
response_model=DevRoleResponse to the `@router.post` decorator on set_my_dev_role;
ensure the handler returns a dict or model instance that matches that schema
(adjust the JSONResponse usage or return the model directly) and add any
necessary imports for the new DevRoleResponse type.
tests/unit/services/test_dev_role_toggle.py (1)

55-56: ⚡ Quick win

Include the "user" switch case in the parameterized test.

The feature supports switching to any built-in role; adding "user" closes the remaining branch in the happy-path matrix.

Suggested refactor
-@pytest.mark.parametrize("target", ["admin", "developer", "viewer"])
+@pytest.mark.parametrize("target", ["admin", "developer", "user", "viewer"])
🤖 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 `@tests/unit/services/test_dev_role_toggle.py` around lines 55 - 56, Update the
parameterized test decorator for test_switch_to_any_builtin_role to include the
"user" role so the test covers all built-in roles; modify the
`@pytest.mark.parametrize`("target", ["admin", "developer", "viewer"]) declaration
in test_switch_to_any_builtin_role to also contain "user" to exercise that
branch of the happy-path matrix.
🤖 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 `@frontend/lib/fetch-server.ts`:
- Around line 15-23: The fetch currently always sends "X-OpenRAG-Brand" using
resolveBrand, causing a default header even when no brand cookie exists; change
this so you read the raw brand cookie via cookieStore.get(BRAND_COOKIE) and only
add the "X-OpenRAG-Brand" header when that cookie value is present (do not call
resolveBrand to supply a fallback), updating the headers building in the fetch
call to conditionally include the header based on the cookie existence.

In `@src/api/connectors.py`:
- Around line 33-49: The connector access policy is only enforced in some
handlers and can be bypassed via other connector routes; ensure all
connector-related endpoints call the central check _connector_access_denied (or
use a middleware/decorator that invokes it) before performing any connector
action. Update the token, browse, disconnect, preview and any other connector
route handlers to call await _connector_access_denied(request, session, user,
connector_type) and return its JSONResponse if non-None, or implement a
request-level middleware that uses is_connector_access_policy_enforced and
is_connector_allowed_for_request to reject disallowed connector_type values with
a 403; keep the existing error message format and status code when rejecting.

In `@src/services/connector_access_service.py`:
- Around line 51-59: Currently src/services/connector_access_service.py reads
IBM_AUTH_ENABLED directly via os.getenv and assigns it to ibm_auth; move this
env read into config/settings.py as a typed setting (e.g., IBM_AUTH_ENABLED:
bool or is_connector_access_policy_enforced: bool) and then replace the
os.getenv usage by importing and using that setting (referencing the ibm_auth
variable and the config setting) so connector_access_service consumes the
centralized, typed config instead of reading os.environ itself.

In `@src/services/dev_role_toggle.py`:
- Around line 49-50: rbac.invalidate is being called before the caller's write
transaction commits, allowing a race that can repopulate stale permissions; move
the invalidation to run only after the DB commit completes. Either register an
on_commit/post_commit callback from within role_repo.assign_role (or return a
token and have the caller call rbac.invalidate after commit) or use your DB
session's after_commit hook to call rbac.invalidate(db_user_id) (target.id can
remain for logging) so invalidation happens post-commit and not inside the
pre-commit window.

---

Outside diff comments:
In `@src/api/auth.py`:
- Around line 1-26: Reorder and clean up imports in auth module to satisfy
linters: remove the unused typing.Optional import and reorder imports so
standard library imports come first, then third-party (fastapi, pydantic,
sqlalchemy), then local project imports; ensure symbols referenced like
get_logger, OPENRAG_VERSION, BaseModel, AsyncSession, get_auth_service,
get_current_user, get_db_session, get_optional_user, CONNECTOR_TYPES,
is_connector_access_policy_enforced, is_connector_allowed_for_request, and User
remain correctly imported after the reorder to avoid E402/F401 errors.

---

Nitpick comments:
In `@frontend/components/dev-role-toggle.tsx`:
- Around line 63-68: The two independent calls to queryClient.invalidateQueries
for queryKey ["connectors"] and ["connector-user-access"] should run in parallel
to reduce latency: replace the sequential awaits with a single await
Promise.all([queryClient.invalidateQueries({ queryKey: ["connectors"] }),
queryClient.invalidateQueries({ queryKey: ["connector-user-access"] })]) while
keeping refreshPermissions awaited before and router.refresh() after,
referencing refreshPermissions, queryClient.invalidateQueries and router.refresh
to locate the changes.

In `@src/api/users.py`:
- Around line 129-167: The endpoint set_my_dev_role should declare an explicit
Pydantic response model to keep OpenAPI/docs and schema validation correct:
create a response model (e.g., DevRoleResponse) with fields roles: List[str],
role: str, permissions: List[str] and add response_model=DevRoleResponse to the
`@router.post` decorator on set_my_dev_role; ensure the handler returns a dict or
model instance that matches that schema (adjust the JSONResponse usage or return
the model directly) and add any necessary imports for the new DevRoleResponse
type.

In `@tests/unit/services/test_dev_role_toggle.py`:
- Around line 55-56: Update the parameterized test decorator for
test_switch_to_any_builtin_role to include the "user" role so the test covers
all built-in roles; modify the `@pytest.mark.parametrize`("target", ["admin",
"developer", "viewer"]) declaration in test_switch_to_any_builtin_role to also
contain "user" to exercise that branch of the happy-path matrix.
🪄 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: ea8e8b32-ff61-4d87-ac27-f4da2bc9bec1

📥 Commits

Reviewing files that changed from the base of the PR and between 6004ef2 and 128faa8.

📒 Files selected for processing (30)
  • .env.example
  • frontend/app/api/[...path]/route.ts
  • frontend/app/api/mutations/useUpdateConnectorAccessMutation.ts
  • frontend/app/api/queries/useGetConnectorAccessQuery.ts
  • frontend/app/api/queries/useGetConnectorsQuery.ts
  • frontend/app/settings/[tab]/page.tsx
  • frontend/app/settings/_components/connector-access-section.tsx
  • frontend/app/settings/_components/settings-nav.tsx
  • frontend/components/dev-role-toggle.tsx
  • frontend/components/header.tsx
  • frontend/contexts/auth-context.tsx
  • frontend/contexts/brand-context.tsx
  • frontend/lib/brand.ts
  • frontend/lib/fetch-server.ts
  • frontend/lib/settings-tab-access.ts
  • src/api/auth.py
  • src/api/connectors.py
  • src/api/users.py
  • src/app/routes/internal.py
  • src/config/settings.py
  • src/db/migrations_runtime.py
  • src/db/seed.py
  • src/dependencies.py
  • src/services/connector_access_service.py
  • src/services/dev_role_toggle.py
  • tests/unit/api/test_auth_init_connector_access.py
  • tests/unit/db/migrations/test_rbac_catalog_sync.py
  • tests/unit/services/test_connector_access_service.py
  • tests/unit/services/test_dev_role_toggle.py
  • tests/unit/services/test_rbac_service.py

Comment thread frontend/lib/fetch-server.ts Outdated
Comment thread src/api/connectors.py
Comment thread src/services/connector_access_service.py Outdated
Comment thread src/services/dev_role_toggle.py Outdated
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Jun 5, 2026
Add admin Connectors Permission (workspace_config-backed) with RBAC
connectors:manage:access, enforce policy on connector APIs and OAuth init,
and keep the permission list independent of the live connectors tab.
Consolidate frontend connector-access hooks into useGetConnectorsQuery and
settings tab helpers into brand.ts. Fix Connectors Permission tab redirects
(RSC dev-brand default, wait for permissionsResolved). Let explicitly
enabled connectors override deployment visibility filters; add
OPENRAG_DEV_CONNECTOR_POLICY for local OSS dev backend enforcement Snapshot and restore all cached connector query keys in connect/disconnect
mutations so optimistic updates stay correct when policy context changes
mid-mutation (brand toggle, permissions resolving).
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Jun 9, 2026
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Jun 9, 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: 2

Caution

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

⚠️ Outside diff range comments (1)
frontend/app/settings/_components/connector-cards.tsx (1)

33-36: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Don't collapse fetch failures into the SaaS "not authorized" empty state.

queryConnectors defaults to [], so when useGetConnectorsQuery errors this branch still renders “No connectors available or authorized…”. A transient /api/connectors failure will look like a policy denial instead of a load error.

💡 Minimal fix
-  const { data: queryConnectors = [], isLoading: connectorsLoading } =
+  const {
+    data: queryConnectors = [],
+    isLoading: connectorsLoading,
+    isError: connectorsError,
+  } =
     useGetConnectorsQuery({
       enabled: isAuthenticated || isNoAuthMode,
     });
@@
-  if (!connectorsLoading && connectors.length === 0) {
+  if (!connectorsLoading && !connectorsError && connectors.length === 0) {
     if (isSaasPolicy) {
       return (
         <p className="text-sm text-muted-foreground">
           No connectors available or authorized for your organization.
         </p>
       );
     }

Also applies to: 82-89

🤖 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 `@frontend/app/settings/_components/connector-cards.tsx` around lines 33 - 36,
The component collapses fetch failures into the "not authorized" empty state
because data is defaulted to []; remove the default assignment from the
useGetConnectorsQuery destructure (do not set data: queryConnectors = []) and
instead use the hook's isError/error flags to distinguish failure from an empty
list: when useGetConnectorsQuery reports isError (or error) show a load-error
UI/message, when !connectorsLoading and data is an empty array show the "no
connectors or authorized" message; apply the same change to the other occurrence
that uses useGetConnectorsQuery (the block around where queryConnectors is read
again).
🤖 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 `@frontend/app/settings/_components/settings-nav.tsx`:
- Around line 57-68: The redirect effect (useEffect) currently only reacts to
tabIsVisible and fallbackTab so navigating between two hidden tabs can leave the
effect stale; include the routed-tab identifier in the dependency array (the
variable that represents the current route tab — e.g., the routed tab value or
route.query.tab / currentTab) so the effect reruns when the user navigates to a
different routed tab; update the dependency list that includes isLoading,
permissionsResolved, tabIsVisible, fallbackTab, visibleTabKey, router to also
include the routed-tab variable (or replace visibleTabKey with the actual
routed-tab variable if visibleTabKey isn't the routed value) so
router.replace(`/settings/${fallbackTab}`) fires correctly.

In `@tests/unit/api/test_connectors_connector_access.py`:
- Around line 45-54: The test fixtures _FakeRequest and _FakeWebhookRequest
currently define mutable dicts as class attributes (headers, query_params) which
can be shared across tests; change them to per-instance attributes by adding
__init__ constructors that assign fresh dicts to self.headers and
self.query_params (and keep method as an instance attribute for
_FakeWebhookRequest if needed) so each test gets its own independent dicts and
mutations cannot leak between tests.

---

Outside diff comments:
In `@frontend/app/settings/_components/connector-cards.tsx`:
- Around line 33-36: The component collapses fetch failures into the "not
authorized" empty state because data is defaulted to []; remove the default
assignment from the useGetConnectorsQuery destructure (do not set data:
queryConnectors = []) and instead use the hook's isError/error flags to
distinguish failure from an empty list: when useGetConnectorsQuery reports
isError (or error) show a load-error UI/message, when !connectorsLoading and
data is an empty array show the "no connectors or authorized" message; apply the
same change to the other occurrence that uses useGetConnectorsQuery (the block
around where queryConnectors is read again).
🪄 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: 54675c31-3697-4a56-b4b7-50e405c5a6e1

📥 Commits

Reviewing files that changed from the base of the PR and between 10a7d41 and 93cb6e8.

📒 Files selected for processing (26)
  • .env.example
  • frontend/app/api/mutations/useConnectConnectorMutation.ts
  • frontend/app/api/mutations/useDisconnectConnectorMutation.ts
  • frontend/app/api/queries/useGetConnectorsQuery.ts
  • frontend/app/settings/[tab]/page.tsx
  • frontend/app/settings/_components/connector-access-section.tsx
  • frontend/app/settings/_components/connector-card.tsx
  • frontend/app/settings/_components/connector-cards.tsx
  • frontend/app/settings/_components/settings-nav.tsx
  • frontend/components/dev-role-toggle.tsx
  • frontend/contexts/auth-context.tsx
  • frontend/contexts/brand-context.tsx
  • frontend/hooks/use-permissions.ts
  • frontend/lib/brand.ts
  • src/api/auth.py
  • src/api/connectors.py
  • src/api/users.py
  • src/app/routes/internal.py
  • src/config/settings.py
  • src/dependencies.py
  • src/services/connector_access_service.py
  • src/services/dev_role_toggle.py
  • tests/unit/api/test_auth_init_connector_access.py
  • tests/unit/api/test_connectors_connector_access.py
  • tests/unit/services/test_connector_access_service.py
  • tests/unit/services/test_dev_role_toggle.py
💤 Files with no reviewable changes (3)
  • src/dependencies.py
  • src/services/dev_role_toggle.py
  • tests/unit/services/test_dev_role_toggle.py
✅ Files skipped from review due to trivial changes (1)
  • frontend/app/settings/_components/connector-card.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • tests/unit/api/test_auth_init_connector_access.py
  • src/app/routes/internal.py
  • src/api/auth.py
  • src/api/users.py
  • frontend/components/dev-role-toggle.tsx
  • src/api/connectors.py

Comment thread frontend/app/settings/_components/settings-nav.tsx
Comment thread tests/unit/api/test_connectors_connector_access.py
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Jun 9, 2026
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Jun 9, 2026
Comment thread .env.example Outdated
Comment on lines +365 to +373
# Local/dev only: enables POST /users/me/dev-role and the header role toggle
# (pair with NEXT_PUBLIC_IBM_THEME_DEV=true). Never enable in production.
# OPENRAG_DEV_ROLE_TOGGLE=true

# Local OSS dev: enforce workspace connector policy on the backend (pair with
# NEXT_PUBLIC_IBM_THEME_DEV=true). Without this, the UI filters connectors but
# connect/OAuth routes ignore Connectors Permission until run mode is saas.
# OPENRAG_DEV_CONNECTOR_POLICY=true

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.

Let's avoid putting mentions of dev only envs in the env.example especially for anything IBM specific

@github-actions github-actions Bot added the lgtm label Jun 9, 2026
@github-actions github-actions Bot added enhancement 🔵 New feature or request and removed enhancement 🔵 New feature or request labels Jun 9, 2026
@Wallgau Wallgau merged commit 499a2c5 into main Jun 9, 2026
19 checks passed
@github-actions github-actions Bot deleted the feat/rbac-connector-access-v2 branch June 9, 2026 18:47
hunterxtang added a commit to hunterxtang/openrag that referenced this pull request Jun 11, 2026
The connector_sync function signature was updated in langflow-ai#1782 to include
request and session parameters. This test was written against the old
signature and failed with TypeError before reaching any assertions.

Fixes the test to pass both required parameters as MagicMock instances.
ricofurtado pushed a commit that referenced this pull request Jun 25, 2026
* feat: add SaaS workspace connector permissions with RBAC gates
Introduce admin Connectors Permission settings (cloud-only) backed by
workspace_config, enforce availability on connector APIs and OAuth init,
and sync the new connectors:manage:access permission at startup without
an Alembic migration. OSS/dev OSS brand bypasses policy; add dev role
toggle and brand-aware proxy headers for local RBAC testing.

* style: ruff autofix (auto)

* address CodeRabbit comments and fix backend lint unused imports

* fix backend lint

* feat: workspace connector permissions with aligned SaaS policy guards
Add admin Connectors Permission (workspace_config-backed) with RBAC
connectors:manage:access, enforce policy on connector APIs and OAuth init,
and keep the permission list independent of the live connectors tab.
Consolidate frontend connector-access hooks into useGetConnectorsQuery and
settings tab helpers into brand.ts. Fix Connectors Permission tab redirects
(RSC dev-brand default, wait for permissionsResolved). Let explicitly
enabled connectors override deployment visibility filters; add
OPENRAG_DEV_CONNECTOR_POLICY for local OSS dev backend enforcement Snapshot and restore all cached connector query keys in connect/disconnect
mutations so optimistic updates stay correct when policy context changes
mid-mutation (brand toggle, permissions resolving).

* style: ruff autofix (auto)

* addressed coderabbit comments

* remove mentions of dev only envs in the env.example

---------

Co-authored-by: Olfa Maslah <[email protected]>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Edwin Jose <[email protected]>
ricofurtado added a commit that referenced this pull request Jul 1, 2026
* feat:  add connectors permissions for Saas (#1782)

* feat: add SaaS workspace connector permissions with RBAC gates
Introduce admin Connectors Permission settings (cloud-only) backed by
workspace_config, enforce availability on connector APIs and OAuth init,
and sync the new connectors:manage:access permission at startup without
an Alembic migration. OSS/dev OSS brand bypasses policy; add dev role
toggle and brand-aware proxy headers for local RBAC testing.

* style: ruff autofix (auto)

* address CodeRabbit comments and fix backend lint unused imports

* fix backend lint

* feat: workspace connector permissions with aligned SaaS policy guards
Add admin Connectors Permission (workspace_config-backed) with RBAC
connectors:manage:access, enforce policy on connector APIs and OAuth init,
and keep the permission list independent of the live connectors tab.
Consolidate frontend connector-access hooks into useGetConnectorsQuery and
settings tab helpers into brand.ts. Fix Connectors Permission tab redirects
(RSC dev-brand default, wait for permissionsResolved). Let explicitly
enabled connectors override deployment visibility filters; add
OPENRAG_DEV_CONNECTOR_POLICY for local OSS dev backend enforcement Snapshot and restore all cached connector query keys in connect/disconnect
mutations so optimistic updates stay correct when policy context changes
mid-mutation (brand toggle, permissions resolving).

* style: ruff autofix (auto)

* addressed coderabbit comments

* remove mentions of dev only envs in the env.example

---------

Co-authored-by: Olfa Maslah <[email protected]>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Edwin Jose <[email protected]>

* fix: google to support WEBHOOK_BASE_URL (#1849)

* Update connector.py

* update env in settings

* fix webhook url of sharepoint

* fix: make connector webhooks work end-to-end (Drive routing, Graph subscriptions, change discovery) (#1867)

* fix: alias legacy /connectors/google/webhook to google_drive and reload connections store on webhook channel lookup miss

* Fix Sharepoint and Google Drive

* fix: propagate deleted items from SharePoint/OneDrive webhook delta query

Main's delete-event coverage (#1852) expects handle_webhook to return
deleted file ids so sync_specific_files can run its deleted-at-source
cleanup (get_file_content -> 404 -> delete indexed chunks). The delta
implementation skipped deleted items; now deleted files propagate and
deleted folders stay excluded.

* use logging _config

* Update test_webhook_type_alias.py

* fix: forward end-user JWT to MCP/API callers via gateway-placed X-OpenRAG-API-JWT header (#1874)

* use fallback header

* Notes on new header

* raises http exception for missing jwt

* feat: Add shared flag for COS ingestion to allow documents to be indexed without an owner

* style: ruff autofix (auto)

* Update src/api/connectors.py

Improving error return

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* feat: Implement shared flag for document replacement in OpenSearch queries

* style: ruff autofix (auto)

* refactor: Remove shared flag from document ingestion options in SDK

* feat: Update resolve_shared_owner_fields to return anonymous user details for shared documents

* style: ruff autofix (auto)

* feat: Add anonymous delete permission for shared documents and update related functionality

* feat: Update delete permission to include anonymous access for shared documents

* style: ruff autofix (auto)

* style: apply ruff autofix

* feat: Restrict shared flag usage to ibm_cos connector in sync_connector_files method

* fix: clarify behavior of documents with owner=null in DLS tests

* fix button types (#1875)

* refactor: no derived state (#1886)

* no derivied state

* coderabbit comments

* OPENSEARCH_NODE_COUNT_CHECK_ENABLED as deafult flag (#1975)

What changed:

  - Renamed the env var read by the backend to OPENSEARCH_NODE_COUNT_CHECK_ENABLED in src/config/settings.py.
  - Updated Docker Compose to pass OPENSEARCH_NODE_COUNT_CHECK_ENABLED in docker-compose.yml.
  - Added the canonical flag to the example env file in .env.example.
  - Documented the flag in the OpenSearch config table in docs/docs/reference/configuration.mdx.
  - Updated the existing readiness test wording in tests/unit/test_opensearch_wait_node_count.py.
  - Added a regression test that loads config.settings with OPENSEARCH_NODE_COUNT_CHECK_ENABLED=false and verifies the canonical flag is what the code reads in tests/unit/config/
    test_opensearch_node_count_check_enabled.py.

* chore: Segment improvements (#1971)

* chore: Segment improvements (#1963)

* Update static properties

* and knowledge/setting actions

* avoid duplicate events

* coderabbit comments

* fix: onboarding timeout cleanup issue (#1977)

* fix the cleanup timeout issue for the embedding step

* final step fix

* feat: add shared parameter to connector_sync function

* feat: add shared parameter to TaskProcessor and update connector_sync for permission checks

* fix: improve response handling in delete_document_endpoint for better status reporting

* fix: clear completeTimeoutRef after completion to prevent memory leaks

* fix: update OPENSEARCH_NODE_COUNT_CHECK_ENABLED to use fallback from OPENSEARCH_NODE_COUNT_CHECK

* fix: onboarding timeout cleanup issue (#1977)

* fix the cleanup timeout issue for the embedding step

* final step fix

* fix: support big csv files on langflow-less ingestion (#1968)

* fix max tokens when splitting for langflow-less ingestion

* fix coderabbit picks

* style: ruff autofix (auto)

* added non lf ingestion test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* fix: upgrade OpenSearch to 3.6.0 (#1972)

* upgrade OpenSearch to 3.6.0

* fixed PR review comments

* fix nitpicks

* Added ibm watsonx ai and langchain ibm to Langflow image (#1989)

* OPENSEARCH_NODE_COUNT_CHECK_ENABLED as deafult flag (#1975)

What changed:

  - Renamed the env var read by the backend to OPENSEARCH_NODE_COUNT_CHECK_ENABLED in src/config/settings.py.
  - Updated Docker Compose to pass OPENSEARCH_NODE_COUNT_CHECK_ENABLED in docker-compose.yml.
  - Added the canonical flag to the example env file in .env.example.
  - Documented the flag in the OpenSearch config table in docs/docs/reference/configuration.mdx.
  - Updated the existing readiness test wording in tests/unit/test_opensearch_wait_node_count.py.
  - Added a regression test that loads config.settings with OPENSEARCH_NODE_COUNT_CHECK_ENABLED=false and verifies the canonical flag is what the code reads in tests/unit/config/
    test_opensearch_node_count_check_enabled.py.

* fix: onboarding timeout cleanup issue (#1977)

* fix the cleanup timeout issue for the embedding step

* final step fix

* fix: universal file names (#1982)

* ascii support for ingest files

* update the flow json

* style: ruff autofix (auto)

* Update langflow_headers.py

* Update test_langflow_ingest_callback.py

* Update test-ci.yml

* Update test_onboarding_sample_docs.py

* style: ruff autofix (auto)

* Update test_ascii_safe_header_value.py

* Update langflow_file_service.py

* re trigger commit

* fix: purge config_manager singleton in non-langflow ingestion test

The _purge_modules() list was missing "config.config_manager", so the
ConfigManager singleton retained its cached _config from a previous test.
Subsequent calls to get_openrag_config() returned the old config where
disable_ingest_with_langflow=False, causing the router to use the Langflow
path even though DISABLE_INGEST_WITH_LANGFLOW=true was set in the environment.
Adding config.config_manager to the purge list forces a fresh load on the
next import, picking up the correct env-var values.

* fix: use hash_id to derive expected document_id in CSV ingestion test

DocumentFileProcessor ignores Docling's binary_hash field and computes
document_id = hash_id(file_path) from the actual file content. The test
was asserting against the literal mock value "sha-csv-integration-123"
which never appears in the indexed documents, giving 0 hits and a false
failure. Now the test derives expected_document_id via hash_id(csv_path)
to match what the production code actually indexes.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

---------

Co-authored-by: Wallgau <[email protected]>
Co-authored-by: Olfa Maslah <[email protected]>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Edwin Jose <[email protected]>
Co-authored-by: Edwin Jose <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Mike Fortman <[email protected]>
Co-authored-by: Sebastián Estévez <[email protected]>
Co-authored-by: Lucas Oliveira <[email protected]>
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 frontend 🟨 Issues related to the UI/UX lgtm tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants