feat(security): severity-aware scheduled scan notifications (#654)

Enrich scheduled vulnerability scan completion notifications with
per-severity CVE counts so recipients can triage from the message body
alone. Expose the scan action in the schedule creation UI, require an
explicit node_id, and harden fire-and-forget alert dispatches so a
failing webhook cannot crash the scheduler.

Notification body now reports scanned/skipped/failed counts plus
critical/high/medium totals aggregated across fresh and cached scans,
reflecting the current node posture rather than only what was newly
scanned on this run.
This commit is contained in:
Anso
2026-04-17 11:08:46 -04:00
committed by GitHub
parent f9dc86bbfd
commit 29ed0524c1
9 changed files with 280 additions and 27 deletions
+9
View File
@@ -6249,6 +6249,9 @@ app.post('/api/scheduled-tasks', (req: Request, res: Response): void => {
if (action === 'scan' && target_type !== 'system') {
res.status(400).json({ error: 'Scan action requires target_type "system".' }); return;
}
if (action === 'scan' && !node_id) {
res.status(400).json({ error: 'Scan action requires node_id.' }); return;
}
if (target_type === 'stack' && (!target_id || !node_id)) {
res.status(400).json({ error: 'Stack operations require target_id and node_id.' }); return;
}
@@ -6370,6 +6373,12 @@ app.put('/api/scheduled-tasks/:id', (req: Request, res: Response): void => {
if (finalAction === 'scan' && finalTargetType !== 'system') {
res.status(400).json({ error: 'Scan action requires target_type "system".' }); return;
}
if (finalAction === 'scan') {
const finalNodeId = node_id !== undefined ? node_id : existing.node_id;
if (!finalNodeId) {
res.status(400).json({ error: 'Scan action requires node_id.' }); return;
}
}
// Validate prune targets
const validPruneTargets = ['containers', 'images', 'networks', 'volumes'];