57 lines
3.1 KiB
TypeScript
57 lines
3.1 KiB
TypeScript
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
import type { Server } from 'node:http';
|
|
import type { AddressInfo } from 'node:net';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { afterEach, beforeEach, expect, it } from 'vitest';
|
|
import { createAssessorHttpServer } from '../../server/assessor-http-server';
|
|
import { LocalComplianceStore } from '../../src/compliance/local-compliance-store';
|
|
import type { RegulatoryMappingBatchRun } from '../../src/compliance/regulatory-mapping';
|
|
import { LocalAssessorRepository } from '../../src/persistence/local-assessor-repository';
|
|
|
|
// The project export keeps the engine's data: the Core export and the Compliance Engine's own
|
|
// project data are combined at the HTTP route, not inside the Core repository.
|
|
const stamp = '2026-10-05T08:00:00.000Z';
|
|
let directory: string;
|
|
let server: Server | undefined;
|
|
|
|
beforeEach(async () => {
|
|
directory = await mkdtemp(join(tmpdir(), 'assessor-compliance-export-'));
|
|
await writeFile(join(directory, 'index.html'), '<main>synthetic app</main>');
|
|
});
|
|
afterEach(async () => {
|
|
await new Promise(resolve => server ? server.close(resolve) : resolve(undefined));
|
|
server = undefined;
|
|
await rm(directory, { recursive: true, force: true });
|
|
});
|
|
|
|
async function exportVia(complianceExport?: LocalComplianceStore) {
|
|
const repository = new LocalAssessorRepository();
|
|
await repository.saveProject({ id: 'dummy-project', name: 'Dummy Customer', createdAt: stamp, updatedAt: stamp, attributes: {} });
|
|
server = createAssessorHttpServer({ repository, staticRoot: directory, ...(complianceExport ? { complianceExport } : {}) });
|
|
await new Promise<void>(resolve => server!.listen(0, '127.0.0.1', resolve));
|
|
const { port } = server.address() as AddressInfo;
|
|
return (await fetch(`http://127.0.0.1:${port}/api/v1/projects/dummy-project/export`)).json();
|
|
}
|
|
|
|
it('adds the Compliance Engine project data to the Core project export', async () => {
|
|
const store = new LocalComplianceStore();
|
|
const batch = await store.createRegulatoryMappingBatchRun({
|
|
version: 1, id: 'dummy-batch', projectId: 'dummy-project', scopeKey: 'scope', filterHash: 'a'.repeat(64),
|
|
idempotencyKey: 'dummy-batch-1', assessmentIds: ['dummy-assessment'], scanRunIds: [], filters: {}, status: 'queued',
|
|
counts: { filteredResultCount: 0, excludedNonScannerCount: 0, eligibleFindingCount: 0, unsupportedFindingCount: 0,
|
|
distinctRuleCount: 0, reusedSucceededRuleCount: 0, reusedActiveRuleCount: 0, scheduledRuleCount: 0,
|
|
succeededRuleCount: 0, failedRuleCount: 0 },
|
|
createdAt: stamp, updatedAt: stamp
|
|
} satisfies RegulatoryMappingBatchRun);
|
|
const exported = await exportVia(store);
|
|
expect(exported).toMatchObject({ project: { id: 'dummy-project' }, regulatoryMappingBatchRuns: [batch],
|
|
regulatoryMappingRuns: [], regulatoryMappingDecisions: [] });
|
|
});
|
|
|
|
it('keeps the Core project export complete without the Compliance Engine', async () => {
|
|
const exported = await exportVia();
|
|
expect(exported).toMatchObject({ project: { id: 'dummy-project' } });
|
|
expect(exported).not.toHaveProperty('regulatoryMappingBatchRuns');
|
|
});
|