Files
jramos 73fd747576 feat: implement group-based access control (Admin, Standard_User, Leadership, Read_Only)
- Add user_group migration and created_by column migration
- Replace requireRole middleware with requireGroup
- Update all backend routes to use group-based authorization
- Add Standard_User conditional delete with ownership, state, and compliance checks
- Add cascade impact check for CVE deletes
- Update AuthContext with group-based permission helpers
- Update all frontend components for group-based rendering
- Update UserManagement UI with group dropdown, confirmation dialogs, self-demotion prevention
2026-04-06 16:18:07 -06:00

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.js migration script

      • Add user_group column (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_group on 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
    • * 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 requireAuth in backend/middleware/auth.js

      • Modify session join query to SELECT user_group and attach as req.user.group
      • Requirements: 3.4
    • 2.2 Add requireGroup middleware 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 requireRole and export requireGroup

      • 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.js to 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.js inline CVE routes

      • Use requireGroup('Admin', 'Standard_User') for POST, PUT, PATCH, DELETE
      • Requirements: 5.2
    • 6.7 Update backend/server.js route 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.js conditional 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-check library 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)