Files
Enterprise-Knowledge-Base/internal/handler/session
wizardchen 9e3c92ca95 feat(rbac): enforce tenant role matrix on routes (PR 2 of 3, #1303)
Build on PR 1's tenant_members schema by enforcing the role matrix on
every authenticated route and at agent run time. Enforcement is gated
behind cfg.Tenant.EnableRBAC so the change ships dormant — the same
code paths log the would-be rejection during the rollout window and
start blocking once operators flip the flag.

Middleware (internal/middleware/rbac.go):
- RequireRole(min, cfg): role-only gate using TenantRole.HasPermission.
- RequireOwnershipOrRole(min, lookup, cfg): allows the original creator
  through even when their role is below min, otherwise falls back to
  the role check. Lookup errors fail closed; an empty creator_id is
  treated as tenant-owned and requires the role.
- Both honour cfg.Tenant.EnableRBAC for the rollout window.

Creator lookups (internal/handler/rbac_lookups.go):
- KBCreatorLookup resolves :id -> KnowledgeBase.CreatorID.
- AgentCreatorLookup resolves :id -> CustomAgent.CreatedBy; built-in
  agents (IsBuiltin=true) return ("", nil) so they remain Admin+ only.
- Compile-time guards keep the methods aligned with CreatorLookup.

Route guards (internal/router/rbac.go + router.go):
- rbacGuards bundles the matrix into Viewer/Contributor/Admin/Owner
  helpers plus OwnedKBOrAdmin / OwnedAgentOrAdmin. Each Register*
  function takes *rbacGuards so route lines remain readable.
- KB / Agent / Knowledge / Chunk / Tenant / Model / MCPService /
  VectorStore / DataSource / IMChannel routes annotated per the PR 1
  design doc matrix. Tenant-wide infra (models, vector stores, MCP,
  data sources, IM channels) reads as Viewer+ and writes as Admin+;
  per-resource mutations on KB / Agent route through the
  ownership-or-Admin guard.

Resource ownership (services):
- CreateKnowledgeBase / CopyKnowledgeBase populate CreatorID from the
  authenticated user, so the OwnedKBOrAdmin guard has a creator to
  match.
- CreateAgent / CopyAgent populate CreatedBy similarly. Built-in
  agents stay tenant-owned.

Agent run-time gate (internal/handler/session/qa.go):
- AgentQA refuses to launch the agent engine for Viewers when the
  target agent has RunnableByViewer=false. Same EnableRBAC gating as
  the middleware so it's a no-op until enforcement is turned on.

Tests:
- 12 unit tests cover RequireRole / RequireOwnershipOrRole, including
  the fail-open and fail-closed branches and the lookup-error path.
2026-05-18 17:28:58 +08:00
..
2026-04-10 12:49:20 +08:00