From 6dab348de2b00e1baba949bbc8321c51b8eee096 Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Fri, 11 Sep 2026 08:01:41 +1000 Subject: [PATCH] BE: conditional device import support, notification supression support during scan #1721 --- server/scan/device_handling.py | 9 +++-- test/scan/test_scan_creates_device.py | 47 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/server/scan/device_handling.py b/server/scan/device_handling.py index f9e37d78..cbaaf97a 100755 --- a/server/scan/device_handling.py +++ b/server/scan/device_handling.py @@ -671,6 +671,7 @@ def create_new_devices(db): GROUP BY scanMac ) agg WHERE agg.scanCreates = 1 + AND agg.scanMac NOT IN ({NULL_EQUIVALENTS_SQL}) AND NOT EXISTS ( SELECT 1 FROM Devices WHERE devMac = agg.scanMac @@ -791,8 +792,12 @@ def create_new_devices(db): # if another row for the same MAC says 0 (enrich-only). Rows for # already-existing devices pass through harmlessly too - the INSERT OR # IGNORE below is already a no-op for them regardless of this filter. - query = """SELECT scanMac, scanName, scanVendor, scanSourcePlugin, scanLastIP, scanSyncHubNode, scanParentMAC, scanParentPort, scanSite, scanSSID, scanType - FROM CurrentScan WHERE scanCreatesDevice = 1""" + # scanMac NOT IN NULL_EQUIVALENTS blocks creating a device from a blank/ + # null-equivalent MAC - a plugin reporting a row it can't originate a + # device from (no real MAC available) should set scanCreatesDevice = 0 + # itself, but this is the backstop for one that doesn't. + query = f"""SELECT scanMac, scanName, scanVendor, scanSourcePlugin, scanLastIP, scanSyncHubNode, scanParentMAC, scanParentPort, scanSite, scanSSID, scanType + FROM CurrentScan WHERE scanCreatesDevice = 1 AND scanMac NOT IN ({NULL_EQUIVALENTS_SQL})""" mylog("debug", f"[New Devices] Collecting New Devices Query: {query}") current_scan_data = sql.execute(query).fetchall() diff --git a/test/scan/test_scan_creates_device.py b/test/scan/test_scan_creates_device.py index 6e50d92b..23615d13 100644 --- a/test/scan/test_scan_creates_device.py +++ b/test/scan/test_scan_creates_device.py @@ -170,3 +170,50 @@ class TestNewDeviceEventNoDuplicatesAcrossPlugins: "differing scanLastIP/scanVendor across plugin rows for the same " "new MAC must not produce duplicate New Device events" ) + + +class TestBlankMacNeverCreatesDevice: + """A row with a blank/null-equivalent scanMac must never originate a + Devices row, even with scanCreatesDevice = 1 (the default) - this is the + backstop for a plugin that has rows it can't attach a real MAC to but + forgot to (or can't) set scanCreatesDevice = 0 itself. A well-behaved + plugin should still set scanCreatesDevice = 0 for such rows (see + plugin-import-behavior-controls.md) - this guard exists for the case + where it doesn't, so a blank MAC can never create a device regardless.""" + + def test_blank_scanmac_with_creates_device_one_creates_nothing(self): + conn = make_db() + insert_current_scan_row_from_dict( + conn, make_current_scan_dict("", scanCreatesDevice=1) + ) + db = DummyDB(conn) + + device_handling.create_new_devices(db) + + assert _devices(db) == set() + rows = conn.execute( + "SELECT * FROM Events WHERE eveMac = '' AND eveEventType = 'New Device'" + ).fetchall() + assert rows == [], "a blank scanMac must not produce an orphan New Device event either" + + def test_multiple_plugins_sharing_blank_scanmac_creates_nothing(self): + """The scenario this guard was actually written for: several + unrelated rows (e.g. containers with no routable MAC) all reporting + scanMac = '' collapse into one CurrentScan group - that group must + never create a device, regardless of how many rows are in it.""" + conn = make_db() + insert_current_scan_row_from_dict( + conn, make_current_scan_dict("", scanSourcePlugin="PLUGINA", scanCreatesDevice=0) + ) + insert_current_scan_row_from_dict( + conn, make_current_scan_dict("", scanSourcePlugin="PLUGINB", scanCreatesDevice=1) + ) + db = DummyDB(conn) + + device_handling.create_new_devices(db) + + assert _devices(db) == set(), ( + "even a single row asserting scanCreatesDevice = 1 for a blank MAC " + "must not create a device - most-permissive-wins does not override " + "the blank-MAC guard" + )