diff --git a/alembic/versions/014_add_nessus_scan_type.py b/alembic/versions/014_add_nessus_scan_type.py new file mode 100644 index 0000000..0b34340 --- /dev/null +++ b/alembic/versions/014_add_nessus_scan_type.py @@ -0,0 +1,34 @@ +"""Add NESSUS value to scans.scan_type enum + +Revision ID: 014 +Revises: 013 +Create Date: 2026-05-18 10:00:00.000000 + +run_nessus_sync now writes one Scan row per host so Nessus syncs +appear in the Scan-Jobs history (previously only Wazuh did). Needs +a new enum value 'nessus' on scans.scan_type. + +Idempotent — the ADD VALUE IF NOT EXISTS guard means re-running this +migration on a schema where the value already lives is a no-op. +""" +from alembic import op + + +revision = '014' +down_revision = '013' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # Postgres enum ALTERs must run outside a transaction in older + # versions. ADD VALUE IF NOT EXISTS is supported on 9.6+ and is + # transaction-safe on 12+ which is our minimum target. + op.execute("ALTER TYPE scantype ADD VALUE IF NOT EXISTS 'nessus'") + + +def downgrade() -> None: + # Postgres has no DROP VALUE for enums. The downgrade is a no-op; + # an existing 'nessus' value is harmless even after the model + # stops emitting it. + pass diff --git a/app/models/scan.py b/app/models/scan.py index f6371f9..c81e4b4 100644 --- a/app/models/scan.py +++ b/app/models/scan.py @@ -12,6 +12,7 @@ class ScanType(str, Enum): FULL = "full" SYSCOLLECTOR = "syscollector" MANUAL = "manual" + NESSUS = "nessus" class ScanStatus(str, Enum): diff --git a/app/services/nessus_sync.py b/app/services/nessus_sync.py index 2891443..116f4ae 100644 --- a/app/services/nessus_sync.py +++ b/app/services/nessus_sync.py @@ -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()