Extend team enforcement to Atlas and Archive routes, update schema reference
- Atlas: add requireTeam() at router level; replace client ?teams= param parsing with req.teamScope in /metrics, /status, and /sync endpoints - Archive: add requireTeam() at router level; replace client ?teams= param parsing with req.teamScope in GET / and GET /stats endpoints - db-schema.sql: add impersonate_user_id column to sessions table reference The frontend still sends ?teams= as a query param to these endpoints (harmless no-op since backend ignores it). Frontend cleanup deferred to avoid churn in the 7000-line ReportingPage component.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// Ivanti Archive Routes — list, stats, and transition history for archived findings
|
||||
const express = require('express');
|
||||
const pool = require('../db');
|
||||
const { requireAuth } = require('../middleware/auth');
|
||||
const { requireAuth, requireTeam } = require('../middleware/auth');
|
||||
|
||||
const VALID_STATES = ['ACTIVE', 'ARCHIVED', 'RETURNED', 'CLOSED'];
|
||||
|
||||
@@ -30,18 +30,18 @@ function findRelatedActive(archive, activeFindings) {
|
||||
function createIvantiArchiveRouter() {
|
||||
const router = express.Router();
|
||||
|
||||
// All routes require authentication
|
||||
// All routes require authentication and team scoping
|
||||
router.use(requireAuth());
|
||||
router.use(requireTeam());
|
||||
|
||||
/**
|
||||
* GET /
|
||||
* List archive records with optional state and teams filtering.
|
||||
* List archive records with optional state filtering.
|
||||
* Team scoping enforced by requireTeam() middleware via req.teamScope.
|
||||
*
|
||||
* @query {string} [state] - Filter by lifecycle state. Valid values: ACTIVE, ARCHIVED, RETURNED, CLOSED.
|
||||
* When state=ACTIVE, returns live open findings from ivanti_findings instead of archives.
|
||||
* When state=CLOSED, includes both CLOSED and CLOSED_GONE records.
|
||||
* @query {string} [teams] - Comma-separated BU team names (e.g. 'STEAM,ACCESS-ENG').
|
||||
* Filters results to findings whose bu_ownership contains one of the specified teams.
|
||||
*
|
||||
* @response {object} 200
|
||||
* { archives: Array<{ id, finding_id, finding_title, host_name, ip_address, current_state, last_severity, first_archived_at, last_transition_at, created_at, related_active: object|null }>, total: number }
|
||||
@@ -51,7 +51,7 @@ function createIvantiArchiveRouter() {
|
||||
* { error: string }
|
||||
*/
|
||||
router.get('/', async (req, res) => {
|
||||
const { state, teams } = req.query;
|
||||
const { state } = req.query;
|
||||
|
||||
if (state && !VALID_STATES.includes(state)) {
|
||||
return res.status(400).json({
|
||||
@@ -59,9 +59,9 @@ function createIvantiArchiveRouter() {
|
||||
});
|
||||
}
|
||||
|
||||
// Parse teams filter into ILIKE patterns
|
||||
const teamPatterns = teams
|
||||
? teams.split(',').map(t => `%${t.trim()}%`).filter(p => p !== '%%')
|
||||
// Build team patterns from middleware (null = admin, no filter)
|
||||
const teamPatterns = req.teamScope
|
||||
? req.teamScope.ivanti.map(t => `%${t}%`)
|
||||
: [];
|
||||
|
||||
try {
|
||||
@@ -148,9 +148,7 @@ function createIvantiArchiveRouter() {
|
||||
/**
|
||||
* GET /stats
|
||||
* Summary counts of archive records grouped by lifecycle state.
|
||||
*
|
||||
* @query {string} [teams] - Comma-separated BU team names (e.g. 'STEAM,ACCESS-ENG').
|
||||
* Filters counts to findings whose bu_ownership contains one of the specified teams.
|
||||
* Team scoping enforced by requireTeam() middleware via req.teamScope.
|
||||
*
|
||||
* @response {object} 200
|
||||
* { ACTIVE: number, ARCHIVED: number, RETURNED: number, CLOSED: number, total: number }
|
||||
@@ -159,9 +157,9 @@ function createIvantiArchiveRouter() {
|
||||
*/
|
||||
router.get('/stats', async (req, res) => {
|
||||
try {
|
||||
const { teams } = req.query;
|
||||
const teamPatterns = teams
|
||||
? teams.split(',').map(t => `%${t.trim()}%`).filter(p => p !== '%%')
|
||||
// Build team patterns from middleware (null = admin, no filter)
|
||||
const teamPatterns = req.teamScope
|
||||
? req.teamScope.ivanti.map(t => `%${t}%`)
|
||||
: [];
|
||||
|
||||
let archiveQuery, archiveParams = [];
|
||||
@@ -190,7 +188,7 @@ function createIvantiArchiveRouter() {
|
||||
}
|
||||
}
|
||||
|
||||
// ACTIVE = total live findings count (scoped by teams if provided)
|
||||
// ACTIVE = total live findings count (scoped by teams)
|
||||
let activeQuery, activeParams = [];
|
||||
if (teamPatterns.length > 0) {
|
||||
activeQuery = `SELECT COUNT(*) as total FROM ivanti_findings WHERE state = 'open' AND bu_ownership ILIKE ANY($1::text[])`;
|
||||
|
||||
Reference in New Issue
Block a user