ADR-074 Implementation Checklist
Status: Accepted Started: 2025-12-09 Completed: 2025-12-09 ADR: ADR-074: Platform Admin Role
Phase 1: Database Migration ✅ COMPLETE
- [x] Create migration file
schema/migrations/028_platform_admin_resources.sql - [x] Register 15 resource types with available_actions
- [x] Create
platform_adminrole with parent_role = 'admin' - [x] Grant permissions to
contributorrole (graph:read, ingest:create, etc.) - [x] Grant permissions to
curatorrole (vocabulary:write, ontologies:create) - [x] Grant permissions to
adminrole (users, oauth_clients, read-only platform) - [x] Grant permissions to
platform_adminrole (full platform access) - [x] Test migration is idempotent (can run multiple times safely)
- [x] Apply migration to dev environment
Results: 19 resources, 5 roles, ~83 permission grants
Phase 2: Replace require_role with require_permission ✅ COMPLETE
Replaced Depends(require_role("admin")) with Depends(require_permission("resource", "action")):
Platform Administration (Critical) ✅
- [x]
admin.py-/admin/status→admin:status - [x]
admin.py-/admin/backup→backups:create - [x]
admin.py-/admin/backups→backups:read - [x]
admin.py-/admin/restore→backups:restore - [x]
admin.py-/admin/keysGET →api_keys:read - [x]
admin.py-/admin/keys/{provider}POST →api_keys:write - [x]
admin.py-/admin/keys/{provider}DELETE →api_keys:delete
Embedding Configuration ✅
- [x]
embedding.py-/admin/embedding/configGET →embedding_config:read - [x]
embedding.py-/admin/embedding/configsGET →embedding_config:read - [x]
embedding.py-/admin/embedding/configPOST →embedding_config:create - [x]
embedding.py-/admin/embedding/config/{id}DELETE →embedding_config:delete - [x]
embedding.py-/admin/embedding/config/{id}/activate→embedding_config:activate - [x]
embedding.py-/admin/embedding/config/reload→embedding_config:reload - [x]
embedding.py-/admin/embedding/regenerate→embedding_config:regenerate - [x]
embedding.py-/admin/embedding/status→embedding_config:read - [x]
admin.py-/admin/regenerate-concept-embeddings→embedding_config:regenerate
Extraction Configuration ✅
- [x]
extraction.py-/admin/extraction/configGET →extraction_config:read - [x]
extraction.py-/admin/extraction/configPOST →extraction_config:write
User Management ✅
- [x]
auth.py-/usersGET →users:read - [x]
auth.py-/users/{id}GET →users:read - [x]
auth.py-/users/{id}PUT →users:write - [x]
auth.py-/users/{id}DELETE →users:delete
OAuth Client Management (Admin) ✅
- [x]
oauth.py-/auth/oauth/clientsGET →oauth_clients:read - [x]
oauth.py-/auth/oauth/clientsPOST →oauth_clients:create - [x]
oauth.py-/auth/oauth/clients/{id}GET →oauth_clients:read - [x]
oauth.py-/auth/oauth/clients/{id}PATCH →oauth_clients:write - [x]
oauth.py-/auth/oauth/clients/{id}DELETE →oauth_clients:delete - [x]
oauth.py-/auth/oauth/clients/{id}/rotate-secret→oauth_clients:write
Ontology Management ✅
- [x]
ontology.py-/ontology/{name}DELETE →ontologies:delete - [x]
ontology.py-/ontology/{name}/rename→ontologies:create
RBAC Management ✅
- [x]
rbac.py- All 17 endpoints →rbac:read/write/create/delete
Vocabulary Configuration ✅
- [x]
vocabulary_config.py-/admin/vocabulary/configGET →vocabulary_config:read - [x]
vocabulary_config.py-/admin/vocabulary/configPUT →vocabulary_config:write - [x]
vocabulary_config.py-/admin/vocabulary/profilesGET →vocabulary_config:read - [x]
vocabulary_config.py-/admin/vocabulary/profilesPOST →vocabulary_config:create - [x]
vocabulary_config.py-/admin/vocabulary/profiles/{name}GET →vocabulary_config:read - [x]
vocabulary_config.py-/admin/vocabulary/profiles/{name}DELETE →vocabulary_config:delete
Vocabulary Operations ✅
- [x]
vocabulary.py- Write operations →vocabulary:write
Results: 9 route files updated, ~60 endpoints migrated to permission-based auth
Phase 3: Verify and Test ✅ COMPLETE
- [x] Fix
require_permissionto be sync factory (was incorrectly async) - [x] Fix
PermissionChecker._get_user_rolesto include user'sprimary_role - [x] Fix role hierarchy with migration 029 (admin → curator → contributor)
- [x] Add
api/tests/test_permissions.pyfor permission coverage testing - [x] Test role inheritance (platform_admin → admin → curator → contributor)
- [x] Verify API starts and responds to authenticated requests
- [ ] Test explicit deny functionality (deferred - no deny grants yet)
- [ ] Verify public endpoints still work without auth
- [ ] Test authenticated-only endpoints (personal OAuth clients, etc.)
Results: 23/23 permission tests passing for admin role
Phase 4: CLI Role Management ✅ COMPLETE (Already Implemented)
CLI commands already existed at kg admin rbac:
- [x]
kg admin rbac role list- List all roles with hierarchy - [x]
kg admin rbac role show <role>- Show role details with permissions - [x]
kg admin rbac role create- Create custom role - [x]
kg admin rbac role delete- Delete custom role - [x]
kg admin rbac resource list- List all resource types and actions - [x]
kg admin rbac permission list- List permissions (filterable by role/resource) - [x]
kg admin rbac permission grant- Grant permission to role - [x]
kg admin rbac permission revoke- Revoke permission
Also fixed:
- [x] kg admin status - Updated AdminService for containerized environment
- Replaced docker exec with direct database connections
- Check API keys from encrypted database storage
- Detect container via /.dockerenv
Phase 5: Web UI Updates ✅ COMPLETE
- [x] Update AdminDashboard to check permissions per section
- Added
canViewUsers,canViewAllOAuthClients,canViewSystemStatuspermission checks - Tabs now show/hide based on actual permissions instead of role equality
- [x] Hide/disable features based on effective permissions
- "All OAuth Clients" section only shows if user has
oauth_clients:read - Users tab only shows if user has
users:read - System tab only shows if user has
admin:status - [x] Add visual indicator for platform admin users
- Purple "Platform Admin" badge in header for platform_admin role
- Role-colored badges in user list (purple=platform_admin, blue=admin, green=curator, gray=contributor)
- [x] Add
/users/me/permissionsAPI endpoint - Returns role, role_hierarchy, permissions list, and
canmap for easy checking - [x] Update auth store with permissions state
loadPermissions()called after authenticationhasPermission(resource, action)helper methodisPlatformAdmin()helper method
Results: Permission-based UI visibility implemented with graceful degradation
Phase 6: Documentation ✅ COMPLETE
- [x] Update
docs/reference/api/ADMIN-ENDPOINTS.md - Added permission-based access level section
- Updated all endpoint tables to show required
resource:actionpermissions - Added role hierarchy documentation
- [ ] Add Platform Admin setup to operator docs (deferred - operator workflow unchanged)
- [ ] Document recovery procedure for self-lockout (deferred - future enhancement)
- [ ] Update CLAUDE.md with platform admin workflow (not needed - existing RBAC CLI docs cover this)
Progress Log
2025-12-09
- Created ADR-074 with full resource inventory (15 resources)
- Updated all API endpoint docstrings with RBAC authorization format
- Implementation checklist created
- Phase 1 complete: Migration 028 applied - 19 resources, 5 roles, ~83 permissions
- Phase 2 complete: Replaced require_role → require_permission in 9 route files (~60 endpoints)
- Fixed
require_permissionasync/sync bug (wasasync def, should bedef) - Fixed
PermissionCheckerto includeprimary_rolefrom users table - Created migration 029 to fix role hierarchy (admin → curator → contributor)
- Added
api/tests/test_permissions.pyfor permission coverage testing - Phase 3 complete: 23/23 permission tests passing
- Phase 4 complete: CLI RBAC commands already existed (
kg admin rbac) - Fixed
AdminServicefor containerized environment (replaced docker exec with direct connections) - Phase 5 complete: Web UI updated with permission-based access control
- Added
/users/me/permissionsendpoint - Updated authStore with
loadPermissions(),hasPermission(),isPlatformAdmin() - AdminDashboard now uses permission checks instead of role equality
- Added platform admin badge and role-colored user badges
- Phase 6 complete: Updated
ADMIN-ENDPOINTS.mdwith permission-based documentation