Assessor_2.0/tests/server/regulatory-finding-retrieva...

90 lines
4.7 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest';
import { RegulatoryFindingRetrievalService } from '../../server/regulatory/regulatory-finding-retrieval';
import type { RegulatoryRetrievalCandidate, RegulatoryRetrievalRequest } from '../../src/domain/regulatory-rag';
import type { UnifiedResultProjection } from '../../src/domain/unified-result';
import { buildRegulatoryFindingQuery } from '../../src/profiles/public-search/regulatory-query';
const privateMarkers = ['Tenant Acme', '10.23.45.67', 'secret.example', 'C:\\Customer\\report.xml', 'analyst@acme.invalid'];
function finding(overrides: Partial<UnifiedResultProjection> = {}): UnifiedResultProjection {
return {
resultProjectionId: 'projection-private', sourceKind: 'scanner-finding', sourceResultId: 'source-private',
projectId: 'tenant-private', assessmentId: 'assessment-private', collectionRunId: 'run-private',
sourceTool: 'purple-knight', title: `${privateMarkers[0]} has SMB signing disabled on ${privateMarkers[1]}`,
description: `Host ${privateMarkers[2]} loaded ${privateMarkers[3]}`,
recommendation: `Contact ${privateMarkers[4]}`, affectedAsset: privateMarkers[2],
severityOriginal: 'high', severityNormalized: 'high', outcomeOriginal: 'fail', outcomeNormalized: 'fail',
technicalExecutionState: 'completed', resultType: 'compliance_check', isIoe: false, isDeviation: true,
lifecycleState: 'new', mappingConfidence: 1, reviewStatus: 'open', reviewOwner: privateMarkers[4],
importedAt: '2026-09-15T10:00:00.000Z', createdAt: '2026-09-15T10:00:00.000Z', categories: [],
...overrides
};
}
const candidate: RegulatoryRetrievalCandidate = {
score: 0.8,
chunk: {
schemaVersion: 1, corpusId: 'synthetic', corpusVersion: '1', documentId: 'control-de',
framework: 'Synthetic Framework', frameworkVersion: '1', controlId: 'CTRL-1', chunkId: 'chunk-1',
chunkIndex: 0, language: 'de', title: 'Synthetic control', text: 'Synthetic regulatory text.',
textSha256: 'a'.repeat(64)
}
};
describe('regulatory finding retrieval boundary', () => {
it('emits only fixed public concepts and never copies private finding data', () => {
const query = buildRegulatoryFindingQuery(finding());
expect(query).toMatchObject({
schemaVersion: 1,
specificity: 'topic',
publicTool: 'Semperis Purple Knight',
publicTopics: ['SMB signing requirements']
});
for (const marker of privateMarkers) expect(query?.query).not.toContain(marker);
expect(query?.query).not.toContain('disabled');
});
it('allows only exact catalog-owned rule IDs', () => {
expect(buildRegulatoryFindingQuery(finding({
sourceTool: 'pingcastle', sourceRuleId: 'a-krbtgt', title: privateMarkers[0], description: undefined, recommendation: undefined
}))).toMatchObject({ specificity: 'rule', publicRuleId: 'A-Krbtgt' });
expect(buildRegulatoryFindingQuery(finding({
sourceTool: 'pingcastle', sourceRuleId: 'A-Customer-Private', title: privateMarkers[0], description: undefined, recommendation: undefined
}))).toBeUndefined();
});
it('fails closed for non-scanner records or findings without a public signal', () => {
expect(buildRegulatoryFindingQuery(finding({ sourceKind: 'environment-observation' }))).toBeUndefined();
expect(buildRegulatoryFindingQuery(finding({
sourceTool: 'customer-private-scanner', title: privateMarkers[0], description: undefined, recommendation: undefined
}))).toBeUndefined();
});
it('passes only the prepared public query and explicit filters to the retriever', async () => {
const retrieve = vi.fn(async (_request: RegulatoryRetrievalRequest) => [candidate]);
const service = new RegulatoryFindingRetrievalService({ retrieve });
const result = await service.retrieve(finding(), 5, { framework: 'Synthetic Framework' });
expect(result).toMatchObject({ sourceResultId: 'source-private', status: 'candidates', candidates: [candidate] });
expect(retrieve).toHaveBeenCalledOnce();
expect(retrieve.mock.calls[0][0]).toEqual({
query: result.preparedQuery?.query,
limit: 5,
filters: { framework: 'Synthetic Framework' }
});
for (const marker of privateMarkers) expect(JSON.stringify(retrieve.mock.calls[0][0])).not.toContain(marker);
});
it('does not call retrieval when public context is insufficient', async () => {
const retrieve = vi.fn();
const service = new RegulatoryFindingRetrievalService({ retrieve });
await expect(service.retrieve(finding({ title: privateMarkers[0], description: undefined, recommendation: undefined }), 5))
.resolves.toEqual({ sourceResultId: 'source-private', status: 'insufficient-public-context', candidates: [] });
expect(retrieve).not.toHaveBeenCalled();
});
});