import { describe, expect, it } from 'vitest'; import { inventoryGpoContainer, recognizeGpoContainer } from '../../server/gpo/gpo-container-inventory'; import { readVerifiedZipFiles } from '../../server/gpo/zip-inventory'; import { createGpoFolderTransport, type GpoFolderFileSource } from '../../src/gpo/gpo-folder-transport'; const encoder = new TextEncoder(); function source(relativePath: string, value: string): GpoFolderFileSource { const bytes = encoder.encode(value); return { relativePath, sizeBytes: bytes.byteLength, readBytes: async () => bytes }; } const entries = [ source('SyntheticBackup/{22222222-2222-4222-8222-222222222222}/Backup.xml', '{22222222-2222-4222-8222-222222222222}{11111111-1111-4111-8111-111111111111}synthetic.example2026-07-21T10:00:00Z'), source('SyntheticBackup/{22222222-2222-4222-8222-222222222222}/DomainSysvol/GPO/gpt.ini', '[General]') ]; describe('unzipped GPO folder transport', () => { it('creates a deterministic byte-preserving ZIP envelope accepted by the hardened GPO inventory', async () => { const first = await createGpoFolderTransport(entries); const reordered = await createGpoFolderTransport([...entries].reverse()); expect(first).toMatchObject({ fileName: 'SyntheticBackup.gpo-backup.zip', fileCount: 2, rootName: 'SyntheticBackup' }); expect(first.bytes).toEqual(reordered.bytes); expect(inventoryGpoContainer(first.bytes).recognition.status).toBe('gpo-backup-candidate'); const recognition = recognizeGpoContainer(first.bytes); expect(recognition.recognition.status).toBe('gpo-backup-candidate'); expect(Object.keys(recognition).sort()).toEqual(['recognition', 'version']); expect('archive' in recognition).toBe(false); expect('inventory' in recognition).toBe(false); const selected = readVerifiedZipFiles(first.bytes, [ 'SyntheticBackup/{22222222-2222-4222-8222-222222222222}/DomainSysvol/GPO/gpt.ini' ]); expect(new TextDecoder().decode(selected[0].bytes)).toBe('[General]'); }); it('rejects traversal and Unicode/case path collisions before reading file content', async () => { await expect(createGpoFolderTransport([source('Backup/../escape.xml', 'x')])) .rejects.toMatchObject({ code: 'gpo-folder-path-rejected' }); await expect(createGpoFolderTransport([ source('Backup/DomainSysvol/GPO/gpt.ini', 'one'), source('backup/domainsysvol/gpo/GPT.INI', 'two') ])).rejects.toMatchObject({ code: 'gpo-folder-path-collision' }); }); it('rejects a changed file size at the browser read boundary', async () => { await expect(createGpoFolderTransport([{ relativePath: 'Backup/Backup.xml', sizeBytes: 2, readBytes: async () => encoder.encode('three') }])).rejects.toMatchObject({ code: 'gpo-folder-file-size-mismatch' }); }); });