import type { FindingRecord } from '../../domain/finding'; export const SECURITY_DOMAIN_FACET_ID = 'derived:security-domain'; export const securityDomainCatalog = [ { id: 'identity', label: 'Identity & Account Hygiene', glyph: 'user', pattern: /account|identity|user|password|stale|inactive|honey\s*pot/i }, { id: 'privilege', label: 'Privilege & Attack Paths', glyph: 'shield', pattern: /privileg|admin|delegat|control\s*path|attack\s*path|tier\s*0|pim/i }, { id: 'authentication', label: 'Authentication & Access', glyph: 'lock', pattern: /authenticat|\bmfa\b|conditional\s*access|kerberos|sign[ -]?in|break[ -]?glass/i }, { id: 'infrastructure', label: 'AD Infrastructure & PKI', glyph: 'server', pattern: /domain\s*controller|forest|\btrust|certificate|\bpki\b|\bdns\b|replication|schema/i }, { id: 'hardening', label: 'System Hardening', glyph: 'code', pattern: /cis-cat|benchmark|hardening|firewall|attack\s*surface|\basr\b|defender|operating\s*system/i }, { id: 'gpo', label: 'GPO & Baseline', glyph: 'policy', pattern: /\bgpo\b|group\s*policy|baseline|policy\s*(?:setting|deviation|conflict)|duplicates?/i }, { id: 'cloud', label: 'Cloud & Applications', glyph: 'cloud', pattern: /\bcloud\b|\bentra\b|application|\bapps?\b|exchange|teams|sharepoint|guest|intune|purview/i }, { id: 'recovery', label: 'Monitoring & Recovery', glyph: 'chart', pattern: /audit|monitor|logging|\bwef\b|backup|recover|recycle\s*bin|sensor|event\s*log/i } ] as const; export const unclassifiedSecurityDomain = { id: 'unclassified', label: 'Unclassified' } as const; const recordDomainEvidenceCache = new WeakMap(); function recordDomainEvidence(record: FindingRecord): { text: string; explicitGpo: boolean } { let cached = recordDomainEvidenceCache.get(record); if (cached === undefined) { const fields = record.fields; cached = { text: [record.title, ...fields .filter(field => /^(?:title|name|finding|description|category|subcategory|sub-category|categories|control area|policy section|policy type)$/i.test(field.label.trim())) .map(field => field.value)].join(' '), explicitGpo: fields.some(field => /^category$/i.test(field.label.trim()) && /^gpos?$/i.test(field.value.trim())) }; recordDomainEvidenceCache.set(record, cached); } return cached; } /** The one shared Client Info / Work classification for a retained record. */ export function securityDomainIdForRecord(record: FindingRecord): string { const evidence = recordDomainEvidence(record); if (evidence.explicitGpo) return 'gpo'; return securityDomainCatalog.find(domain => domain.pattern.test(evidence.text))?.id ?? unclassifiedSecurityDomain.id; } /** Assign every record once so Client Info distributions reconcile to the total. */ export function dashboardDomainAssignment(records: FindingRecord[]): Map { const buckets = new Map([ ...securityDomainCatalog.map(domain => [domain.id, [] as FindingRecord[]] as const), [unclassifiedSecurityDomain.id, [] as FindingRecord[]] as const ]); records.forEach(record => buckets.get(securityDomainIdForRecord(record))!.push(record)); return buckets; } export function dashboardDomainRecords(records: FindingRecord[], domainId: string): FindingRecord[] { return dashboardDomainAssignment(records).get(domainId) ?? []; }