Quickstart: Enterprise RBAC Local Development
Phase 1 Output | Date: 2026-03-25 | Plan: plan.md
Prerequisitesβ
- Docker + Docker Compose
- Node.js 20+ (via nvm)
- Python 3.11+ with uv
- Access to the
098-enterprise-rbac-slack-uibranch
1. Start Keycloakβ
cd deploy/keycloak
docker compose up -d
Keycloak will be available at http://localhost:7080 with the caipe realm pre-configured.
Default admin: admin / admin (Keycloak console)
Verify realm rolesβ
Open http://localhost:7080/admin/master/console/#/caipe/roles and confirm these roles exist:
admin,chat_user,team_member,kb_admin,offline_access
Configure client mapper (if not in realm-config.json)β
- Navigate to Clients β caipe-ui β Client scopes β caipe-ui-dedicated
- Add mapper: Realm Roles β Claim name:
realm_access(already default) - Add mapper: Group Membership β Claim name:
groups, Full group path: OFF
2. Start MongoDBβ
# From repo root
docker compose -f docker-compose.dev.yaml up -d mongodb
3. Configure UI environmentβ
Ensure ui/.env.local has:
# Keycloak OIDC
OIDC_ISSUER=http://localhost:7080/realms/caipe
OIDC_CLIENT_ID=caipe-ui
OIDC_CLIENT_SECRET=caipe-ui-dev-secret
# Optional Web UI admission group (must match a group in your IdP)
OIDC_REQUIRED_GROUP=<your-web-ui-access-group>
# Bootstrap admin (for initial setup before group mapping works)
BOOTSTRAP_ADMIN_EMAILS=your.email@example.com
# Keycloak Admin API β UI BFF (NextAuth.js role-mapping CRUD)
KEYCLOAK_URL=http://localhost:7080
KEYCLOAK_REALM=caipe
KEYCLOAK_ADMIN_CLIENT_ID=admin-cli
KEYCLOAK_ADMIN_CLIENT_SECRET=<generate-in-keycloak>
# Keycloak Admin API β Slack bot (user lookup by slack_user_id).
# MUST be a confidential client with view-users + query-users on
# realm-management. Distinct from KEYCLOAK_ADMIN_* above to avoid the
# namespace collision that would silently break slack-bot. The surface-
# specific prefix leaves room for future bots (Webex, Teams, β¦).
# (defaults to caipe-platform / caipe-platform-dev-secret in dev compose)
# KEYCLOAK_SLACK_BOT_ADMIN_CLIENT_ID=caipe-platform
# KEYCLOAK_SLACK_BOT_ADMIN_CLIENT_SECRET=<keycloak-managed-secret>
# MongoDB
MONGODB_URI=mongodb://admin:changeme@localhost:27017
MONGODB_DATABASE=caipe
4. Start the UIβ
cd ui
npm install
npm run dev
5. Run testsβ
UI testsβ
cd ui
npm test # All tests
npm test -- --coverage # With coverage report
Supervisor testsβ
# Install missing deps
uv add --dev pytest-asyncio pytest-cov
# Run tests
PYTHONPATH=. uv run pytest tests/ -v
# With coverage
PYTHONPATH=. uv run pytest tests/ --cov=ai_platform_engineering --cov-report=term-missing
6. Verify RBAC is workingβ
- Log in at
http://localhost:3000 - Check server console for
[Auth JWT] User groups count:β should show your groups - Check
[Auth JWT] User role:β should showadminif your group matches - Navigate to Admin dashboard β Roles and Slack Integration tabs should be visible
- Open user system menu β should show your realm roles and teams
7. Persona validation checklist (SC-003)β
Use Keycloak users from deploy/keycloak/realm-config.json (adjust passwords locally) or create equivalent realm roles. Goal: no protected surface grants a high-risk action that the permission matrix forbids for that persona.
Record Pass / Fail and notes (which endpoint or UI path was exercised).
admin β full accessβ
| # | Check | Pass? |
|---|---|---|
| A1 | UI: Admin dashboard loads; Users, Teams, Roles, sensitive tabs available per admin_tab_policies | |
| A2 | API: GET /api/admin/users returns 200 | |
| A3 | Can assign roles / team membership (if exercised) | |
| A4 | RAG proxy / query succeeds for all KBs the deployment exposes | |
| A5 | MCP via Agent Gateway: admin-prefixed or supervisor_config tools allowed when JWT has admin realm role |
chat_user β chat access, no adminβ
| # | Check | Pass? |
|---|---|---|
| C1 | UI: Main chat works; Admin entry hidden or returns 403 on deep link | |
| C2 | API: GET /api/admin/users returns 403 | |
| C3 | User menu: shows own RBAC posture (/api/auth/my-roles); no admin-only tabs | |
| C4 | Supervisor / A2A invoke allowed where matrix grants chat_user | |
| C5 | MCP (AG): generic tool invoke allowed; admin_ / rag_ingest / supervisor_config denied |
team_member β team-scoped KB / agent contextβ
| # | Check | Pass? |
|---|---|---|
| T1 | Can access team-scoped RAG tools / KBs only for member teams (MongoDB + Keycloak roles) | |
| T2 | Cannot modify another teamβs tool configs without kb_admin / admin | |
| T3 | Slack (if configured): channelβteam mapping scopes context; without team_member for that team, bot denies with clear message (FR-031 / FR-004) |
kb_admin β KB administrationβ
| # | Check | Pass? |
|---|---|---|
| K1 | RAG ingest and KB admin operations succeed | |
| K2 | UI admin user/role management still 403 unless also admin / bootstrap admin | |
| K3 | AG: rag_ingest* allowed; platform user management remains blocked |
denied β no baseline accessβ
Use a user with no chat_user, team_member, kb_admin, or admin (seed user denied@example.com is a starting point).
| # | Check | Pass? |
|---|---|---|
| D1 | UI: cannot reach agent chat or receives clear unauthorized experience | |
| D2 | GET /api/chat/conversations or equivalent protected API returns 401/403 | |
| D3 | AG MCP: tool list/invoke denied (no valid role in jwt.realm_access.roles) | |
| D4 | No leakage of other usersβ data in error messages (FR-004) |
Optional regressionβ
| # | Check | Pass? |
|---|---|---|
| R1 | Stop Keycloak: BFF protected route returns 503 fail-closed (no silent allow) | |
| R2 | With ASP denying a tool: RBAC allow + ASP deny β deny |
References: security-review.md, operator-guide.md.
Troubleshootingβ
"User role: user" after loginβ
Product admin is granted through OpenFGA relationships, not the legacy OIDC admin-group flag. Check:
- Server logs for
[Auth JWT] User groups count:β if 0, the groups claim is missing - Add a Group Membership mapper on the
caipe-uiclient in Keycloak - Map your enterprise admin group to a CAIPE admin team through Identity Group Sync
- Use
BOOTSTRAP_ADMIN_EMAILS=your.email@example.comonly as a temporary workaround
Supervisor tests fail with "async def functions are not natively supported"β
uv add --dev pytest-asyncio
UI tests fail with ESM module errorsβ
Some dependencies (uuid, jose, @a2a-js) require ESM transforms. Check jest.config.js has them in transformIgnorePatterns.