Wire up remaining TODO stubs: P3 test notifications, P2 drift notification trigger
- P3: test notification endpoint now instantiates real Slack/Email/Webhook notifiers - P2: drift processor triggers notification service when drift_score > 0 (non-fatal on failure)
This commit is contained in:
@@ -56,8 +56,21 @@ export async function registerProcessorRoutes(app: FastifyInstance) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Trigger notification if drift_score > threshold
|
// Trigger notification if drift score exceeds threshold
|
||||||
// TODO: Trigger remediation workflow if auto-remediate enabled
|
if (report.drift_score > 0) {
|
||||||
|
try {
|
||||||
|
const { DriftNotificationService } = await import('../notifications/service.js');
|
||||||
|
const notifService = new DriftNotificationService(pool);
|
||||||
|
await notifService.notifyDrift(tenantId, {
|
||||||
|
stackName: report.stack_name,
|
||||||
|
driftScore: report.drift_score,
|
||||||
|
totalResources: report.total_resources,
|
||||||
|
driftedResources: report.drifted_resources?.length ?? 0,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
app.log.warn({ tenantId, error: (err as Error).message }, 'Notification dispatch failed (non-fatal)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return reply.status(201).send({ status: 'accepted' });
|
return reply.status(201).send({ status: 'accepted' });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -50,8 +50,35 @@ export function registerNotificationRoutes(app: FastifyInstance) {
|
|||||||
const { channel } = req.params as { channel: string };
|
const { channel } = req.params as { channel: string };
|
||||||
const tenantId = (req as any).tenantId;
|
const tenantId = (req as any).tenantId;
|
||||||
|
|
||||||
// TODO: Send test notification via the configured channel
|
const configResult = await withTenant(tenantId, async (client) => {
|
||||||
logger.info({ tenantId, channel }, 'Test notification sent');
|
return client.query('SELECT * FROM notification_configs WHERE channel = $1', [channel]);
|
||||||
return { status: 'sent', channel };
|
});
|
||||||
|
|
||||||
|
const cfg = configResult.rows[0];
|
||||||
|
if (!cfg) return reply.status(404).send({ error: `No ${channel} config found` });
|
||||||
|
|
||||||
|
const { SlackNotifier, EmailNotifier, WebhookNotifier } = await import('../notifications/dispatcher.js');
|
||||||
|
const testIncident = {
|
||||||
|
incidentId: 'test-000',
|
||||||
|
title: '[TEST] dd0c/alert notification test',
|
||||||
|
severity: 'info',
|
||||||
|
service: 'test-service',
|
||||||
|
alertCount: 1,
|
||||||
|
firstAlertAt: new Date(),
|
||||||
|
fingerprint: 'test',
|
||||||
|
dashboardUrl: `https://alert.dd0c.dev/incidents/test-000`,
|
||||||
|
};
|
||||||
|
|
||||||
|
let sent = false;
|
||||||
|
if (channel === 'slack' && cfg.config?.slack_webhook_url) {
|
||||||
|
sent = await new SlackNotifier(cfg.config.slack_webhook_url).send(testIncident);
|
||||||
|
} else if (channel === 'email' && cfg.config?.email_to) {
|
||||||
|
sent = await new EmailNotifier(process.env.RESEND_API_KEY ?? '', 'alerts@dd0c.dev', cfg.config.email_to).send(testIncident);
|
||||||
|
} else if (channel === 'webhook' && cfg.config?.webhook_url) {
|
||||||
|
sent = await new WebhookNotifier(cfg.config.webhook_url).send(testIncident);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info({ tenantId, channel, sent }, 'Test notification sent');
|
||||||
|
return { status: sent ? 'sent' : 'failed', channel };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user