Assessor_2.0/tests/server/gpo-policy-evaluation-servi...

227 lines
14 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { buildPolicyEvaluation } from '../../server/gpo/gpo-policy-evaluation-service';
import { buildPolicyFindingRun } from '../../server/gpo/gpo-policy-finding-service';
import type { MicrosoftSecurityBaselineRecord } from '../../src/domain/microsoft-security-baseline';
import type { StoredMicrosoftSecurityBaselineAnalysis } from '../../src/domain/microsoft-security-baseline-analysis';
import type { GpoRegistryPolicyValue } from '../../src/domain/gpo-policy';
import type { GpoTechnicalPolicyIdentity } from '../../src/domain/gpo-policy-identity';
import type { EnvironmentProfile, StoredPolicySnapshotAggregation } from '../../src/domain/gpo-snapshot-aggregation';
import type { PolicyEvaluationRuleCatalog } from '../../src/domain/policy-evaluation-rules';
const timestamp = '2026-09-06T10:00:00.000Z';
const projectId = 'synthetic-policy-project';
const identity: GpoTechnicalPolicyIdentity = {
version: 1, id: 'gpo-policy-identity-' + '1'.repeat(32),
resolver: { id: 'gpo-technical-registry-target', version: '1.0.0' }, scope: 'computer',
target: { kind: 'registry-value', hive: 'HKEY_LOCAL_MACHINE', key: 'Software\\Policies\\Synthetic', valueName: 'Mode' },
admx: { status: 'not-found' }
};
const profile: EnvironmentProfile = {
version: 1, id: 'synthetic-profile', projectId, name: 'Synthetic', revision: 1,
contexts: [{ version: 1, id: 'all', kind: 'operating-system', productFamily: 'Group Policy',
productVersion: 'All imported baselines', role: 'Any', scope: 'mixed' }], createdAt: timestamp
};
const ruleCatalog: PolicyEvaluationRuleCatalog = {
version: 1, id: 'synthetic-empty-catalog',
catalog: { id: 'policy-evaluation-rule-catalog', version: '1.0.0' }, status: 'released', rules: []
};
function value(number: number): GpoRegistryPolicyValue {
return { kind: 'registry-policy', operation: 'set-value', key: 'Software\\Policies\\Synthetic',
valueName: 'Mode', typeCode: 4, data: { kind: 'uint32', value: number } };
}
function aggregation(actual?: number, options: { partial?: boolean; conflicted?: boolean } = {}): StoredPolicySnapshotAggregation {
const states = actual === undefined ? [] : [{
version: 1 as const, id: 'synthetic-state', aggregationRunId: 'synthetic-aggregation', identity,
deliveryMechanism: 'registry-policy' as const, status: options.conflicted ? 'conflicted' as const : 'configured' as const,
values: options.conflicted ? [value(actual), value(actual + 1)] : [value(actual)],
observationIds: ['synthetic-observation'], backupInstanceIds: ['synthetic-backup'], applicableContextIds: ['all'],
ordering: options.conflicted ? 'cross-gpo-conflict' as const : 'single-gpo' as const,
targeting: 'none' as const, completeness: 'complete' as const, effectiveState: 'unknown' as const, diagnosticCodes: []
}];
return {
version: 1,
run: { version: 1, id: 'synthetic-aggregation', projectId, environmentProfileId: profile.id,
sourceAnalysisRunIds: ['synthetic-analysis'], snapshotId: 'synthetic-snapshot',
aggregator: { id: 'gpo-policy-snapshot-aggregation', version: '1.1.0' },
status: options.partial ? 'partial' : 'complete', stateCount: states.length,
conflictCount: options.conflicted ? 1 : 0, unresolvedIdentityCount: 0, reviewHintCount: 0,
permitsFindingGeneration: false, diagnosticCodes: options.partial ? ['policy-aggregation-snapshot-incomplete'] : [],
startedAt: timestamp, completedAt: timestamp },
snapshot: { version: 1, id: 'synthetic-snapshot', projectId,
domain: { status: 'resolved', key: 'synthetic.example', evidence: 'backup-metadata' },
backupSetId: 'synthetic-set', instanceIds: ['synthetic-backup'], status: 'consistent',
completeness: options.partial ? 'selected-subset' : 'complete', permitsSetAbsenceConclusions: !options.partial,
diagnosticCodes: [], createdAt: timestamp },
states,
reviewHints: []
};
}
function baseline(name: string, recommended: number): {
record: MicrosoftSecurityBaselineRecord;
analysis: StoredMicrosoftSecurityBaselineAnalysis;
} {
const baselineId = `baseline-${name}`;
const analysisId = `baseline-analysis-${name}`;
const sha256 = name.padEnd(64, 'a').slice(0, 64).replace(/[^a-f0-9]/g, 'a');
return {
record: { version: 1, id: baselineId, fileName: `${name}.zip`, sha256, sizeBytes: 100,
storageKey: `baseline/${name}`, importedAt: timestamp, status: 'eligible',
metadata: { roles: ['Any'], scopes: ['mixed'], source: 'confirmed' } },
analysis: { version: 1, analysis: { version: 1, id: analysisId, baselineId, packageSha256: sha256,
analyzer: { id: 'microsoft-baseline-gpo-settings', version: '1.1.0' }, analyzedAt: timestamp,
status: 'complete', admxCatalog: { version: 1, id: `catalog-${name}`,
parser: { id: 'admx-policy-metadata-catalog', version: '1.0.0' },
source: { kind: 'microsoft-security-baseline', baselineId, packageSha256: sha256 },
status: 'complete', policies: [], languageResources: [], diagnosticCodes: [] },
backupCount: 1, registryPolicyFileCount: 1, settings: [{ version: 1, id: `setting-${name}`,
baselineId, backupId: `backup-${name}`, observation: { sourcePath: 'synthetic/Registry.pol',
sourceSha256: 'b'.repeat(64), scope: 'computer', deliveryMechanism: 'registry-policy',
parser: { id: 'registry-policy-preg', version: '1.0.0' },
reducer: { id: 'registry-policy-reducer', version: '1.0.0' }, state: 'instruction',
values: [value(recommended)], registryPolicy: { sequence: 0, operation: 'set-value' },
effectiveState: 'unknown', diagnosticCodes: [] },
identity: { version: 1, status: 'resolved', identity } }], diagnosticCodes: [] } }
};
}
function evaluate(actual: number | undefined, sources = [baseline('primary', 1)], options: { partial?: boolean; conflicted?: boolean } = {}) {
return buildPolicyEvaluation({ profile, aggregation: aggregation(actual, options),
baselineRecords: sources.map(source => source.record), baselineAnalyses: sources.map(source => source.analysis),
ruleCatalog, startedAt: timestamp, completedAt: timestamp });
}
describe('baseline-driven policy evaluation', () => {
function templates() {
const source = baseline('roles', 1);
const original = source.analysis.analysis.settings[0];
source.analysis.analysis.settings = ['Client', 'Member Server', 'Domain Controller'].map((role, index) => ({
...structuredClone(original), id: `role-setting-${index}`, backupId: `role-backup-${index}`,
observation: { ...structuredClone(original.observation), values: [value(index === 2 ? 1 : 0)] },
template: { names: [{ value: `Synthetic ${role}`, sourcePath: `Synthetic/${index}/Backup.xml`, sourceSha256: 'a'.repeat(64) }],
context: { productFamily: index === 0 ? 'Windows 10' : 'Windows Server', productVersion: index === 0 ? '1607' : '2016',
role: role as 'Client' | 'Member Server' | 'Domain Controller' } }
}));
return source;
}
function evaluateTemplates(source = templates(), target?: Partial<EnvironmentProfile['contexts'][number]>) {
const selectedProfile = target ? { ...profile, contexts: [{ ...profile.contexts[0], productFamily: 'Windows Server',
productVersion: '2016', role: 'Domain Controller', ...target }] } : profile;
return buildPolicyEvaluation({ profile: selectedProfile, aggregation: aggregation(1),
baselineRecords: [source.record], baselineAnalyses: [source.analysis], ruleCatalog,
startedAt: timestamp, completedAt: timestamp });
}
it('selects only the explicit comparison role and retains all candidate evidence', () => {
const source = templates();
const before = JSON.stringify(source);
const output = evaluateTemplates(source, {});
expect(output.results[0]).toMatchObject({ classification: 'configured_match', baselineSettingIds: ['role-setting-2'],
baselineTemplateSelection: { status: 'selected', candidateSettingIds: ['role-setting-0', 'role-setting-1', 'role-setting-2'] } });
expect(output.results[0].diagnosticCodes).not.toContain('policy-evaluation-baseline-consensus-conflict');
expect(output.evidence.filter(item => item.kind === 'baseline-setting')).toHaveLength(3);
expect(JSON.stringify(source)).toBe(before);
expect(evaluateTemplates(source, { role: 'Member Server' }).results[0].classification).toBe('confirmed_configured_deviation');
});
it('does not use observed inventory or a generic profile to choose the matching variant', () => {
for (const output of [evaluateTemplates(), evaluateTemplates(templates(), { sourceObservationIds: ['synthetic-os'] })]) {
expect(output.results[0].classification).toBe('review_required');
expect(output.results[0].diagnosticCodes).toContain('policy-evaluation-template-context-required');
expect(output.results[0].baselineSettingIds).toHaveLength(3);
}
});
it('keeps unanimous values comparable without a target-role decision', () => {
const source = templates();
source.analysis.analysis.settings.forEach(item => { item.observation.values = [value(1)]; });
expect(evaluateTemplates(source).results[0].classification).toBe('configured_match');
});
it('does not ignore unknown templates or conflicting values in the selected role', () => {
const unknown = templates();
unknown.analysis.analysis.settings[0].template = undefined;
expect(evaluateTemplates(unknown, {}).results[0].classification).toBe('review_required');
const conflict = templates();
const copy = structuredClone(conflict.analysis.analysis.settings[2]);
copy.id = 'role-setting-other'; copy.observation.values = [value(0)];
conflict.analysis.analysis.settings.push(copy);
expect(evaluateTemplates(conflict, {}).results[0].diagnosticCodes).toContain('policy-evaluation-baseline-consensus-conflict');
});
it('does not produce Pass or Fail for a mismatching OS version', () => {
expect(evaluateTemplates(templates(), { productVersion: '2025' }).results[0]).toMatchObject({
classification: 'review_required', baselineTemplateSelection: { status: 'no-match' }
});
});
it('reports exact values as Passed and different values as deviations', () => {
expect(evaluate(1)).toMatchObject({ run: { status: 'complete', matchCount: 1, deviationCount: 0 },
results: [{ customerState: 'configured', classification: 'configured_match',
comparator: { relation: 'match' }, findingEligibility: 'ineligible' }] });
expect(evaluate(2)).toMatchObject({ run: { status: 'complete', matchCount: 0, deviationCount: 1 },
results: [{ customerState: 'configured', classification: 'confirmed_configured_deviation',
comparator: { relation: 'different' }, findingEligibility: 'ineligible' }] });
});
it('creates a deviation when a recommended setting is missing from the customer backup', () => {
expect(evaluate(undefined)).toMatchObject({ run: { status: 'complete', deviationCount: 1 }, results: [{
aggregationStateId: undefined, customerState: 'missing', observationIds: [],
classification: 'confirmed_configured_deviation', comparator: { relation: 'different' }
}] });
});
it('does not emit actual-only settings without a baseline recommendation', () => {
const source = baseline('empty', 1);
source.analysis.analysis.settings = [];
expect(evaluate(2, [source])).toMatchObject({ run: { resultCount: 0, matchCount: 0, deviationCount: 0 }, results: [] });
});
it('does not emit PASS or FAIL for a structurally present baseline row without a Microsoft value', () => {
const source = baseline('blank', 1);
source.analysis.analysis.settings[0].observation.values = [];
expect(evaluate(undefined, [source])).toMatchObject({
run: { resultCount: 0, matchCount: 0, deviationCount: 0, reviewCount: 0 },
results: []
});
});
it('keeps an unsupported baseline value out of PASS and FAIL', () => {
const source = baseline('unsupported', 1);
source.analysis.analysis.settings[0].observation.values = [{
kind: 'service-preference', serviceName: 'Synthetic', serviceAction: 'start',
startupType: 'automatic', passwordAttributePresent: false
}];
expect(evaluate(undefined, [source])).toMatchObject({
run: { deviationCount: 0, matchCount: 0, reviewCount: 1 },
results: [{ classification: 'review_required', baselineState: 'unsupported-setting' }]
});
});
it('compares every baseline independently', () => {
const record = evaluate(1, [baseline('one', 1), baseline('two', 2)]);
expect(record.run).toMatchObject({ resultCount: 2, matchCount: 1, deviationCount: 1, reviewCount: 0 });
expect(new Set(record.results.map(result => result.baselineAnalysisId))).toEqual(
new Set(['baseline-analysis-one', 'baseline-analysis-two'])
);
});
it('keeps configured comparison usable for a selected-subset backup', () => {
expect(evaluate(2, undefined, { partial: true })).toMatchObject({
run: { status: 'complete', deviationCount: 1, reviewCount: 0 },
results: [{ classification: 'confirmed_configured_deviation' }]
});
});
it('keeps conflicting customer values in review', () => {
expect(evaluate(1, undefined, { conflicted: true })).toMatchObject({
run: { status: 'partial', reviewCount: 1 }, results: [{ customerState: 'conflicted',
classification: 'review_required', diagnosticCodes: expect.arrayContaining(['policy-evaluation-customer-conflict']) }]
});
});
it('does not manufacture security findings from neutral comparison rows', () => {
const evaluation = evaluate(2);
const findings = buildPolicyFindingRun({ evaluation, aggregation: aggregation(2), profile,
startedAt: timestamp, completedAt: timestamp });
expect(findings).toMatchObject({ run: { status: 'complete', eligibleResultCount: 0, findingCount: 0 },
definitions: [], occurrences: [], rejections: [] });
});
});