Intune's detectedApps refreshes every 7 days per device, so the app-CVE scan
ran against week-old version strings — a browser patched this morning still
read last week's version, and the finding stayed open until the next
Discovered-apps cycle.
Intune's replacement, Enhanced App Inventory, collects multiple times per day
but has no API: `deviceInventories` is absent from the Graph beta $metadata
(no entity, no navigation property on managedDevice), its doc pages 404, and
the official export-report list has no app-inventory reportName —
AppInv{RawData,Aggregate,ByDevice} are all Discovered apps. Microsoft says
Graph support is planned for later in 2026. Until then the data is
portal-only.
Defender for Endpoint already exposes the same thing app-only and documented:
/machines/SoftwareInventoryByMachine, one tenant-wide paginated call, keyed by
the machine ids the Defender sync already matches to assets. It follows device
telemetry rather than a weekly cycle. Feed it into _run_app_inventory — the
same EOL / M365 / app→CVE pipeline detectedApps feeds — so the fresher list
wins wherever Defender covers the device, and detectedApps stays for the rest.
The only translation is the name: Defender reports CPE-style tokens (vendor
`microsoft`, product `visual_studio_code`) while the product registry matches
installer names. _pkg_name joins and un-escapes them, dropping the vendor when
the product already carries it.
Best-effort throughout: a tenant without Software.Read.All or without Defender
Vulnerability Management gets an empty inventory and the previous behaviour.
Also extends tools/probe_intune_app_inventory.py to walk the whole matrix —
URL shapes, the documented config resource, and every plausible export report
name — so the Intune-side verdict can be re-checked against a live tenant when
Microsoft ships the Graph route.
23 lines
954 B
Python
23 lines
954 B
Python
"""Defender's normalised (vendor, product) must land on a name the product
|
|
registry actually matches — that join is the only translation between MDE's
|
|
software inventory and the app-CVE scan."""
|
|
from app.services.defender_service import _pkg_name
|
|
from app.services.app_cve_scanner_service import resolve_product
|
|
|
|
|
|
def test_pkg_name_joins_vendor_and_product():
|
|
assert _pkg_name("microsoft", "edge") == "microsoft edge"
|
|
assert _pkg_name("microsoft", "visual_studio_code") == "microsoft visual studio code"
|
|
|
|
|
|
def test_pkg_name_does_not_repeat_the_vendor():
|
|
assert _pkg_name("microsoft", "microsoft_office") == "microsoft office"
|
|
assert _pkg_name("", "7-zip") == "7-zip"
|
|
assert _pkg_name("igor pavlov", "") == ""
|
|
|
|
|
|
def test_joined_name_resolves_to_a_product():
|
|
# the whole point: what MDE reports must be scannable
|
|
assert resolve_product(_pkg_name("google", "chrome"))
|
|
assert resolve_product(_pkg_name("microsoft", "edge"))
|