12 KiB
Implementation Plan: Group-Based Access Control
Overview
Replace the existing role-based access control (admin/editor/viewer) with a four-group model (Admin, Standard_User, Leadership, Read_Only). This touches the database schema, backend middleware, all route authorization, frontend permission helpers, and the admin panel UI. Tasks build incrementally: migration first, then middleware, then routes, then frontend.
Tasks
-
1. Create database migration for user groups
-
1.1 Create
backend/migrations/add_user_groups.jsmigration script- Add
user_groupcolumn (VARCHAR(20), NOT NULL, DEFAULT 'Read_Only') to users table - Map existing role values: admin to Admin, editor to Standard_User, viewer to Read_Only
- Map NULL or unrecognized role values to Read_Only
- Add CHECK constraint: user_group IN ('Admin', 'Standard_User', 'Leadership', 'Read_Only')
- Add index
idx_users_user_groupon user_group column - Use idempotent checks so migration is safe to run multiple times
- Follow existing migration pattern: open db, db.serialize(), log progress, close db
- Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 2.2, 2.3, 2.4, 2.5
- Add
-
* 1.2 Write property test for migration role mapping
- Property 8: Migration maps all role values correctly
- Generate users with random roles from {admin, editor, viewer, NULL, arbitrary}, run migration against in-memory SQLite, verify mapping
- Validates: Requirements 2.1, 2.2, 2.3, 2.5
-
* 1.3 Write property test for migration idempotency
- Property 9: Migration is idempotent
- Run migration N times (N in 1-5) against in-memory SQLite, verify schema and data identical each time
- Validates: Requirements 2.4
-
1.4 Write unit tests for migration
- Test column creation with correct CHECK constraint
- Test role mapping: admin to Admin, editor to Standard_User, viewer to Read_Only
- Test NULL and unrecognized role handling defaults to Read_Only
- Test new user defaults to Read_Only group
- Requirements: 1.3, 1.4, 2.1, 2.2, 2.3, 2.5
-
-
2. Update auth middleware to use groups
-
2.1 Update
requireAuthinbackend/middleware/auth.js- Modify session join query to SELECT user_group and attach as req.user.group
- Requirements: 3.4
-
2.2 Add
requireGroupmiddleware function- Accept spread of allowed group names
- Return 401 if req.user is missing
- Return 403 with error details if user group not in allowed set
- Call next() if group is allowed
- Requirements: 3.1, 3.2, 3.3
-
2.3 Remove
requireRoleand exportrequireGroup- Remove requireRole function and its export
- Export requireGroup in its place
- Requirements: 3.1
-
* 2.4 Write property test for group constraint
- Property 1: Group constraint rejects invalid values
- Generate random strings not in valid group set, attempt DB insert, verify constraint error
- Validates: Requirements 1.1, 1.4
-
* 2.5 Write property test for requireGroup
- Property 3: requireGroup rejects unauthorized groups
- Generate random group and allowedGroups pairs where group is not in allowed set, verify 403
- Validates: Requirements 3.3
-
2.6 Write unit tests for requireGroup middleware
- Test 401 for unauthenticated requests
- Test 403 for wrong group
- Test group attached to req.user
- Test next() called for allowed group
- Requirements: 3.2, 3.3, 3.4
-
-
3. Checkpoint: Verify migration and middleware
- Ensure all tests pass, ask the user if questions arise.
-
4. Update auth routes to return group
-
4.1 Update login endpoint in
backend/routes/auth.js- Return group (from user_group) instead of role in user response object
- Update audit log details to log group instead of role
- Requirements: 3.4, 9.2
-
4.2 Update me endpoint in
backend/routes/auth.js- Return group instead of role in user response object
- Requirements: 3.4
-
-
5. Update user management routes
-
5.1 Switch
backend/routes/users.jsto use requireGroup- Replace requireRole('admin') with requireGroup('Admin')
- Requirements: 4.2, 4.3
-
5.2 Update GET endpoints to return user_group
- Return user_group instead of role in user records
- Requirements: 8.1
-
5.3 Update POST create user to accept group param
- Validate group against valid values
- Default to Read_Only if not provided
- Return 400 for invalid group values
- Requirements: 1.3, 8.2
-
5.4 Update PATCH update user to accept group param
- Validate group against valid values
- Prevent admin self-demotion (return 400)
- Requirements: 8.2, 8.5
-
5.5 Add audit logging for group changes
- Log acting user ID, target user ID, previous group, new group, IP address, timestamp
- Requirements: 9.1, 9.3
-
* 5.6 Write property test for user group validity
- Property 2: Every user has exactly one valid group
- Generate random user sets, query all users, verify each has exactly one valid group
- Validates: Requirements 1.2
-
5.7 Write unit tests for user management group logic
- Test group validation rejects invalid values
- Test self-demotion prevention
- Test audit logging includes all required fields
- Requirements: 8.2, 8.5, 9.1, 9.3
-
-
6. Update backend route authorization across all routes
-
6.1 Update
backend/routes/auditLog.js- Replace requireRole('admin') with requireGroup('Admin')
- Requirements: 4.2
-
6.2 Update
backend/routes/archerTickets.js- Use requireGroup('Admin', 'Standard_User') for create, update, delete
- Requirements: 5.2
-
6.3 Update
backend/routes/knowledgeBase.js- Use requireGroup('Admin', 'Standard_User') for upload and delete
- Requirements: 5.2
-
6.4 Update
backend/routes/ivantiFindings.js- Use requireGroup('Admin', 'Standard_User') for override endpoint
- Requirements: 5.2
-
6.5 Update
backend/routes/compliance.js- Use requireGroup('Admin', 'Standard_User') for preview and commit
- Requirements: 5.2
-
6.6 Update
backend/server.jsinline CVE routes- Use requireGroup('Admin', 'Standard_User') for POST, PUT, PATCH, DELETE
- Requirements: 5.2
-
6.7 Update
backend/server.jsroute mounting- Pass requireGroup instead of requireRole to route factories
- Requirements: 3.1
-
* 6.8 Write property test for Leadership restrictions
- Property 5: Leadership cannot mutate any resource
- Generate random mutation requests as Leadership, verify 403
- Validates: Requirements 6.3
-
* 6.9 Write property test for Read_Only restrictions
- Property 6: Read_Only cannot mutate or export
- Generate random mutation and export requests as Read_Only, verify 403
- Validates: Requirements 7.2, 7.3
-
-
7. Checkpoint: Verify backend route authorization
- Ensure all tests pass, ask the user if questions arise.
-
8. Implement Standard User conditional delete logic
-
8.1 Add created_by column tracking
- Add created_by to CVE, finding, and ticket creation endpoints storing req.user.id on insert
- Requirements: 3.5
-
8.2 Implement ownership check for CVE delete
- Standard_User can only delete CVEs they created
- Return 403 if not owner
- Requirements: 3.5
-
8.3 Implement cascade impact check for CVE delete
- Query associated Archer tickets and documents
- Check compliance linkage on cascaded tickets
- Return cascade_impact response schema
- Block deletion if any cascaded ticket is compliance-linked
- Requirements: 3.8, 3.9
-
8.4 Implement state check for finding delete
- Standard_User cannot delete resolved or closed findings
- Return 403 with appropriate error message
- Requirements: 3.6
-
8.5 Implement compliance linkage check for ticket delete
- Standard_User cannot delete tickets linked to compliance reports
- Return 403 with appropriate error message
- Requirements: 3.7
-
8.6 Ensure Admin bypasses all delete restrictions
- Admin group skips ownership, state, and compliance checks
- Requirements: 3.10, 4.5
-
* 8.7 Write property test for Admin delete bypass
- Property 4: Admin bypasses all delete restrictions
- Generate resources with random ownership, state, compliance linkage, delete as Admin, verify success
- Validates: Requirements 3.10, 4.1, 4.5
-
8.8 Write unit tests for conditional delete logic
- Test ownership rejection for non-owner
- Test state rejection for resolved/closed findings
- Test compliance linkage rejection
- Test cascade impact response format
- Test Admin bypass of all restrictions
- Requirements: 3.5, 3.6, 3.7, 3.8, 3.9, 3.10
-
-
9. Checkpoint: Verify conditional delete logic
- Ensure all tests pass, ask the user if questions arise.
-
10. Update frontend AuthContext with group helpers
-
10.1 Update
frontend/src/contexts/AuthContext.js- Read group from user object instead of role
- Replace hasRole with isInGroup(...groups) helper
- Update canWrite to check isInGroup('Admin', 'Standard_User')
- Add canDelete(resource) helper: Admin always true, Standard_User only if owns resource, others false
- Add canExport() helper: true for Admin, Standard_User, Leadership
- Update isAdmin() to check isInGroup('Admin')
- Requirements: 10.1, 10.2, 10.3, 10.4, 10.5
-
* 10.2 Write property test for permission helpers
- Property 7: Group permission helpers are consistent with group matrix
- Generate all valid group values, call each helper, verify against permission matrix
- Validates: Requirements 10.5
-
-
11. Update frontend UI for group-based rendering
-
11.1 Update
App.jsconditional rendering- Use canWrite, canDelete, canExport, isAdmin for button and link visibility
- Requirements: 10.1, 10.2, 10.3
-
11.2 Update
NavDrawer.js- Show admin panel link only when isAdmin() is true
- Requirements: 10.3
-
11.3 Update
UserMenu.js- Display user group instead of role
- Requirements: 10.1
-
11.4 Update all components using hasRole or canWrite
- Replace with new group-based helpers throughout components
- Requirements: 10.5
-
11.5 Hide delete buttons for non-owned resources
- Standard_User sees delete only on resources they created
- Requirements: 10.4
-
-
12. Update User Management UI
-
12.1 Replace role dropdown with group dropdown in
UserManagement.js- Options: Admin, Standard_User, Leadership, Read_Only
- Requirements: 8.1, 8.2
-
12.2 Update form data and API calls to use group field
- Send group instead of role in create and update requests
- Requirements: 8.2
-
12.3 Add confirmation dialog for group changes
- Show confirmation before applying any group change
- Requirements: 8.3
-
12.4 Add extra warning when downgrading Admin
- Show additional warning in confirmation dialog
- Requirements: 8.4
-
12.5 Prevent admin self-demotion in UI
- Disable group change dropdown for current user if Admin
- Requirements: 8.5
-
12.6 Update user table to show group badges
- Display group badge with appropriate colors instead of role badge
- Requirements: 8.1
-
-
13. Final checkpoint: Verify full integration
- Ensure all tests pass, ask the user if questions arise.
Notes
- Tasks marked with
*are optional and can be skipped for faster MVP - Each task references specific requirements for traceability
- Checkpoints ensure incremental validation
- Property tests use
fast-checklibrary with minimum 100 iterations per test - All backend code uses callback-based SQLite API wrapped in promises (matching existing patterns)
- All frontend code uses plain JavaScript (no TypeScript)