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

507 lines
19 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 { createPolicyUnifiedResult } from '../../src/domain/unified-result';
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 { PolicyEvaluationRule, PolicyEvaluationRuleCatalog } from '../../src/domain/policy-evaluation-rules';
const timestamp = '2026-08-04T18:00:00.000Z';
const projectId = 'policy-evaluation-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: 'environment-profile-evaluation',
projectId,
name: 'Synthetic evaluation profile',
revision: 1,
contexts: [{
version: 1,
id: 'windows-server-2022',
kind: 'operating-system',
productFamily: 'Windows Server',
productVersion: '2022',
role: 'Member Server',
scope: 'computer'
}],
createdAt: timestamp
};
function evaluationRule(overrides: Partial<PolicyEvaluationRule> = {}): PolicyEvaluationRule {
return {
version: 1,
id: 'synthetic-policy-evaluation-rule',
identityId: identity.id,
deliveryMechanism: 'registry-policy',
contexts: [{
version: 1,
productFamily: 'Windows Server',
productVersion: '2022',
roles: ['Member Server'],
scopes: ['computer']
}],
baselineDisposition: 'explicit-recommendation',
comparator: { kind: 'equality' },
riskRule: { version: 1, id: 'synthetic-policy-risk', severity: 'high' },
dependencies: [],
...overrides
};
}
function ruleCatalog(rules: PolicyEvaluationRule[] = [evaluationRule()]): PolicyEvaluationRuleCatalog {
return {
version: 1,
id: 'synthetic-policy-evaluation-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: identity.target.key, valueName: 'Mode',
typeCode: 4, data: { kind: 'uint32', value: number }
};
}
function aggregation(actual: number, status: 'complete' | 'partial' = 'complete'): StoredPolicySnapshotAggregation {
return {
version: 1,
run: {
version: 1,
id: 'policy-snapshot-aggregation-evaluation',
projectId,
environmentProfileId: profile.id,
sourceAnalysisRunIds: ['identity-analysis-evaluation'],
snapshotId: 'snapshot-evaluation',
aggregator: { id: 'gpo-policy-snapshot-aggregation', version: '1.0.0' },
status,
stateCount: 1,
conflictCount: 0,
unresolvedIdentityCount: 0,
reviewHintCount: 0,
permitsFindingGeneration: false,
diagnosticCodes: status === 'complete' ? [] : ['policy-aggregation-snapshot-incomplete'],
startedAt: timestamp,
completedAt: timestamp
},
snapshot: {
version: 1,
id: 'snapshot-evaluation',
projectId,
domain: { status: 'resolved', key: 'synthetic.example', evidence: 'backup-metadata' },
backupSetId: 'set-evaluation',
instanceIds: ['backup-evaluation'],
status: 'consistent',
completeness: status === 'complete' ? 'complete' : 'selected-subset',
permitsSetAbsenceConclusions: status === 'complete',
diagnosticCodes: [],
createdAt: timestamp
},
states: [{
version: 1,
id: 'aggregated-state-evaluation',
aggregationRunId: 'policy-snapshot-aggregation-evaluation',
identity,
deliveryMechanism: 'registry-policy',
status: 'configured',
values: [value(actual)],
observationIds: ['observation-evaluation'],
backupInstanceIds: ['backup-evaluation'],
applicableContextIds: ['windows-server-2022'],
ordering: 'single-gpo',
targeting: 'none',
completeness: 'complete',
effectiveState: 'unknown',
diagnosticCodes: []
}],
reviewHints: []
};
}
function baseline(id: string, recommended: number, status: 'complete' | 'partial' = 'complete'):
{ record: MicrosoftSecurityBaselineRecord; analysis: StoredMicrosoftSecurityBaselineAnalysis } {
const baselineId = 'baseline-' + id;
const analysisId = 'baseline-analysis-' + id;
const packageSha256 = id.padEnd(64, 'a').slice(0, 64).replace(/[^a-f0-9]/g, 'a');
return {
record: {
version: 1,
id: baselineId,
fileName: id + '.zip',
sha256: packageSha256,
sizeBytes: 100,
storageKey: 'baseline/' + id,
importedAt: timestamp,
status: 'eligible',
metadata: {
productContexts: [{ productFamily: 'Windows Server', productVersion: '2022', roles: ['Member Server'], scopes: ['computer'] }],
roles: ['Member Server'], scopes: ['computer'], source: 'confirmed'
}
},
analysis: {
version: 1,
analysis: {
version: 1,
id: analysisId,
baselineId,
packageSha256,
analyzer: { id: 'microsoft-baseline-gpo-settings', version: '1.0.0' },
analyzedAt: timestamp,
status,
admxCatalog: {
version: 1,
id: 'admx-catalog-' + id,
parser: { id: 'admx-policy-metadata-catalog', version: '1.0.0' },
source: { kind: 'microsoft-security-baseline', baselineId, packageSha256 },
status,
policies: [],
languageResources: [],
diagnosticCodes: status === 'complete' ? [] : ['admx-catalog-partial']
},
backupCount: 1,
registryPolicyFileCount: 1,
settings: [{
version: 1,
id: 'baseline-setting-' + id,
baselineId,
backupId: 'baseline-backup-' + id,
observation: {
sourcePath: 'GPO/DomainSysvol/GPO/Machine/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: status === 'complete' ? [] : ['baseline-analysis-partial']
}
}
};
}
function evaluate(actual: number, recommended: number, options: { aggregationStatus?: 'complete' | 'partial'; baselineStatus?: 'complete' | 'partial' } = {}) {
const source = baseline('primary', recommended, options.baselineStatus);
return buildPolicyEvaluation({
profile,
aggregation: aggregation(actual, options.aggregationStatus),
baselineRecords: [source.record],
baselineAnalyses: [source.analysis],
ruleCatalog: ruleCatalog(),
startedAt: timestamp,
completedAt: timestamp
});
}
function evaluateWithCatalog(
actual: number,
recommended: number,
catalog: PolicyEvaluationRuleCatalog,
aggregated: StoredPolicySnapshotAggregation = aggregation(actual)
) {
const source = baseline('catalog-case', recommended);
return buildPolicyEvaluation({
profile,
aggregation: aggregated,
baselineRecords: [source.record],
baselineAnalyses: [source.analysis],
ruleCatalog: catalog,
startedAt: timestamp,
completedAt: timestamp
});
}
describe('policy baseline evaluation', () => {
it('distinguishes an exact match from a confirmed configured deviation', () => {
expect(evaluate(1, 1)).toMatchObject({
run: { status: 'complete', matchCount: 1, deviationCount: 0, projectedFindingCount: 0 },
results: [{ classification: 'configured_match', findingEligibility: 'ineligible', effectiveState: 'unknown' }]
});
expect(evaluate(2, 1)).toMatchObject({
run: { status: 'complete', matchCount: 0, deviationCount: 1, projectedFindingCount: 0 },
results: [{ classification: 'confirmed_configured_deviation', findingEligibility: 'eligible', effectiveState: 'unknown' }]
});
});
it('turns incomplete customer evidence into review and never into an eligible deviation', () => {
const record = evaluate(2, 1, { aggregationStatus: 'partial' });
expect(record.run).toMatchObject({ status: 'partial', deviationCount: 0, reviewCount: 1, projectedFindingCount: 0 });
expect(record.results[0]).toMatchObject({
classification: 'review_required',
findingEligibility: 'ineligible',
diagnosticCodes: expect.arrayContaining(['policy-evaluation-snapshot-incomplete'])
});
});
it('turns a partial baseline catalog into review', () => {
const record = evaluate(2, 1, { baselineStatus: 'partial' });
expect(record.results[0]).toMatchObject({
classification: 'review_required',
findingEligibility: 'ineligible',
diagnosticCodes: expect.arrayContaining(['policy-evaluation-baseline-incomplete'])
});
});
it('keeps a conflicting customer state as review', () => {
const source = baseline('conflict', 1);
const conflicted = aggregation(2);
conflicted.states[0].status = 'conflicted';
conflicted.states[0].values = [value(1), value(2)];
conflicted.run.conflictCount = 1;
const record = buildPolicyEvaluation({
profile, aggregation: conflicted, baselineRecords: [source.record], baselineAnalyses: [source.analysis],
ruleCatalog: ruleCatalog(),
startedAt: timestamp, completedAt: timestamp
});
expect(record.results[0]).toMatchObject({
classification: 'review_required', findingEligibility: 'ineligible',
diagnosticCodes: expect.arrayContaining(['policy-evaluation-customer-conflict'])
});
});
it('keeps a missing applicable baseline recommendation as review', () => {
const source = baseline('wrong-context', 1);
source.record.metadata.productContexts![0].productVersion = '2019';
const record = buildPolicyEvaluation({
ruleCatalog: ruleCatalog(),
profile, aggregation: aggregation(2), baselineRecords: [source.record], baselineAnalyses: [source.analysis],
startedAt: timestamp, completedAt: timestamp
});
expect(record.results[0]).toMatchObject({
classification: 'review_required', findingEligibility: 'ineligible',
diagnosticCodes: expect.arrayContaining(['policy-evaluation-baseline-missing'])
});
});
it('requires exactly one matching baseline per context', () => {
const first = baseline('first', 1);
const second = baseline('second', 1);
const record = buildPolicyEvaluation({
profile,
aggregation: aggregation(2),
baselineRecords: [first.record, second.record],
ruleCatalog: ruleCatalog(),
baselineAnalyses: [first.analysis, second.analysis],
startedAt: timestamp,
completedAt: timestamp
});
expect(record.results[0]).toMatchObject({
classification: 'review_required',
findingEligibility: 'ineligible',
diagnosticCodes: expect.arrayContaining(['policy-evaluation-baseline-ambiguous'])
});
});
it('requires an explicit setting-specific released rule instead of an implicit equality fallback', () => {
const record = evaluateWithCatalog(2, 1, ruleCatalog([]));
expect(record.results[0]).toMatchObject({
classification: 'review_required',
baselineState: 'catalog-gap',
findingEligibility: 'ineligible',
ruleIds: [],
diagnosticCodes: expect.arrayContaining(['policy-evaluation-rule-catalog-gap'])
});
});
it('uses an explicitly bound minimum comparator and a released risk rule', () => {
const catalog = ruleCatalog([evaluationRule({ comparator: { kind: 'minimum' } })]);
expect(evaluateWithCatalog(2, 1, catalog).results[0]).toMatchObject({
classification: 'configured_match',
baselineState: 'explicit-recommendation',
comparator: { relation: 'stronger', comparator: { kind: 'minimum' } },
riskRuleIds: ['synthetic-policy-risk'],
findingEligibility: 'ineligible'
});
expect(evaluateWithCatalog(0, 1, catalog).results[0]).toMatchObject({
classification: 'confirmed_configured_deviation',
comparator: { relation: 'weaker' },
findingEligibility: 'eligible'
});
});
it('persists an explicit not-applicable baseline state without a comparator or finding eligibility', () => {
const catalog = ruleCatalog([evaluationRule({
baselineDisposition: 'explicitly-not-applicable',
comparator: undefined,
riskRule: undefined
})]);
const record = evaluateWithCatalog(2, 1, catalog);
expect(record.run).toMatchObject({ status: 'complete', notApplicableCount: 1, projectedFindingCount: 0 });
expect(record.results[0]).toMatchObject({
classification: 'not_applicable',
baselineState: 'explicitly-not-applicable',
baselineSettingIds: [],
riskRuleIds: [],
findingEligibility: 'ineligible',
effectiveState: 'unknown'
});
});
it('treats a missing prerequisite as not applicable only for a complete absence-capable snapshot', () => {
const catalog = ruleCatalog([evaluationRule({ dependencies: [{
version: 1,
id: 'synthetic-prerequisite',
kind: 'prerequisite',
identityId: 'gpo-policy-identity-' + '2'.repeat(32),
deliveryMechanism: 'registry-policy'
}] })]);
expect(evaluateWithCatalog(2, 1, catalog).results[0]).toMatchObject({
classification: 'not_applicable',
baselineState: 'explicitly-not-applicable',
dependencyRuleIds: ['synthetic-prerequisite'],
findingEligibility: 'ineligible'
});
const incomplete = aggregation(2, 'partial');
incomplete.snapshot.permitsSetAbsenceConclusions = false;
expect(evaluateWithCatalog(2, 1, catalog, incomplete).results[0]).toMatchObject({
classification: 'review_required',
findingEligibility: 'ineligible',
diagnosticCodes: expect.arrayContaining([
'policy-dependency-target-absence-unknown',
'policy-evaluation-snapshot-incomplete'
])
});
});
it('keeps an active mutual exclusion as review instead of inventing precedence', () => {
const otherIdentity = { ...identity, id: 'gpo-policy-identity-' + '3'.repeat(32) };
const aggregated = aggregation(2);
aggregated.states.push({
...aggregated.states[0],
id: 'aggregated-state-mutual-exclusion',
identity: otherIdentity
});
aggregated.run.stateCount = 2;
const catalog = ruleCatalog([evaluationRule({ dependencies: [{
version: 1,
id: 'synthetic-mutual-exclusion',
kind: 'mutual-exclusion',
identityId: otherIdentity.id,
deliveryMechanism: 'registry-policy'
}] })]);
expect(evaluateWithCatalog(2, 1, catalog, aggregated).results.find(result => result.identity.id === identity.id)).toMatchObject({
classification: 'review_required',
findingEligibility: 'ineligible',
diagnosticCodes: expect.arrayContaining(['policy-dependency-mutual-exclusion-active'])
});
});
it('applies an explicit override as not applicable when the overriding state is configured', () => {
const otherIdentity = { ...identity, id: 'gpo-policy-identity-' + '4'.repeat(32) };
const aggregated = aggregation(2);
aggregated.states.push({
...aggregated.states[0],
id: 'aggregated-state-override',
identity: otherIdentity
});
aggregated.run.stateCount = 2;
const catalog = ruleCatalog([evaluationRule({ dependencies: [{
version: 1,
id: 'synthetic-override',
kind: 'override',
identityId: otherIdentity.id,
deliveryMechanism: 'registry-policy'
}] })]);
expect(evaluateWithCatalog(2, 1, catalog, aggregated).results.find(result => result.identity.id === identity.id)).toMatchObject({
classification: 'not_applicable',
baselineState: 'explicitly-not-applicable',
dependencyRuleIds: ['synthetic-override'],
findingEligibility: 'ineligible'
});
});
it('keeps an explicit no-recommendation state distinct and review-only', () => {
const catalog = ruleCatalog([evaluationRule({
baselineDisposition: 'no-recommendation',
comparator: undefined,
riskRule: undefined
})]);
const record = evaluateWithCatalog(2, 1, catalog);
expect(record.results[0]).toMatchObject({
classification: 'review_required',
baselineState: 'no-recommendation',
baselineSettingIds: [],
findingEligibility: 'ineligible',
diagnosticCodes: expect.arrayContaining(['policy-evaluation-no-recommendation'])
});
});
it('creates a policy finding only for a fully evidenced eligible configured deviation', () => {
const record = buildPolicyFindingRun({
evaluation: evaluate(2, 1),
aggregation: aggregation(2),
profile,
startedAt: timestamp,
completedAt: timestamp
});
expect(record).toMatchObject({
run: { status: 'complete', eligibleResultCount: 1, findingCount: 1, rejectedResultCount: 0 },
occurrences: [{
classification: 'confirmed_configured_deviation',
outcome: 'fail',
severity: 'high',
scopeState: 'unknown',
effectiveState: 'not-verified'
}],
rejections: []
});
const projected = createPolicyUnifiedResult({
definition: record.definitions[0],
occurrence: record.occurrences[0]
});
expect(projected).toMatchObject({
sourceKind: 'policy-evaluation',
resultType: 'policy_deviation',
outcomeNormalized: 'fail',
isIoe: false,
isDeviation: true,
effectiveState: 'unknown_effective_state',
scopeState: 'unknown',
effectivenessVerification: 'not-verified'
});
expect(projected).not.toHaveProperty('assessmentId');
});
it('never creates a finding when eligible evidence is incomplete or the result is not a deviation', () => {
const incomplete = structuredClone(evaluate(2, 1));
incomplete.evidence = incomplete.evidence.filter(item => item.kind !== 'baseline-setting');
const rejected = buildPolicyFindingRun({
evaluation: incomplete,
aggregation: aggregation(2),
profile,
startedAt: timestamp,
completedAt: timestamp
});
expect(rejected).toMatchObject({
run: { status: 'partial', eligibleResultCount: 1, findingCount: 0, rejectedResultCount: 1 },
occurrences: [],
rejections: [{ diagnosticCodes: expect.arrayContaining(['policy-finding-evidence-incomplete']) }]
});
const matched = buildPolicyFindingRun({
evaluation: evaluate(1, 1), aggregation: aggregation(1), profile,
startedAt: timestamp, completedAt: timestamp
});
expect(matched.run).toMatchObject({ status: 'complete', eligibleResultCount: 0, findingCount: 0 });
expect(matched.occurrences).toEqual([]);
});
});