feat(scans): nessus sync now writes per-host scan history rows
Tester noticed that scheduled + manual Nessus syncs left no trace in
the Scan-Jobs page — only Wazuh autoscan was visible there. Made
it impossible to verify Nessus scheduler runs after the fact.
Changes:
- New enum value ScanType.NESSUS + idempotent migration 014.
- run_nessus_sync (services/nessus_sync.py) now opens a Scan row
per host at the top of the per-host loop:
scan_type = NESSUS
status = RUNNING → COMPLETED / FAILED
started_at = now
asset_id = matched VulnCheck asset
and closes it after the backfill, setting
vulnerabilities_found = len(seen_cves_for_asset)
completed_at = now
The skip-backfill defensive branch (host returned 0 findings)
marks the row COMPLETED with an explanatory error_message so the
operator sees the run happened but produced nothing.
- Scheduler path inherits this for free — app/scheduler.py already
calls run_nessus_sync for scanner_type='nessus' schedules.
- Existing /scans/summary endpoint groups consecutive Scan rows of
the same type into a "run", so the UI shows one entry per Nessus
sync (covering all hosts).
Migration required on deploy:
docker compose exec backend alembic upgrade head # 013 → 014
This commit is contained in:
@@ -30,6 +30,7 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app.integrations.nessus_client import NessusClient
|
||||
from app.models.asset import Asset, AssetSource, AssetStatus
|
||||
from app.models.scan import Scan, ScanStatus, ScanType
|
||||
from app.models.setting import Setting
|
||||
from app.models.vulnerability import (
|
||||
Vulnerability,
|
||||
@@ -231,6 +232,19 @@ def run_nessus_sync(
|
||||
continue
|
||||
stats["hosts_synced"] += 1
|
||||
|
||||
# Record one Scan row per host so Nessus runs appear in
|
||||
# the Scan-Jobs history (previously only Wazuh autoscan
|
||||
# populated this table). Status updated to COMPLETED /
|
||||
# FAILED at the end of this host's loop iteration.
|
||||
scan_row = Scan(
|
||||
asset_id=asset.id,
|
||||
scan_type=ScanType.NESSUS,
|
||||
status=ScanStatus.RUNNING,
|
||||
started_at=datetime.now(),
|
||||
)
|
||||
db.add(scan_row)
|
||||
host_vulns_found = 0
|
||||
|
||||
# Track cves we observe on THIS asset in THIS sync run.
|
||||
# Used for backfill (drop nessus source on disappeared findings).
|
||||
seen_cves_for_asset: set = set()
|
||||
@@ -469,6 +483,10 @@ def run_nessus_sync(
|
||||
asset.hostname, scan_id,
|
||||
)
|
||||
asset.last_scan = datetime.now()
|
||||
scan_row.status = ScanStatus.COMPLETED
|
||||
scan_row.completed_at = datetime.now()
|
||||
scan_row.vulnerabilities_found = 0
|
||||
scan_row.error_message = "Host returned 0 findings (skipped backfill)"
|
||||
continue
|
||||
stale_nessus_vulns = (
|
||||
db.query(Vulnerability)
|
||||
@@ -489,6 +507,10 @@ def run_nessus_sync(
|
||||
stats["vulns_marked_patched"] += 1
|
||||
|
||||
asset.last_scan = datetime.now()
|
||||
# Close out the per-host scan row.
|
||||
scan_row.status = ScanStatus.COMPLETED
|
||||
scan_row.completed_at = datetime.now()
|
||||
scan_row.vulnerabilities_found = len(seen_cves_for_asset)
|
||||
|
||||
db.commit()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user