import { createElement } from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import { describe, expect, it } from 'vitest'; import type { FindingRecord } from '../../src/domain/finding'; import { policyFindingCategories } from '../../src/profiles/group-policy/categories'; import { FindingReader, selectFindingFields } from '../../src/features/finding-reader/FindingReader'; import { FindingCard } from '../../src/components/FindingCard/FindingCard'; function fixture(values: Record, title = 'Synthetic setting'): FindingRecord { return { id: 'synthetic', index: 0, title, filled: [], meta: [], fields: Object.entries(values).map(([label, value], index) => ({ index, label, value })) }; } describe('GPO category badges', () => { it.each([ ['system access · lockoutbadcount', 'System Access', 'Account Lockout'], ['system access · passwordhistorysize', 'System Access', 'Password Policy'], ['privilege rights · senetworklogonright', 'Privilege Rights', 'Logon Rights'], ['privilege rights · sebackupprivilege', 'Privilege Rights', 'Security'], ['registry values · machine\\software\\synthetic', 'Registry Values', 'Security'], ['system services · synthetic', 'System Services', 'Security'], ])('uses native section evidence from legacy headings: %s', (title, section, detail) => { const badges = policyFindingCategories(fixture({}, title), 'group-policy'); expect(badges).toContain(section); expect(badges).toContain(detail); }); it('uses structural registry branches only when no more specific family is known', () => { expect(policyFindingCategories(fixture({ 'Registry path': 'SOFTWARE\\Synthetic' }), 'group-policy')).toEqual(['Registry', 'Software']); expect(policyFindingCategories(fixture({ 'Registry path': 'SYSTEM\\CurrentControlSet\\Synthetic' }), 'group-policy')).toEqual(['Registry', 'System']); expect(policyFindingCategories(fixture({ 'Registry path': 'SOFTWARE\\Policies\\Microsoft\\Office\\16.0' }), 'group-policy')).toEqual(['Office']); expect(policyFindingCategories(fixture({ Description: 'privilege rights · sebackupprivilege' }), 'group-policy')).toEqual([]); }); it('derives the Office badge from a retained Registry Preference title when Registry path is unavailable', () => { const title = 'registry · HKEY_CURRENT_USER\\Software\\Microsoft\\Office\\16.0\\Outlook\\AutoDiscover\\ExcludeScpLookup'; const record = fixture({ Category: 'GPOs', Status: 'Not comparable', 'Policy type': 'group-policy-preference' }, title); expect(policyFindingCategories(record, 'group-policy')).toEqual(['Office']); const html = renderToStaticMarkup(createElement(FindingReader, { record, title, linkedSheets: [], resultReferences: [], search: '', position: 0, recordCount: 1, toolId: 'group-policy', onPrevious() {}, onNext() {}, onReview() {} })); expect(html).toContain('data-derived-category="gpo">Office'); }); it.each(['computer', 'user'])('adds the %s scope badge and retains the report field', scope => { const record = fixture({ Category: 'GPOs', Scope: scope }); const html = renderToStaticMarkup(createElement(FindingReader, { record, title: record.title, linkedSheets: [], resultReferences: [], search: '', position: 0, recordCount: 1, toolId: 'group-policy', onPrevious() {}, onNext() {}, onReview() {} })); expect(html).toContain(`data-policy-scope="true">Scope: ${scope}`); expect(selectFindingFields(record, record.title, false, 'group-policy').summary).toContainEqual({ index: 1, label: 'Scope', value: scope }); expect(html).toContain('

Scope

'); }); it('does not invent a scope badge when scope is absent or blank', () => { const examples: Record[] = [{}, { Scope: ' ' }]; for (const values of examples) { const record = fixture(values); const html = renderToStaticMarkup(createElement(FindingReader, { record, title: record.title, linkedSheets: [], resultReferences: [], search: '', position: 0, recordCount: 1, toolId: 'group-policy', onPrevious() {}, onNext() {}, onReview() {} })); expect(html).not.toContain('data-policy-scope'); } }); it('contains a long Registry Values MACHINE path in both reader headings', () => { const path = 'MACHINE\\System\\CurrentControlSet\\Services\\NTDS\\Parameters\\SyntheticChannelBinding'; const title = `Registry Values \u00b7 ${path}`; const record = fixture({ Category: 'GPOs', Status: 'Not configured', Scope: 'computer' }, title); const html = renderToStaticMarkup(createElement(FindingReader, { record, title, linkedSheets: [], resultReferences: [], search: 'SyntheticChannelBinding', position: 0, recordCount: 1, toolId: 'group-policy', onPrevious() {}, onNext() {}, onReview() {} })); expect(html.match(//g)).toHaveLength(2); // Two headings plus the dedicated Policy Analyzer search key. expect(html.match(/SyntheticChannelBinding<\/mark>/g)).toHaveLength(3); expect(html).toContain(`

Registry Values \u00b7 MACHINE\\System\\CurrentControlSet`); expect(html).toContain(`

Registry Values \u00b7 MACHINE\\System\\CurrentControlSet`); }); it('labels audit settings even when the customer setting is absent', () => { const record = fixture({ Baseline: 'Windows Server 2022 Security Baseline', 'Policy type': 'advanced-audit-policy', 'Configured Value': 'Not configured' }); expect(policyFindingCategories(record, 'group-policy')).toEqual(['Windows', 'Audit']); expect(selectFindingFields(record, record.title, false, 'group-policy').summary.map(field => field.label)).not.toContain('Policy type'); }); it('supports the previous generated audit heading and legacy audit templates', () => { expect(policyFindingCategories(fixture({}, 'system audit subcategory · synthetic-id'), 'group-policy')).toEqual(['Audit']); expect(policyFindingCategories(fixture({ 'Policy type': 'security-template', 'Policy section': 'Event Audit' }), 'group-policy')).toEqual(['Audit']); }); it.each([ ['Microsoft 365 Apps for enterprise Security Baseline', 'Office'], ['Office 2016 Security Baseline', 'Office'], ['Microsoft Edge Security Baseline', 'Edge'] ])('identifies the product family of %s', (baseline, category) => { expect(policyFindingCategories(fixture({ Baseline: baseline }), 'group-policy')).toEqual([category]); }); it.each([ ['SOFTWARE\\Policies\\Microsoft\\Windows Defender', 'Defender'], ['SOFTWARE\\Policies\\Microsoft\\WindowsFirewall\\DomainProfile', 'Firewall'], ['SOFTWARE\\Policies\\Microsoft\\FVE', 'BitLocker'], ['SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\LAPS', 'LAPS'] ])('identifies a known registry family %s', (path, category) => { expect(policyFindingCategories(fixture({ 'Registry path': path, Baseline: 'Windows 11 Security Baseline' }), 'group-policy')).toEqual(['Windows', category]); }); it('prefers explicit Office or Edge paths over the package product', () => { for (const product of ['Office', 'Edge']) { expect(policyFindingCategories(fixture({ 'Registry path': `HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\${product}\\16.0`, Baseline: 'Windows 11 Security Baseline' }), 'group-policy')).toEqual([product]); } }); it('uses a conservative fallback and does not search arbitrary finding text', () => { expect(policyFindingCategories(fixture({ Baseline: 'Windows 11 Security Baseline' }), 'group-policy')).toEqual(['Windows', 'Security']); expect(policyFindingCategories(fixture({ Description: 'Office Audit Firewall' }), 'group-policy')).toEqual([]); expect(policyFindingCategories(fixture({ Baseline: 'Windows 11 Security Baseline' }), 'cis-cat')).toEqual([]); }); it('renders compact badges alongside GPOs without changing the outcome', () => { const record = fixture({ Category: 'GPOs', Status: 'Fail', Baseline: 'Windows Server 2022 Security Baseline', 'Policy type': 'advanced-audit-policy' }); const html = renderToStaticMarkup(createElement(FindingReader, { record, title: record.title, linkedSheets: [], resultReferences: [], search: '', position: 0, recordCount: 1, toolId: 'group-policy', onPrevious() {}, onNext() {}, onReview() {} })); expect(html).toContain('Category: GPOs'); expect(html).toContain('data-derived-category="gpo">Windows'); expect(html).toContain('data-derived-category="gpo">Audit'); expect(html).toContain('data-outcome="fail"'); }); it.each([ ['Duplicates', 'Duplicate'], ['Conflict', 'Conflict'] ])('keeps Fail as the verdict and adds a %s diagnostic badge in list and reader', (field, badge) => { const record = fixture({ Category: 'GPOs', Status: 'Fail', [field]: '1 setting · 2 sources' }); const card = renderToStaticMarkup(createElement(FindingCard, { record, title: record.title, bookmarked: false, toolId: 'group-policy', onOpen() {} })); const reader = renderToStaticMarkup(createElement(FindingReader, { record, title: record.title, linkedSheets: [], resultReferences: [], search: '', position: 0, recordCount: 1, toolId: 'group-policy', onPrevious() {}, onNext() {}, onReview() {} })); for (const html of [card, reader]) { expect(html).toContain('data-outcome="fail"'); expect(html).toContain(`data-policy-diagnostic="${badge.toLowerCase()}"`); expect(html).toContain(`>${badge}`); } }); it('does not turn explicit negative diagnostic fields into badges', () => { const record = fixture({ Category: 'GPOs', Status: 'Fail', Conflict: 'No', Duplicates: 'No' }); const html = renderToStaticMarkup(createElement(FindingCard, { record, title: record.title, bookmarked: false, toolId: 'group-policy', onOpen() {} })); expect(html).toContain('data-outcome="fail"'); expect(html).not.toContain('data-policy-diagnostic'); }); });