import { describe, it, expect } from 'vitest'; import { validateDatadogHmac, validatePagerdutyHmac, validateOpsgenieHmac, normalizeDatadog, normalizePagerduty, normalizeOpsgenie, } from '../../src/ingestion/webhook.js'; import crypto from 'node:crypto'; const SECRET = 'test-webhook-secret'; describe('HMAC Validation', () => { describe('Datadog', () => { it('accepts valid signature with fresh timestamp', () => { const body = '{"alert_id":"123"}'; const ts = Math.floor(Date.now() / 1000).toString(); const sig = crypto.createHmac('sha256', SECRET).update(ts + body).digest('hex'); const result = validateDatadogHmac(body, sig, ts, SECRET); expect(result.valid).toBe(true); }); it('rejects stale timestamp (>5 minutes)', () => { const body = '{"alert_id":"123"}'; const ts = (Math.floor(Date.now() / 1000) - 301).toString(); const sig = crypto.createHmac('sha256', SECRET).update(ts + body).digest('hex'); const result = validateDatadogHmac(body, sig, ts, SECRET); expect(result.valid).toBe(false); expect(result.error).toContain('stale timestamp'); }); it('rejects missing signature', () => { const result = validateDatadogHmac('{}', undefined, '123', SECRET); expect(result.valid).toBe(false); }); it('rejects invalid signature', () => { const ts = Math.floor(Date.now() / 1000).toString(); const result = validateDatadogHmac('{}', 'bad-sig', ts, SECRET); expect(result.valid).toBe(false); }); }); describe('PagerDuty', () => { it('rejects missing signature', () => { const result = validatePagerdutyHmac('{}', undefined, SECRET); expect(result.valid).toBe(false); }); it('rejects malformed signature', () => { const result = validatePagerdutyHmac('{}', 'garbage', SECRET); expect(result.valid).toBe(false); }); }); describe('OpsGenie', () => { it('rejects stale timestamp from payload body', () => { const staleTs = Date.now() - 6 * 60 * 1000; // 6 minutes ago const body = JSON.stringify({ alert: { alertId: '1' }, timestamp: staleTs }); const sig = crypto.createHmac('sha256', SECRET).update(body).digest('hex'); const result = validateOpsgenieHmac(body, sig, SECRET); expect(result.valid).toBe(false); expect(result.error).toContain('stale timestamp'); }); it('accepts fresh payload', () => { const body = JSON.stringify({ alert: { alertId: '1' }, timestamp: Date.now() }); const sig = crypto.createHmac('sha256', SECRET).update(body).digest('hex'); const result = validateOpsgenieHmac(body, sig, SECRET); expect(result.valid).toBe(true); }); }); }); describe('Payload Normalizers', () => { it('normalizes Datadog payload', () => { const alert = normalizeDatadog({ alert_id: 'dd-123', title: 'High CPU', priority: 'P1', alert_transition: 'Triggered', tags: { service: 'auth', env: 'prod' }, date_happened: 1709251200, }); expect(alert.sourceProvider).toBe('datadog'); expect(alert.severity).toBe('critical'); expect(alert.status).toBe('firing'); expect(alert.service).toBe('auth'); }); it('normalizes PagerDuty payload', () => { const alert = normalizePagerduty({ event: { event_type: 'incident.triggered', data: { id: 'pd-456', title: 'Disk Full', urgency: 'high', service: { name: 'storage' }, created_at: '2026-03-01T00:00:00Z', }, }, }); expect(alert.sourceProvider).toBe('pagerduty'); expect(alert.severity).toBe('critical'); expect(alert.service).toBe('storage'); }); it('normalizes OpsGenie payload', () => { const alert = normalizeOpsgenie({ action: 'Create', alert: { alertId: 'og-789', message: 'Memory Leak', priority: 'P2', tags: ['service:api'], }, }); expect(alert.sourceProvider).toBe('opsgenie'); expect(alert.severity).toBe('high'); expect(alert.status).toBe('firing'); }); it('maps Datadog Recovered to resolved', () => { const alert = normalizeDatadog({ alert_transition: 'Recovered' }); expect(alert.status).toBe('resolved'); }); it('maps OpsGenie Close to resolved', () => { const alert = normalizeOpsgenie({ action: 'Close', alert: {} }); expect(alert.status).toBe('resolved'); }); });