mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 14:12:10 +01:00
- Fix 36+ biome linting issues reducing errors/warnings from 227 to 191 - Replace explicit 'any' types with proper TypeScript interfaces - Fix React hooks dependencies and useCallback patterns - Resolve unused variables and parameter assignment issues - Improve accessibility with proper label associations - Add comprehensive API documentation for admin and security features - Update README.md with accurate PostgreSQL setup and current tech stack - Create complete documentation for audit logging, CSP monitoring, and batch processing - Fix outdated project information and missing developer workflows
181 lines
4.9 KiB
TypeScript
181 lines
4.9 KiB
TypeScript
import cron from "node-cron";
|
|
import { executeScheduledRetention } from "./auditLogRetention";
|
|
import {
|
|
AuditOutcome,
|
|
createAuditMetadata,
|
|
SecurityEventType,
|
|
securityAuditLogger,
|
|
} from "./securityAuditLogger";
|
|
|
|
export class AuditLogScheduler {
|
|
private retentionTask: cron.ScheduledTask | null = null;
|
|
private isRunning = false;
|
|
|
|
constructor() {
|
|
this.isRunning = false;
|
|
}
|
|
|
|
start(): void {
|
|
if (this.isRunning) {
|
|
console.log("Audit log scheduler is already running");
|
|
return;
|
|
}
|
|
|
|
const retentionSchedule =
|
|
process.env.AUDIT_LOG_RETENTION_SCHEDULE || "0 2 * * 0"; // Default: 2 AM every Sunday
|
|
const isDryRun = process.env.AUDIT_LOG_RETENTION_DRY_RUN === "true";
|
|
|
|
console.log(
|
|
`Starting audit log scheduler with schedule: ${retentionSchedule}`
|
|
);
|
|
console.log(`Dry run mode: ${isDryRun}`);
|
|
|
|
// Schedule retention policy execution
|
|
this.retentionTask = cron.schedule(
|
|
retentionSchedule,
|
|
async () => {
|
|
console.log("Executing scheduled audit log retention...");
|
|
|
|
try {
|
|
await executeScheduledRetention(isDryRun);
|
|
|
|
await securityAuditLogger.log({
|
|
eventType: SecurityEventType.SYSTEM_CONFIG,
|
|
action: "scheduled_audit_retention_success",
|
|
outcome: AuditOutcome.SUCCESS,
|
|
context: {
|
|
metadata: createAuditMetadata({
|
|
schedule: retentionSchedule,
|
|
isDryRun,
|
|
executionTime: new Date().toISOString(),
|
|
}),
|
|
},
|
|
});
|
|
} catch (error) {
|
|
console.error("Scheduled audit log retention failed:", error);
|
|
|
|
await securityAuditLogger.log({
|
|
eventType: SecurityEventType.SYSTEM_CONFIG,
|
|
action: "scheduled_audit_retention_failure",
|
|
outcome: AuditOutcome.FAILURE,
|
|
errorMessage: `Scheduled audit retention failed: ${error}`,
|
|
context: {
|
|
metadata: createAuditMetadata({
|
|
schedule: retentionSchedule,
|
|
isDryRun,
|
|
executionTime: new Date().toISOString(),
|
|
error: "retention_execution_failed",
|
|
}),
|
|
},
|
|
});
|
|
}
|
|
},
|
|
{
|
|
scheduled: false, // Don't start immediately
|
|
timezone: "UTC", // Use UTC to avoid timezone issues
|
|
}
|
|
);
|
|
|
|
this.retentionTask.start();
|
|
this.isRunning = true;
|
|
|
|
// Log scheduler startup
|
|
securityAuditLogger.log({
|
|
eventType: SecurityEventType.SYSTEM_CONFIG,
|
|
action: "audit_log_scheduler_started",
|
|
outcome: AuditOutcome.SUCCESS,
|
|
context: {
|
|
metadata: createAuditMetadata({
|
|
retentionSchedule,
|
|
isDryRun,
|
|
timezone: "UTC",
|
|
}),
|
|
},
|
|
});
|
|
|
|
console.log("Audit log scheduler started successfully");
|
|
}
|
|
|
|
stop(): void {
|
|
if (!this.isRunning) {
|
|
console.log("Audit log scheduler is not running");
|
|
return;
|
|
}
|
|
|
|
if (this.retentionTask) {
|
|
this.retentionTask.stop();
|
|
this.retentionTask = null;
|
|
}
|
|
|
|
this.isRunning = false;
|
|
|
|
// Log scheduler shutdown
|
|
securityAuditLogger.log({
|
|
eventType: SecurityEventType.SYSTEM_CONFIG,
|
|
action: "audit_log_scheduler_stopped",
|
|
outcome: AuditOutcome.SUCCESS,
|
|
context: {
|
|
metadata: createAuditMetadata({
|
|
shutdownTime: new Date().toISOString(),
|
|
}),
|
|
},
|
|
});
|
|
|
|
console.log("Audit log scheduler stopped");
|
|
}
|
|
|
|
getStatus(): {
|
|
isRunning: boolean;
|
|
nextExecution?: Date;
|
|
schedule?: string;
|
|
} {
|
|
return {
|
|
isRunning: this.isRunning,
|
|
nextExecution: this.retentionTask?.getStatus()?.next || undefined,
|
|
schedule: process.env.AUDIT_LOG_RETENTION_SCHEDULE || "0 2 * * 0",
|
|
};
|
|
}
|
|
|
|
async executeNow(isDryRun = false): Promise<void> {
|
|
console.log(
|
|
`Manually executing audit log retention (dry run: ${isDryRun})...`
|
|
);
|
|
|
|
await securityAuditLogger.log({
|
|
eventType: SecurityEventType.SYSTEM_CONFIG,
|
|
action: "manual_audit_retention_triggered",
|
|
outcome: AuditOutcome.SUCCESS,
|
|
context: {
|
|
metadata: createAuditMetadata({
|
|
isDryRun,
|
|
triggerTime: new Date().toISOString(),
|
|
triggerType: "manual",
|
|
}),
|
|
},
|
|
});
|
|
|
|
try {
|
|
await executeScheduledRetention(isDryRun);
|
|
} catch (error) {
|
|
await securityAuditLogger.log({
|
|
eventType: SecurityEventType.SYSTEM_CONFIG,
|
|
action: "manual_audit_retention_failed",
|
|
outcome: AuditOutcome.FAILURE,
|
|
errorMessage: `Manual audit retention failed: ${error}`,
|
|
context: {
|
|
metadata: createAuditMetadata({
|
|
isDryRun,
|
|
triggerTime: new Date().toISOString(),
|
|
triggerType: "manual",
|
|
error: "retention_execution_failed",
|
|
}),
|
|
},
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const auditLogScheduler = new AuditLogScheduler();
|