Add API to manage webhook secrets for alert integrations
All checks were successful
CI — P3 Alert / test (push) Successful in 15s

This commit is contained in:
2026-03-02 05:00:40 +00:00
parent 9d33c536d5
commit 9f46b84257
2 changed files with 51 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import { withTenant } from '../data/db.js';
const createSecretSchema = z.object({
provider: z.enum(['datadog', 'pagerduty', 'opsgenie', 'grafana', 'custom']),
secret: z.string().min(1).max(500),
});
export function registerWebhookSecretRoutes(app: FastifyInstance) {
// List webhook secrets
app.get('/api/v1/webhooks/secrets', async (req, reply) => {
const tenantId = (req as any).tenantId;
const result = await withTenant(tenantId, async (client) => {
return client.query('SELECT provider, created_at FROM webhook_secrets ORDER BY provider');
});
return { secrets: result.rows };
});
// Create or update webhook secret
app.put('/api/v1/webhooks/secrets', async (req, reply) => {
const tenantId = (req as any).tenantId;
const { provider, secret } = createSecretSchema.parse(req.body);
await withTenant(tenantId, async (client) => {
await client.query(
`INSERT INTO webhook_secrets (tenant_id, provider, secret)
VALUES ($1, $2, $3)
ON CONFLICT (tenant_id, provider) DO UPDATE
SET secret = EXCLUDED.secret, created_at = now()`,
[tenantId, provider, secret]
);
});
return reply.status(200).send({ status: 'success', provider });
});
// Delete webhook secret
app.delete('/api/v1/webhooks/secrets/:provider', async (req, reply) => {
const tenantId = (req as any).tenantId;
const { provider } = req.params as { provider: string };
await withTenant(tenantId, async (client) => {
await client.query('DELETE FROM webhook_secrets WHERE provider = $1', [provider]);
});
return reply.status(200).send({ status: 'success', deleted: provider });
});
}

View File

@@ -6,6 +6,7 @@ import { config } from './config/index.js';
import { pool } from './data/db.js'; import { pool } from './data/db.js';
import { registerAuth, registerAuthRoutes } from './auth/middleware.js'; import { registerAuth, registerAuthRoutes } from './auth/middleware.js';
import { registerWebhookRoutes } from './api/webhooks.js'; import { registerWebhookRoutes } from './api/webhooks.js';
import { registerWebhookSecretRoutes } from './api/webhook_secrets.js';
import { registerIncidentRoutes } from './api/incidents.js'; import { registerIncidentRoutes } from './api/incidents.js';
import { registerNotificationRoutes } from './api/notifications.js'; import { registerNotificationRoutes } from './api/notifications.js';
@@ -22,6 +23,7 @@ app.get('/health', async () => ({ status: 'ok', service: 'dd0c-alert' }));
registerAuthRoutes(app, config.JWT_SECRET, pool); registerAuthRoutes(app, config.JWT_SECRET, pool);
registerWebhookRoutes(app); registerWebhookRoutes(app);
registerWebhookSecretRoutes(app);
registerIncidentRoutes(app); registerIncidentRoutes(app);
registerNotificationRoutes(app); registerNotificationRoutes(app);