diff --git a/backend/routes/ivantiFindings.js b/backend/routes/ivantiFindings.js index 791b93f..8788c3a 100644 --- a/backend/routes/ivantiFindings.js +++ b/backend/routes/ivantiFindings.js @@ -734,7 +734,9 @@ async function runBUDriftChecker(newlyArchivedIds, apiKey, clientId, skipTls) { const bu = f.assetCustomAttributes?.['1550_host_1']?.[0] || 'UNKNOWN'; const severity = typeof f.severity === 'number' ? f.severity : parseFloat(f.severity) || 0; const state = f.status || f.generic_state || ''; - foundMap.set(String(f.id), { bu, severity, state }); + const title = f.title || ''; + const hostName = f.host?.hostName || f.hostName || ''; + foundMap.set(String(f.id), { bu, severity, state, title, hostName }); } page++; @@ -791,6 +793,25 @@ async function runBUDriftChecker(newlyArchivedIds, apiKey, clientId, skipTls) { } catch (err) { console.error(`[BU Drift Checker] Error updating transition reason for finding ${id}:`, err.message); } + + // Record BU reassignment in ivanti_finding_bu_history for detail view + if (classification === 'bu_reassignment' && found) { + try { + // Determine previous BU — look up from the cached finding record + const { rows: prevRows } = await pool.query( + `SELECT bu_ownership FROM ivanti_findings WHERE id = $1`, + [id] + ); + const previousBu = prevRows[0]?.bu_ownership || 'UNKNOWN'; + await pool.query( + `INSERT INTO ivanti_finding_bu_history (finding_id, finding_title, host_name, previous_bu, new_bu, detected_at) + VALUES ($1, $2, $3, $4, $5, NOW())`, + [id, found.title || '', found.hostName || '', previousBu, found.bu] + ); + } catch (err) { + console.error(`[BU Drift Checker] Error recording BU change for finding ${id}:`, err.message); + } + } } console.log(`[BU Drift Checker] Classification complete:`, summary); diff --git a/frontend/src/components/pages/AnomalyBanner.js b/frontend/src/components/pages/AnomalyBanner.js index 3b3a181..d2a118d 100644 --- a/frontend/src/components/pages/AnomalyBanner.js +++ b/frontend/src/components/pages/AnomalyBanner.js @@ -247,11 +247,18 @@ export default function AnomalyBanner() { setBuLoading(true); setBuExpanded(true); try { - // Scope to changes detected since this anomaly's sync + // Scope to changes detected around this anomaly's sync. + // The drift checker writes BU history records slightly before the anomaly + // summary is recorded, so use a 10-minute window before sync_timestamp. const since = anomaly?.sync_timestamp || ''; - const url = since - ? `${API_BASE}/ivanti/findings/bu-changes?since=${encodeURIComponent(since)}` - : `${API_BASE}/ivanti/findings/bu-changes?limit=50`; + let url; + if (since) { + const sinceDate = new Date(since); + sinceDate.setMinutes(sinceDate.getMinutes() - 10); + url = `${API_BASE}/ivanti/findings/bu-changes?since=${encodeURIComponent(sinceDate.toISOString())}`; + } else { + url = `${API_BASE}/ivanti/findings/bu-changes?limit=50`; + } const res = await fetch(url, { credentials: 'include' }); if (res.ok) { const data = await res.json();