import { describe, expect, it, vi } from 'vitest'; import { GpoAutomaticAnalysisService } from '../../server/gpo/gpo-automatic-analysis-service'; import { ingestGpoBackupContainer } from '../../server/gpo/gpo-backup-ingestion'; import { syntheticGpoBackupZip } from './gpo-synthetic-fixture'; import type { AssessorRepository } from '../../src/persistence/assessor-repository'; import type { GpoPolicySnapshotService } from '../../server/gpo/gpo-policy-snapshot-service'; import type { GpoPolicyEvaluationService } from '../../server/gpo/gpo-policy-evaluation-service'; import type { GpoPolicyFindingService } from '../../server/gpo/gpo-policy-finding-service'; const timestamp = '2026-09-06T10:00:00Z'; function setup() { const instances = ingestGpoBackupContainer(syntheticGpoBackupZip(), { projectId: 'project', sourceArtifactId: 'artifact', discoveredAt: timestamp }).backupInstances.map(instance => ({ processingRunId: 'processing', instance })); const environment = { observations: [{ id: 'dc-os', state: 'observed', property: 'operating_system.name', originalValue: 'Windows 2019', subject: { type: 'computer-information.domain-controllers' } }] }; const repository = { listGpoPolicyAnalyses: vi.fn().mockResolvedValue([{ run: { id: 'analysis', sourceProcessingRunId: 'processing', artifactId: 'artifact', completedAt: timestamp } }]), listImportArtifacts: vi.fn().mockResolvedValue([{ id: 'artifact', assessmentId: 'slot' }]), getEnvironmentSnapshot: vi.fn().mockResolvedValue(environment), listGpoBackupInstances: vi.fn().mockResolvedValue(instances), listMicrosoftSecurityBaselines: vi.fn().mockResolvedValue([{ id: 'baseline', status: 'eligible', metadata: { productFamily: 'Windows Server', productVersion: '2019', roles: ['Domain Controller'], scopes: ['computer'] } }]), listMicrosoftSecurityBaselineAnalyses: vi.fn().mockResolvedValue([{ analysis: { id: 'baseline-analysis', baselineId: 'baseline' } }]) }; const snapshots = { createEnvironmentProfile: vi.fn().mockResolvedValue({ id: 'profile' }), aggregate: vi.fn().mockResolvedValue({ run: { id: 'aggregation' } }) }; const evaluations = { evaluate: vi.fn().mockResolvedValue({ run: { id: 'evaluation', status: 'partial' } }) }; const findings = { create: vi.fn().mockResolvedValue({}) }; const service = new GpoAutomaticAnalysisService(repository as unknown as AssessorRepository, snapshots as unknown as GpoPolicySnapshotService, evaluations as unknown as GpoPolicyEvaluationService, findings as unknown as GpoPolicyFindingService); return { service, repository, snapshots, evaluations, findings, environment, instances }; } describe('automatic GPO analysis', () => { it('uses timeslot-local observed context and the matching persisted baseline', async () => { const test = setup(); const results = await Promise.all([test.service.run('project', 'processing'), test.service.run('project', 'processing')]); expect(results).toEqual([{ state: 'review', evaluationRunId: 'evaluation' }, { state: 'review', evaluationRunId: 'evaluation' }]); expect(test.repository.getEnvironmentSnapshot).toHaveBeenCalledWith({ projectId: 'project', assessmentId: 'slot' }); expect(test.snapshots.createEnvironmentProfile).toHaveBeenCalledWith('project', expect.objectContaining({ contexts: expect.arrayContaining([ expect.objectContaining({ productVersion: '2019', role: 'Domain Controller', sourceObservationIds: ['dc-os'] }), expect.objectContaining({ id: 'gpo-baseline-comparison', scope: 'mixed' }) ]) })); expect(test.snapshots.aggregate).toHaveBeenCalledWith('project', { environmentProfileId: 'profile', sourceAnalysisRunIds: ['analysis'] }); expect(test.evaluations.evaluate).toHaveBeenCalledTimes(1); expect(test.evaluations.evaluate).toHaveBeenCalledWith('project', { aggregationRunId: 'aggregation', baselineAnalysisIds: ['baseline-analysis'] }); }); it('evaluates imported baselines without requiring an inferred operating-system context', async () => { const test = setup(); test.environment.observations[0].property = 'domain.functional_level'; expect(await test.service.run('project', 'processing')).toEqual({ state: 'review', evaluationRunId: 'evaluation' }); expect(test.snapshots.createEnvironmentProfile).toHaveBeenCalledWith('project', expect.objectContaining({ contexts: [expect.objectContaining({ id: 'gpo-baseline-comparison', scope: 'mixed' })] })); expect(test.evaluations.evaluate).toHaveBeenCalledWith('project', { aggregationRunId: 'aggregation', baselineAnalysisIds: ['baseline-analysis'] }); }); it('does not make the neutral comparison depend on a global server-role choice', async () => { const test = setup(); test.repository.getEnvironmentSnapshot.mockResolvedValue({ observations: [ ...test.environment.observations, { id: 'inventory-os', state: 'observed', property: 'operating_system.name', originalValue: 'Windows Server 2019', subject: { type: 'computer-information.operating-systems', identity: 'server-row' } }, { id: 'inventory-count', state: 'observed', property: 'operating_system.count', originalValue: 2, subject: { type: 'computer-information.operating-systems', identity: 'server-row' } } ] }); expect(await test.service.run('project', 'processing')).toEqual({ state: 'review', evaluationRunId: 'evaluation' }); expect(test.evaluations.evaluate).toHaveBeenCalledTimes(1); }); it('keeps incompatible snapshot groups in review without failing the parsed import', async () => { const test = setup(); test.instances.push({ ...test.instances[0], instance: { ...test.instances[0].instance, id: 'other-backup', backupSet: { ...test.instances[0].instance.backupSet, id: 'other-backup-set' }, domain: { status: 'unknown' }, policyObservations: [] } }); expect(await test.service.run('project', 'processing')).toEqual({ state: 'review', diagnosticCode: 'policy-aggregation-multiple-snapshots' }); expect(test.evaluations.evaluate).not.toHaveBeenCalled(); }); it('compares independent active baseline analyses instead of treating them as ambiguous', async () => { const test = setup(); test.repository.listMicrosoftSecurityBaselineAnalyses.mockResolvedValue([ { analysis: { id: 'one', baselineId: 'baseline' } }, { analysis: { id: 'two', baselineId: 'baseline' } } ]); expect(await test.service.run('project', 'processing')).toEqual({ state: 'review', evaluationRunId: 'evaluation' }); expect(test.evaluations.evaluate).toHaveBeenCalledWith('project', { aggregationRunId: 'aggregation', baselineAnalysisIds: ['one', 'two'] }); }); it('evaluates every eligible imported baseline as a separate benchmark', async () => { const test = setup(); test.repository.listMicrosoftSecurityBaselines.mockResolvedValue([ { id: 'baseline', status: 'eligible', metadata: { productFamily: 'Windows Server', productVersion: '2019', roles: ['Any'], scopes: ['computer'] } }, { id: 'unrelated', status: 'eligible', metadata: { productFamily: 'Windows 11', productVersion: '24H2', roles: ['Any'], scopes: ['computer'] } } ]); test.repository.listMicrosoftSecurityBaselineAnalyses.mockResolvedValue([ { analysis: { id: 'baseline-analysis', baselineId: 'baseline' } }, { analysis: { id: 'unrelated-analysis', baselineId: 'unrelated' } } ]); await test.service.run('project', 'processing'); expect(test.evaluations.evaluate).toHaveBeenCalledWith('project', { aggregationRunId: 'aggregation', baselineAnalysisIds: ['baseline-analysis', 'unrelated-analysis'] }); }); it('excludes baseline packages whose metadata is not eligible', async () => { const test = setup(); test.repository.listMicrosoftSecurityBaselines.mockResolvedValue([ { id: 'baseline', status: 'eligible', metadata: { productFamily: 'Windows Server', productVersion: '2019', roles: ['Any'], scopes: ['computer'] } }, { id: 'unclassified', status: 'metadata-required', metadata: { roles: ['Any'], scopes: ['mixed'] } } ]); test.repository.listMicrosoftSecurityBaselineAnalyses.mockResolvedValue([ { analysis: { id: 'baseline-analysis', baselineId: 'baseline' } }, { analysis: { id: 'unclassified-analysis', baselineId: 'unclassified' } } ]); await test.service.run('project', 'processing'); expect(test.evaluations.evaluate).toHaveBeenCalledWith('project', { aggregationRunId: 'aggregation', baselineAnalysisIds: ['baseline-analysis'] }); }); });