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
This commit is contained in:
jramos
2026-04-06 16:18:07 -06:00
parent 1ef57b0504
commit 73fd747576
19 changed files with 1171 additions and 149 deletions

View File

@@ -213,7 +213,7 @@ function groupByHostname(rows, noteHostnames) {
// ---------------------------------------------------------------------------
// Router factory
// ---------------------------------------------------------------------------
function createComplianceRouter(db, upload, requireAuth, requireRole) {
function createComplianceRouter(db, upload, requireAuth, requireGroup) {
const router = express.Router();
// Idempotent column additions — errors mean column already exists, which is fine
@@ -228,7 +228,7 @@ function createComplianceRouter(db, upload, requireAuth, requireRole) {
// Parse the uploaded xlsx, compute diff, save parsed data to a temp JSON.
// Returns diff counts + tempFile path for the commit step.
// -----------------------------------------------------------------------
router.post('/preview', requireRole('editor', 'admin'), (req, res) => {
router.post('/preview', requireGroup('Admin', 'Standard_User'), (req, res) => {
upload.single('file')(req, res, async (uploadErr) => {
if (uploadErr) {
return res.status(400).json({ error: uploadErr.message });
@@ -291,7 +291,7 @@ function createComplianceRouter(db, upload, requireAuth, requireRole) {
// Commit a previewed upload to the DB.
// Body: { tempFile, filename, report_date }
// -----------------------------------------------------------------------
router.post('/commit', requireRole('editor', 'admin'), async (req, res) => {
router.post('/commit', requireGroup('Admin', 'Standard_User'), async (req, res) => {
const { tempFile, filename, report_date } = req.body;
if (!tempFile || typeof tempFile !== 'string') {