feat: error audit middleware, impersonation attribution, account lockout logging
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m13s

- Add withErrorAudit middleware tracking FORBIDDEN/UNAUTHORIZED/NOT_FOUND per user
- Fix impersonation attribution: log real admin ID, prefix IMPERSONATED_ on actions
- Add ACCOUNT_LOCKED audit events on login lockout (distinct from LOGIN_FAILED)
- Audit export of assignments and audit logs (meta-audit gap)
- Update audit page UI with new security event types and colors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 18:28:56 +01:00
parent c8c26beed2
commit 13f125af28
4 changed files with 214 additions and 50 deletions

View File

@@ -235,6 +235,16 @@ export const exportRouter = router({
orderBy: [{ project: { title: 'asc' } }, { user: { name: 'asc' } }],
})
await logAudit({
prisma: ctx.prisma,
userId: ctx.user.id,
action: 'EXPORT',
entityType: 'Assignment',
detailsJson: { roundId: input.roundId, count: assignments.length, exportType: 'assignments' },
ipAddress: ctx.ip,
userAgent: ctx.userAgent,
})
const data = assignments.map((a) => ({
projectTitle: a.project.title,
teamName: a.project.teamName,
@@ -398,6 +408,20 @@ export const exportRouter = router({
take: 10000, // Limit export to 10k records
})
await logAudit({
prisma: ctx.prisma,
userId: ctx.user.id,
action: 'EXPORT',
entityType: 'AuditLog',
detailsJson: {
count: logs.length,
exportType: 'auditLogs',
filters: { userId, action, entityType, startDate: startDate?.toISOString(), endDate: endDate?.toISOString() },
},
ipAddress: ctx.ip,
userAgent: ctx.userAgent,
})
const data = logs.map((log) => ({
timestamp: log.timestamp.toISOString(),
userName: log.user?.name ?? 'System',