From b438f25fd8055166e42368c59a26ba17a8bf055f Mon Sep 17 00:00:00 2001 From: Binh Date: Fri, 11 Sep 2026 16:03:47 +0200 Subject: [PATCH] fix: Adjust NvdCveClient to correctly handle baseSeverity from CVSS metrics --- .gitignore | 1 + docs/IMPLEMENTATION_PLAN.md | 12 +++ server/cve/nvd-cve-client.ts | 4 +- .../DefenderVulnerabilityPanel.tsx | 64 +++++++----- .../defender-for-iot-source-extractor.ts | 15 +-- src/styles/defender-for-iot.css | 8 +- tests/features/defender-dashboard.test.ts | 4 +- .../defender-inline-drilldown.test.tsx | 99 +++++++++++++++++++ tests/importers/defender-for-iot.test.ts | 8 +- tests/server/nvd-cve-client.test.ts | 9 +- 10 files changed, 182 insertions(+), 42 deletions(-) create mode 100644 tests/features/defender-inline-drilldown.test.tsx diff --git a/.gitignore b/.gitignore index f7a6652..7eef6e7 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ vite.config.js vite.config.d.ts *.png artifacts/objects/ +Mock-Defender/ .env.postgres .assessor-data/ diff --git a/docs/IMPLEMENTATION_PLAN.md b/docs/IMPLEMENTATION_PLAN.md index 3bb79f7..f6fd5ca 100644 --- a/docs/IMPLEMENTATION_PLAN.md +++ b/docs/IMPLEMENTATION_PLAN.md @@ -2,6 +2,18 @@ Status: lebendes Projektdokument +Defender-Device-CVE-Kurzliste 2026-09-11 (Phase 7, Nutzerpraezisierung): Das Device-Detail und die dort wiederverwendete Device-Liste innerhalb eines Site-Details zeigen je zugeordnetem CVE nur noch CVE-Kennung und Severity. Description und Reporting sensors entfallen aus dieser Tabelle, weil die CVE-Beschreibung in der CVE-Ansicht und der Sensor bereits im Device-Kontext verfuegbar sind. Eine synthetische Interaktionsregression sichert den exakten Zwei-Spalten-Vertrag. Verifikation: 1.243 Tests bestanden, acht optionale PostgreSQL-Tests uebersprungen; Local-only- und Designpruefung sowie Client-/Serverbuild erfolgreich. Reine Darstellungsaenderung; Quelldaten bleiben im Modell erhalten, keine Datenmutation, API-, Persistenz-, Importer-, Profil-, Scoring- oder Reimportaenderung. Phasenstatus unveraendert. + +Defender-CVE-Evidenzliste 2026-09-11 (Phase 7, Nutzerpraezisierung): Das geoeffnete CVE-Detail zeigt alle betroffenen Geraete und ihre Sensorbeobachtungen unmittelbar in einer gemeinsamen flachen Liste statt als einzeln aufklappbare Device-Gruppen. Die Liste enthaelt nur Device, IP, Site und Sensor; interne Source-row-Provenienz und die bereits durch das ausgewaehlte CVE feststehende Severity werden nicht redundant angezeigt. Die Detailprojektion wird nur fuer das aktuell geoeffnete CVE aufgebaut. Eine synthetische Regression mit zwei Geraeten fuer dasselbe CVE prueft fehlende Unter-Expander, beide sichtbaren Zeilen und den exakten Vier-Spalten-Vertrag. Verifikation: 1.243 Tests bestanden, acht optionale PostgreSQL-Tests uebersprungen; Local-only- und Designpruefung sowie Client-/Serverbuild erfolgreich. Reine Darstellungsaenderung; Quellprovenienz und Severity bleiben im Modell erhalten, keine Datenmutation, API-, Persistenz-, Importer-, Profil-, Scoring- oder Reimportaenderung. Phasenstatus unveraendert. + +Defender-Inline-Detailflaeche 2026-09-11 (Phase 7, Nutzerkorrektur): Aufgeklappte CVE-, Device- und Site-Details verwenden wieder dieselbe themenabhaengige `--tile-surface` wie die zugehoerige Tabellenliste statt der deutlich dunkleren `--client-info-surface`. Gelbe Auswahlmarkierung, Detailgrenze, Inhalte und Interaktion bleiben unveraendert. Eine Stilregression sichert die gemeinsame Flaeche und schliesst den dunklen Client-Info-Token fuer `.defender-drilldown` aus. Verifikation: 1.243 Tests bestanden, acht optionale PostgreSQL-Tests uebersprungen; Local-only- und Designpruefung sowie Client-/Serverbuild erfolgreich. Reine Darstellungsaenderung; keine Datenmutation, API-, Persistenz-, Importer-, Profil-, Scoring- oder Reimportaenderung. Phasenstatus unveraendert. + +Defender-CVE-Observations nur im Detail 2026-09-11 (Phase 7, Nutzerpraezisierung): Die CVE-Uebersicht entfernt die fuer den aktuellen Ein-Sensor-je-Geraet-Datenstand redundante Observations-Spalte. Affected devices bleibt als eindeutige Geraetezahl sichtbar; die Anzahl der zugrunde liegenden Quellbeobachtungen bleibt je Geraet im aufgeklappten Evidenzdetail erhalten, damit kuenftige Mehrfachmeldungen weiterhin nachvollziehbar sind. Die synthetische Interaktionsregression prueft die nun fuenf Uebersichtsspalten und die unveraenderte Detaildarstellung. Verifikation: 1.243 Tests bestanden, acht optionale PostgreSQL-Tests uebersprungen; Local-only- und Designpruefung sowie Client-/Serverbuild erfolgreich. Reine Darstellungsaenderung; keine Datenmutation, API-, Persistenz-, Importer-, Profil-, Scoring- oder Reimportaenderung. Phasenstatus unveraendert. + +Defender-CVE-Beschreibung nur im Detail 2026-09-11 (Phase 7, Nutzerpraezisierung): Die CVE-Uebersicht entfernt die redundante Description-Spalte; die vollstaendige Beschreibung bleibt unveraendert direkt im aufgeklappten Inline-Detail sichtbar. Affected devices bezeichnet weiterhin die Anzahl unterschiedlicher betroffener Geraete, Observations die Anzahl der zugrunde liegenden Sensor-Quellzeilen und kann deshalb durch mehrere Sensoren oder wiederholte Meldungen groesser sein. Die synthetische Interaktionsregression prueft die sechs Uebersichtsspalten sowie die erhaltene Beschreibung im Detail. Verifikation: 1.243 Tests bestanden, acht optionale PostgreSQL-Tests uebersprungen; Local-only- und Designpruefung sowie Client-/Serverbuild erfolgreich. Reine Darstellungsaenderung; keine Datenmutation, API-, Persistenz-, Importer-, Profil-, Scoring- oder Reimportaenderung. Phasenstatus unveraendert. + +Defender-for-IoT-Inline-Drilldowns 2026-09-11 (Phase 7, Nutzerkorrektur): CVE-, Device- und Site-Details erscheinen jetzt unmittelbar unter der ausgewaehlten Tabellenzeile statt gesammelt am Ende der jeweiligen Liste. Die vorhandenen Bezeichnungsbuttons verwenden ein einheitliches Auf-/Zuklappdreieck, `aria-expanded` und stabile `aria-controls`-Ziele; ein erneuter Klick schliesst das Detail, eine andere Auswahl verschiebt das einzige offene Detail. Die ausgewaehlte Zeile nutzt die gemeinsame gelbe Markierung, waehrend der Tastaturfokus blau bleibt. Verschachtelte Evidenztabellen bleiben innerhalb ihrer Detailzeile horizontal scrollbar und werden weder abgeschnitten noch verkuerzt. Synthetische Interaktionstests pruefen Oeffnen, Verschieben, Schliessen, unmittelbare Zeilennachbarschaft und Zugaenglichkeitszustand in allen drei Ansichten. Verifikation: 1.243 Tests bestanden, acht optionale PostgreSQL-Tests uebersprungen; Local-only- und Designpruefung sowie Client-/Serverbuild erfolgreich. Reine Darstellungsaenderung; keine Datenmutation, API-, Persistenz-, Importer-, Profil-, Scoring- oder Reimportaenderung. Phasenstatus unveraendert. + Defender-for-IoT-Client-Info-Stil 2026-09-11 (Phase 7, Nutzerpraezisierung): Microsoft Defender for IoT bleibt eine eigenstaendige Client-Info-Registerkarte mit unveraenderten CVE-, Device- und Site-Ansichten. Die Registerkarte verwendet jetzt denselben themenabhaengigen Client-Info-Canvas, dieselbe Client-/Assessment-/Source-Kopfzeile, denselben Panel-Inset sowie die flache Kachel-, Flaechen-, Typografie-, Auswahl- und Responsive-Grammatik wie Overview. Scannerprojektion, Finding-Semantik, Scoreberechnung, Import- und Persistenzvertraege bleiben unveraendert; kein Reimport erforderlich. Verifikation: 1.239 Tests bestanden, acht optionale PostgreSQL-Tests uebersprungen; Local-only- und Designpruefung sowie Client-/Serverbuild erfolgreich. Keine Datenmutation, Migration, Realdateninspektion oder Backendneustart; Phasenstatus unveraendert. Reimport-Schutz 2026-09-10 (Phase 6/8/9/13C mit Phase-7-Hinweis, ausdruecklicher Nutzerauftrag): Verarbeitungsrelevante Aenderungen an Formaterkennung, Parser/Extractor, Scannerprofil, stabiler Identitaet, Mapping, Normalisierung, Status-/Evidenzvertrag oder nativer Scoregewinnung muessen ueber append-only Processing-Manifeste versioniert und fuer bestehende Importe als Reimportbedarf sichtbar werden; reine Darstellungsaenderungen auf bereits gespeicherten Daten benoetigen keinen Reimport. Generische/tabellarische Importe ohne belastbares Profil erscheinen vorsorglich als gelber Pruefstatus. Direkter Reimport und die Uebernahme eines bereits importierten Ersatzlaufs uebertragen kundenbezogene Finding-Reviews atomar in lokaler und PostgreSQL-Persistenz. Die Zuordnung verwendet ausschliesslich die eindeutige stabile Identitaet aus Scannerwerkzeug, nativer Regel-ID und betroffenem Asset; bei fehlender oder mehrdeutiger Zuordnung wird nicht nach Titel oder Position geraten. Der vollstaendige Reviewvertrag wird kopiert und erhaelt dadurch Status, Prioritaet, Action-Plan-Zuordnung, Owner, Termin, Kommentar, Voraussetzungen, Zugriffe, naechsten Schritt, Akzeptanzevidenz, Marker/Accepted Risk sowie spaetere additive JSON-Felder. Bereits vorhandene Angaben am Ersatzlauf haben Vorrang. Nicht eindeutig uebertragbare Angaben bleiben am auditierbar erhaltenen Ursprungslauf gespeichert; Anzahl und dauerhafter `Review required`-Hinweis werden am Ersatzimport persistiert. Original-SHA, Vorgaengerbezug und Uebertragungsherkunft bleiben nachvollziehbar. Regeln und Szenarien stehen in `docs/REIMPORT_POLICY.md`. Verifikation: 1.205 Tests bestanden, acht optionale Tests uebersprungen; Local-only- und Designpruefung erfolgreich. Keine SQL-Migration, Realdateninspektion oder kanonische Datenmutation; Phasenstatus unveraendert. diff --git a/server/cve/nvd-cve-client.ts b/server/cve/nvd-cve-client.ts index afce7b3..b3d779e 100644 --- a/server/cve/nvd-cve-client.ts +++ b/server/cve/nvd-cve-client.ts @@ -63,12 +63,14 @@ function metrics(value: unknown): CveMetric[] { const baseScore = number(data?.baseScore); const vector = string(data?.vectorString); if (!item || !data || baseScore === undefined || !vector) return []; + // CVSS v3.x/v4.0 carry baseSeverity inside cvssData; CVSS v2 carries it on the metric entry itself. + const baseSeverity = string(data.baseSeverity) || string(item.baseSeverity); return [{ version, source: string(item.source) || 'unknown', ...(string(item.type) ? { type: string(item.type) } : {}), baseScore, - ...(string(data.baseSeverity) ? { baseSeverity: string(data.baseSeverity) } : {}), + ...(baseSeverity ? { baseSeverity } : {}), vector, ...(number(item.exploitabilityScore) === undefined ? {} : { exploitabilityScore: number(item.exploitabilityScore) }), ...(number(item.impactScore) === undefined ? {} : { impactScore: number(item.impactScore) }) diff --git a/src/features/defender-for-iot/DefenderVulnerabilityPanel.tsx b/src/features/defender-for-iot/DefenderVulnerabilityPanel.tsx index 8d7e3db..a721bca 100644 --- a/src/features/defender-for-iot/DefenderVulnerabilityPanel.tsx +++ b/src/features/defender-for-iot/DefenderVulnerabilityPanel.tsx @@ -1,4 +1,5 @@ -import { useMemo, useState, type ReactNode } from 'react'; +import { Fragment, useMemo, useState, type ReactNode } from 'react'; +import { TriangleIcon } from '../../components/TriangleIcon'; import type { DefenderDevice, DefenderSeverity, DefenderSeverityMeasure } from '../../domain/defender-for-iot'; import type { ImportedDataset } from '../../domain/dataset'; import { WorkTimeslotControl } from '../search-filter/WorkTimeslotControl'; @@ -28,17 +29,17 @@ function SeverityMark({ severity }: { severity: DefenderSeverity | 'unknown' }) return