import { strict as assert } from 'node:assert'; import { createHmac } from 'node:crypto'; import { describe, it } from 'node:test'; import type { Database } from '@pig/db'; import type { Principal } from '../src/lib/auth'; import { AuthError } from '../src/lib/auth'; import { executeMutation } from '../src/lib/mutation'; import { createSlackLinkMutationDefinition, parseSlashRequirement, verifySlackRequest, } from '../src/routes/slack'; import { NotificationDeliveryError } from '../src/services/notifier'; import { SlackNotifier, slackClientMessageId } from '../src/services/slack'; const NOW = 1_786_579_200; const SECRET = 'test-signing-secret'; function signature(timestamp: number, body: string): string { return `v0=${createHmac('sha256', SECRET).update(`v0:${timestamp}:${body}`).digest('hex')}`; } describe('Slack request verification', () => { it('accepts the exact signed bytes and rejects tampering', () => { const body = 'team_id=T1&channel_id=C1&text=8+H100_80GB'; const signed = signature(NOW, body); assert.equal(verifySlackRequest(SECRET, String(NOW), signed, body, NOW), true); assert.equal(verifySlackRequest(SECRET, String(NOW), signed, `${body}+fabric`, NOW), false); }); it('rejects replayed requests outside Slack\'s five-minute window', () => { const body = 'team_id=T1&channel_id=C1&text=8+H100_80GB'; const old = NOW - 301; assert.equal(verifySlackRequest(SECRET, String(old), signature(old, body), body, NOW), false); }); }); describe('Slack capacity command', () => { it('turns transport syntax into a CapacityService requirement without matching in the handler', () => { assert.deepEqual( parseSlashRequirement('8 H100_80GB hours=640 max=2.50 fabric tier=secure_cloud'), { gpuCount: 8, gpuType: 'H100_80GB', totalGpuHours: 640, maxPricePerGpuHourCents: 250, requiresHighSpeedInterconnect: true, minSecurityTier: 'secure_cloud', }, ); assert.equal(parseSlashRequirement('eight H100_80GB'), null); }); }); describe('Slack channel link authorization', () => { it('denies non-admins before reading link input or opening a transaction', async () => { const events: string[] = []; const principal: Principal = { userId: '00000000-0000-4000-8000-000000000001', email: 'seller@example.com', name: 'Seller', isPlatformAdmin: false, teams: [{ team: 'demand', role: 'admin' }], via: 'jwt', scopes: ['read', 'write'], }; const db = { transaction: async () => { events.push('transaction'); }, } as unknown as Database; await assert.rejects( executeMutation( db, principal, async () => { events.push('body'); return {}; }, createSlackLinkMutationDefinition(), ), (error: unknown) => error instanceof AuthError && error.code === 'insufficient_permission', ); assert.deepEqual(events, []); }); }); describe('Slack delivery decisions', () => { it('reuses a deterministic client message id across retries', async () => { const bodies: Record[] = []; const notifier = new SlackNotifier({ botToken: 'xoxb-test', fetchImpl: async (_input, init) => { bodies.push(JSON.parse(String(init?.body)) as Record); return Response.json({ ok: true, ts: '123.456' }); }, }); const envelope = { idempotencyKey: 'slack:link:event', destination: 'C123', notification: { kind: 'stage_change' as const, accountId: '10000000-0000-4000-8000-000000000001', dealId: '20000000-0000-4000-8000-000000000002', dealSide: 'demand' as const, dealName: 'Reserved H100 cluster', fromStage: 'proposal', toStage: 'procurement', changedAt: '2026-08-12T12:00:00.000Z', }, }; await notifier.send(envelope); await notifier.send(envelope); assert.equal(bodies[0]?.client_msg_id, slackClientMessageId(envelope.idempotencyKey)); assert.equal(bodies[1]?.client_msg_id, bodies[0]?.client_msg_id); }); it('marks rate limits retryable and honours Slack retry-after', async () => { const notifier = new SlackNotifier({ botToken: 'xoxb-test', fetchImpl: async () => new Response('', { status: 429, headers: { 'retry-after': '7' } }), }); await assert.rejects( notifier.send({ idempotencyKey: 'one', destination: 'C1', notification: { kind: 'idle_capacity', accountId: '10000000-0000-4000-8000-000000000001', commitmentId: '20000000-0000-4000-8000-000000000002', commitmentName: 'Eight H100s', gpuType: 'H100_80GB', idleGpuHours: 640, idleCostCents: 120_000, utilisation: 0, observedAt: '2026-08-12T12:00:00.000Z', }, }), (error: unknown) => error instanceof NotificationDeliveryError && error.retryable && error.retryAfterMs === 7_000, ); }); });