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';
import { ImportError } from '../../src/shared/errors';
function verifiedFile(content: string | Uint8Array, name = 'Registry.xml'): VerifiedZipFile {
const bytes = typeof content === 'string' ? new TextEncoder().encode(content) : content;
return {
entry: {
index: 1,
relativePath: `synthetic/DomainSysvol/GPO/Machine/Preferences/Registry/${name}`,
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' };
}
const rootClsid = '{A3CCFC41-DFDB-43a5-8D26-0FE8B954DA51}';
const itemClsid = '{9CD4B2F4-923D-47f5-A062-E897DD1DAD50}';
describe('Group Policy Preferences parser and Registry reducer', () => {
it('preserves Registry action, order, common options and opaque item-level targeting', () => {
const document = parseGroupPolicyPreferenceXml(verifiedFile([
``,
` `,
' ',
' ',
' ',
` `,
' ',
' ',
''
].join('\r\n')), 'computer');
expect(document).toMatchObject({ status: 'complete', preferenceType: 'registry', secretIndicatorStatus: 'not-detected' });
const observations = reduceGroupPolicyPreferences(document, context());
expect(observations).toHaveLength(2);
expect(observations[0]).toMatchObject({
deliveryMechanism: 'group-policy-preference',
state: 'instruction',
identity: { namespace: 'group-policy-preference', section: 'registry' },
preference: {
cse: 'registry', operation: 'replace', sequence: 0, disabled: false, removePolicy: true, applyOnce: false,
targeting: { status: 'present', filterTypes: ['filtergroup'], evaluability: 'unknown' }
},
values: [{
kind: 'registry-preference', hive: 'HKEY_LOCAL_MACHINE', key: 'Software\\Synthetic', target: 'value',
valueName: 'Mode', valueType: 'REG_SZ', rawData: 'Strict'
}],
sourceLines: [2],
effectiveState: 'unknown',
diagnosticCodes: ['gpo-preference-targeting-unevaluated']
});
expect(observations[1]).toMatchObject({ preference: { operation: 'delete', sequence: 1 }, sourceLines: [6] });
});
it('recognizes but never returns cpassword values', () => {
const secret = 'synthetic-secret-must-not-leave-parser';
const document = parseGroupPolicyPreferenceXml(verifiedFile(
``
), 'user');
expect(document).toMatchObject({ status: 'complete', secretIndicatorStatus: 'present' });
expect(document.diagnosticCodes).toContain('gpo-secret-indicator-present');
expect(JSON.stringify(document)).not.toContain(secret);
expect(JSON.stringify(reduceGroupPolicyPreferences(document, context()))).not.toContain(secret);
});
it('keeps unsupported Preference CSEs partial without producing policy observations', () => {
const document = parseGroupPolicyPreferenceXml(verifiedFile(
'',
'Groups.xml'
), 'computer');
expect(document).toMatchObject({
preferenceType: 'unsupported', status: 'partial', secretIndicatorStatus: 'present', instructions: [],
diagnosticCodes: ['gpo-preference-type-unsupported', 'gpo-secret-indicator-present']
});
expect(reduceGroupPolicyPreferences(document, context())).toEqual([]);
});
it('fails closed for malformed supported actions, targets, common flags and targeting', () => {
const document = parseGroupPolicyPreferenceXml(verifiedFile(
``
), 'computer');
expect(document.status).toBe('invalid');
expect(document.instructions).toEqual([]);
expect(document.diagnosticCodes).toEqual(expect.arrayContaining([
'gpo-preference-remove-policy-invalid', 'gpo-preference-targeting-invalid'
]));
});
it('keeps unsupported Registry subproperties partial instead of inventing bitfield semantics', () => {
const document = parseGroupPolicyPreferenceXml(verifiedFile(
''
), 'computer');
expect(document).toMatchObject({
status: 'partial', instructions: [], diagnosticCodes: ['gpo-preference-registry-item-unsupported']
});
expect(reduceGroupPolicyPreferences(document, context())).toEqual([]);
});
it('rejects active XML constructs before parsing', () => {
expect(() => parseGroupPolicyPreferenceXml(verifiedFile(
`]>&x;`
), 'computer')).toThrow(ImportError);
});
});