Assessor_2.0/tests/domain/gpo-source-identity-project...

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);
});
});