58 lines
2.4 KiB
TypeScript
58 lines
2.4 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
// The reusable evaluation command is plain ESM so it can run directly with Node.
|
|
// @ts-expect-error The script intentionally has no separate declaration file.
|
|
import { changeFor, evaluateRun, validateBaseline } from '../../scripts/compare-regulatory-mappings.mjs';
|
|
|
|
function run(candidates: string[], mappings: Array<{ controlId: string; relationship: 'primary' | 'supporting' }>, status = 'succeeded') {
|
|
return {
|
|
run_status: status,
|
|
data: {
|
|
candidates: candidates.map((controlId, index) => ({ controlId, score: 1 / (61 + index) })),
|
|
result: { mappings: mappings.map(mapping => ({ ...mapping, confidence: 'high' })) }
|
|
}
|
|
};
|
|
}
|
|
|
|
const finding = { sourceRuleId: 'RULE-1', primary: '1.1', supporting: ['1.2'] };
|
|
|
|
describe('regulatory mapping comparison script', () => {
|
|
it('allows a manual baseline with no primary and rejects duplicate relationships', () => {
|
|
expect(() => validateBaseline({
|
|
schemaVersion: 1,
|
|
scanners: [{ sourceTool: 'scanner', label: 'Scanner', findings: [{ sourceRuleId: 'RULE-1', primary: null, supporting: ['1.1'] }] }]
|
|
})).not.toThrow();
|
|
|
|
expect(() => validateBaseline({
|
|
schemaVersion: 1,
|
|
scanners: [{ sourceTool: 'scanner', label: 'Scanner', findings: [{ sourceRuleId: 'RULE-1', primary: '1.1', supporting: ['1.1'] }] }]
|
|
})).toThrow(/duplicate controls/i);
|
|
});
|
|
|
|
it('separates retrieval, selection, role and extra-control results', () => {
|
|
const evaluation = evaluateRun(run(
|
|
['1.1', '1.2', '2.1'],
|
|
[{ controlId: '1.1', relationship: 'supporting' }, { controlId: '2.1', relationship: 'primary' }]
|
|
), finding);
|
|
|
|
expect(evaluation.retrievalGaps).toEqual([]);
|
|
expect(evaluation.selectionGaps).toEqual(['1.2']);
|
|
expect(evaluation.roleMismatches).toEqual(['1.1']);
|
|
expect(evaluation.extras).toEqual(['2.1']);
|
|
expect(evaluation.verdict).toBe('Incomplete + extras');
|
|
});
|
|
|
|
it('classifies opposing recall and extra-control changes as mixed', () => {
|
|
const previous = evaluateRun(run(['1.1'], [{ controlId: '1.1', relationship: 'primary' }]), finding);
|
|
const current = evaluateRun(run(
|
|
['1.1', '1.2', '2.1'],
|
|
[
|
|
{ controlId: '1.1', relationship: 'primary' },
|
|
{ controlId: '1.2', relationship: 'supporting' },
|
|
{ controlId: '2.1', relationship: 'supporting' }
|
|
]
|
|
), finding);
|
|
|
|
expect(changeFor(previous, current)).toBe('Mixed');
|
|
});
|
|
});
|