You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Anchor dedup window at first alert and make prune non-critical
The suppression window is now decided entirely from first_seen at read
time: no row or a fully elapsed row notifies and (re-)anchors the window
at now, while an alert inside the window is counted without touching the
anchor. A flood of alerts can no longer slide the window forward and
silence a package.
Because the read path already re-notifies past an elapsed window, prune
is pure housekeeping. It drops rows on the same window and needs no
particular schedule, so RETENTION_SECONDS goes away and
DEDUP_TTL_SECONDS is the only knob left.
Also drop the per-row CVE list. It cost a JSON parse and dump on the
suppression hot path with no consumer, and the CVEs are already in
alerts.json and the indexer.
Add test_dedup.py, covering one email per key under a 1000-alert burst,
no window slide while alerts keep arriving, a fresh email plus re-anchor
once the window elapses, and prune taking only elapsed rows.
Expected, since the rows just created are still inside their window:
341
394
342
395
```
343
-
2026-07-18T10:05:00 INFO Prune complete: removed 0 expired row(s).
396
+
2026-07-18T10:05:00 INFO Prune complete: removed 0 elapsed row(s).
344
397
```
345
398
346
399
---
@@ -353,7 +406,8 @@ Expected:
353
406
|`has write permissions` in `ossec.log`| Permissions are too broad. Re-apply `chmod 750` and `chown root:wazuh`. |
354
407
| One email per CVE, no suppression | Alerts are not matching the expected schema. Confirm `data.vulnerability.package.name` is present in the raw alert. |
355
408
|`DB open failed ... sending without dedup`| The database path is not writable by the `wazuh` user. Check `DB_PATH` and its parent directory. |
356
-
| Emails stop for a package that is still vulnerable | Expected inside the window. Lower `DEDUP_TTL_SECONDS` if you want more frequent reminders. |
409
+
| Emails stop for a package that is still vulnerable | Expected inside the window. Check `first_seen` for that row: one fresh email is sent on the first detection after it plus `DEDUP_TTL_SECONDS`. Lower the TTL if you want more frequent reminders. |
410
+
| The dedup table is larger than expected | Prune has not run recently. It is housekeeping only, so this affects nothing but disk. Run `custom-email prune` and confirm the wodle is enabled. |
357
411
| SMTP errors in the script log | Verify relay reachability with `nc -zv <SMTP_HOST> 25`. |
358
412
359
413
---
@@ -366,10 +420,10 @@ Expected:
366
420
-**Adapted by**: Leon Fuller.
367
421
-**Tested versions**: Wazuh manager 4.x with Vulnerability Detection enabled
368
422
and the 4.8+ vulnerability alert schema. Python 3 standard library only, no
369
-
third-party dependencies. Logic validated on Python 3.11 against a synthetic
370
-
2,000-alert burst at 64-way concurrency: 300 distinct keys produced 300
371
-
emails, `SUM(cve_count)` matched the 2,000 alerts fed in, and no lock errors
372
-
occurred.
423
+
third-party dependencies. Logic validated on Python 3.11 by the bundled
424
+
`test_dedup.py`, plus a synthetic 2,000-alert burst at 64-way concurrency: 300
425
+
distinct keys produced 300 emails, `SUM(cve_count)` matched the 2,000 alerts
426
+
fed in, and no lock errors occurred.
373
427
-**Maintainer**: Leon Fuller.
374
428
-**Support boundary**: Community-maintained and provided as is. Not covered by
0 commit comments