feat(audit): comprehensive logging — auth events, severity, source, IP
Audit log was previously silent on authentication and on background work. This wires: - Login (success + failed) and logout via a wrapper around better-auth's [...all] handler. Failed logins are severity 'warning' and carry the attempted email so brute-force attempts surface in the inspector. - New severity (info|warning|error|critical) and source (user|auth| system|webhook|cron|job) columns on audit_logs. permission_denied defaults to 'warning', hard_delete to 'critical'. - Webhook delivery success/failure/DLQ/retry now write audit rows alongside the webhook_deliveries detail table. - IP address is now visible as a column in the inspector (was already captured at the helper level). - Audit UI: severity badges per row, severity + source dropdowns, IP column, expanded action filter covering hard-delete, webhook events, job/cron events. Migration 0044 adds the two columns + their port-scoped indexes. 1175/1175 vitest passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -200,6 +200,8 @@ export const webhooksWorker = new Worker(
|
||||
const maxAttempts = QUEUE_CONFIGS.webhooks.maxAttempts;
|
||||
const isFinalAttempt = attempt >= maxAttempts;
|
||||
|
||||
const { createAuditLog } = await import('@/lib/audit');
|
||||
|
||||
if (success) {
|
||||
// 6a. Record success
|
||||
await db
|
||||
@@ -214,6 +216,17 @@ export const webhooksWorker = new Worker(
|
||||
.where(eq(webhookDeliveries.id, deliveryId));
|
||||
|
||||
logger.info({ webhookId, deliveryId, event }, 'Webhook delivered successfully');
|
||||
|
||||
void createAuditLog({
|
||||
userId: null,
|
||||
portId,
|
||||
action: 'webhook_delivered',
|
||||
entityType: 'webhook_delivery',
|
||||
entityId: deliveryId,
|
||||
metadata: { webhookId, event, responseStatus, attempt },
|
||||
source: 'webhook',
|
||||
severity: 'info',
|
||||
});
|
||||
} else if (!success && isFinalAttempt) {
|
||||
// 6b. Final failure → dead_letter + system alert
|
||||
await db
|
||||
@@ -231,6 +244,17 @@ export const webhooksWorker = new Worker(
|
||||
'Webhook delivery permanently failed - dead_letter',
|
||||
);
|
||||
|
||||
void createAuditLog({
|
||||
userId: null,
|
||||
portId,
|
||||
action: 'webhook_dead_letter',
|
||||
entityType: 'webhook_delivery',
|
||||
entityId: deliveryId,
|
||||
metadata: { webhookId, event, responseStatus, attempt, responseBody },
|
||||
source: 'webhook',
|
||||
severity: 'error',
|
||||
});
|
||||
|
||||
// Notify all super admins
|
||||
try {
|
||||
const superAdmins = await db
|
||||
@@ -272,6 +296,17 @@ export const webhooksWorker = new Worker(
|
||||
})
|
||||
.where(eq(webhookDeliveries.id, deliveryId));
|
||||
|
||||
void createAuditLog({
|
||||
userId: null,
|
||||
portId,
|
||||
action: 'webhook_failed',
|
||||
entityType: 'webhook_delivery',
|
||||
entityId: deliveryId,
|
||||
metadata: { webhookId, event, responseStatus, attempt },
|
||||
source: 'webhook',
|
||||
severity: 'warning',
|
||||
});
|
||||
|
||||
throw new Error(
|
||||
`Webhook delivery attempt ${attempt} failed. Status: ${responseStatus ?? 'network error'}. Retrying...`,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user