import { describe, expect, it } from 'vitest'; import { artifactPathCollisionKey, normalizeArtifactRelativePath } from '../../src/domain/artifact-path'; import type { GpoBackupInstance } from '../../src/domain/gpo-ingestion'; import { gpoArtifactInventoryValidationErrors, gpoBackupCompleteness, gpoBackupInstanceValidationErrors } from '../../src/domain/gpo-ingestion'; import { buildGpoAnalysisSnapshots } from '../../src/gpo/snapshot-builder'; const timestamp = '2026-07-20T12:00:00.000Z'; function instance( id: string, gpoId: string, backupSetId: string, overrides: Partial = {} ): GpoBackupInstance { return { version: 1, id, projectId: 'project-synthetic', sourceArtifactId: `artifact-${id}`, identity: { status: 'resolved', gpoId, backupId: `${id.length.toString(16).padStart(8, '0')}-1111-4111-8111-111111111111`, evidence: 'backup-metadata' }, domain: { status: 'resolved', key: 'domain-synthetic', evidence: 'backup-metadata' }, collection: { status: 'observed', collectedAt: timestamp, evidence: 'collection-manifest' }, backupSet: { id: backupSetId, scope: 'complete-domain-export', evidence: 'collection-manifest', expectedGpoCount: 1 }, metadataStatus: 'complete', sections: { computer: 'empty', user: 'disabled' }, inventory: { version: 1, status: 'complete', entries: [{ version: 1, artifactId: `metadata-${id}`, relativePath: `${id}/Backup.xml`, role: 'backup-metadata', scope: 'shared', disposition: 'supported', secretIndicatorStatus: 'not-inspected' }], diagnosticCodes: [] }, discoveredAt: timestamp, ...overrides }; } describe('GPO ingestion contracts', () => { it('normalizes safe archive paths and rejects traversal, aliases and Windows special paths', () => { expect(normalizeArtifactRelativePath('Domain\\Policies\\Machine\\Registry.pol')) .toBe('Domain/Policies/Machine/Registry.pol'); expect(artifactPathCollisionKey('Domain/Backup.XML')).toBe('domain/backup.xml'); for (const unsafe of [ '../escape.xml', '/absolute.xml', '\\server\\share.xml', 'C:\\drive.xml', 'safe/../escape.xml', 'safe/file.xml:stream', 'safe/CON.txt', 'safe/name. ', 'safe//double.xml', 'safe/fi\u202ele.xml' ]) expect(normalizeArtifactRelativePath(unsafe)).toBeNull(); }); it('blocks case-colliding inventory paths and executable script treatment', () => { const value = instance('one', '11111111-1111-4111-8111-111111111111', 'set-one'); value.inventory.entries.push({ version: 1, artifactId: 'script-one', relativePath: 'ONE/backup.xml', role: 'script', scope: 'computer', disposition: 'supported', secretIndicatorStatus: 'not-inspected' }); expect(gpoArtifactInventoryValidationErrors(value.inventory)).toEqual(expect.arrayContaining([ expect.stringContaining('kollidiert'), expect.stringContaining('Skript') ])); }); it('keeps inventory-only scripts from authorizing set-absence conclusions', () => { const value = instance('scripted', '55555555-5555-4555-8555-555555555555', 'set-scripted'); value.inventory.entries.push({ version: 1, artifactId: 'script-file', relativePath: 'scripted/Machine/Scripts/startup.ps1', role: 'script', scope: 'computer', disposition: 'inventory-only', secretIndicatorStatus: 'not-inspected' }); expect(gpoBackupInstanceValidationErrors(value)).toEqual([]); expect(gpoBackupCompleteness(value)).toBe('partial'); expect(buildGpoAnalysisSnapshots([value], { createdAt: timestamp })[0]) .toMatchObject({ status: 'indeterminate', permitsSetAbsenceConclusions: false }); }); it('forms a complete manifest-backed snapshot without inventing scope or effectiveness', () => { const first = instance('first', '11111111-1111-4111-8111-111111111111', 'set-complete', { backupSet: { id: 'set-complete', scope: 'complete-domain-export', evidence: 'collection-manifest', expectedGpoCount: 2 } }); const second = instance('second', '22222222-2222-4222-8222-222222222222', 'set-complete', { backupSet: { id: 'set-complete', scope: 'complete-domain-export', evidence: 'collection-manifest', expectedGpoCount: 2 } }); const snapshots = buildGpoAnalysisSnapshots([second, first], { createdAt: timestamp }); expect(snapshots).toEqual([expect.objectContaining({ instanceIds: ['first', 'second'], status: 'consistent', completeness: 'complete', permitsSetAbsenceConclusions: true, diagnosticCodes: [] })]); }); it('separates historical sets and blocks duplicate GPO identities inside one snapshot', () => { const historical = buildGpoAnalysisSnapshots([ instance('old', '11111111-1111-4111-8111-111111111111', 'set-old'), instance('new', '11111111-1111-4111-8111-111111111111', 'set-new') ], { createdAt: timestamp }); expect(historical).toHaveLength(2); expect(historical.every(snapshot => snapshot.status === 'consistent')).toBe(true); const duplicated = buildGpoAnalysisSnapshots([ instance('copy-a', '11111111-1111-4111-8111-111111111111', 'set-duplicate', { backupSet: { id: 'set-duplicate', scope: 'complete-domain-export', evidence: 'collection-manifest', expectedGpoCount: 2 } }), instance('copy-b', '11111111-1111-4111-8111-111111111111', 'set-duplicate', { backupSet: { id: 'set-duplicate', scope: 'complete-domain-export', evidence: 'collection-manifest', expectedGpoCount: 2 } }) ], { createdAt: timestamp }); expect(duplicated[0]).toMatchObject({ status: 'inconsistent', completeness: 'inconsistent', permitsSetAbsenceConclusions: false }); expect(duplicated[0].diagnosticCodes).toContain('gpo-duplicate-identity-in-snapshot'); }); it('splits mixed domains and keeps partial or selected sets from negative conclusions', () => { const otherDomain = instance('other', '22222222-2222-4222-8222-222222222222', 'set-domain'); otherDomain.domain = { status: 'resolved', key: 'other-domain', evidence: 'backup-metadata' }; const split = buildGpoAnalysisSnapshots([ instance('primary', '11111111-1111-4111-8111-111111111111', 'set-domain'), otherDomain ], { createdAt: timestamp }); expect(split).toHaveLength(2); expect(split.every(snapshot => snapshot.status === 'inconsistent' && snapshot.diagnosticCodes.includes('gpo-backup-set-domain-split'))).toBe(true); const selected = instance('selected', '33333333-3333-4333-8333-333333333333', 'set-selected', { backupSet: { id: 'set-selected', scope: 'selected-gpos', evidence: 'user-selection' } }); const selectedSnapshot = buildGpoAnalysisSnapshots([selected], { createdAt: timestamp })[0]; expect(selectedSnapshot).toMatchObject({ status: 'consistent', completeness: 'selected-subset', permitsSetAbsenceConclusions: false }); const selectedOtherDomain = instance('selected-other', '55555555-5555-4555-8555-555555555555', 'set-selected', { sourceArtifactId: selected.sourceArtifactId, domain: { status: 'resolved', key: 'other-domain', evidence: 'backup-metadata' }, backupSet: { id: 'set-selected', scope: 'selected-gpos', evidence: 'user-selection' } }); const mixedSelected = buildGpoAnalysisSnapshots([selected, selectedOtherDomain], { createdAt: timestamp }); expect(mixedSelected).toEqual([expect.objectContaining({ status: 'indeterminate', completeness: 'selected-subset', domain: { status: 'unknown' }, instanceIds: ['selected', 'selected-other'], permitsSetAbsenceConclusions: false, diagnosticCodes: expect.arrayContaining(['gpo-backup-set-domain-mixed']) })]); const incomplete = instance('incomplete', '44444444-4444-4444-8444-444444444444', 'set-incomplete', { sections: { computer: 'missing', user: 'disabled' } }); expect(gpoBackupCompleteness(incomplete)).toBe('partial'); expect(gpoBackupInstanceValidationErrors(incomplete)).toEqual([]); expect(buildGpoAnalysisSnapshots([incomplete], { createdAt: timestamp })[0]).toMatchObject({ status: 'indeterminate', permitsSetAbsenceConclusions: false, diagnosticCodes: expect.arrayContaining(['gpo-backup-instance-incomplete']) }); }); });