Files
CASAN/packages/casan-control-panel/backend/test/ingest.test.ts
T

46 lines
1.7 KiB
TypeScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { BadRequestException, ServiceUnavailableException } from '@nestjs/common';
import { IngestService, expectedSignature, stableJson } from '../src/ingest/ingest.service.js';
test('ingest canonical JSON is stable across object key order', () => {
assert.equal(stableJson({ z: 1, a: { y: 2, b: 3 } }), '{"a":{"b":3,"y":2},"z":1}');
});
test('ingest is disabled unless an HMAC secret is configured', () => {
const previous = process.env.CASAN_CP_INGEST_TOKEN;
delete process.env.CASAN_CP_INGEST_TOKEN;
try {
assert.throws(() => new IngestService().ingest({}, '0', 'none'), ServiceUnavailableException);
} finally {
if (previous === undefined) delete process.env.CASAN_CP_INGEST_TOKEN;
else process.env.CASAN_CP_INGEST_TOKEN = previous;
}
});
test('signed ingest rejects raw prompt/content fields before persistence', () => {
const previous = process.env.CASAN_CP_INGEST_TOKEN;
process.env.CASAN_CP_INGEST_TOKEN = 'test-only-secret';
const timestamp = String(Math.floor(Date.now() / 1000));
const body = {
schema_version: 1,
sent_at: new Date().toISOString(),
project_id: 'safe-project',
trace_id: 'safe-trace',
receipt: {},
metric: { trace_id: 'safe-trace', prompt: 'must-not-cross-boundary' },
trace: { trace_id: 'safe-trace' },
events: [],
};
try {
const signature = expectedSignature('test-only-secret', timestamp, body);
assert.throws(
() => new IngestService().ingest(body, timestamp, signature),
BadRequestException,
);
} finally {
if (previous === undefined) delete process.env.CASAN_CP_INGEST_TOKEN;
else process.env.CASAN_CP_INGEST_TOKEN = previous;
}
});