Files
vulncheck/app/services
vulncheck 527c708814 feat(vulns): per-package detail table + UI for multi-package CVEs
Tester reported CVE-2023-48795 hitting PuTTY 0.73 AND WinSCP 6.1.2
on the same host — both joined into a single
`vulnerabilities.package_name` string ("PuTTY..., WinSCP...") with
ONE `fixed_version`. Per-package fix tracking impossible.

Schema (migration 023)
- New table `vulnerability_packages` (vuln_id, package_name,
  package_version, fixed_version, source, first_detected_at,
  last_seen_at). Unique on (vuln_id, package_name).
- Backfill creates one child per existing vuln carrying the joined
  string verbatim (no comma-split — joined names may contain commas).
- ON DELETE CASCADE + ORM passive_deletes so asset deletes propagate.

Sync (Wazuh)
- sync_agent_vulnerabilities collects per-package rows in a dict
  keyed by package_name and upserts VulnerabilityPackage children
  after the parent insert/update.
- last_seen_at updated each sync; future enhancement can prune
  packages Wazuh stopped reporting (mirror parent-row stale logic).

Override service
- _apply_single_override propagates Vulnrichment/NVD/cvelistV5
  fixed_version into every child package row that has none AND
  whose installed_version differs from the proposed fix
  (Ghostscript inclusive-bound case).

API
- VulnerabilityResponse gains `packages: List[PackageInfo]` and
  `has_fix_any: bool`. _build_vuln_response emits per-package data.
- Forward refs resolved with model_rebuild().

Frontend
- VulnerabilityPackage type + Vulnerability.packages + has_fix_any
- PATCH AVAILABLE badge on list page now uses has_fix_any +
  fixed_version != installed_version check (no more false positives
  when supposed fix equals affected version).
- Detail page renders a per-package table (Installed / Fixed in /
  FIX indicator / source tag) when child rows exist, falls back to
  legacy single-package summary for pseudo-CVEs.

No breaking changes — parent columns (`package_name`,
`package_version`, `fixed_version`) stay for legacy queries. Nessus
sync still writes only the parent row; per-package Nessus support
can land as a follow-up.
2026-05-25 19:08:01 +02:00
..
2026-02-08 10:15:20 +01:00