121 lines
6.3 KiB
TypeScript
121 lines
6.3 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
createCurrentPolicyObservationUnifiedResults,
|
|
createPolicyObservationUnifiedResult,
|
|
type PolicyObservationUnifiedResultSource
|
|
} from '../../src/domain/unified-result';
|
|
|
|
const timestamp = '2026-09-17T08:00:00.000Z';
|
|
const gpoId = '11111111-1111-4111-8111-111111111111';
|
|
const nativeBackupId = '22222222-2222-4222-8222-222222222222';
|
|
|
|
function source(): PolicyObservationUnifiedResultSource {
|
|
return {
|
|
artifact: {
|
|
version: 1, id: 'synthetic-artifact', projectId: 'synthetic-project',
|
|
assessmentId: 'synthetic-assessment', kind: 'source-file', relativePath: 'synthetic.zip',
|
|
sha256: 'a'.repeat(64), sizeBytes: 1, sensitivity: 'confidential', parseStatus: 'parsed',
|
|
storage: { kind: 'not-retained', reason: 'Synthetic fixture' }, createdAt: timestamp
|
|
},
|
|
backup: {
|
|
version: 1, id: 'synthetic-stored-backup', projectId: 'synthetic-project',
|
|
artifactId: 'synthetic-artifact', processingRunId: 'synthetic-processing', createdAt: timestamp,
|
|
instance: {
|
|
version: 1, id: 'synthetic-backup-instance', projectId: 'synthetic-project',
|
|
sourceArtifactId: 'synthetic-artifact',
|
|
identity: { status: 'resolved', gpoId, backupId: nativeBackupId, evidence: 'backup-metadata' },
|
|
domain: { status: 'unknown' }, collection: { status: 'unknown' },
|
|
backupSet: { scope: 'selected-gpos', evidence: 'user-selection' },
|
|
metadataStatus: 'partial', sections: { computer: 'present', user: 'unknown' },
|
|
inventory: { version: 1, status: 'partial', entries: [], diagnosticCodes: [] },
|
|
discoveredAt: timestamp
|
|
}
|
|
},
|
|
observation: {
|
|
version: 1, id: 'synthetic-observation', backupInstanceId: 'synthetic-backup-instance',
|
|
sourceArtifactId: 'synthetic-artifact', artifactId: 'synthetic-registry-artifact',
|
|
sourcePath: `{${nativeBackupId}}/DomainSysvol/GPO/Machine/registry.pol`,
|
|
sourceSha256: 'b'.repeat(64), scope: 'computer', deliveryMechanism: 'registry-policy',
|
|
parser: { id: 'synthetic-parser', version: '1.0.0' },
|
|
reducer: { id: 'synthetic-reducer', version: '1.0.0' },
|
|
identity: { status: 'unresolved', namespace: 'registry-policy', section: 'Software\\Policies\\Synthetic', key: 'Enabled' },
|
|
state: 'instruction',
|
|
values: [{ kind: 'registry-policy', operation: 'set-value', key: 'Software\\Policies\\Synthetic', valueName: 'Enabled', typeCode: 4, data: { kind: 'uint32', value: 1 } }],
|
|
registryPolicy: { sequence: 0, operation: 'set-value' },
|
|
sourceRecords: [{ index: 0, byteOffset: 8 }], effectiveState: 'unknown', diagnosticCodes: []
|
|
}
|
|
};
|
|
}
|
|
|
|
describe('GPO source identity read projection', () => {
|
|
it('keeps native GPO, native backup and internal backup identities separate and preserves instruction zero', () => {
|
|
const input = source();
|
|
const before = JSON.stringify(input);
|
|
const result = createPolicyObservationUnifiedResult(input);
|
|
|
|
expect(result).toMatchObject({
|
|
sourceKind: 'policy-observation', sourceResultId: 'synthetic-observation',
|
|
projectId: 'synthetic-project', assessmentId: 'synthetic-assessment',
|
|
policyBackupInstanceId: 'synthetic-backup-instance', policyGpoId: gpoId,
|
|
policyNativeBackupId: nativeBackupId, policySourceSequence: 0,
|
|
sourceLocator: { objectPath: `${input.observation.sourcePath}#records=0` },
|
|
isDeviation: false, effectiveState: 'unresolved_identity'
|
|
});
|
|
expect(result.policyValues).toBe(input.observation.values);
|
|
expect(JSON.stringify(input)).toBe(before);
|
|
});
|
|
|
|
it('does not infer native identities from a source path when backup identity is unresolved', () => {
|
|
const input = source();
|
|
input.backup.instance.identity = { status: 'unresolved', reasonCode: 'synthetic-metadata-missing' };
|
|
const result = createPolicyObservationUnifiedResult(input);
|
|
|
|
expect(result.policyBackupInstanceId).toBe('synthetic-backup-instance');
|
|
expect(result.policyGpoId).toBeUndefined();
|
|
expect(result.policyNativeBackupId).toBeUndefined();
|
|
expect(result.sourceLocator?.objectPath).toContain(nativeBackupId);
|
|
expect(result.policySourceSequence).toBe(0);
|
|
});
|
|
|
|
it('preserves the retained preference sequence without changing its value, action or targeting', () => {
|
|
const input = source();
|
|
input.observation.deliveryMechanism = 'group-policy-preference';
|
|
input.observation.identity.namespace = 'group-policy-preference';
|
|
input.observation.values = [{ kind: 'registry-preference', hive: 'HKEY_LOCAL_MACHINE', key: 'Software\\Synthetic', target: 'value', valueName: 'Enabled', valueType: 'REG_DWORD', rawData: '1' }];
|
|
delete input.observation.registryPolicy;
|
|
input.observation.preference = {
|
|
cse: 'registry', itemUid: '33333333-3333-4333-8333-333333333333', operation: 'update',
|
|
sequence: 0, disabled: false, removePolicy: false, applyOnce: false,
|
|
targeting: { status: 'none', filterTypes: [] }
|
|
};
|
|
const before = JSON.stringify(input);
|
|
|
|
expect(createPolicyObservationUnifiedResult(input).policySourceSequence).toBe(0);
|
|
input.observation.preference.sequence = 12;
|
|
expect(createPolicyObservationUnifiedResult(input).policySourceSequence).toBe(12);
|
|
input.observation.preference.sequence = 0;
|
|
expect(JSON.stringify(input)).toBe(before);
|
|
});
|
|
|
|
it('does not invent a sequence from source-record position when no instruction context is retained', () => {
|
|
const input = source();
|
|
delete input.observation.registryPolicy;
|
|
input.observation.sourceRecords = [{ index: 9, byteOffset: 80 }];
|
|
|
|
expect(createPolicyObservationUnifiedResult(input).policySourceSequence).toBeUndefined();
|
|
});
|
|
|
|
it('exposes the same metadata through the shared current-run projection without adding observations', () => {
|
|
const input = source();
|
|
input.backup.instance.policyObservations = [input.observation];
|
|
const result = createCurrentPolicyObservationUnifiedResults([input.artifact], [{
|
|
version: 1, id: 'synthetic-processing', projectId: 'synthetic-project', artifactId: 'synthetic-artifact',
|
|
status: 'complete', processors: [], diagnosticCodes: [], startedAt: timestamp, completedAt: timestamp
|
|
}], [input.backup], []);
|
|
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0]).toMatchObject({ policyGpoId: gpoId, policyNativeBackupId: nativeBackupId, policySourceSequence: 0 });
|
|
expect(result[0].policyValues).toEqual(input.observation.values);
|
|
});
|
|
});
|