111 lines
4.5 KiB
TypeScript
111 lines
4.5 KiB
TypeScript
import { createHash } from 'node:crypto';
|
|
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
parseAdvancedAuditCsv,
|
|
reduceAdvancedAuditPolicy
|
|
} from '../../server/gpo/advanced-audit-parser';
|
|
import type { VerifiedZipFile } from '../../server/gpo/zip-inventory';
|
|
|
|
const firstGuid = '0cce9210-69ae-11d9-bed3-505054503030';
|
|
const secondGuid = '0cce9211-69ae-11d9-bed3-505054503030';
|
|
|
|
function verifiedFile(content: string | Uint8Array): VerifiedZipFile {
|
|
const bytes = typeof content === 'string' ? new TextEncoder().encode(content) : content;
|
|
return {
|
|
entry: {
|
|
index: 1,
|
|
relativePath: 'synthetic/DomainSysvol/GPO/Machine/Microsoft/Windows NT/Audit/audit.csv',
|
|
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' };
|
|
}
|
|
|
|
function csv(rows: string[]): string {
|
|
return [
|
|
'Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting,Setting Value',
|
|
...rows
|
|
].join('\r\n');
|
|
}
|
|
|
|
describe('Advanced Audit Policy parser and reducer', () => {
|
|
it('uses technical subcategory GUIDs and numeric audit flags instead of display names', () => {
|
|
const document = parseAdvancedAuditCsv(verifiedFile(csv([
|
|
`,System,"Localized, ignored name",{${firstGuid}},Success and Failure,,3`,
|
|
`,System,Another ignored name,{${secondGuid}},Failure,,2`
|
|
])), 'computer');
|
|
expect(document).toMatchObject({ status: 'complete', scope: 'computer' });
|
|
expect(reduceAdvancedAuditPolicy(document, context())).toEqual(expect.arrayContaining([
|
|
expect.objectContaining({
|
|
identity: expect.objectContaining({ key: firstGuid }),
|
|
values: [{ kind: 'audit-flags', code: 3, success: true, failure: true }],
|
|
sourceLines: [2],
|
|
effectiveState: 'unknown'
|
|
}),
|
|
expect.objectContaining({
|
|
identity: expect.objectContaining({ key: secondGuid }),
|
|
values: [{ kind: 'audit-flags', code: 2, success: false, failure: true }]
|
|
})
|
|
]));
|
|
});
|
|
|
|
it('models differing duplicate GUID settings as a conflict', () => {
|
|
const document = parseAdvancedAuditCsv(verifiedFile(csv([
|
|
`,System,ignored,{${firstGuid}},Success,,1`,
|
|
`,System,ignored,{${firstGuid}},Failure,,2`
|
|
])), 'computer');
|
|
expect(reduceAdvancedAuditPolicy(document, context())).toEqual([
|
|
expect.objectContaining({
|
|
state: 'conflicted',
|
|
values: [
|
|
{ kind: 'audit-flags', code: 1, success: true, failure: false },
|
|
{ kind: 'audit-flags', code: 2, success: false, failure: true }
|
|
],
|
|
diagnosticCodes: ['gpo-advanced-audit-value-conflict']
|
|
})
|
|
]);
|
|
});
|
|
|
|
it('keeps non-system targets partial without interpreting per-user semantics', () => {
|
|
const document = parseAdvancedAuditCsv(verifiedFile(csv([
|
|
`,SyntheticUser,ignored,{${firstGuid}},Success,,1`,
|
|
`,System,ignored,{${secondGuid}},Success,,1`
|
|
])), 'computer');
|
|
expect(document).toMatchObject({
|
|
status: 'partial',
|
|
diagnosticCodes: ['gpo-advanced-audit-target-unsupported']
|
|
});
|
|
expect(reduceAdvancedAuditPolicy(document, context())).toHaveLength(1);
|
|
});
|
|
|
|
it('fails closed for malformed technical GUIDs, setting codes, rows and headers', () => {
|
|
const invalidValue = parseAdvancedAuditCsv(verifiedFile(csv([
|
|
',System,ignored,not-a-guid,Success,,7'
|
|
])), 'computer');
|
|
expect(invalidValue).toMatchObject({ status: 'invalid', instructions: [] });
|
|
expect(reduceAdvancedAuditPolicy(invalidValue, context())).toEqual([]);
|
|
|
|
const missingHeader = parseAdvancedAuditCsv(verifiedFile('Policy Target,Subcategory GUID\r\nSystem,{0cce9210-69ae-11d9-bed3-505054503030}'), 'computer');
|
|
expect(missingHeader).toMatchObject({
|
|
status: 'invalid',
|
|
diagnosticCodes: ['gpo-advanced-audit-required-column-missing']
|
|
});
|
|
});
|
|
|
|
it('rejects user-scope interpretation and accepts BOM-marked UTF-16LE', () => {
|
|
const encoded = Buffer.from(`\ufeff${csv([`,System,ignored,{${firstGuid}},Success,,1`])}`, 'utf16le');
|
|
const document = parseAdvancedAuditCsv(verifiedFile(encoded), 'user');
|
|
expect(document).toMatchObject({ status: 'partial', diagnosticCodes: ['gpo-advanced-audit-scope-unsupported'] });
|
|
expect(reduceAdvancedAuditPolicy(document, context())).toEqual([]);
|
|
});
|
|
});
|