Add API to manage webhook secrets for alert integrations
All checks were successful
CI — P3 Alert / test (push) Successful in 15s
All checks were successful
CI — P3 Alert / test (push) Successful in 15s
This commit is contained in:
49
products/03-alert-intelligence/src/api/webhook_secrets.ts
Normal file
49
products/03-alert-intelligence/src/api/webhook_secrets.ts
Normal 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 });
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user