feat(audit-logging): Implement Edge-compatible audit logging utility and safe logging module

- Added `auditLogEdge.js` for Edge Runtime compatible audit logging, including console logging and API fallback.
- Introduced `auditLogSafe.js` for safe audit logging without direct database imports, ensuring compatibility across runtimes.
- Enhanced `auth.js` to integrate safe audit logging for login actions, including success and failure cases.
- Created middleware `auditLog.js` to facilitate audit logging for API routes with predefined configurations.
- Updated `middleware.js` to allow API route access without authentication checks.
- Added tests for audit logging functionality and Edge compatibility in `test-audit-logging.mjs` and `test-edge-compatibility.mjs`.
- Implemented safe audit logging tests in `test-safe-audit-logging.mjs` to verify functionality across environments.
This commit is contained in:
Chop
2025-07-09 23:08:16 +02:00
parent 90875db28b
commit b1a78bf7a8
20 changed files with 2943 additions and 130 deletions

138
test-audit-logging.mjs Normal file
View File

@@ -0,0 +1,138 @@
import {
logAuditEvent,
getAuditLogs,
getAuditLogStats,
AUDIT_ACTIONS,
RESOURCE_TYPES,
} from "./src/lib/auditLog.js";
// Test audit logging functionality
console.log("Testing Audit Logging System...\n");
// Test 1: Log some sample events
console.log("1. Creating sample audit events...");
logAuditEvent({
action: AUDIT_ACTIONS.LOGIN,
userId: "user123",
resourceType: RESOURCE_TYPES.SESSION,
ipAddress: "192.168.1.100",
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
details: {
email: "test@example.com",
role: "user",
},
});
logAuditEvent({
action: AUDIT_ACTIONS.PROJECT_CREATE,
userId: "user123",
resourceType: RESOURCE_TYPES.PROJECT,
resourceId: "proj-456",
ipAddress: "192.168.1.100",
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
details: {
project_name: "Test Project",
project_number: "TP-001",
},
});
logAuditEvent({
action: AUDIT_ACTIONS.PROJECT_UPDATE,
userId: "user456",
resourceType: RESOURCE_TYPES.PROJECT,
resourceId: "proj-456",
ipAddress: "192.168.1.101",
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
details: {
updatedFields: ["project_name", "address"],
oldValues: { project_name: "Test Project" },
newValues: { project_name: "Updated Test Project" },
},
});
logAuditEvent({
action: AUDIT_ACTIONS.LOGIN_FAILED,
userId: null,
resourceType: RESOURCE_TYPES.SESSION,
ipAddress: "192.168.1.102",
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
details: {
email: "hacker@evil.com",
reason: "invalid_password",
failed_attempts: 3,
},
});
console.log("Sample events created!\n");
// Test 2: Retrieve audit logs
console.log("2. Retrieving audit logs...");
const allLogs = getAuditLogs();
console.log(`Found ${allLogs.length} total audit events`);
// Show the latest 3 events
console.log("\nLatest audit events:");
allLogs.slice(0, 3).forEach((log, index) => {
console.log(
`${index + 1}. ${log.timestamp} - ${log.action} by user ${
log.user_id || "anonymous"
} on ${log.resource_type}:${log.resource_id || "N/A"}`
);
if (log.details) {
console.log(` Details: ${JSON.stringify(log.details, null, 2)}`);
}
});
// Test 3: Filtered queries
console.log("\n3. Testing filtered queries...");
const loginEvents = getAuditLogs({ action: AUDIT_ACTIONS.LOGIN });
console.log(`Found ${loginEvents.length} login events`);
const projectEvents = getAuditLogs({ resourceType: RESOURCE_TYPES.PROJECT });
console.log(`Found ${projectEvents.length} project-related events`);
const user123Events = getAuditLogs({ userId: "user123" });
console.log(`Found ${user123Events.length} events by user123`);
// Test 4: Statistics
console.log("\n4. Getting audit statistics...");
const stats = getAuditLogStats();
console.log("Overall statistics:");
console.log(`- Total events: ${stats.total}`);
console.log("- Action breakdown:");
stats.actionBreakdown.forEach((action) => {
console.log(` - ${action.action}: ${action.count}`);
});
console.log("- User breakdown:");
stats.userBreakdown.forEach((user) => {
console.log(
` - ${user.user_name || user.user_id || "Anonymous"}: ${user.count}`
);
});
console.log("- Resource breakdown:");
stats.resourceBreakdown.forEach((resource) => {
console.log(` - ${resource.resource_type}: ${resource.count}`);
});
// Test 5: Date range filtering
console.log("\n5. Testing date range filtering...");
const now = new Date();
const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);
const recentLogs = getAuditLogs({
startDate: oneHourAgo.toISOString(),
endDate: now.toISOString(),
});
console.log(`Found ${recentLogs.length} events in the last hour`);
console.log("\nAudit logging test completed successfully! ✅");
console.log("\nTo view audit logs in the application:");
console.log("1. Start your Next.js application");
console.log("2. Login as an admin or project manager");
console.log("3. Navigate to /admin/audit-logs");
console.log("4. Use the filters to explore the audit trail");