Assessor_2.0/docs/REPORT_IMPLEMENTATION_BRIEF.md

349 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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:
```ts
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:
```ts
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`:
```ts
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**
```ts
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**
```ts
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**
```ts
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`:
```ts
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`
```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
```bash
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.