import { describe, expect, it } from 'vitest'; import { RELEASED_ASSESSMENT_CONTEXT_CATALOG } from '../../src/assessment-context/context-catalog'; import { contextClusterSeverities } from '../../src/assessment-context/context-cluster-severity'; import { contextHeatmap } from '../../src/assessment-context/context-heatmap'; import { buildAssessmentContext } from '../../src/assessment-context/context-engine'; import type { UnifiedResultProjection } from '../../src/domain/unified-result'; import { emptyHeatmapContext, syntheticHeatmapContext, reassignedHeatmapContext } from './context-heatmap-fixture'; describe('Context category severity and heatmap', () => { it('excludes GPO settings from Other after recognition assigns their real cluster', () => { const context = reassignedHeatmapContext(); const before = JSON.stringify(context); const cells = contextHeatmap(context); const other = cells.find(item => item.cluster.clusterId === 'other-deviations')!; expect(other.scannerDeviations + other.gpoDeviations).toBe(2); expect(cells.find(item => item.cluster.clusterId === 'lateral-movement-exposure')!.gpoDeviations).toBe(29); expect(JSON.stringify(context)).toBe(before); }); it('catalogues the reported smartcard rule but never guesses the unspecified Entra recommendation', () => { const scannerFindings = ['fail', 'warning', 'pass', 'not_run'].map((outcome, index) => ({ sourceKind: 'scanner-finding', resultProjectionId: `smartcard-${index}`, sourceResultId: `smartcard-${index}`, sourceTool: 'purple-knight', sourceRuleId: 'SI000147', outcomeNormalized: outcome, title: 'Smart card password rotation disabled', categories: [] } as unknown as UnifiedResultProjection)); scannerFindings.push({ sourceKind: 'scanner-finding', resultProjectionId: 'entra', sourceResultId: 'entra', sourceTool: 'maester', sourceRuleId: 'MT.1024', outcomeNormalized: 'fail', title: 'Entra Recommendation - .', categories: [] } as unknown as UnifiedResultProjection); const before = JSON.stringify(scannerFindings); const context = buildAssessmentContext({ projectId: 'synthetic', assessmentIds: ['slot'], repositoryRevision: 1, generatedAt: '2026-10-02T12:00:00Z', observations: [], analyses: [], scannerFindings, catalog: RELEASED_ASSESSMENT_CONTEXT_CATALOG }); expect(context.findings.find(item => item.occurrenceId === 'smartcard-0')!.clusterIds).toEqual(['lateral-movement-exposure']); expect(context.observations.find(item => item.occurrenceId === 'smartcard-0')!.matchedBy).toBe('rule-id'); expect(context.findings.find(item => item.occurrenceId === 'entra')!.clusterIds).toEqual(['other-deviations']); const cells = contextHeatmap(context); expect(cells.find(item => item.cluster.clusterId === 'lateral-movement-exposure')!.scannerDeviations).toBe(2); expect(cells.find(item => item.cluster.clusterId === 'other-deviations')!.scannerDeviations).toBe(1); expect(JSON.stringify(scannerFindings)).toBe(before); }); it('covers every released cluster exactly once with the approved category assessment and local sources', () => { expect(contextClusterSeverities.map(item => item.clusterId).sort()).toEqual(RELEASED_ASSESSMENT_CONTEXT_CATALOG.clusters.map(item => item.id).sort()); expect(contextClusterSeverities).toHaveLength(22); expect(contextClusterSeverities.filter(item => item.severity === 'critical').map(item => item.clusterId)).toEqual([ 'cloud-privileged-access-exposure', 'ad-privileged-account-exposure', 'kerberos-delegation-abuse', 'adcs-escalation' ]); expect(contextClusterSeverities.filter(item => item.severity === 'high')).toHaveLength(13); expect(contextClusterSeverities.filter(item => item.severity === 'medium')).toHaveLength(4); for (const item of contextClusterSeverities) { expect(item.rationale.length).toBeGreaterThan(30); expect(item.qualification.length).toBeGreaterThan(30); if (item.severity === 'undetermined') expect(item.clusterId).toBe('other-deviations'); else expect(item.sources.length).toBeGreaterThan(0); for (const source of item.sources) expect(new URL(source.url).protocol).toBe('https:'); } }); it('retains unknown and passed-only areas as neutral and never treats missing coverage as low severity', () => { const context = emptyHeatmapContext(); expect(contextHeatmap(context).every(cell => !cell.hasEvidence)).toBe(true); const cluster = context.clusters[0]; cluster.unknown = 0; cluster.notSatisfied = cluster.conditions.length; cluster.state = 'not-present'; expect(contextHeatmap(context)[0].hasEvidence).toBe(false); expect(contextHeatmap(context).find(cell => cell.cluster.clusterId === 'other-deviations')?.reference.severity).toBe('undetermined'); context.clusters.push({ ...cluster, clusterId: 'future-cluster' }); expect(contextHeatmap(context).at(-1)?.reference.severity).toBe('undetermined'); }); it('retains the Context threshold and all conditions without re-evaluating or mutating them', () => { const context = syntheticHeatmapContext(); const before = JSON.stringify(context); const cells = contextHeatmap(context); expect(cells.some(cell => cell.hasEvidence && cell.cluster.state === 'undetermined')).toBe(true); for (const cell of cells) { expect(cell.hasEvidence).toBe(cell.cluster.satisfied > 0); expect(cell.cluster).toBe(context.clusters.find(cluster => cluster.clusterId === cell.cluster.clusterId)); } expect(JSON.stringify(context)).toBe(before); }); it('includes scanner deviations without source severity and retains recognized confidence', () => { const source = { sourceKind: 'scanner-finding', resultProjectionId: 'scanner-finding:one', sourceResultId: 'one', sourceTool: 'purple-knight', sourceRuleId: 'SYNTHETIC', outcomeNormalized: 'fail', title: 'Users with SPN defined', categories: [] } as unknown as UnifiedResultProjection; const context = buildAssessmentContext({ projectId: 'synthetic', assessmentIds: ['slot'], repositoryRevision: 1, generatedAt: '2026-10-02T12:00:00Z', observations: [], analyses: [], scannerFindings: [source], catalog: RELEASED_ASSESSMENT_CONTEXT_CATALOG }); const cell = contextHeatmap(context).find(item => item.cluster.clusterId === 'kerberoasting-exposure')!; expect(cell.hasEvidence).toBe(true); expect(cell.scannerDeviations).toBe(1); expect(cell.recognized).toBe(1); expect(cell.reference.severity).toBe('high'); expect(context.recognitions.some(item => item.confidence === 'recognized')).toBe(true); expect(source.severityNormalized).toBeUndefined(); }); it('deduplicates scanner and GPO deviations per cluster and excludes passed evaluations', () => { const context = syntheticHeatmapContext(); const cluster = context.clusters.find(item => item.clusterId === 'adcs-escalation')!; const conditionId = cluster.conditions[0].conditionId; const before = contextHeatmap(context).find(item => item.cluster.clusterId === cluster.clusterId)!.scannerDeviations; context.observations.push({ ...context.observations.find(item => item.conditionId === conditionId)!, id: 'duplicate-evidence' }); const evaluation = { id: 'gpo-a', conditionId, identityKey: 'setting-one', scope: 'computer' as const, settingName: 'Synthetic setting', verdict: 'deviation' as const, matchedBy: 'setting' as const, resultProjectionIds: ['gpo-a'], assertion: 'evaluated-by-assessor' as const }; context.evaluations.push(evaluation, { ...evaluation, id: 'gpo-b' }, { ...evaluation, id: 'passed', identityKey: 'passed-setting', verdict: 'passed' }); const cell = contextHeatmap(context).find(item => item.cluster.clusterId === cluster.clusterId)!; expect(cell.scannerDeviations).toBe(before); expect(cell.gpoDeviations).toBe(1); }); });