import { createHash } from 'node:crypto'; import { describe, expect, it } from 'vitest'; import { parseGroupPolicyPreferenceXml, reduceGroupPolicyPreferences } from '../../server/gpo/group-policy-preference-parser'; import type { VerifiedZipFile } from '../../server/gpo/zip-inventory'; const rootClsid = '{3125E937-EB16-4b4c-9934-544FC6D24D26}'; const userClsid = '{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}'; const groupClsid = '{6D4A79E4-529C-4481-ABD0-F5BD7EA93BA7}'; function verifiedFile(content: string): VerifiedZipFile { const bytes = new TextEncoder().encode(content); return { entry: { index: 1, relativePath: 'synthetic/DomainSysvol/GPO/Machine/Preferences/Groups/Groups.xml', kind: 'file', compressionMethod: 8, compressedBytes: bytes.byteLength, uncompressedBytes: bytes.byteLength, crc32: '00000000', sha256: createHash('sha256').update(bytes).digest('hex') }, bytes }; } function context() { return { backupInstanceId: 'backup-synthetic', sourceArtifactId: 'source-synthetic', artifactId: 'entry-synthetic' }; } describe('Local Users and Groups preference CSE', () => { it('keeps user, group and ordered membership semantics without retaining cpassword', () => { const secret = 'synthetic-secret-never-return'; const document = parseGroupPolicyPreferenceXml(verifiedFile([ ``, ` `, ` `, ' ', ' ', ` `, ' ', ' ', ' ', ' ', ' ', ' ', ' ', '' ].join('\r\n')), 'computer'); expect(document).toMatchObject({ preferenceType: 'local-users-groups', status: 'complete', secretIndicatorStatus: 'present' }); expect(JSON.stringify(document)).not.toContain(secret); const observations = reduceGroupPolicyPreferences(document, context()); expect(JSON.stringify(observations)).not.toContain(secret); expect(observations).toEqual([ expect.objectContaining({ state: 'instruction', identity: expect.objectContaining({ section: 'local user', key: 'syntheticadmin' }), preference: expect.objectContaining({ cse: 'local-users-groups', operation: 'update', sequence: 0, applyOnce: true }), values: [{ kind: 'local-user-preference', userName: 'SyntheticAdmin', newName: 'SyntheticOperator', fullName: 'Synthetic Operator', passwordAttributePresent: true, changePasswordAtLogon: true, accountDisabled: false, passwordNeverExpires: true, passwordChangeAllowed: false }], sourceLines: [2], effectiveState: 'unknown', diagnosticCodes: ['gpo-preference-targeting-unevaluated', 'gpo-secret-indicator-present'] }), expect.objectContaining({ identity: expect.objectContaining({ section: 'local group', key: 'S-1-5-32-544' }), preference: expect.objectContaining({ cse: 'local-users-groups', operation: 'update', sequence: 1 }), values: [{ kind: 'local-group-preference', groupName: 'Administrators', groupSid: 'S-1-5-32-544', suppressCurrentUserOperation: false, deleteAllUsers: true, deleteAllGroups: false, members: [ { sequence: 0, operation: 'remove', selector: { kind: 'name', value: 'Synthetic\\Old' } }, { sequence: 1, operation: 'add', selector: { kind: 'sid', value: 'S-1-5-21-1-2-3-1001' } } ] }], sourceLines: [6], effectiveState: 'unknown' }) ]); }); it('fails closed for malformed supported member and boolean semantics', () => { const document = parseGroupPolicyPreferenceXml(verifiedFile( `` ), 'computer'); expect(document).toMatchObject({ status: 'invalid', instructions: [] }); expect(document.diagnosticCodes).toEqual(expect.arrayContaining([ 'gpo-preference-boolean-invalid', 'gpo-preference-local-group-member-invalid' ])); expect(reduceGroupPolicyPreferences(document, context())).toEqual([]); }); it('keeps unknown supported-CSE item shapes partial without salvaging those items', () => { const document = parseGroupPolicyPreferenceXml(verifiedFile( `` ), 'user'); expect(document).toMatchObject({ preferenceType: 'local-users-groups', status: 'partial', instructions: [], diagnosticCodes: ['gpo-preference-local-user-item-unsupported'] }); expect(reduceGroupPolicyPreferences(document, context())).toEqual([]); }); });