import { createHash } from 'node:crypto'; import { describe, expect, it } from 'vitest'; import { buildAdmxPolicyCatalog, resolveRegistryPolicyIdentity } from '../../server/gpo/admx-policy-catalog'; import { parseRegistryPolicyFile, reduceRegistryPolicy } from '../../server/gpo/registry-policy-parser'; import type { VerifiedZipFile } from '../../server/gpo/zip-inventory'; function verified(path: string, content: Uint8Array | string): VerifiedZipFile { const bytes = typeof content === 'string' ? Buffer.from(content) : content; return { entry: { index: 0, relativePath: path, kind: 'file', compressionMethod: 0, compressedBytes: bytes.byteLength, uncompressedBytes: bytes.byteLength, crc32: '00000000', sha256: createHash('sha256').update(bytes).digest('hex') }, bytes }; } function registryPolicy(key: string, name: string, value: number): Uint8Array { const unicode = (text: string) => Buffer.from(text, 'utf16le'); const header = Buffer.alloc(8); header.write('PReg'); header.writeUInt32LE(1, 4); const type = Buffer.alloc(4); type.writeUInt32LE(4); const size = Buffer.alloc(4); size.writeUInt32LE(4); const data = Buffer.alloc(4); data.writeUInt32LE(value); return Buffer.concat([ header, unicode('['), unicode(key), Buffer.alloc(2), unicode(';'), unicode(name), Buffer.alloc(2), unicode(';'), type, unicode(';'), size, unicode(';'), data, unicode(']') ]); } const namespace = 'http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions'; describe('ADMX technical policy identity catalog', () => { it('keeps technical identity stable while attaching locale-independent ADMX metadata', () => { const admx = verified('Templates/Synthetic.admx', ` `); const adml = verified('Templates/en-US/Synthetic.adml', ` Harden modeSynthetic help `); const catalog = buildAdmxPolicyCatalog([adml, admx], { kind: 'microsoft-security-baseline', baselineId: 'baseline-1', packageSha256: 'a'.repeat(64) }); expect(catalog).toMatchObject({ status: 'complete', policies: [{ technicalId: 'Contoso.Policies.Synthetic#HardenMode', displayNameResourceId: 'HardenMode' }], languageResources: [{ locale: 'en-US', strings: { HardenMode: 'Harden mode' } }] }); const source = verified('GPOs/one/DomainSysvol/GPO/Machine/Registry.pol', registryPolicy('Software\\Policies\\Synthetic', 'Mode', 1)); const document = parseRegistryPolicyFile(source, 'computer'); const observation = reduceRegistryPolicy(document, { backupInstanceId: 'backup-1', sourceArtifactId: 'artifact-1', artifactId: 'entry-1' })[0]; const withoutCatalog = resolveRegistryPolicyIdentity(observation); const withCatalog = resolveRegistryPolicyIdentity(observation, catalog); expect(withoutCatalog).toMatchObject({ status: 'resolved', identity: { admx: { status: 'not-found' } } }); expect(withCatalog).toMatchObject({ status: 'resolved', identity: { id: withoutCatalog.status === 'resolved' ? withoutCatalog.identity.id : undefined, target: { kind: 'registry-value', hive: 'HKEY_LOCAL_MACHINE', key: 'Software\\Policies\\Synthetic', valueName: 'Mode' }, admx: { status: 'matched', reference: { technicalId: 'Contoso.Policies.Synthetic#HardenMode', settingId: '$policy' } } } }); }); it('fails closed on duplicate namespaces and external XML constructs', () => { const source = (path: string) => verified(path, ``); expect(() => buildAdmxPolicyCatalog([source('one.admx'), source('two.admx')], { kind: 'microsoft-security-baseline', baselineId: 'baseline-1', packageSha256: 'b'.repeat(64) })).toThrow(/Zielnamespace/); expect(() => buildAdmxPolicyCatalog([verified('bad.admx', `]>`)], { kind: 'microsoft-security-baseline', baselineId: 'baseline-1', packageSha256: 'c'.repeat(64) })).toThrow(/Externe/); }); it('does not pretend that multi-target delete instructions have one identity', () => { const source = verified('GPOs/one/DomainSysvol/GPO/User/Registry.pol', registryPolicy('Software\\Policies\\Synthetic', '**DeleteValues', 1)); const document = parseRegistryPolicyFile(source, 'user'); expect(document.status).toBe('invalid'); }); });