Assessor_2.0/tests/evaluation/policy-comparator.test.ts

84 lines
4.1 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { comparePolicyValues } from '../../src/evaluation/policy-comparator';
import type { GpoPolicyValue } from '../../src/domain/gpo-policy';
const integer = (value: number): GpoPolicyValue => ({
kind: 'registry-policy', operation: 'set-value', key: 'Software\\Policies\\Synthetic', valueName: 'Mode',
typeCode: 4, data: { kind: 'uint32', value }
});
describe('typed policy comparators', () => {
it('compares exact typed values', () => {
expect(comparePolicyValues(integer(2), integer(2), { kind: 'equality' }).relation).toBe('match');
expect(comparePolicyValues(integer(1), integer(2), { kind: 'equality' }).relation).toBe('different');
});
it('retains supported Registry.pol state operations as comparable requirements', () => {
const instruction = (operation: 'delete-value' | 'delete-all-values' | 'create-key'): GpoPolicyValue => ({
kind: 'registry-policy', operation, key: 'Software\\Policies\\Synthetic',
...(operation === 'delete-value' ? { valueName: 'Mode' } : {}),
...(operation === 'create-key' ? { typeCode: 0 as const, data: { kind: 'none' as const } } : {})
});
for (const operation of ['delete-value', 'delete-all-values', 'create-key'] as const) {
expect(comparePolicyValues(instruction(operation), instruction(operation), { kind: 'equality' }))
.toMatchObject({ relation: 'match', diagnosticCodes: [] });
}
expect(comparePolicyValues(integer(1), instruction('delete-value'), { kind: 'equality' }).relation).toBe('different');
});
it('treats an explicitly empty typed string as a value', () => {
const empty: GpoPolicyValue = { kind: 'registry-policy', operation: 'set-value',
key: 'Software\\Policies\\Synthetic', valueName: 'Hosts', typeCode: 2, data: { kind: 'string', value: '' } };
expect(comparePolicyValues(empty, empty, { kind: 'equality' })).toMatchObject({
relation: 'match', baseline: { kind: 'text', value: '' }
});
});
it('compares registry values parsed from security templates with their type intact', () => {
const baseline = { kind: 'registry', typeCode: 4, rawData: '1' } as const;
expect(comparePolicyValues(baseline, baseline, { kind: 'equality' })).toMatchObject({
relation: 'match', baseline: { kind: 'text', value: '4,1' }
});
expect(comparePolicyValues(
{ kind: 'registry', typeCode: 4, rawData: '0' },
baseline,
{ kind: 'equality' }
).relation).toBe('different');
});
it('orders minimum and maximum requirements', () => {
expect(comparePolicyValues(integer(3), integer(2), { kind: 'minimum' }).relation).toBe('stronger');
expect(comparePolicyValues(integer(3), integer(2), { kind: 'maximum' }).relation).toBe('weaker');
});
it('orders explicit enum catalogs only', () => {
const low = { kind: 'scalar', raw: 'low' } as const;
const high = { kind: 'scalar', raw: 'high' } as const;
expect(comparePolicyValues(high, low, {
kind: 'enum', orderedValues: ['low', 'medium', 'high'], direction: 'higher-is-stronger'
}).relation).toBe('stronger');
});
it('compares bitmasks, sets and audit flags with explicit semantics', () => {
expect(comparePolicyValues(integer(3), integer(1), { kind: 'bitmask', mode: 'contains-baseline' }).relation).toBe('stronger');
expect(comparePolicyValues(
{ kind: 'principal-set', principals: ['A', 'B'] },
{ kind: 'principal-set', principals: ['A'] },
{ kind: 'set', mode: 'superset' }
).relation).toBe('stronger');
expect(comparePolicyValues(
{ kind: 'audit-flags', code: 3, success: true, failure: true },
{ kind: 'audit-flags', code: 1, success: true, failure: false },
{ kind: 'audit-flags', mode: 'contains-baseline' }
).relation).toBe('stronger');
});
it('never coerces unsupported values into a comparison', () => {
expect(comparePolicyValues(
{ kind: 'service-preference', serviceName: 'Synthetic', serviceAction: 'start', startupType: 'automatic', passwordAttributePresent: false },
integer(1),
{ kind: 'equality' }
)).toMatchObject({ relation: 'incomparable', diagnosticCodes: ['policy-comparator-value-unsupported'] });
});
});