444 lines
32 KiB
TypeScript
444 lines
32 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import { createElement } from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
import { DynamicFilterControls } from '../../src/features/search-filter/DynamicFilterControls';
|
|
import {
|
|
deriveUnifiedResultFacets,
|
|
queryUnifiedResultItems,
|
|
selectCurrentPolicyEvaluations,
|
|
type UnifiedResultProjection
|
|
} from '../../src/domain/unified-result';
|
|
import { createPolicyConsistencyUnifiedResults } from '../../src/evaluation/policy-consistency-results';
|
|
import type { ImportedDataset } from '../../src/domain/dataset';
|
|
import { POLICY_EVALUATION_ENGINE, type PolicyEvaluationResult, type StoredPolicyEvaluation } from '../../src/domain/policy-evaluation';
|
|
import type { CanonicalAssessmentModel } from '../../src/domain/canonical-model';
|
|
import { makeSheet } from '../../src/importers/sheet-factory';
|
|
import { appendPolicyObservationsToDataset } from '../../src/features/project-import/policy-observations-to-dataset';
|
|
import { loadCanonicalProjectWorkspace } from '../../src/features/project-import/load-canonical-project-workspace';
|
|
import { deriveDynamicFacets, recountFacetsAgainstActiveFilters } from '../../src/features/search-filter/dynamic-facets';
|
|
import { filterAndSortRecords } from '../../src/features/search-filter/filter-records';
|
|
import { buildPolicyWorkResults, countPolicyWorkResults, policyMisconfigurationImpact } from '../../src/evaluation/policy-work-results';
|
|
import { genericProfile } from '../../src/profiles/generic/generic-profile';
|
|
import { outcomeForStatusValue, toolIdForRecord } from '../../src/importers/status-normalization';
|
|
|
|
function source(id: string, value = 1, patch: Partial<UnifiedResultProjection> = {}): UnifiedResultProjection {
|
|
return {
|
|
sourceKind: 'policy-observation', sourceResultId: id, resultProjectionId: 'policy-observation:' + id,
|
|
projectId: 'synthetic', assessmentId: 'slot', importArtifactId: 'import-one', title: 'Mode', importedAt: '2026-09-06T00:00:00Z',
|
|
policyScope: 'computer', policyDeliveryMechanism: 'registry-policy', policyState: 'configured',
|
|
policyIdentityStatus: 'resolved', policyIdentityKey: 'identity-mode', policyBackupInstanceId: 'backup-' + id,
|
|
policyValues: [{ kind: 'registry-policy', key: 'Software\\Policies\\Synthetic', valueName: 'Mode',
|
|
operation: 'set-value', typeCode: 4, data: { kind: 'uint32', value } }], ...patch
|
|
} as UnifiedResultProjection;
|
|
}
|
|
function comparison(id: string, ids: string[], patch: Partial<PolicyEvaluationResult> = {}): PolicyEvaluationResult {
|
|
return {
|
|
id, observationIds: ids, baselineId: 'ms-baseline', baselineLabel: 'Synthetic Microsoft Baseline',
|
|
baselineState: 'explicit-recommendation', classification: 'configured_match', customerState: 'configured',
|
|
comparator: { version: 1, comparator: { kind: 'equality' }, relation: 'match',
|
|
actual: { kind: 'integer', value: '1' }, baseline: { kind: 'integer', value: '1' }, diagnosticCodes: [] },
|
|
identity: { id: 'identity-mode', scope: 'computer', target: {
|
|
kind: 'registry-value', hive: 'HKEY_LOCAL_MACHINE', key: 'Software\\Policies\\Synthetic', valueName: 'Mode'
|
|
} }, diagnosticCodes: [], ...patch
|
|
} as PolicyEvaluationResult;
|
|
}
|
|
const run = (results: PolicyEvaluationResult[]) => ({
|
|
run: { completedAt: '2026-09-06T00:00:00Z' }, results
|
|
}) as StoredPolicyEvaluation;
|
|
const statuses = (sources: UnifiedResultProjection[], comparisons: PolicyEvaluationResult[] = []) =>
|
|
buildPolicyWorkResults(sources, [run(comparisons)]).map(result => result.status);
|
|
|
|
describe('Policy Analyzer outcome contract in Work', () => {
|
|
it('keeps previous results as history without presenting them as current Pass/Fail/conflict outcomes', async () => {
|
|
const observations = [source('a'), source('b')];
|
|
const pass = comparison('pass', ['a', 'b']);
|
|
const conflict = comparison('conflict', ['a'], { diagnosticCodes: ['policy-evaluation-baseline-consensus-conflict'], classification: 'review_required' });
|
|
const missing = comparison('missing', [], { customerState: 'missing', classification: 'confirmed_configured_deviation',
|
|
comparator: { ...pass.comparator, actual: undefined, relation: 'different' } });
|
|
const previous = run([pass, conflict, missing]);
|
|
previous.run = { ...previous.run, id: 'legacy', aggregationRunId: 'aggregation',
|
|
evaluator: { ...POLICY_EVALUATION_ENGINE, version: '1.3.3' } as unknown as typeof POLICY_EVALUATION_ENGINE,
|
|
baselineAnalysisIds: ['baseline'] };
|
|
const before = JSON.stringify(previous);
|
|
const model = { schemaVersion: 1, project: { id: 'synthetic', name: 'Synthetic' }, assessment: { id: 'slot', projectId: 'synthetic' },
|
|
scanRuns: [], importFiles: [], sourceTables: [], findingDefinitions: [], findingOccurrences: [], evidence: [], reviews: [], diagnostics: [] } as unknown as CanonicalAssessmentModel;
|
|
const loaded = await loadCanonicalProjectWorkspace({
|
|
listProjectAssessments: async () => [model.assessment], loadAssessmentModel: async () => model,
|
|
queryUnifiedResults: async () => ({ items: observations, total: observations.length, limit: 500, offset: 0 }),
|
|
listPolicyEvaluations: async () => ({ records: [previous] }),
|
|
getPolicyAnalysisOverview: async () => ({ current: { evaluationRunIds: ['legacy'] } as never })
|
|
}, 'synthetic');
|
|
const sheet = loaded.dataset!.sheets[0];
|
|
const facets = deriveDynamicFacets(sheet, loaded.dataset, genericProfile, {});
|
|
const counted = recountFacetsAgainstActiveFilters({ facets, records: sheet.analysis.records, filters: {}, reviews: {},
|
|
statusFilter: 'deviation', matchesStatus: genericProfile.matchesStatus });
|
|
const status = counted.find(facet => facet.source === 'profile-status')!;
|
|
for (const key of ['duplicates']) {
|
|
expect(status.values.find(value => value.value === key)?.count).toBe(1);
|
|
expect(filterAndSortRecords(sheet, { activeProfile: genericProfile, dataset: loaded.dataset,
|
|
search: '', statusFilter: key, sortColumn: '', sortDirection: 'asc', actionOnly: false, reviews: {} })).toHaveLength(1);
|
|
}
|
|
expect(status.values.find(value => value.value === 'deviation')?.count).toBe(0);
|
|
for (const key of ['conflicts', 'not-configured', 'passed']) {
|
|
expect(status.values.find(value => value.value === key)?.count).toBe(0);
|
|
}
|
|
const noHits = recountFacetsAgainstActiveFilters({ facets, records: [], filters: {}, reviews: {},
|
|
statusFilter: 'conflicts', matchesStatus: genericProfile.matchesStatus });
|
|
expect(noHits.find(facet => facet.source === 'profile-status')?.values.find(value => value.value === 'conflicts')?.count).toBe(0);
|
|
const html = renderToStaticMarkup(createElement(DynamicFilterControls, { facets: noHits, filters: {},
|
|
statusFilter: 'conflicts', onStatusFilter() {}, onFilter() {} }));
|
|
expect(html).toContain('value="conflicts" selected=""');
|
|
expect(html).toContain('Conflicts · 0');
|
|
const headers = sheet.rows[0];
|
|
const readiness = headers.indexOf('Evaluation readiness');
|
|
const savedRows = sheet.rows.slice(1).filter(row => row[headers.indexOf('Status')] !== 'Duplicates');
|
|
// These fixture comparisons intentionally reuse one identity: Work now groups them.
|
|
expect(savedRows).toHaveLength(1);
|
|
expect(savedRows.every(row => row[readiness].includes('Re-evaluation required'))).toBe(true);
|
|
expect(savedRows.every(row => row[headers.indexOf('Historical result')].includes('1.3.3'))).toBe(true);
|
|
expect(savedRows.every(row => row[headers.indexOf('Status')] === 'Review required')).toBe(true);
|
|
expect(savedRows.every(row => row[headers.indexOf('Description')].includes('1.3.3'))).toBe(false);
|
|
expect(JSON.stringify(previous)).toBe(before);
|
|
});
|
|
it('loads one actual import for current comparisons, missing settings and consistency rows', async () => {
|
|
const observations = [source('a'), source('b'), source('c')];
|
|
const match = comparison('match', ['a', 'b', 'c']);
|
|
const missing = comparison('missing', [], { customerState: 'missing', classification: 'confirmed_configured_deviation',
|
|
identity: { ...match.identity, id: 'identity-missing' },
|
|
comparator: { ...match.comparator, actual: undefined, relation: 'different' } });
|
|
const current = run([match, missing]);
|
|
current.run = { ...current.run, id: 'current', aggregationRunId: 'aggregation', evaluator: POLICY_EVALUATION_ENGINE,
|
|
baselineAnalysisIds: ['baseline'], completedAt: '2026-09-08T10:00:00Z' };
|
|
const previous = { ...current, run: { ...current.run, id: 'previous', completedAt: '2026-09-08T09:00:00Z' },
|
|
results: [comparison('old-match', ['a', 'b']), comparison('old-missing', [], { ...missing, id: 'old-missing' })] };
|
|
const history = { ...previous, run: { ...previous.run, id: 'history', aggregationRunId: 'superseded' } };
|
|
const model = { schemaVersion: 1, project: { id: 'synthetic', name: 'Synthetic' }, assessment: { id: 'slot', projectId: 'synthetic' },
|
|
scanRuns: [], importFiles: [], sourceTables: [], findingDefinitions: [], findingOccurrences: [], evidence: [], reviews: [], diagnostics: [] } as unknown as CanonicalAssessmentModel;
|
|
const reader = {
|
|
listProjectAssessments: vi.fn().mockResolvedValue([model.assessment]), loadAssessmentModel: vi.fn().mockResolvedValue(model),
|
|
queryUnifiedResults: vi.fn().mockResolvedValue({ total: observations.length, limit: 500, offset: 0, items: observations }),
|
|
listPolicyEvaluations: vi.fn().mockResolvedValue({ records: [previous, history, current] }),
|
|
getPolicyAnalysisOverview: vi.fn().mockResolvedValue({ current: { evaluationRunIds: ['current'] } })
|
|
};
|
|
const before = JSON.stringify([observations, previous, history, current]);
|
|
const workspace = await loadCanonicalProjectWorkspace(reader, 'synthetic', [], ['slot']);
|
|
expect(reader.getPolicyAnalysisOverview).toHaveBeenCalledExactlyOnceWith('synthetic');
|
|
const sheet = workspace.dataset!.sheets[0];
|
|
const [headers, ...rows] = sheet.rows;
|
|
expect(rows.map(row => row[headers.indexOf('Status')])).toEqual(['Pass', 'Not configured']);
|
|
expect(rows[0][headers.indexOf('Duplicates')]).toContain('setting');
|
|
expect(new Set(rows.map(row => row[headers.indexOf('Imported')]))).toEqual(new Set(['2026-09-06T00:00:00Z']));
|
|
expect(rows.map(row => row[headers.indexOf('Evaluated')])).toEqual([current.run.completedAt, current.run.completedAt]);
|
|
const facet = deriveDynamicFacets(sheet, workspace.dataset, genericProfile, {}).find(item => item.id === 'provenance:source-scan')!;
|
|
expect(facet.values).toHaveLength(1);
|
|
expect(facet.values[0]).toMatchObject({ label: 'GPOs · 2026-09-06T00:00:00Z', count: 2 });
|
|
expect(JSON.stringify([observations, previous, history, current])).toBe(before);
|
|
});
|
|
|
|
it('preserves distinct real import dates in GPO-only and mixed scanner workspaces', () => {
|
|
const first = source('a');
|
|
const second = source('b', 1, { importArtifactId: 'import-two', importedAt: '2026-09-07T00:00:00Z' });
|
|
const evaluations = [run([comparison('first', ['a'])]), run([comparison('second', ['b'])])];
|
|
evaluations.forEach((evaluation, index) => { evaluation.run.aggregationRunId = `aggregation-${index}`; });
|
|
const scanner = makeSheet('All', [['Title', 'Status', 'Source: Scan'], ['Synthetic scanner', 'Fail', 'Scanner · original']], '', 'Synthetic', { isProjectSheet: true });
|
|
for (const dataset of [null, { sheets: [scanner], scanTool: 'Scanner' } as ImportedDataset]) {
|
|
const combined = appendPolicyObservationsToDataset(dataset, 'Synthetic', [first, second], evaluations)!;
|
|
const sheet = combined.sheets[0];
|
|
const facet = deriveDynamicFacets(sheet, combined, genericProfile, {}).find(item => item.id === 'provenance:source-scan')!;
|
|
expect(facet.values.map(value => value.label).sort()).toEqual([
|
|
'GPOs · 2026-09-06T00:00:00Z', 'GPOs · 2026-09-07T00:00:00Z', ...(dataset ? ['Scanner · original'] : [])
|
|
]);
|
|
if (dataset) expect(sheet.rows[1].slice(0, 3)).toEqual(scanner.rows[1]);
|
|
}
|
|
});
|
|
|
|
it('never invents an import date from evaluation time when source context is unavailable', () => {
|
|
const missing = comparison('missing', [], { customerState: 'missing', classification: 'confirmed_configured_deviation',
|
|
comparator: { version: 1, comparator: { kind: 'equality' }, relation: 'different', baseline: { kind: 'integer', value: '1' }, diagnosticCodes: [] } });
|
|
const dataset = appendPolicyObservationsToDataset(null, 'Synthetic', [], [run([missing])])!;
|
|
const [headers, row] = dataset.sheets[0].rows;
|
|
expect(row[headers.indexOf('Imported')]).toBe('');
|
|
expect(row[headers.indexOf('Source: Scan')]).toBe('GPOs');
|
|
expect(dataset.lastModified).toBe(0);
|
|
});
|
|
|
|
it('keeps preferences and unsupported comparisons out of every baseline verdict', () => {
|
|
const drive = source('drive', 1, { policyDeliveryMechanism: 'group-policy-preference', policyIdentityStatus: 'unresolved',
|
|
policyIdentityKey: 'group-policy-preference:drive map:H:', policyPreferenceCse: 'drive-maps',
|
|
policyPreferenceAction: 'update', policyPreferenceTargeting: 'present' });
|
|
// A preference is retained evidence: never compared, but never silently dropped either.
|
|
expect(buildPolicyWorkResults([drive], [])).toMatchObject([{ status: 'Not comparable', conflict: false, duplicate: false }]);
|
|
expect(statuses([drive, { ...drive, sourceResultId: 'drive2' }])).toEqual(['Not comparable']);
|
|
// A retained comparison without a safe verdict stays reviewable instead of vanishing.
|
|
expect(statuses([source('a')], [comparison('r', ['a'], { classification: 'review_required' })])).toEqual(['Review required']);
|
|
// A resolved customer setting with no baseline rule at all reaches Work score-neutrally.
|
|
expect(statuses([source('a')])).toEqual(['No baseline rule']);
|
|
});
|
|
|
|
it('requires an explicit nonempty baseline and retains explicit zero and empty principal sets', () => {
|
|
const good = comparison('r', ['a']);
|
|
for (const baseline of [undefined, { kind: 'none' }, { kind: 'text', value: '' }] as const) {
|
|
expect(statuses([source('a')], [{ ...good, comparator: { ...good.comparator, baseline } }])).toEqual(['Review required']);
|
|
}
|
|
expect(statuses([source('a')], [{ ...good, baselineState: 'catalog-gap' }])).toEqual(['Review required']);
|
|
expect(statuses([source('a')], [{ ...good, comparator: { ...good.comparator, baseline: { kind: 'integer', value: '0' } } }])).toEqual(['Pass']);
|
|
expect(statuses([source('a')], [{ ...good, comparator: { ...good.comparator, baseline: { kind: 'string-set', values: [] } } }])).toEqual(['Pass']);
|
|
});
|
|
|
|
it('rolls multiple baseline comparisons into one verdict per technical setting', () => {
|
|
const pass = comparison('pass', ['a', 'b']);
|
|
const fail = comparison('fail', ['a', 'b'], { baselineLabel: 'Another baseline', classification: 'confirmed_configured_deviation',
|
|
comparator: { ...pass.comparator, relation: 'different', baseline: { kind: 'integer', value: '2' } } });
|
|
const results = buildPolicyWorkResults([source('a'), source('b')], [run([pass, fail, pass])]);
|
|
expect(countPolicyWorkResults(results)).toEqual({ Fail: 1, Pass: 0, Conflicts: 0, Duplicates: 1,
|
|
'Not configured': 0, 'Review required': 0, 'No baseline rule': 0, 'Not comparable': 0 });
|
|
expect(policyMisconfigurationImpact([...results, ...results])).toEqual({ settings: 1, backups: 2 });
|
|
expect(results.find(result => result.status === 'Pass')?.sources).toHaveLength(2);
|
|
});
|
|
|
|
it('projects conflicts and duplicates into Result DB without classifying them as deviations', () => {
|
|
const duplicate = createPolicyConsistencyUnifiedResults([source('duplicate-a'), source('duplicate-b')]);
|
|
const conflict = createPolicyConsistencyUnifiedResults([source('conflict-a', 0), source('conflict-b', 1)]);
|
|
const items = [...duplicate, ...conflict];
|
|
|
|
expect(items).toMatchObject([
|
|
{ policyClassification: 'duplicate', outcomeNormalized: 'warning', isDeviation: false, policySourceCount: 2 },
|
|
{ policyClassification: 'conflict', outcomeNormalized: 'warning', isDeviation: false, policySourceCount: 2 }
|
|
]);
|
|
expect(queryUnifiedResultItems(items, { deviation: true }).total).toBe(0);
|
|
expect(queryUnifiedResultItems(items, { policyClassification: ['duplicate'] }).items)
|
|
.toMatchObject([{ policyClassification: 'duplicate' }]);
|
|
expect(deriveUnifiedResultFacets(items, { deviation: true }).facets
|
|
.find(facet => facet.id === 'policyClassification')?.values)
|
|
.toEqual([]);
|
|
expect(deriveUnifiedResultFacets(items, {}).facets
|
|
.find(facet => facet.id === 'policyClassification')?.values)
|
|
.toEqual(expect.arrayContaining([
|
|
{ value: 'conflict', label: 'Conflicts', count: 1 },
|
|
{ value: 'duplicate', label: 'Duplicates', count: 1 }
|
|
]));
|
|
});
|
|
|
|
it('keeps baseline-only missing settings separate from Fail and Deviation', () => {
|
|
const missing = comparison('missing', [], { classification: 'confirmed_configured_deviation', customerState: 'missing' });
|
|
missing.comparator = { ...missing.comparator, actual: undefined, relation: 'different' };
|
|
const dataset = appendPolicyObservationsToDataset(null, 'Synthetic', [], [run([missing])])!;
|
|
const [headers, row] = dataset.sheets[0].rows;
|
|
expect(row[headers.indexOf('Status')]).toBe('Not configured');
|
|
expect(row[headers.indexOf('Configured Value')]).toBe('Not configured');
|
|
const record = dataset.sheets[0].analysis.records[0];
|
|
expect(genericProfile.matchesStatus(record, 'deviation')).toBe(false);
|
|
expect(genericProfile.matchesStatus(record, 'not-configured')).toBe(true);
|
|
expect(genericProfile.matchesStatus(record, 'all')).toBe(true);
|
|
expect(outcomeForStatusValue('group-policy', 'Not configured')).toBe('informational');
|
|
});
|
|
|
|
it('keeps only configured mismatches in Deviation even when other fields contain Fail or Open', () => {
|
|
for (const status of ['Pass', 'Not configured', 'Conflicts', 'Duplicates']) {
|
|
const sheet = makeSheet('GPOs', [['Category', 'Status', 'Description'], ['GPOs', status, 'Fail']], '', 'Synthetic');
|
|
expect(genericProfile.matchesStatus(sheet.analysis.records[0], 'deviation')).toBe(false);
|
|
}
|
|
const fail = makeSheet('GPOs', [['Category', 'Status', 'Configured Value'], ['GPOs', 'Fail', '0']], '', 'Synthetic');
|
|
expect(genericProfile.matchesStatus(fail.analysis.records[0], 'deviation')).toBe(true);
|
|
});
|
|
|
|
it('keeps Conflict as a category when one member makes the whole policy setting Fail', () => {
|
|
const evaluated = comparison('r', ['a', 'b'], {
|
|
customerState: 'conflicted', classification: 'confirmed_configured_deviation',
|
|
comparator: { version: 1, comparator: { kind: 'equality' }, relation: 'different',
|
|
baseline: { kind: 'integer', value: '1' }, diagnosticCodes: [] },
|
|
baselineVariantAssessment: { version: 1, scope: 'backup-configuration', decision: 'all-fail',
|
|
actualValues: [], variants: [], diagnosticCodes: [] }
|
|
});
|
|
const results = buildPolicyWorkResults([source('a', 0), source('b', 1)], [run([evaluated])]);
|
|
expect(results).toMatchObject([{ status: 'Fail', conflict: true }]);
|
|
expect(countPolicyWorkResults(results)).toMatchObject({ Fail: 1, Conflicts: 1 });
|
|
const dataset = appendPolicyObservationsToDataset(null, 'Synthetic', [source('a', 0), source('b', 1)], [run([evaluated])])!;
|
|
const record = dataset.sheets[0].analysis.records[0];
|
|
expect(genericProfile.matchesStatus(record, 'deviation')).toBe(true);
|
|
expect(genericProfile.matchesStatus(record, 'conflicts')).toBe(true);
|
|
});
|
|
|
|
it('compares registry address case-insensitively while preserving value data and type', () => {
|
|
const lower = source('b', 1, { policyValues: [{ kind: 'registry-policy', key: 'software\\policies\\synthetic',
|
|
valueName: 'MODE', operation: 'set-value', typeCode: 4, data: { kind: 'uint32', value: 1 } }] });
|
|
expect(buildPolicyWorkResults([source('a'), lower], [])).toMatchObject([{ status: 'No baseline rule', duplicate: true }]);
|
|
const text = source('b', 1, { policyValues: [{ kind: 'registry-policy', key: 'Software\\Policies\\Synthetic',
|
|
valueName: 'Mode', operation: 'set-value', typeCode: 1, data: { kind: 'string', value: '1' } }] });
|
|
expect(buildPolicyWorkResults([source('a'), text], [])).toMatchObject([{ status: 'No baseline rule', conflict: true }]);
|
|
const expanded = { ...text, sourceResultId: 'c', policyValues: [{ ...(text.policyValues![0] as object), typeCode: 2 }] } as UnifiedResultProjection;
|
|
expect(buildPolicyWorkResults([text, expanded], [])).toMatchObject([{ status: 'No baseline rule', conflict: true }]);
|
|
});
|
|
|
|
it('keeps distinct value names, user/computer scopes, and timeslots separate', () => {
|
|
const otherName = source('b', 1, { policyIdentityKey: 'identity-another', policyValues: [{ kind: 'registry-policy', key: 'Software\\Policies\\Synthetic',
|
|
valueName: 'Another', operation: 'set-value', typeCode: 4, data: { kind: 'uint32', value: 1 } }] });
|
|
// Separate rows per technical setting, never one merged consistency group.
|
|
const separate = ['No baseline rule', 'No baseline rule'];
|
|
expect(statuses([source('a'), otherName])).toEqual(separate);
|
|
expect(statuses([source('a'), source('b', 1, { policyScope: 'user' })])).toEqual(separate);
|
|
expect(statuses([source('a'), source('b', 1, { assessmentId: 'another-slot' })])).toEqual(separate);
|
|
for (const result of buildPolicyWorkResults([source('a'), otherName], [])) {
|
|
expect(result.conflict).toBe(false);
|
|
expect(result.duplicate).toBe(false);
|
|
}
|
|
// The comparison already covers the identity, so no second row is invented for it.
|
|
expect(statuses([source('a')], [comparison('mixed', ['a', 'absent-source'])])).toEqual([]);
|
|
});
|
|
|
|
it('deduplicates repeated read rows without counting baseline comparisons as duplicate customer settings', () => {
|
|
const a = source('a');
|
|
expect(buildPolicyWorkResults([a, a], [])).toMatchObject([{ status: 'No baseline rule', duplicate: false }]);
|
|
expect(statuses([a], [comparison('r1', ['a']), comparison('r2', ['a'])])).toEqual(['Pass', 'Pass']);
|
|
});
|
|
|
|
it('surfaces explicitly conflicting baseline recommendations', () => {
|
|
expect(statuses([source('a')], [comparison('r', ['a'], { classification: 'review_required',
|
|
diagnosticCodes: ['policy-evaluation-baseline-consensus-conflict'] })])).toEqual(['Conflicts']);
|
|
});
|
|
|
|
it('does not repeat stale aggregation conflicts when the source evidence proves identical values', () => {
|
|
expect(buildPolicyWorkResults([source('a'), source('b')], [run([comparison('old', ['a', 'b'], {
|
|
classification: 'review_required', customerState: 'conflicted'
|
|
})])])).toMatchObject([{ status: 'Review required', conflict: false, duplicate: true }]);
|
|
});
|
|
|
|
it('handles a 2300-GPO source set with one deterministic row per duplicate group', () => {
|
|
const sources = Array.from({ length: 2300 }, (_, index) => source(String(index)));
|
|
const result = buildPolicyWorkResults(sources, []);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0]).toMatchObject({ status: 'No baseline rule', duplicate: true });
|
|
expect(result[0].sources).toHaveLength(2300);
|
|
});
|
|
|
|
it('selects configured settings without a baseline rule through the Work Result Status filter', () => {
|
|
const evaluated = source('evaluated');
|
|
const orphan = source('orphan', 7, { policyIdentityKey: 'identity-orphan', sourceResultId: 'orphan',
|
|
resultProjectionId: 'policy-observation:orphan', title: 'Orphan',
|
|
policyValues: [{ kind: 'registry-policy', key: 'Software\Policies\Other', valueName: 'Orphan',
|
|
operation: 'set-value', typeCode: 4, data: { kind: 'uint32', value: 7 } }] });
|
|
const observations = [evaluated, orphan];
|
|
const evaluations = [run([comparison('pass', ['evaluated'])])];
|
|
const results = buildPolicyWorkResults(observations, evaluations);
|
|
|
|
// Every resolved customer setting reaches Work under exactly one verdict.
|
|
expect(results.map(result => result.status).sort()).toEqual(['No baseline rule', 'Pass']);
|
|
expect(countPolicyWorkResults(results)).toMatchObject({ Pass: 1, 'No baseline rule': 1, Fail: 0 });
|
|
// Score-neutral: it is never a misconfiguration or a GPO impact source.
|
|
expect(policyMisconfigurationImpact(results)).toEqual({ settings: 0, backups: 0 });
|
|
|
|
const dataset = appendPolicyObservationsToDataset(null, 'Synthetic', observations, evaluations)!;
|
|
const sheet = dataset.sheets[0];
|
|
const select = (statusFilter: string) => filterAndSortRecords(sheet, { activeProfile: genericProfile, dataset,
|
|
search: '', statusFilter, sortColumn: '', sortDirection: 'asc', actionOnly: false, reviews: {} });
|
|
expect(select('no-baseline-rule')).toHaveLength(1);
|
|
expect(select('no-baseline-rule')[0].fields.find(field => field.label === 'Technical Identity')?.value)
|
|
.toBe('identity-orphan');
|
|
// The retained customer value stays inspectable instead of reading as an absent setting.
|
|
expect(select('no-baseline-rule')[0].fields.find(field => field.label === 'Configured Value')?.value)
|
|
.toContain('"value":7');
|
|
expect(select('deviation')).toHaveLength(0);
|
|
expect(select('not-configured')).toHaveLength(0);
|
|
expect(select('passed')).toHaveLength(1);
|
|
|
|
const facets = deriveDynamicFacets(sheet, dataset, genericProfile, {});
|
|
const status = facets.find(facet => facet.source === 'profile-status')!;
|
|
expect(status.values.find(value => value.value === 'no-baseline-rule')?.count).toBe(1);
|
|
});
|
|
|
|
it('selects Group Policy Preferences through the Work Result Status filter without comparing them', () => {
|
|
const preference = (id: string, cse: 'local-users-groups' | 'drive-maps', key: string) => source(id, 1, {
|
|
sourceResultId: id, resultProjectionId: 'policy-observation:' + id, title: `${cse} · ${key}`,
|
|
policyDeliveryMechanism: 'group-policy-preference', policyIdentityStatus: 'unresolved',
|
|
policyIdentityKey: `group-policy-preference:${cse}:${key}`, policyPreferenceCse: cse,
|
|
policyPreferenceAction: 'replace', policyPreferenceTargeting: cse === 'drive-maps' ? 'present' : 'none',
|
|
policyDiagnosticCodes: ['identity-resolver-unsupported-group-policy-preference']
|
|
});
|
|
const observations = [source('evaluated'), preference('gpp-group', 'local-users-groups', 'Administrators'),
|
|
preference('gpp-drive', 'drive-maps', 'H:')];
|
|
const evaluations = [run([comparison('pass', ['evaluated'])])];
|
|
const results = buildPolicyWorkResults(observations, evaluations);
|
|
|
|
expect(results.map(result => result.status).sort()).toEqual(['Not comparable', 'Not comparable', 'Pass']);
|
|
expect(countPolicyWorkResults(results)).toMatchObject({ Pass: 1, 'Not comparable': 2, Fail: 0,
|
|
'No baseline rule': 0, Conflicts: 0, Duplicates: 0 });
|
|
// Score-neutral and never a misconfiguration source.
|
|
expect(policyMisconfigurationImpact(results)).toEqual({ settings: 0, backups: 0 });
|
|
|
|
const dataset = appendPolicyObservationsToDataset(null, 'Synthetic', observations, evaluations)!;
|
|
const sheet = dataset.sheets[0];
|
|
const select = (statusFilter: string) => filterAndSortRecords(sheet, { activeProfile: genericProfile, dataset,
|
|
search: '', statusFilter, sortColumn: '', sortDirection: 'asc', actionOnly: false, reviews: {} });
|
|
expect(select('not-comparable')).toHaveLength(2);
|
|
expect(select('deviation')).toHaveLength(0);
|
|
expect(select('not-configured')).toHaveLength(0);
|
|
expect(select('no-baseline-rule')).toHaveLength(0);
|
|
|
|
const field = (label: string) => select('not-comparable')
|
|
.map(record => record.fields.find(item => item.label === label)?.value);
|
|
// The retained preference context stays readable in the agreed columns; no new column is added.
|
|
expect(field('Policy type')).toEqual(['group-policy-preference', 'group-policy-preference']);
|
|
expect(field('Policy section').sort()).toEqual(['drive maps', 'local users and groups']);
|
|
expect(field('Comparison').every(value => value?.includes('not compared with a Microsoft baseline'))).toBe(true);
|
|
expect(field('Comparison').some(value => value?.includes('item-level targeting: present'))).toBe(true);
|
|
expect(field('Comparison').some(value => value?.includes('action: replace'))).toBe(true);
|
|
// Preferences use the agreed GPO columns; no extra column and therefore no extra facet.
|
|
const withoutPreferences = appendPolicyObservationsToDataset(null, 'Synthetic', [source('evaluated')], evaluations)!;
|
|
expect(sheet.analysis.headers).toEqual(withoutPreferences.sheets[0].analysis.headers);
|
|
|
|
const facets = deriveDynamicFacets(sheet, dataset, genericProfile, {});
|
|
expect(facets.find(facet => facet.source === 'profile-status')!
|
|
.values.find(value => value.value === 'not-comparable')?.count).toBe(2);
|
|
});
|
|
|
|
it('prefers the run covering more baselines, not the one listing more analysis references', () => {
|
|
const observations = [source('a')];
|
|
const withDuplicateGenerations = run([comparison('old', ['a'], { baselineId: 'one' }),
|
|
comparison('old-again', ['a'], { baselineId: 'one' })]);
|
|
withDuplicateGenerations.run = { ...withDuplicateGenerations.run, id: 'stale', aggregationRunId: 'aggregation',
|
|
completedAt: '2026-09-17T10:00:00Z', evaluator: POLICY_EVALUATION_ENGINE,
|
|
baselineAnalysisIds: ['gen-a', 'gen-b'] } as never;
|
|
const singleGeneration = run([comparison('fresh', ['a'], { baselineId: 'one',
|
|
classification: 'confirmed_configured_deviation',
|
|
comparator: { version: 1, comparator: { kind: 'equality' }, relation: 'different',
|
|
actual: { kind: 'integer', value: '1' }, baseline: { kind: 'integer', value: '2' }, diagnosticCodes: [] } })]);
|
|
singleGeneration.run = { ...singleGeneration.run, id: 'fresh', aggregationRunId: 'aggregation',
|
|
completedAt: '2026-09-17T12:00:00Z', evaluator: POLICY_EVALUATION_ENGINE,
|
|
baselineAnalysisIds: ['gen-b'] } as never;
|
|
|
|
// Two retained generations of one baseline are one benchmark, not broader coverage.
|
|
const selected = selectCurrentPolicyEvaluations([withDuplicateGenerations, singleGeneration],
|
|
{ allowPreviousVersionForDisplay: true });
|
|
expect(selected.map(item => item.run.id)).toEqual(['fresh']);
|
|
expect(buildPolicyWorkResults(observations, selected).map(item => item.status)).toEqual(['Fail']);
|
|
});
|
|
|
|
it('preserves scanner sheets and exposes GPO warning statuses in the project aggregate', () => {
|
|
const aggregate = makeSheet('All Records', [['Source: Scan', 'Title', 'Status'],
|
|
['PurpleKnight · 2026-09-06', 'Synthetic scanner finding', 'Failed']], '', 'Synthetic', { isProjectSheet: true });
|
|
const scanner = makeSheet('Scanner', [['Title'], ['Synthetic']], '', 'Synthetic', { toolId: 'purple-knight' });
|
|
const dataset = { fileName: 'Synthetic', fileSize: 0, lastModified: 0, format: 'Project', rawText: '',
|
|
sheets: [aggregate, scanner], profileId: 'generic' } as ImportedDataset;
|
|
const result = appendPolicyObservationsToDataset(dataset, 'Synthetic', [source('a'), source('b')])!;
|
|
expect(result.sheets).toHaveLength(3);
|
|
expect(result.sheets[2]).toBe(scanner);
|
|
const record = result.sheets[0].analysis.records.find(record =>
|
|
record.fields.some(field => field.label === 'Status' && field.value === 'No baseline rule'))!;
|
|
expect(toolIdForRecord(record, 'generic')).toBe('group-policy');
|
|
expect(outcomeForStatusValue('group-policy', 'Duplicates')).toBe('warning');
|
|
expect(outcomeForStatusValue('group-policy', 'Conflicts')).toBe('warning');
|
|
// Score-neutral: a setting without an applicable baseline rule is never a deviation.
|
|
expect(outcomeForStatusValue('group-policy', 'No baseline rule')).toBe('informational');
|
|
// A single configured setting is no longer dropped: it reaches Work as its own row.
|
|
const single = appendPolicyObservationsToDataset(dataset, 'Synthetic', [source('a')])!;
|
|
expect(single).not.toBe(dataset);
|
|
expect(single.sheets[1].analysis.records).toHaveLength(1);
|
|
// An unresolved identity is no longer dropped either: it reaches Work as 'Not comparable'.
|
|
const unresolved = appendPolicyObservationsToDataset(dataset, 'Synthetic',
|
|
[source('a', 1, { policyIdentityStatus: 'unresolved' })])!;
|
|
expect(unresolved.sheets[1].analysis.records).toHaveLength(1);
|
|
expect(unresolved.sheets[1].analysis.records[0].fields
|
|
.find(field => field.label === 'Status')?.value).toBe('Not comparable');
|
|
});
|
|
});
|