fix: align Defender branch with Michael's Business Impact base
Read Maester `Result` as the native status when no separate Status column exists, so the Work deviation filter matches the documented Maester rule again (regressed in the vulnerability result type commit). Expect the Result DB audience in Michael's empty-state test and record the rebase and product version 2.17.0 in the implementation plan.
This commit is contained in:
parent
fd97b111d1
commit
f9c347ae7c
|
|
@ -4231,6 +4231,7 @@ Verifiziert 2026-09-08 (Phase 7/13B): GPO-Quellenkorrektur fuer Work und Client
|
||||||
| 2026-10-06 | Phase 7: Data Hub Deviation/Passed now use the same assessed-percentage helper as Client Info; all six donuts state their population basis. 29 focused tests and synthetic Chrome Dark/Light checks passed; absolute counts, other population shares and assessment semantics retained. Client build, design and UI/API version checks passed. Nine out-of-scope report test failures, a report Local-only failure and report server type errors prevent full release verification; attempted 2.16.9 reverted to 2.16.8 pending successful production builds. |
|
| 2026-10-06 | Phase 7: Data Hub Deviation/Passed now use the same assessed-percentage helper as Client Info; all six donuts state their population basis. 29 focused tests and synthetic Chrome Dark/Light checks passed; absolute counts, other population shares and assessment semantics retained. Client build, design and UI/API version checks passed. Nine out-of-scope report test failures, a report Local-only failure and report server type errors prevent full release verification; attempted 2.16.9 reverted to 2.16.8 pending successful production builds. |
|
||||||
| 2026-10-06 | Phase 7: Client Info Deviations percentage now divides by Passed + Deviations and labels Of assessed checks; zero assessed shows a dash while preserving absolute zero. Permanent UI/click invariance tests in both themes and synthetic Chrome presentation verified; unchanged counts, verdicts, scores and other donuts. Patch 2.16.8: both builds and version contracts passed; full run 1,936 passed/15 skipped with one stale API-version assertion corrected and passed in the 43-test focused rerun; Local-only/design checks passed. |
|
| 2026-10-06 | Phase 7: Client Info Deviations percentage now divides by Passed + Deviations and labels Of assessed checks; zero assessed shows a dash while preserving absolute zero. Permanent UI/click invariance tests in both themes and synthetic Chrome presentation verified; unchanged counts, verdicts, scores and other donuts. Patch 2.16.8: both builds and version contracts passed; full run 1,936 passed/15 skipped with one stale API-version assertion corrected and passed in the 43-test focused rerun; Local-only/design checks passed. |
|
||||||
| 2026-10-06 | Phase 13B: GPO folder read diagnostics retain only safe error names, stages and counts, distinguish empty/denied/unreadable selections, preserve cancellation and wrap complete timeslot messages. 27 focused GPO UI tests and synthetic Chrome Dark/Light checks passed; both builds and version contracts verified for patch 2.16.7. Full run: 1,932 passed, 15 skipped, one general import timeout passed on separate rerun; Local-only/design checks passed. Customer-specific read failure remains unconfirmed; no customer path/data used, Phase 13B remains in progress. |
|
| 2026-10-06 | Phase 13B: GPO folder read diagnostics retain only safe error names, stages and counts, distinguish empty/denied/unreadable selections, preserve cancellation and wrap complete timeslot messages. 27 focused GPO UI tests and synthetic Chrome Dark/Light checks passed; both builds and version contracts verified for patch 2.16.7. Full run: 1,932 passed, 15 skipped, one general import timeout passed on separate rerun; Local-only/design checks passed. Customer-specific read failure remains unconfirmed; no customer path/data used, Phase 13B remains in progress. |
|
||||||
|
| 2026-10-05 | Phasen 6/7/13A, Produktversion 2.17.0: `merge/defender-for-iot` auf `250c213` (Michael, Business Impact + Management Report, 2.16.5) rebased; Michaels Commit ist die Basis, die 25 Branch-Commits liegen darauf. Die Minor-Erhoehung der Defender-Serie (zuvor 2.11.2 -> 2.12.0, Eintrag unten historisch) wird auf dieser Basis 2.16.5 -> 2.17.0; `package.json`, Root-Eintraege in `package-lock.json` und die Versionsvertragstests sind synchron. Korrektur aus `2b5fdf3`: `isDeviationRecord` uebersprang Maester `Result` immer als Ergebnisnachricht; nach AGENTS.md ist `Result` nur neben einer eigenen Statusspalte Evidenz, sonst der native Status. Michaels neuer Sidebar-Test deckte das auf; synthetische Regression in `tests/domain/deviation-predicate.test.ts`. Michaels Result-DB-Leerzustandstest erwartet nun das mit `55da786` eingefuehrte `audience: 'result-db'`. Kein Reimport, keine Migration, nicht im Browser geprueft. Verifikation: Gesamtlauf mit 2.049 bestandenen und 18 uebersprungenen Tests, beide Produktionsbuilds erfolgreich. |
|
||||||
| 2026-10-02 | Phase 13A, Disclosure Policy 3.5.0: Defender-Teil von `21a6266` uebernommen; `48a1888` (PingCastle-Aggregate, steht gegen die Zaehlwert-Grenze der Policy 2.0.0) und `78ea9a6` auf Nutzerentscheidung ausgelassen. Die Result DB kennt Microsoft Defender for IoT als Werkzeug statt `Security assessment`; freigegeben wird nur eine formal gueltige oeffentliche CVE-ID als Rule ID und zugleich als Titel. Geraete-, Site-, Sensor- und Zaehlwerte bleiben ausgeschlossen, `affectedAsset` bleibt zurueckgehalten; das Alerts-Profil bleibt generisch. Die zurueckgestellte `securityToolId`-Zeile aus `c056c21` bildet beide Defender-Namen auf den Schluessel `defender-for-iot` ab. Regression: Work und Result DB benennen ein Defender-Finding ueber die Projektion mit seiner CVE. `docs/RESULT_CONTRACT.md` beschreibt 3.5.0; die Versionsaufzaehlung der Result-DB-Regel in `AGENTS.md` ist nicht angepasst (Governance nicht freigegeben). Die materialisierte Result DB wird nach dem naechsten Backendstart mit der neuen Policy neu aufgebaut. Verifikation: beide Typechecks, Gesamtlauf mit 1.921 bestandenen und 18 uebersprungenen Tests sowie dem bekannten lastbedingten Ausfall von `sheet-selection-cost.test.tsx` (allein bestanden), Local-only-/Designpruefung und beide Produktionsbuilds erfolgreich. |
|
| 2026-10-02 | Phase 13A, Disclosure Policy 3.5.0: Defender-Teil von `21a6266` uebernommen; `48a1888` (PingCastle-Aggregate, steht gegen die Zaehlwert-Grenze der Policy 2.0.0) und `78ea9a6` auf Nutzerentscheidung ausgelassen. Die Result DB kennt Microsoft Defender for IoT als Werkzeug statt `Security assessment`; freigegeben wird nur eine formal gueltige oeffentliche CVE-ID als Rule ID und zugleich als Titel. Geraete-, Site-, Sensor- und Zaehlwerte bleiben ausgeschlossen, `affectedAsset` bleibt zurueckgehalten; das Alerts-Profil bleibt generisch. Die zurueckgestellte `securityToolId`-Zeile aus `c056c21` bildet beide Defender-Namen auf den Schluessel `defender-for-iot` ab. Regression: Work und Result DB benennen ein Defender-Finding ueber die Projektion mit seiner CVE. `docs/RESULT_CONTRACT.md` beschreibt 3.5.0; die Versionsaufzaehlung der Result-DB-Regel in `AGENTS.md` ist nicht angepasst (Governance nicht freigegeben). Die materialisierte Result DB wird nach dem naechsten Backendstart mit der neuen Policy neu aufgebaut. Verifikation: beide Typechecks, Gesamtlauf mit 1.921 bestandenen und 18 uebersprungenen Tests sowie dem bekannten lastbedingten Ausfall von `sheet-selection-cost.test.tsx` (allein bestanden), Local-only-/Designpruefung und beide Produktionsbuilds erfolgreich. |
|
||||||
| 2026-10-02 | Phase 13A: Geraeteteil von `95ec322` nachgezogen. `defenderRiskTargetsForOccurrences` ordnet Devices ueber die Quellzeilen der jeweiligen Occurrence zu statt ueber die CVE allein; fuehren zwei Occurrences dieselbe CVE mit unterschiedlichen Devices, bleibt jedes Device bei seiner eigenen Occurrence, und ein `device-finding` fuer ein Device ausserhalb der gewaehlten Occurrence wird abgelehnt. Das stuetzt die Regel, dass eine geraetebezogene Entscheidung nur ihre erfassten Occurrences deckt. Zwei Regressionen (Domain, lokales Repository) uebernommen. Keine API-, SQL- oder Persistenzaenderung. Verifikation: beide Typechecks, Gesamtlauf mit 1.922 bestandenen und 18 uebersprungenen Tests, Local-only-/Designpruefung und beide Produktionsbuilds erfolgreich. |
|
| 2026-10-02 | Phase 13A: Geraeteteil von `95ec322` nachgezogen. `defenderRiskTargetsForOccurrences` ordnet Devices ueber die Quellzeilen der jeweiligen Occurrence zu statt ueber die CVE allein; fuehren zwei Occurrences dieselbe CVE mit unterschiedlichen Devices, bleibt jedes Device bei seiner eigenen Occurrence, und ein `device-finding` fuer ein Device ausserhalb der gewaehlten Occurrence wird abgelehnt. Das stuetzt die Regel, dass eine geraetebezogene Entscheidung nur ihre erfassten Occurrences deckt. Zwei Regressionen (Domain, lokales Repository) uebernommen. Keine API-, SQL- oder Persistenzaenderung. Verifikation: beide Typechecks, Gesamtlauf mit 1.922 bestandenen und 18 uebersprungenen Tests, Local-only-/Designpruefung und beide Produktionsbuilds erfolgreich. |
|
||||||
| 2026-10-02 | Phase 7: Defender-Teil von `3f6259d` (Stile und Dashboardtest) nachgezogen. Kennzahlbeschriftungen und Tabellenkoepfe des Defender-Panels nutzen die 14px-Tabellenrolle statt der 12px-Labelrolle; die Kennzahlen stehen als kompakte Kacheln (`--tile-compact-width`) in einem Segment statt in sechs festen Spalten; der Zeilenmarker nutzt `--marker-width`. Beibehalten gegenueber dem Original: Kachelkontur `--tile-border`, gemeinsame Textrollen und die blaue Tabellenzeilen-Markierung. Nur CSS und Testassertions; nicht im Browser geprueft. Verifikation: beide Typechecks, Gesamtlauf mit 1.920 bestandenen und 18 uebersprungenen Tests, Local-only-/Designpruefung und beide Produktionsbuilds erfolgreich. |
|
| 2026-10-02 | Phase 7: Defender-Teil von `3f6259d` (Stile und Dashboardtest) nachgezogen. Kennzahlbeschriftungen und Tabellenkoepfe des Defender-Panels nutzen die 14px-Tabellenrolle statt der 12px-Labelrolle; die Kennzahlen stehen als kompakte Kacheln (`--tile-compact-width`) in einem Segment statt in sechs festen Spalten; der Zeilenmarker nutzt `--marker-width`. Beibehalten gegenueber dem Original: Kachelkontur `--tile-border`, gemeinsame Textrollen und die blaue Tabellenzeilen-Markierung. Nur CSS und Testassertions; nicht im Browser geprueft. Verifikation: beide Typechecks, Gesamtlauf mit 1.920 bestandenen und 18 uebersprungenen Tests, Local-only-/Designpruefung und beide Produktionsbuilds erfolgreich. |
|
||||||
|
|
|
||||||
|
|
@ -126,13 +126,18 @@ export function toolIdForRecord(record: FindingRecord, fallbackToolId?: string):
|
||||||
function statusValueForRecord(record: FindingRecord, toolId: string | undefined): string {
|
function statusValueForRecord(record: FindingRecord, toolId: string | undefined): string {
|
||||||
const presentation = toolId ? definitionsByToolId.get(toolId)?.presentation : undefined;
|
const presentation = toolId ? definitionsByToolId.get(toolId)?.presentation : undefined;
|
||||||
const headers = presentation?.statusHeaders ?? [/^(?:status|evaluation|result)$/i];
|
const headers = presentation?.statusHeaders ?? [/^(?:status|evaluation|result)$/i];
|
||||||
|
const isMessage = (label: string) => presentation?.resultMessageHeaders?.some(pattern => pattern.test(label)) ?? false;
|
||||||
|
// Eine Ergebnisnachricht (Maester `Result`) ist nur neben einer eigenen
|
||||||
|
// Statusspalte Evidenz; ohne sie ist sie der native Status.
|
||||||
|
for (const skipMessages of [true, false]) {
|
||||||
for (const header of headers) {
|
for (const header of headers) {
|
||||||
const field = record.fields.find(candidate =>
|
const field = record.fields.find(candidate =>
|
||||||
candidate.value
|
candidate.value
|
||||||
&& header.test(candidate.label.trim())
|
&& header.test(candidate.label.trim())
|
||||||
&& !presentation?.resultMessageHeaders?.some(pattern => pattern.test(candidate.label.trim())));
|
&& !(skipMessages && isMessage(candidate.label.trim())));
|
||||||
if (field) return field.value;
|
if (field) return field.value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,13 @@ describe('Outcome eines rohen Statusfeldes fuer die Arbeitsansichten', () => {
|
||||||
expect(isDeviationRecord(recordWith([['Result', 'Passed']]), 'cis-cat')).toBe(false);
|
expect(isDeviationRecord(recordWith([['Result', 'Passed']]), 'cis-cat')).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('liest Maester `Result` ohne eigene Statusspalte als Status und daneben als Evidenz', () => {
|
||||||
|
expect(isDeviationRecord(recordWith([['Result', 'Failed']]), 'maester')).toBe(true);
|
||||||
|
expect(isDeviationRecord(recordWith([['Result', 'Passed']]), 'maester')).toBe(false);
|
||||||
|
expect(isDeviationRecord(recordWith([['Status', 'Passed'], ['Result', 'Failed']]), 'maester')).toBe(false);
|
||||||
|
expect(isDeviationRecord(recordWith([['Status', 'Failed'], ['Result', 'Passed']]), 'maester')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('unterscheidet die drei Maester-Ergebnisse voneinander', () => {
|
it('unterscheidet die drei Maester-Ergebnisse voneinander', () => {
|
||||||
expect(outcomeForStatusValue('maester', 'Passed')).toBe('pass');
|
expect(outcomeForStatusValue('maester', 'Passed')).toBe('pass');
|
||||||
expect(outcomeForStatusValue('maester', 'Failed')).toBe('fail');
|
expect(outcomeForStatusValue('maester', 'Failed')).toBe('fail');
|
||||||
|
|
|
||||||
|
|
@ -94,5 +94,5 @@ it.each(['Reset filters', 'Search all Findings'])('Result DB action %s preserves
|
||||||
expect(host.querySelector('.filter-empty-state')).toBeNull();
|
expect(host.querySelector('.filter-empty-state')).toBeNull();
|
||||||
expect(host.querySelectorAll('.results-browser-row[role="row"]')).toHaveLength(2);
|
expect(host.querySelectorAll('.results-browser-row[role="row"]')).toHaveLength(2);
|
||||||
expect(item.title).toBe('Synthetic result'); // Disclosure controls presentation; the source remains intact.
|
expect(item.title).toBe('Synthetic result'); // Disclosure controls presentation; the source remains intact.
|
||||||
expect(query.mock.calls.at(-1)![0]).toEqual({ ...(action === 'Reset filters' ? { deviation: true } : {}), projectId: 'synthetic', scanRunIds: ['scan'], assessmentIds: ['slot'], offset: 0, limit: 50 });
|
expect(query.mock.calls.at(-1)![0]).toEqual({ ...(action === 'Reset filters' ? { deviation: true } : {}), audience: 'result-db', projectId: 'synthetic', scanRunIds: ['scan'], assessmentIds: ['slot'], offset: 0, limit: 50 });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue