Assessor_2.0/docs/REPORT_IMPLEMENTATION_BRIEF.md

16 KiB
Raw Blame History

Umsetzungsauftrag: Report A (Management) und Report B (Technical)

Adressat: Codex. Dieser Auftrag ist verbindlich und abschließend formuliert. Wo dieser Auftrag schweigt, gelten AGENTS.md, docs/REPORT_STRATEGY.md, docs/SCORING_MODEL.md und .claude/skills/assessor-ui/SKILL.md unverändert weiter. Bei einem Widerspruch zwischen diesem Auftrag und einer dieser Quellen: anhalten und den Widerspruch melden, nicht eigenmächtig auflösen.

Plan-Zuordnung: Die Artefakte A–D sind in docs/REPORT_STRATEGY.md als Deliverable ohne zugewiesene Plan-Phase festgehalten. Dieser Auftrag setzt A und B um und ändert die Strategie inhaltlich nicht.

0. Ausgangszustand im Code (verifiziert)

Baustein Zustand
src/domain/report-projection.ts vorhanden, REPORT_PROJECTION_VERSION = '1.0.0', getestet
src/exports/management-overview-report.ts vorhanden, buildManagementOverviewHtml, Renderer-Version '1.0.0', getestet
Produktiver Aufrufer von buildReportProjection existiert nicht — nur Tests
Produktiver Aufrufer von buildManagementOverviewHtml existiert nicht — nur Tests
Report B (Technical) existiert nicht
Security-Domain-Zuordnung über UnifiedResultProjection existiert nicht (Katalog arbeitet auf FindingRecord)
Framework-Referenzen (MITRE ATT&CK / D3FEND) in der Unified-Projektion nicht enthalten (nur targetRole === 'category' wird übernommen)

Die beiden vorhandenen Bausteine sind korrekt und werden nicht neu geschrieben, sondern additiv erweitert.

1. Lieferumfang

Acht Arbeitspakete, in dieser Reihenfolge. Jedes Paket ist einzeln lauffähig, getestet und wird einzeln committet.

AP1 — Security-Domain-Zuordnung für UnifiedResultProjection

Datei: src/features/dashboard/security-domains.ts (erweitern, nicht ersetzen)

Neue Funktion:

export function securityDomainIdForUnifiedResult(result: UnifiedResultProjection): string

Bindende Semantik:

  • Es gilt derselbe securityDomainCatalog in derselben Reihenfolge. Kein zweiter Katalog, keine zweite Regex-Menge, keine report-eigene Zuordnung.
  • Evidenztext ist: title, description sowie categoryLabel aller Einträge aus result.categories.
  • Die explizite GPO-Erkennung geht wie bisher der Regex-Prüfung vor: erfüllt, wenn result.sourceKind einer von 'policy-evaluation' | 'policy-observation' ist oder ein categoryLabel exakt GPO/GPOs lautet (case-insensitiv).
  • Kein Treffer ⇒ unclassifiedSecurityDomain.id.

Akzeptanzkriterium (Pflichttest): Für einen synthetischen Fall, der sowohl als FindingRecord als auch als UnifiedResultProjection gebaut wird, liefern securityDomainIdForRecord und securityDomainIdForUnifiedResult dieselbe Domain — für alle acht Katalogeinträge, für den GPO-Sonderfall und für unclassified. Grund: Client-Info-Drilldown und Reports müssen dieselben Datensatzidentitäten auswählen (AGENTS.md, Abschnitt UI Work filter context).

AP2 — Framework-Referenzen in der Unified-Projektion sichtbar machen

Datei: src/domain/unified-result.ts

Neu:

export interface UnifiedResultFrameworkReference {
  namespace: string;        // Tool-ID der Quelle
  value: string;            // normalizedValue der Mapping-Eintragung, unverändert
  sourceFieldKey?: string;  // sourceFieldKeys[0], falls vorhanden
  sourceLabel?: string;     // Original-Spaltenüberschrift, falls vorhanden
}

und additiv auf UnifiedResultProjection:

frameworkReferences: UnifiedResultFrameworkReference[];

Befüllung analog zu scannerResultCategories, aber aus den Mappings mit targetRole === 'framework-reference'. Leere Werte werden verworfen, alle übrigen unverändert und unnormalisiert übernommen.

Bindende Randbedingungen:

  • Die Ableitung erfolgt zur Projektionszeit aus bereits persistierten fieldMappings. Es wird keine neue Spalte, Tabelle oder Migration angelegt und kein Parsing geändert.
  • Damit ist dies presentation-only über bereits gespeicherte Fakten: kein neuer Processing-Manifest-Eintrag, keine Reimport-Markierung (docs/REIMPORT_POLICY.md).
  • Sollte sich beim Umsetzen zeigen, dass eine Persistenzänderung nötig wäre: anhalten und melden, nicht persistieren.

Akzeptanzkriterium: Synthetische Occurrence mit zwei framework-reference-Mappings und einem category-Mapping ⇒ zwei frameworkReferences, eine category, keine Vermischung, Originalwerte identisch.

AP3 — Korrelationsmodul (Domain, plattformneutral)

Neue Datei: src/domain/report-correlation.ts Konstante: export const REPORT_CORRELATION_VERSION = '1.0.0';

Kein Storage, keine Uhr, kein Netzwerk, keine Präsentationstypen. Drei Ergebnisse:

(a) Quellenkonvergenz je Security Domain

export interface ReportDomainConvergence {
  domainId: string;
  sources: Array<{ toolId: string; assessed: number; deviations: number }>;
  sourceCount: number;   // Quellen mit mindestens einer Abweichung
  evidence: 'shared-framework-reference' | 'domain-only';
}

evidence ist 'shared-framework-reference' nur dann, wenn mindestens zwei Quellen in dieser Domain eine exakt gleiche, nicht leere frameworkReferences-Zeichenkette tragen. Andernfalls 'domain-only'.

(b) Maßnahmenbündel

export interface ReportRemediationBundle {
  key: string;         // die Framework-Referenz, unverändert
  namespace: string;
  members: string[];   // resultProjectionIds
  toolIds: string[];
  domainIds: string[];
}

Gebildet über identische frameworkReferences-Werte von Abweichungen. Bündel mit weniger als zwei Mitgliedern entfallen. Sortierung: Mitgliederzahl absteigend, danach key alphabetisch — stabil, damit Ausgaben reproduzierbar sind.

(c) GPO-Einzelquellen-Maßnahmen

export interface ReportSingleSourcePolicyAction {
  policyEntryId: string;
  backupInstanceId: string;
}

Genau die ReportPolicyEntry mit verdict === 'Fail', conflict === false, duplicate === false und exakt einem Eintrag in backupInstanceIds.

Bindende Verbote für AP3:

  • Keine Titel-, Wort-, Fuzzy- oder Ähnlichkeitsheuristik über Quellen hinweg.
  • Kein quellenübergreifender Score, Rang oder normalisierter Schweregrad.
  • Keine Aussage „gleicher Befund" — die Aussage lautet ausschließlich „dieselbe Domain" bzw. „dieselbe Framework-Referenz".
  • Keine Aufwands-, Kosten- oder Quick-Win-Schätzung. Ein Bündel trägt eine Mitgliederzahl, keine Bewertung.

AP4 — Projektion erweitern

Datei: src/domain/report-projection.ts Version: REPORT_PROJECTION_VERSION von '1.0.0' auf '1.1.0'.

Additiv auf ReportProjection:

convergence: ReportDomainConvergence[];
bundles: ReportRemediationBundle[];
singleSourcePolicyActions: ReportSingleSourcePolicyAction[];

Bestehende Felder, Typen und Semantiken bleiben unverändert. Die bestehenden Zusicherungen in tests/domain/report-projection.test.ts müssen ohne Änderung grün bleiben; neue Tests kommen hinzu.

AP5 — Report-Eingabe zusammenstellen

Neue Datei: src/features/reports/report-input-assembler.ts

export async function assembleReportProjectionInput(
  repository: AssessorRepository,
  scope: { projectId: string; assessmentId?: string; generatedAt: string }
): Promise<ReportProjectionInput>

Quellen, ausschließlich:

  • Ergebnisse: repository.queryUnifiedResults über den Scope.
  • domainOf: securityDomainIdForUnifiedResult aus AP1.
  • priorityBases: reportPriorityBases(...) über die registrierten Profile.
  • scoreSources / overallScore: die vorhandene Scoring-Schicht (src/domain/security-scoring.ts, src/features/dashboard/dashboard-security-score.ts). Keine eigene Score-Arithmetik.
  • environment: normalisierte Fakten aus dem Environment-Snapshot. Fehlende Fakten bleiben absent und werden nie zu 0.
  • policyEntries / policyScopeLimited: aus der Evaluations- und Aggregationsschicht mit dem autoritativen, hochgerollten Verdict. Kein Verdict wird hier neu abgeleitet.
  • reviews, diagnostics, provenance: aus den vorhandenen Repository-Pfaden.
  • delta: nur, wenn ein gespeicherter Timeslot-Vergleich existiert. Es wird keine Referenzlauf-Auswahl und keine Paarung im Export gebildet.

Die Zusammenstellung läuft nur beim Export, nie beim Laden eines Workspace.

AP6 — Management-Renderer erweitern

Datei: src/exports/management-overview-report.ts Version: MANAGEMENT_OVERVIEW_RENDERER_VERSION auf '1.1.0'.

Bestehende Abschnitte bleiben unverändert. Zwei neue Abschnitte:

  1. „Konvergenz der Quellen" — direkt nach Security Domains. Je Domain: Anzahl unabhängiger Quellen mit Abweichungen, die Quellen namentlich, und eine sichtbare Unterscheidung zwischen belegter Konvergenz (shared-framework-reference) und thematischer Nähe (domain-only). Letztere trägt im Fließtext ausdrücklich den Hinweis auf Validierungsbedarf.
  2. „Maßnahmenbündel" — direkt nach Priority Findings. Die Bündel aus AP3(b) mit Referenz und Mitgliederzahl sowie die Anzahl der Einzelquellen-GPO- Maßnahmen aus AP3(c). Keine Aufwands- oder Nutzenaussage.

Der Abschnitt „Abdeckung und Lücken" wird vor „Priority Findings" gezogen und zeigt zusätzlich je Quelle den Anteil not_run an der Gesamtzahl. Begründung: Die Aussagegrenze muss vor der Priorisierung stehen.

Unverändert bindend: keine Registry-Keys, SIDs, Evidenzpfade, Parser- oder Manifest-Versionen in Report A.

AP7 — Report B (Technical)

Neue Datei: src/exports/technical-report.ts Konstante: export const TECHNICAL_REPORT_RENDERER_VERSION = '1.0.0'; Signatur: export function buildTechnicalReportHtml(projection: ReportProjection): string

Abschnitte in dieser Reihenfolge, gemäß docs/REPORT_STRATEGY.md Report B:

  1. Scope und Provenance — Importe, Processing-, Analyzer- und Manifest-Versionen, Reimport-Status, Aggregations- und Evaluations-Run-IDs.
  2. Ergebnisinventar — Totals je Status, Severity, Domain und Tool, inklusive der score-neutralen Klassen; Passed erscheint als Zahl.
  3. Findings im Detail — gruppiert je Domain, innerhalb der Gruppe nach Severity.
  4. GPO-Policy-Register — alle sieben Verdicts vollständig; die score-neutralen sind am Ort der Anzeige als score-neutral gekennzeichnet.
  5. Konvergenz-Nachweis — die Paare aus AP3(a) mit ihrer Begründung, damit die Managementaussage aus AP6 nachprüfbar ist.
  6. Scope-Grenzen — ausdrücklich: kein RSoP, keine Aussage über wirksame Endpoint-Konfiguration, GPO-Aussagen gelten für das importierte Backup-Set, not_run ist kein Pass.
  7. Diagnostik — jede Beobachtung einmal, mit ihrem autoritativen Resolver-Grund.
  8. Anhang — vollständiger Ergebnisindex.

AP8 — Auslösung in der Anwendung

Zwei Aktionen in der bestehenden Oberfläche, die den Scope des aktuellen Projekts bzw. Assessments verwenden und über src/exports/download-adapter.ts bzw. src/exports/text-download.ts ausliefern. Keine neue Navigationsebene, keine neue Shell, keine neuen Farb- oder Geometrie-Tokens. Es gilt .claude/skills/assessor-ui/SKILL.md und der 20px-Panel-Inset.

2. Gestaltungsvorgaben für beide Dateien

  • Sprache: Deutsch. Etablierte englische Fachbegriffe bleiben englisch (Deviation, Passed, Not configured, No baseline rule, Not comparable, Conflicts, Duplicates, Finding, Baseline, Score, Pass Rate, Security-Domain-Namen, Group Policy, Registry, Domain Controller).
  • Zahlen und Daten in deutscher Formatierung. Unbekanntes ist ein Geviertstrich, niemals eine 0.
  • Getrennte Dateien. Report A enthält keine technischen Identifikatoren.
  • Vollständig eigenständig: alle Styles inline, kein CDN, keine externe Font, kein Skript, kein Bild, kein Netzwerkzugriff beim Öffnen. Druckbar nach PDF ohne Layoutverlust.
  • Typografie-Rollen, Donut-Geometrie, Tile- und Segment-Grammatik, Statusfarbregeln und Panel-Inset wie in der Anwendung. Statusfarbe nur in Akzentlinie, Marker, Arc oder Score-Node — nie als Flächenfüllung.

3. Harte Verbote

Nicht verhandelbar, auch dann nicht, wenn sie eine Lücke schließen würden:

  1. Kein quellenübergreifender, normalisierter Schweregrad, Rang oder Risiko-Score.
  2. Keine Aussage über wirksame Endpoint-Konfiguration aus einem Backup-Vergleich.
  3. Kein GPO-Verdict aus Vergleichsprosa, Historie, Baseline-Text, Guidance oder Evidenz — ausschließlich das autoritative hochgerollte Verdict plus die expliziten Conflict- und Duplicate-Flags.
  4. Ein selbst gemeldeter Review-Status wird nie zu einem gelösten Finding.
  5. Kein Delta ohne gespeicherten Vergleich; keine Referenzlauf-Auswahl im Export.
  6. Keine Score-Arithmetik, kein quellenspezifisches Parsing und kein Datenbankzugriff in einem Renderer.
  7. Not configured, No baseline rule und Not comparable bleiben score-neutral und erscheinen nie in den Priority Findings.
  8. Keine Titel- oder Ähnlichkeitsheuristik als Beleg für „gleicher Befund".
  9. Keine echten Kunden-, Mandanten- oder Scan-Inhalte in Tests, Fixtures, Logs oder Commit-Nachrichten. Ausschließlich synthetische Fixtures.

4. Tests (Pflicht, synthetisch)

Paket Testdatei Muss nachweisen
AP1 tests/features/security-domain-unified.test.ts Gleichstand beider Klassifizierer über alle acht Domains, GPO-Sonderfall, unclassified
AP2 tests/domain/unified-result-framework-references.test.ts Trennung category / framework-reference, Originalwerte unverändert, leere Werte verworfen
AP3 tests/domain/report-correlation.test.ts shared-framework-reference nur bei exakter Übereinstimmung über mindestens zwei Quellen; Bündel unter zwei Mitgliedern entfallen; stabile Sortierung; GPO-Einzelquelle schließt Conflict, Duplicate und Mehrfach-Backups aus
AP4 Erweiterung tests/domain/report-projection.test.ts Neue Felder vorhanden, bestehende Zusicherungen unverändert grün
AP5 tests/features/report-input-assembler.test.ts Kein Verdict wird neu abgeleitet; fehlende Fakten bleiben absent; delta bleibt ohne gespeicherten Vergleich undefined; Zusammenstellung nur beim Export
AP6 Erweiterung tests/exports/management-overview-report.test.ts Beide neuen Abschnitte vorhanden; domain-only trägt den Validierungshinweis; keine Registry-Keys, SIDs, Pfade oder Versionen im Output; Abdeckung steht vor Priority Findings
AP7 tests/exports/technical-report.test.ts Alle acht Abschnitte; score-neutrale Verdicts als solche gekennzeichnet; Diagnostik je Beobachtung genau einmal; Scope-Grenzen-Abschnitt vorhanden
AP8 Verhaltenstest der Auslösung Export läuft nur auf Klick, nicht beim Laden des Workspace

Zusätzlich für Report A und B je ein Selbstgenügsamkeits-Test: der erzeugte HTML-String enthält kein <script, kein @import, keine externe Font-URL und keine http- oder https-Ressourcenreferenz in src oder href.

5. Verifikation

npm test
npm run build

Beide müssen grün sein. Zusätzlich ist zu belegen, dass die bestehenden Tests zu report-projection und management-overview-report ohne inhaltliche Änderung weiter bestehen.

6. Nicht Teil dieses Auftrags

  • Artefakt C (Arbeitsgrundlage) und Artefakt D (Delta Report). D ist mangels gespeicherter Vergleiche ohnehin nicht lieferbar.
  • Framework-Abdeckung aus Maester-Tags (CISA SCuBA, CIS M365, Lizenzstufen). Grund: Die Tag-Liste ist heute als eine opake Category-Zeichenkette gespeichert, teils doppelt in zwei Serialisierungen. Eine belastbare Tag-Sicht erfordert eine Profil- und Importer-Änderung mit Reimport-Pflicht nach docs/REIMPORT_POLICY.md und ist als eigener Auftrag zu beschließen. Bis dahin wird die Zeichenkette nicht geraten, gesplittet oder interpretiert.
  • Asset- und Angriffspfad-Korrelation. assessor_canonical_assets und assessor_asset_edges sind leer, affectedAsset ist nur bei einer Quelle und dort nahezu konstant belegt. Ein Pfad-Graph wäre eine Erfindung.
  • Änderungen an Data Hub, Work, Pathfinder oder Client Info, die über die Auslösung aus AP8 hinausgehen.

7. Abschluss

Nach Abschluss aller Pakete ist docs/REPORT_STRATEGY.md im selben Change um einen Change-Log-Eintrag zu ergänzen, der festhält: Report A auf Renderer-Version 1.1.0 erweitert, Report B in Version 1.0.0 implementiert, Projektion auf 1.1.0, Korrelationsmodul in 1.0.0 eingeführt, Reimport nicht erforderlich. Kein Meilenstein wird als erfüllt markiert, bevor seine Akzeptanzkriterien verifiziert sind.