Skip to content

feat(rbac/ui): per-tab OpenFGA gates and empty states for Knowledge sidebar#1572

Closed
sriaradhyula wants to merge 1 commit into
prebuild/fix/rbac-kb-org-admin-super-grantfrom
prebuild/feat/ui-kb-tab-gates
Closed

feat(rbac/ui): per-tab OpenFGA gates and empty states for Knowledge sidebar#1572
sriaradhyula wants to merge 1 commit into
prebuild/fix/rbac-kb-org-admin-super-grantfrom
prebuild/feat/ui-kb-tab-gates

Conversation

@sriaradhyula
Copy link
Copy Markdown
Member

Summary

PR 2 of the 2026-05-27 fine-grained KB ReBAC plan. Stops the Knowledge sidebar from showing tabs the user cannot use. Non-admin users who own zero knowledge bases would previously see Search / Data Sources / Graph / MCP Tools live in the sidebar and only discover the 403 after clicking. This PR renders those tabs as disabled-with-tooltip and replaces the page body with an empty state.

  • New BFF route GET /api/rbac/kb-tab-gates returns {search, data_sources, graph, mcp_tools, has_any_kb, kb_count}. Org admins (via OpenFGA can_manage organization or BOOTSTRAP_ADMIN_EMAILS) short-circuit to every tab true with kb_count = -1; non-admins get the count derived from /v1/datasources filtered by knowledge_base#can_read. Honours RAG_ADMIN_BYPASS_DISABLED.
  • New useKbTabGates SWR-style hook the sidebar consumes. Fails closed — until the BFF responds, every tab is hidden so the UI never exposes a control the BFF would 403.
  • KnowledgeSidebar renders disabled tabs with hover tooltips, suppresses the empty-state banner on the org-admin bypass, and respects both graphRagEnabled AND RBAC on Graph.
  • New NoKbAccessEmpty page-level fallback for Search / Data Sources / Graph / MCP Tools when no KB is readable.

Depends on PR #1571 (bypassForOrgAdmin infrastructure).

Test plan

  • ui/src/app/api/rbac/__tests__/kb-tab-gates.test.ts — BFF tests (admin bypass, non-admin zero KBs, kill switch, error fallthrough) pass.
  • ui/src/components/rag/__tests__/KnowledgeSidebar.test.tsx — sidebar render tests pass.
  • Full UI Jest suite: 5257 / 5258 passed (1 skip, no failures).
  • npx eslint clean on every touched file.

Manual verification (post-merge)

  • Sign in as a non-org-admin with zero KB tuples; confirm Search / Data Sources / Graph / MCP Tools all render as disabled-with-tooltip.
  • Grant the user one team→KB tuple; confirm tabs flip to enabled and kb_count increments.
  • Sign in as an org admin; confirm every tab is enabled with no empty-state banner.
  • Set RAG_ADMIN_BYPASS_DISABLED=true; confirm even admins go through the per-resource path.

…idebar

PR 2 of the 2026-05-27 fine-grained KB ReBAC plan.

Stops the Knowledge sidebar from showing tabs the user cannot actually
use. Non-admin users who own zero knowledge bases would previously see
Search / Data Sources / Graph / MCP Tools live in the sidebar and only
discover the 403 after clicking through. This PR renders those tabs as
disabled-with-tooltip and replaces the page body with a clear empty
state.

Changes:
- ui/src/app/api/rbac/kb-tab-gates/route.ts: new BFF route that returns
  `{search, data_sources, graph, mcp_tools, has_any_kb, kb_count}`.
  Org admins (resolved via OpenFGA can_manage organization or via
  BOOTSTRAP_ADMIN_EMAILS) short-circuit to every tab true with
  kb_count = -1; non-admins get the count derived from the
  /v1/datasources response filtered by knowledge_base#can_read with
  bypassForOrgAdmin = false. Honours RAG_ADMIN_BYPASS_DISABLED.
- ui/src/hooks/use-kb-tab-gates.ts: SWR-style hook that fetches the
  route. Fails closed — until the BFF responds every tab is hidden so
  the UI never exposes a control the BFF would 403.
- ui/src/components/rag/KnowledgeSidebar.tsx: renders disabled tabs
  with hover tooltips explaining the missing access, suppresses the
  empty-state banner when the org-admin bypass fires, and respects
  both graphRagEnabled AND RBAC on the Graph tab.
- ui/src/components/rag/NoKbAccessEmpty.tsx: page-level fallback for
  Search / Data Sources / Graph / MCP Tools when no KB is readable.
- ui/src/lib/rbac/types.ts: adds KbTabKey and KbTabGatesMap.

Tests:
- ui/src/app/api/rbac/__tests__/kb-tab-gates.test.ts: BFF tests
  (admin bypass, non-admin with zero KBs, kill switch, error
  fallthrough).
- ui/src/components/rag/__tests__/KnowledgeSidebar.test.tsx: sidebar
  render tests (disabled-with-tooltip, empty-state banner, org-admin
  bypass, graphRagEnabled interaction).
- Full UI Jest suite passes (5257 / 5258, 1 skip; no failures).
- npx eslint clean on every touched file.

Docs:
- docs/docs/security/rbac/architecture.md: policy paragraph.
- docs/docs/security/rbac/file-map.md and pdp-coverage-audit.md: rows.

Assisted-by: Cursor claude-opus-4-7
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions
Copy link
Copy Markdown
Contributor

🧪 CAIPE UI Test Results

All tests passed

🟠 Overall Coverage: 55%

Coverage
lines
statements
functions
branches

📊 Detailed Coverage

Metric Covered Total Percentage
Lines 24316 41023 59.27%
Statements 25881 45041 57.46%
Functions 4382 8272 52.97%
Branches 15634 32284 48.42%

✅ Test Suites

  • ✅ auth-guard.test.tsx - Route protection & authorization
  • ✅ token-expiry-guard.test.tsx - Token expiry handling
  • ✅ a2a-sdk-client.test.ts - A2A streaming SDK
  • ✅ auth-utils.test.ts - Authentication utilities (100% coverage)
  • ✅ auth-config.test.ts - OIDC configuration
📈 Coverage Thresholds
Threshold Target Current Status
Minimum 40% 55% ✅ Pass
Good 60% 55% ⚠️ Below target
Excellent 80% 55% ⚠️ Below target
⚠️ Areas Needing Tests

High Priority:

  • hooks/use-a2a-streaming.ts - Core streaming functionality
  • store/chat-store.ts - Chat state management
  • store/agent-skills-store.ts - Agent skills
  • lib/api-client.ts - API communication
  • lib/storage-mode.ts - MongoDB/localStorage switching

Medium Priority:

  • components/chat/ChatPanel.tsx - Main chat interface
  • components/agent-builder/* - Agent builder UI
  • lib/mongodb.ts - MongoDB integration

💡 Run locally: make caipe-ui-tests
📦 Full report: Check workflow artifacts

@sriaradhyula
Copy link
Copy Markdown
Member Author

Superseded by collapsed replacement PR #1584.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant