feat(rbac): add fine-grained Knowledge Base access controls#1584
Conversation
|
✅ No proprietary content detected. This PR is clear for review! |
🧪 CAIPE UI Test Results❌ Tests failed - Please review the logs 🟠 Overall Coverage: 55%📊 Detailed Coverage
✅ Test Suites
📈 Coverage Thresholds
|
Prebuild Artifacts for `2915d0b` (archived)Prebuild Artifacts for
|
| Artifact | Image | Tag | Status | CI |
|---|---|---|---|---|
| caipe-ui | - | - | Failed | CI |
These prebuild artifacts will be automatically cleaned up when the PR is closed or merged.
Prebuild Artifacts for `742a250` (archived)Prebuild Artifacts for
|
| Artifact | Image | Tag | Status | CI |
|---|---|---|---|---|
| caipe-ui | - | - | Failed | CI |
These prebuild artifacts will be automatically cleaned up when the PR is closed or merged.
Prebuild Artifacts for `01cc9f3` (archived)Prebuild Artifacts for
|
| Artifact | Image | Tag | Status | CI |
|---|---|---|---|---|
| caipe-ui | ghcr.io/cnoe-io/prebuild/caipe-ui |
collapse-rbac-kb-prs-11 |
Published | CI |
Docker pull commands
docker pull ghcr.io/cnoe-io/prebuild/caipe-ui:collapse-rbac-kb-prs-11These prebuild artifacts will be automatically cleaned up when the PR is closed or merged.
Prebuild Artifacts for `e4b1fa0` (archived)Prebuild Artifacts for
|
| Artifact | Image | Tag | Status | CI |
|---|---|---|---|---|
| caipe-ui | ghcr.io/cnoe-io/prebuild/caipe-ui |
collapse-rbac-kb-prs-12 |
Published | CI |
Docker pull commands
docker pull ghcr.io/cnoe-io/prebuild/caipe-ui:collapse-rbac-kb-prs-12These prebuild artifacts will be automatically cleaned up when the PR is closed or merged.
| | "mcp_server" | ||
| | "tool" | ||
| | "knowledge_base" | ||
| | "data_source" | ||
| | "mcp_tool" |
There was a problem hiding this comment.
whats the diference between knowledge_base vs data_source?
and "tool" vs "mcp_tool"?
why do we have "document" as a resource, is that kb document or another CAIPE concept?
…es / Graph / MCP Tools
PR 1 of the 2026-05-27 fine-grained KB ReBAC plan.
Restore the org-admin super-grant on every Knowledge Base sidebar
surface so platform admins can never be locked out of one specific KB
while staying org admin. The previous strict per-resource enforcement
pass had silently cut admin users off from KB / Search / Data Sources /
Graph / MCP Tools when no `team:<slug>#member reader knowledge_base:<id>`
tuples were present.
Changes:
- `ui/src/lib/rbac/resource-authz.ts`: add explicit `bypassForOrgAdmin`
option to `requireResourcePermission` and `filterResourcesByPermission`.
When true, the helper short-circuits to allow if the caller holds
`user:<sub> can_manage organization:<key>` in OpenFGA. Default is OFF
so the bypass is auditable in code review. Honours
`RAG_ADMIN_BYPASS_DISABLED=true` as a kill switch.
- `ui/src/app/api/rag/[...path]/route.ts` and
`ui/src/app/api/rag/kb/[...path]/route.ts`: pass
`bypassForOrgAdmin: true` to every per-`knowledge_base:<id>` check
(per-KB gate, datasource list filter, readable-datasource enumerator)
and replace the legacy `session.role === 'admin'` short-circuit in
`constrainSearchBody` with an OpenFGA-resolved org-admin check so
admins skip filter injection regardless of JWT role-claim shape.
- `ui/src/lib/rbac/baseline-access.ts`: add `rag_datasources` to
`PRIVILEGED_ADMIN_SURFACES` so new org admins receive an explicit
`user:<sub> manager admin_surface:rag_datasources` tuple at login
instead of relying on OpenFGA model inheritance only.
- `ui/src/lib/rbac/migrations/registry.ts`: add
`admin_surface_rag_datasources_admin_grant_v1` migration. Walks
OpenFGA for existing `user:<sub> admin organization:<key>` tuples and
writes the matching `manager admin_surface:rag_datasources` tuple for
every previously-bootstrapped org admin. Idempotent.
Tests:
- `ui/src/lib/rbac/__tests__/resource-authz-admin-bypass.test.ts`: 11
cases covering happy path, kill switch, default-off, and check-failure
fallthrough for both helpers.
- `ui/src/app/api/rag/__tests__/admin-kb-bypass.test.ts`: integration
smoke tests verifying the BFF proxies through for org admins.
- `ui/src/lib/rbac/migrations/__tests__/agent-organization-inheritance.test.ts`:
2 new cases for the admin-surface backfill (dedup, invalid-subject
warning).
- `ui/src/lib/rbac/__tests__/keycloak-bootstrap-admins.test.ts`: tuple
counts bumped to reflect the new admin-surface entry.
- `ui/src/app/api/__tests__/rag-rbac.test.ts`: existing assertions
updated to include the new `{ bypassForOrgAdmin: true }` option.
Docs:
- `docs/docs/security/rbac/architecture.md`: add the policy paragraph
for the org-admin super-grant and the kill switch.
- `docs/docs/security/rbac/file-map.md` and
`docs/docs/security/rbac/pdp-coverage-audit.md`: row updates.
Total: 48 tests in this PR pass; no lint regressions.
Assisted-by: Cursor claude-opus-4-7
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Fixes a registry-guardrails test failure introduced by PR 1's new admin_surface_rag_datasources_admin_grant_v1 migration: the admin_surfaces schema area was registered in MIGRATION_DEFINITIONS but never classified in SCHEMA_AREA_CLASSIFICATIONS, so getUnclassifiedSchemaAreas([...all defs]) returned a non-empty array and the guardrail asserted that should be empty. Adds the entry with classification "migration" and a description pointing at the new backfill migration. Assisted-by: Cursor claude-opus-4-7 Signed-off-by: Sri Aradhyula <sraradhy@cisco.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…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>
PR 3 of the 2026-05-27 fine-grained KB ReBAC plan. KB admins (anyone with `knowledge_base:<id>#can_manage`) and org admins can now share a Knowledge Base with additional teams from a dedicated panel. - New `/knowledge-bases/sharing/[id]` page hosts `KbSharingPanel`, which uses the existing `TeamMultiPicker` plus an Effective-Access callout listing reader/manager teams and org admins. - `PUT /api/rag/kbs/[id]/sharing` reconciles the team list through `reconcileKnowledgeBaseRelationships` (gated by `knowledge_base:<id>#can_manage` with `bypassForOrgAdmin: true`). - `buildKnowledgeBaseRelationshipTupleDiff` now diffs `nextSharedTeamSlugs` vs `previousSharedTeamSlugs` and emits explicit deletes for teams the operator unchecks (mirrors `reconcileAgentRelationships`). - New `knowledge_base_shared_team_grants_backfill_v1` migration walks the legacy `team_kb_ownership` Mongo collection and writes the canonical `team:<slug>#member reader knowledge_base:<id>` plus `team:<slug>#admin manager knowledge_base:<id>` tuples for every existing (team, kb) row so admins can migrate without losing access. - `schema-area-classifications.ts` reclassifies `team_kb_ownership` as a `migration` schema area to keep the registry guardrails passing. - RBAC docs (architecture / file-map / pdp-coverage-audit) describe the new sharing panel, route, and backfill migration. Tests added: `openfga-kb-shared-teams.test.ts` (reconciler diff), `sharing-route.test.ts` (BFF route), and four new cases in `agent-organization-inheritance.test.ts` for the backfill migration. Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Sri Aradhyula <sraradhy@cisco.com> Co-authored-by: Cursor <cursoragent@cursor.com>
PR 4 of the 2026-05-27 fine-grained KB ReBAC plan. Introduces two new per-resource OpenFGA types so per-KB ingest and per-tool invoke can be granted independently of `knowledge_base:<id>` reads. OpenFGA model - `deploy/openfga/model.fga` adds `type data_source` and `type mcp_tool` with the same shared-teams relation set as `knowledge_base` (`team#member reader`, `team#admin manager`). Both expose `manager: [..., organization#admin]` so org admins are an explicit model edge, not just a runtime bypass. - `mcp_tool` additionally exposes `user` and `caller` relations so team members get `can_call` (mirrors how `mcp_server` invokers are modelled). - `knowledge_base#manager` also gains `organization#admin` for parity. - `deploy/openfga/init/authorization-model.json` regenerated. Reconcilers - `buildDataSourceRelationshipTupleDiff` and `buildMcpToolRelationshipTupleDiff` (with their `reconcileDataSourceRelationships` / `reconcileMcpToolRelationships` wrappers) mirror the shared-teams diff that PR 3 added for KBs. - The shared helper `buildOwnedResourceWithSharedTeamsDiff` factors the diff logic for `knowledge_base`, `data_source`, and `mcp_tool`. BFF integration - `/api/rag/[...path]` writes `mcp_tool:<tool_id>` tuples on a successful `PUT /v1/mcp/custom-tools/<tool_id>` (owner subject + owner team slug from the request body). Owner-team writes are gated by `team:<slug>#can_use`. - `GET /v1/mcp/custom-tools` responses are filtered by `mcp_tool:<id>#can_read`. Org admins bypass via PR 1's super-grant. Migrations - `data_source_grants_backfill_v1` — strictly additive, mirrors every existing `knowledge_base:<id>` tuple as a parallel `data_source:<id>` tuple so day-zero KB readers stay data-source readers. - `mcp_tool_grants_backfill_v1` — walks Mongo `team_rag_tools` and writes the canonical `reader` + `user` (member) and `manager` (admin) tuples for every team-owned tool. - `schema-area-classifications.ts` adds `openfga_tuples` so `registry-guardrails.test.ts` keeps passing. Docs - RBAC architecture / file-map / pdp-coverage-audit updated to describe the new types, BFF integration, and backfill migrations. Tests - `openfga-data-source-mcp-tool.test.ts` exercises the new reconcilers. - `mcp-tool-list-filter.test.ts` exercises the BFF list filter. - `agent-organization-inheritance.test.ts` covers both backfill migrations. Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Sri Aradhyula <sraradhy@cisco.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Two follow-on fixes for the new types introduced in this PR that were missing from the original commit: - `ui/src/types/rbac-universal.ts` now lists `data_source` and `mcp_tool` in `UniversalRebacResourceType`. Without this, callers that pass these types through the universal RBAC helpers (`reconcileTeamResourceTuples`, `requireResourcePermission`, etc.) hit a TS-level "type 'data_source' is not assignable to UniversalRebacResourceType" error. - `ui/src/app/api/__tests__/rag-rbac.test.ts` now mocks `reconcileDataSourceRelationships` and `reconcileMcpToolRelationships` in the `@/lib/rbac/openfga-owned-resources` jest factory. Without these mocks the BFF tests pull in the real reconcilers and start hitting the production OpenFGA client. Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Sri Aradhyula <sraradhy@cisco.com> Co-authored-by: Cursor <cursoragent@cursor.com>
PR 5 of the 2026-05-27 fine-grained KB ReBAC plan. Closes out the sidebar work and documents the remaining RAG-server effort needed for true per-KB ontology filtering. - `/knowledge-bases/graph` now consults `useKbTabGates` (the PR 2 hook). Non-admins with zero readable KBs see the `NoKbAccessEmpty` empty state instead of the global graph. - New `GraphInfoBanner` is rendered whenever the tab is visible, reminding users (and org admins under PR 1's super-grant) that the ontology graph is currently global. When `kb_count >= 0` the banner also surfaces "you have read access to N knowledge bases" so non- admins know exactly what their scope is. - `__tests__/page.test.tsx` covers: org-admin sees the banner; non-admin with reads sees the banner; non-admin with zero reads sees the empty state instead of the graph; banner stays hidden until the BFF responds (fails closed). - New spec `docs/docs/specs/2026-05-27-per-kb-ontology-graph-filtering/spec.md` tracks the RAG-server work needed for true per-KB filtering (a `kb_ids` filter on `/v1/graphrag/*` plus an OpenFGA-driven membership probe in the BFF). This intentionally lives outside the PR 5 code change because it is a multi-week server-side effort. - RBAC architecture / file-map updated to describe the gate, banner, and the follow-up spec. Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Sri Aradhyula <sraradhy@cisco.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Shared Knowledge Base teams need ingest access as well as read access so team members can use the KB the way the sharing UI describes. Add the `ingestor` tuple to the reconciler and legacy backfill path, and cover both tuple generation paths with regression tests. Assisted-by: Cursor:GPT-5.5 Signed-off-by: Sri Aradhyula <sraradhy@cisco.com> Co-authored-by: Cursor <cursoragent@cursor.com>
The RBAC comments should describe durable behavior rather than the temporary stack and phase numbers used while preparing the PR. Reword the comments and migration descriptions so they stay useful after merge. Assisted-by: Cursor:GPT-5.5 Signed-off-by: Sri Aradhyula <sraradhy@cisco.com> Co-authored-by: Cursor <cursoragent@cursor.com>
The data_source backfill attempted to use `knowledge_base:` as an OpenFGA tuple-key prefix filter. OpenFGA rejects that shape because the object id is empty, which blocked migration preview/status loading. Read valid pages and filter knowledge_base objects client-side instead. Assisted-by: Cursor:GPT-5.5 Signed-off-by: Sri Aradhyula <sraradhy@cisco.com> Co-authored-by: Cursor <cursoragent@cursor.com>
e4b1fa0 to
83af5b9
Compare
Prebuild Artifacts for `83af5b9` (archived)Prebuild Artifacts for
|
| Artifact | Image | Tag | Status | CI |
|---|---|---|---|---|
| caipe-ui | - | - | Failed | CI |
These prebuild artifacts will be automatically cleaned up when the PR is closed or merged.
Prebuild Artifacts for `315473b` (archived)Prebuild Artifacts for
|
| Artifact | Image | Tag | Status | CI |
|---|---|---|---|---|
| caipe-ui | ghcr.io/cnoe-io/prebuild/caipe-ui |
collapse-rbac-kb-prs-12 |
Published | CI |
Docker pull commands
docker pull ghcr.io/cnoe-io/prebuild/caipe-ui:collapse-rbac-kb-prs-12These prebuild artifacts will be automatically cleaned up when the PR is closed or merged.
RAG authorization now consistently uses OpenFGA for human users, including the organization-admin super-grant needed for new datasource creation before datasource ownership tuples exist. The UI reflects the same permission model and replaces blocking RAG error alerts with in-app notifications. Assisted-by: Cursor:GPT-5.5 Signed-off-by: Sri Aradhyula <sraradhy@cisco.com> Co-authored-by: Cursor <cursoragent@cursor.com>
❗ Branch update neededCommit: CI failed to bump chart and app versions because this branch does not contain the latest Run: git fetch origin main
git checkout prebuild/collapse-rbac-kb-prs
git merge FETCH_HEAD
git pushThis is a |
Prebuild Artifacts for
|
| Chart | Registry | Version | Status | CI |
|---|---|---|---|---|
| ai-platform-engineering | ghcr.io/cnoe-io/prebuild-helm-charts |
0.5.0-dev.2-collapse-rbac-kb-prs-12 |
Published | CI |
| rag-stack | ghcr.io/cnoe-io/prebuild-helm-charts |
0.5.0-dev.2-collapse-rbac-kb-prs-12 |
Published | CI |
Helm install commands
helm upgrade --install ai-platform oci://ghcr.io/cnoe-io/prebuild-helm-charts/ai-platform-engineering --version 0.5.0-dev.2-collapse-rbac-kb-prs-12
helm upgrade --install rag oci://ghcr.io/cnoe-io/prebuild-helm-charts/rag-stack --version 0.5.0-dev.2-collapse-rbac-kb-prs-12These prebuild artifacts will be automatically cleaned up when the PR is closed or merged.
Summary
data_sourceandmcp_toolOpenFGA resource types, reconciliation/backfill support, and valid paginated OpenFGA tuple reads.OpenFGArole label, replaces blocking RAG alerts with in-app toasts, and adds local UI build optimizations.Why
KB access was inconsistent across UI, BFF, and RAG server paths: some flows still depended on legacy role/group/trusted-network concepts while newer surfaces relied on OpenFGA. This PR makes OpenFGA the source of truth for human KB access, keeps org-admin access explicit, and avoids confusing read-only or access-denied states for authorized admins.
Test Plan
uv run pytest tests/test_openfga_team_rebac.py -quv run ruff check src/server/rbac.py tests/test_openfga_team_rebac.pynpm test -- --runTestsByPath src/components/rag/__tests__/IngestView.reingest-error.test.ts --runInBandnpx eslint src/components/rag/IngestView.tsx src/components/rag/__tests__/IngestView.reingest-error.test.tsdocker compose -f docker-compose.dev.yaml build rag-server caipe-ui-proddocker compose -f docker-compose.dev.yaml up -d --no-deps --force-recreate rag-server caipe-ui-prod