fix(eol): resolve stale MS-lifecycle findings the rescan no longer matches
run_eol_for_packages only ever ADDED findings; _supersede_old_eol fires only when a replacement is created. So after the Edge→Azure-Stack-Edge name-match fix, the wrong 'Microsoft Edge = EOL' finding stayed open forever (no replacement is produced for a now-unmatched product). Add a reconcile scoped to the EOL-MS-LIFECYCLE- prefix (package path only; OS-level endoflife.date findings use other slugs and are untouched): resolve open MS-lifecycle findings the current run didn't re-produce. Guarded on a non-empty package list so a failed inventory read can't mass-close.
This commit is contained in:
@@ -776,6 +776,7 @@ def run_eol_for_packages(db: "Session", asset, packages: list) -> int:
|
||||
"""
|
||||
count = 0
|
||||
seen: set = set()
|
||||
kept_msl: set = set() # MS-lifecycle EOL cve_ids still valid this run
|
||||
for pkg in packages or []:
|
||||
name = (pkg.get("name") or "").strip()
|
||||
version = (pkg.get("version") or "").strip()
|
||||
@@ -804,6 +805,8 @@ def run_eol_for_packages(db: "Session", asset, packages: list) -> int:
|
||||
pass
|
||||
if not actionable:
|
||||
continue
|
||||
if status and status.product_slug == "ms-lifecycle":
|
||||
kept_msl.add(_pseudo_cve_id("ms-lifecycle", status.release_name or "unknown"))
|
||||
try:
|
||||
upsert_eol_vulnerability(
|
||||
db, asset_id=asset.id, product_name=name,
|
||||
@@ -812,4 +815,45 @@ def run_eol_for_packages(db: "Session", asset, packages: list) -> int:
|
||||
count += 1
|
||||
except Exception as e:
|
||||
logger.warning("EOL-for-packages upsert failed (%s on asset %s): %s", name, asset.id, e)
|
||||
|
||||
# Guard on a non-empty inventory: an empty list is a transient/failed read,
|
||||
# not proof the products are gone (same safety as the other reconciles).
|
||||
if packages:
|
||||
_resolve_stale_ms_lifecycle(db, asset.id, kept_msl)
|
||||
return count
|
||||
|
||||
|
||||
def _resolve_stale_ms_lifecycle(db: "Session", asset_id: int, kept: set) -> None:
|
||||
"""Resolve open MS-lifecycle EOL findings the current run no longer produced.
|
||||
|
||||
Without this, fixing a bad name→product match (tester: 'Microsoft Edge'
|
||||
browser mis-mapped to the 'Azure Stack Edge' listing) left the wrong finding
|
||||
open forever, since _supersede_old_eol only fires when a REPLACEMENT is
|
||||
created. Scoped to the EOL-MS-LIFECYCLE- prefix, which only the package path
|
||||
produces — OS-level endoflife.date findings use other slugs and are
|
||||
untouched. Only reconciles when at least one package was inventoried (empty
|
||||
package list = nothing to conclude)."""
|
||||
from app.models.vulnerability import Vulnerability, VulnerabilityStatus
|
||||
stale = (
|
||||
db.query(Vulnerability)
|
||||
.filter(Vulnerability.asset_id == asset_id,
|
||||
Vulnerability.status == VulnerabilityStatus.open,
|
||||
Vulnerability.cve_id.like("EOL-MS-LIFECYCLE-%"))
|
||||
.all()
|
||||
)
|
||||
for v in stale:
|
||||
if v.cve_id in kept:
|
||||
continue
|
||||
old_status = v.status
|
||||
v.status = VulnerabilityStatus.patched
|
||||
v.patched_at = datetime.now()
|
||||
try:
|
||||
from app.routers.vulnerabilities import log_vulnerability_change
|
||||
log_vulnerability_change(
|
||||
db, None, v.id, old_status, v.status,
|
||||
reason="MS lifecycle no longer matches this installed product "
|
||||
"(re-evaluated — not end-of-life)",
|
||||
cve_id=v.cve_id, source="eol_reconcile",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("audit log for MS-lifecycle reconcile failed (vuln_id=%s): %s", v.id, e)
|
||||
|
||||
Reference in New Issue
Block a user