feat: Implement centralized audit logging admin interface (refs #10)
Some checks failed
Deploy to Staging / Build Images (pull_request) Successful in 4m42s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 37s
Deploy to Staging / Verify Staging (pull_request) Failing after 6s
Deploy to Staging / Notify Staging Ready (pull_request) Has been skipped
Deploy to Staging / Notify Staging Failure (pull_request) Successful in 6s
Some checks failed
Deploy to Staging / Build Images (pull_request) Successful in 4m42s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 37s
Deploy to Staging / Verify Staging (pull_request) Failing after 6s
Deploy to Staging / Notify Staging Ready (pull_request) Has been skipped
Deploy to Staging / Notify Staging Failure (pull_request) Successful in 6s
- Add audit_logs table with categories, severities, and indexes - Create AuditLogService and AuditLogRepository - Add REST API endpoints for viewing and exporting logs - Wire audit logging into auth, vehicles, admin, and backup features - Add desktop AdminLogsPage with filters and CSV export - Add mobile AdminLogsMobileScreen with card layout - Implement 90-day retention cleanup job - Remove old AuditLogPanel from AdminCatalogPage Security fixes: - Escape LIKE special characters to prevent pattern injection - Limit CSV export to 5000 records to prevent memory exhaustion - Add truncation warning headers for large exports 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
ScheduleIdParam,
|
||||
UpdateSettingsBody,
|
||||
} from './backup.validation';
|
||||
import { auditLogService } from '../../audit-log';
|
||||
|
||||
export class BackupController {
|
||||
private backupService: BackupService;
|
||||
@@ -54,12 +55,32 @@ export class BackupController {
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
// Log backup creation to unified audit log
|
||||
await auditLogService.info(
|
||||
'system',
|
||||
adminSub || null,
|
||||
`Backup created: ${request.body.name || 'Manual backup'}`,
|
||||
'backup',
|
||||
result.backupId,
|
||||
{ name: request.body.name, includeDocuments: request.body.includeDocuments }
|
||||
).catch(err => logger.error('Failed to log backup create audit event', { error: err }));
|
||||
|
||||
reply.status(201).send({
|
||||
backupId: result.backupId,
|
||||
status: 'completed',
|
||||
message: 'Backup created successfully',
|
||||
});
|
||||
} else {
|
||||
// Log backup failure
|
||||
await auditLogService.error(
|
||||
'system',
|
||||
adminSub || null,
|
||||
`Backup failed: ${request.body.name || 'Manual backup'}`,
|
||||
'backup',
|
||||
result.backupId,
|
||||
{ error: result.error }
|
||||
).catch(err => logger.error('Failed to log backup failure audit event', { error: err }));
|
||||
|
||||
reply.status(500).send({
|
||||
backupId: result.backupId,
|
||||
status: 'failed',
|
||||
@@ -196,6 +217,8 @@ export class BackupController {
|
||||
request: FastifyRequest<{ Params: BackupIdParam; Body: RestoreBody }>,
|
||||
reply: FastifyReply
|
||||
): Promise<void> {
|
||||
const adminSub = (request as any).userContext?.auth0Sub;
|
||||
|
||||
try {
|
||||
const result = await this.restoreService.executeRestore({
|
||||
backupId: request.params.id,
|
||||
@@ -203,6 +226,16 @@ export class BackupController {
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
// Log successful restore to unified audit log
|
||||
await auditLogService.info(
|
||||
'system',
|
||||
adminSub || null,
|
||||
`Backup restored: ${request.params.id}`,
|
||||
'backup',
|
||||
request.params.id,
|
||||
{ safetyBackupId: result.safetyBackupId }
|
||||
).catch(err => logger.error('Failed to log restore success audit event', { error: err }));
|
||||
|
||||
reply.send({
|
||||
success: true,
|
||||
safetyBackupId: result.safetyBackupId,
|
||||
@@ -210,6 +243,16 @@ export class BackupController {
|
||||
message: 'Restore completed successfully',
|
||||
});
|
||||
} else {
|
||||
// Log restore failure
|
||||
await auditLogService.error(
|
||||
'system',
|
||||
adminSub || null,
|
||||
`Backup restore failed: ${request.params.id}`,
|
||||
'backup',
|
||||
request.params.id,
|
||||
{ error: result.error, safetyBackupId: result.safetyBackupId }
|
||||
).catch(err => logger.error('Failed to log restore failure audit event', { error: err }));
|
||||
|
||||
reply.status(500).send({
|
||||
success: false,
|
||||
safetyBackupId: result.safetyBackupId,
|
||||
|
||||
Reference in New Issue
Block a user