@devilsdev/rag-pipeline-utils 2.1.11 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ragrc.schema.json +218 -0
- package/README.md +651 -393
- package/bin/cli.js +8 -14
- package/dist/index.d.ts +237 -0
- package/dist/index.mjs +22 -7
- package/package.json +17 -13
- package/src/ai/adaptive-retrieval.js +191 -0
- package/src/ai/federated-learning.js +214 -0
- package/src/ai/federation/federated-learning-coordinator.js +345 -0
- package/src/ai/federation.js +76 -0
- package/src/ai/index-fixed.js +509 -0
- package/src/ai/index.js +33 -0
- package/src/ai/model-trainer.js +217 -0
- package/src/ai/model-training.js +205 -0
- package/src/ai/module-template.js +37 -0
- package/src/ai/multimodal/multi-modal-processor.js +345 -0
- package/src/ai/multimodal-processing.js +268 -0
- package/src/ai/multimodal.js +71 -0
- package/src/ai/orchestrator.js +70 -0
- package/src/ai/retrieval/adaptive-retrieval-engine.js +398 -0
- package/src/ai/retrieval-engine.js +69 -0
- package/src/ai/training/model-training-orchestrator.js +228 -0
- package/src/ci/workflow-analyzer.js +71 -0
- package/src/cli/commands/ai-ml.js +967 -0
- package/src/cli/commands/docs.js +228 -0
- package/src/cli/commands/dx.js +538 -0
- package/src/cli/commands/plugin-hub.js +875 -0
- package/src/cli/doctor-command.js +639 -0
- package/src/cli/enhanced-cli-commands.js +945 -0
- package/src/cli/interactive-wizard.js +997 -0
- package/src/cli/plugin-marketplace-commands.js +869 -0
- package/src/cli.js +17 -0
- package/src/config/enhanced-ragrc-schema.js +632 -0
- package/src/config/load-config.js +54 -0
- package/src/config/load-plugin-config.js +69 -0
- package/src/config/normalize-config.js +105 -0
- package/src/config/schema-validator.js +315 -0
- package/src/config/validate-plugin-schema.js +35 -0
- package/src/config/validate-schema.js +113 -0
- package/src/contracts/plugin-contracts.js +33 -0
- package/src/core/create-pipeline.js +99 -0
- package/src/core/dependency-injection.js +242 -0
- package/src/core/observability/event-logger.js +241 -0
- package/src/core/observability/instrumented-pipeline.js +609 -0
- package/src/core/observability/metrics.js +497 -0
- package/src/core/observability/tracing.js +781 -0
- package/src/core/performance/benchmark.js +516 -0
- package/src/core/performance/parallel-processor.js +240 -0
- package/src/core/performance/streaming-safeguards.js +611 -0
- package/src/core/pipeline-factory.js +60 -0
- package/src/core/plugin-contracts.js +89 -0
- package/src/core/plugin-marketplace/plugin-metadata.js +485 -0
- package/src/core/plugin-marketplace/plugin-publisher.js +574 -0
- package/src/core/plugin-marketplace/plugin-registry-format.js +419 -0
- package/src/core/plugin-marketplace/version-resolver.js +61 -0
- package/src/core/plugin-registry.js +265 -0
- package/src/dag/dag-engine.js +954 -0
- package/src/dag/dag-node.js +76 -0
- package/src/dag/enhanced-dag-engine.js +822 -0
- package/src/dx/index.js +40 -0
- package/src/dx/integration-templates.js +665 -0
- package/src/dx/performance-profiler.js +968 -0
- package/src/dx/realtime-debugger.js +755 -0
- package/src/dx/visual-pipeline-builder.js +578 -0
- package/src/ecosystem/plugin-analytics-dashboard.js +778 -0
- package/src/ecosystem/plugin-certification.js +580 -0
- package/src/ecosystem/plugin-hub.js +821 -0
- package/src/enterprise/audit-logging.js +967 -0
- package/src/enterprise/data-governance.js +408 -0
- package/src/enterprise/multi-tenancy.js +496 -0
- package/src/enterprise/sso-integration.js +903 -0
- package/src/evaluate/evaluator.js +52 -0
- package/src/evaluate/scoring.js +91 -0
- package/src/index.js +67 -0
- package/src/ingest.js +59 -0
- package/src/loader/csv-loader.js +38 -0
- package/src/loader/directory-loader.js +48 -0
- package/src/loader/html-loader.js +62 -0
- package/src/loader/markdown-loader.js +67 -0
- package/src/mocks/openai-embedder.js +119 -0
- package/src/mocks/openai-llm.js +77 -0
- package/src/mocks/pdf-loader.js +21 -0
- package/src/mocks/pinecone-retriever.js +106 -0
- package/src/observability/audit-logger.js +758 -0
- package/src/observability/dashboard-config.json +675 -0
- package/src/observability/event-logger.js +310 -0
- package/src/observability/metrics.js +691 -0
- package/src/observability/security-monitor.js +830 -0
- package/src/observability/slo-monitor.js +319 -0
- package/src/observability/telemetry.js +686 -0
- package/src/pipeline/pipeline.js +18 -0
- package/src/plugins/sample-embedder.js +53 -0
- package/src/plugins/sample-llm.js +30 -0
- package/src/plugins/sample-loader.js +24 -0
- package/src/plugins/sample-retriever.js +84 -0
- package/src/query.js +117 -0
- package/src/reranker/llm-reranker.js +85 -0
- package/src/scripts/script-utilities.js +36 -0
- package/src/security/plugin-sandbox.js +586 -0
- package/src/security/plugin-signature-verifier.js +414 -0
- package/src/security/validator.js +36 -0
- package/src/utils/ci/diagnostic-reporter.js +57 -0
- package/src/utils/logger.js +211 -0
- package/src/utils/performance-monitor.js +561 -0
- package/src/utils/plugin-scaffolder.js +447 -0
- package/src/utils/retry-policy.js +443 -0
- package/src/utils/retry.js +107 -0
- package/src/utils/safe-expression-evaluator.js +579 -0
- package/src/utils/structured-logger.js +361 -0
- package/src/utils/validate-plugin-contract.js +42 -0
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Structured audit logging system for security compliance and governance.
|
|
3
|
+
* Provides immutable audit trails, compliance reporting, and regulatory compliance features.
|
|
4
|
+
*
|
|
5
|
+
* @author DevilsDev Team
|
|
6
|
+
* @since 2.1.0
|
|
7
|
+
* @version 2.1.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs').promises;
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const crypto = require('crypto');
|
|
13
|
+
const { AsyncLocalStorage } = require('async_hooks');
|
|
14
|
+
const { EventEmitter } = require('events');
|
|
15
|
+
const logger = require('../utils/structured-logger');
|
|
16
|
+
const { getTelemetryService } = require('./telemetry');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Audit context for tracking compliance events across async operations.
|
|
20
|
+
*/
|
|
21
|
+
const auditContext = new AsyncLocalStorage();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Structured audit logging service for compliance and security governance.
|
|
25
|
+
*
|
|
26
|
+
* Features:
|
|
27
|
+
* - Immutable audit trail generation
|
|
28
|
+
* - Compliance framework support (SOX, GDPR, HIPAA, PCI-DSS)
|
|
29
|
+
* - Digital signatures for tamper detection
|
|
30
|
+
* - Structured event categorization
|
|
31
|
+
* - Real-time compliance monitoring
|
|
32
|
+
* - Automated compliance reporting
|
|
33
|
+
*
|
|
34
|
+
* @class AuditLogger
|
|
35
|
+
* @extends EventEmitter
|
|
36
|
+
*/
|
|
37
|
+
class AuditLogger extends EventEmitter {
|
|
38
|
+
constructor(options = {}) {
|
|
39
|
+
super();
|
|
40
|
+
|
|
41
|
+
this.config = {
|
|
42
|
+
// Core Configuration
|
|
43
|
+
enabled: options.enabled !== false,
|
|
44
|
+
serviceName: options.serviceName || '@devilsdev/rag-pipeline-utils',
|
|
45
|
+
instanceId: options.instanceId || crypto.randomUUID(),
|
|
46
|
+
|
|
47
|
+
// Storage Configuration
|
|
48
|
+
storage: {
|
|
49
|
+
type: options.storage?.type || 'file', // file, database, s3
|
|
50
|
+
location: options.storage?.location || './audit-logs',
|
|
51
|
+
maxFileSize: options.storage?.maxFileSize || 100 * 1024 * 1024, // 100MB
|
|
52
|
+
compression: options.storage?.compression !== false,
|
|
53
|
+
encryption: options.storage?.encryption !== false,
|
|
54
|
+
backup: options.storage?.backup !== false,
|
|
55
|
+
...options.storage,
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Compliance Configuration
|
|
59
|
+
compliance: {
|
|
60
|
+
frameworks: options.compliance?.frameworks || ['GDPR', 'SOX'], // GDPR, SOX, HIPAA, PCI-DSS
|
|
61
|
+
retentionPeriod:
|
|
62
|
+
options.compliance?.retentionPeriod || 7 * 365 * 24 * 60 * 60 * 1000, // 7 years
|
|
63
|
+
immutableStorage: options.compliance?.immutableStorage !== false,
|
|
64
|
+
digitalSignatures: options.compliance?.digitalSignatures !== false,
|
|
65
|
+
realTimeMonitoring: options.compliance?.realTimeMonitoring !== false,
|
|
66
|
+
...options.compliance,
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// Security Configuration
|
|
70
|
+
security: {
|
|
71
|
+
signatureAlgorithm:
|
|
72
|
+
options.security?.signatureAlgorithm || 'RSA-SHA256',
|
|
73
|
+
encryptionAlgorithm:
|
|
74
|
+
options.security?.encryptionAlgorithm || 'aes-256-gcm',
|
|
75
|
+
keyRotationInterval:
|
|
76
|
+
options.security?.keyRotationInterval || 90 * 24 * 60 * 60 * 1000, // 90 days
|
|
77
|
+
integrityChecks: options.security?.integrityChecks !== false,
|
|
78
|
+
...options.security,
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
// Event Configuration
|
|
82
|
+
events: {
|
|
83
|
+
categories: options.events?.categories || [
|
|
84
|
+
'authentication',
|
|
85
|
+
'authorization',
|
|
86
|
+
'data_access',
|
|
87
|
+
'data_modification',
|
|
88
|
+
'system_access',
|
|
89
|
+
'configuration_change',
|
|
90
|
+
'security_event',
|
|
91
|
+
'compliance_event',
|
|
92
|
+
],
|
|
93
|
+
requiredFields: options.events?.requiredFields || [
|
|
94
|
+
'timestamp',
|
|
95
|
+
'eventType',
|
|
96
|
+
'userId',
|
|
97
|
+
'resource',
|
|
98
|
+
'action',
|
|
99
|
+
'outcome',
|
|
100
|
+
],
|
|
101
|
+
sensitiveFields: options.events?.sensitiveFields || [
|
|
102
|
+
'password',
|
|
103
|
+
'token',
|
|
104
|
+
'apiKey',
|
|
105
|
+
'ssn',
|
|
106
|
+
'creditCard',
|
|
107
|
+
],
|
|
108
|
+
...options.events,
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// Monitoring Configuration
|
|
112
|
+
monitoring: {
|
|
113
|
+
alertOnFailures: options.monitoring?.alertOnFailures !== false,
|
|
114
|
+
healthCheckInterval: options.monitoring?.healthCheckInterval || 60000, // 1 minute
|
|
115
|
+
integrityCheckInterval:
|
|
116
|
+
options.monitoring?.integrityCheckInterval || 3600000, // 1 hour
|
|
117
|
+
complianceCheckInterval:
|
|
118
|
+
options.monitoring?.complianceCheckInterval || 86400000, // 24 hours
|
|
119
|
+
...options.monitoring,
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
...options,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Internal state
|
|
126
|
+
this.isInitialized = false;
|
|
127
|
+
this.currentLogFile = null;
|
|
128
|
+
this.auditChain = [];
|
|
129
|
+
this.signingKey = null;
|
|
130
|
+
this.encryptionKey = null;
|
|
131
|
+
this.eventCounter = 0;
|
|
132
|
+
this.lastIntegrityCheck = null;
|
|
133
|
+
|
|
134
|
+
// Compliance trackers
|
|
135
|
+
this.complianceEvents = new Map();
|
|
136
|
+
this.retentionTracker = new Map();
|
|
137
|
+
this.violationTracker = new Map();
|
|
138
|
+
|
|
139
|
+
// Telemetry service
|
|
140
|
+
this.telemetry = getTelemetryService();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Initialize the audit logging service.
|
|
145
|
+
*
|
|
146
|
+
* @returns {Promise<void>} Initialization promise
|
|
147
|
+
*/
|
|
148
|
+
async initialize() {
|
|
149
|
+
if (this.isInitialized) {
|
|
150
|
+
logger.warn('Audit logger already initialized');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!this.config.enabled) {
|
|
155
|
+
logger.info('Audit logging is disabled');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
logger.info('Initializing audit logging service', {
|
|
161
|
+
serviceName: this.config.serviceName,
|
|
162
|
+
instanceId: this.config.instanceId,
|
|
163
|
+
compliance: this.config.compliance.frameworks,
|
|
164
|
+
storage: this.config.storage.type,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Initialize storage
|
|
168
|
+
await this.initializeStorage();
|
|
169
|
+
|
|
170
|
+
// Initialize security (keys, signatures)
|
|
171
|
+
await this.initializeSecurity();
|
|
172
|
+
|
|
173
|
+
// Load existing audit chain
|
|
174
|
+
await this.loadAuditChain();
|
|
175
|
+
|
|
176
|
+
// Start monitoring
|
|
177
|
+
this.startMonitoring();
|
|
178
|
+
|
|
179
|
+
this.isInitialized = true;
|
|
180
|
+
|
|
181
|
+
// Record initialization in audit log
|
|
182
|
+
await this.logAuditEvent({
|
|
183
|
+
eventType: 'system_startup',
|
|
184
|
+
category: 'system_access',
|
|
185
|
+
userId: 'system',
|
|
186
|
+
resource: 'audit_logger',
|
|
187
|
+
action: 'initialize',
|
|
188
|
+
outcome: 'success',
|
|
189
|
+
details: {
|
|
190
|
+
version: this.config.serviceVersion,
|
|
191
|
+
compliance: this.config.compliance.frameworks,
|
|
192
|
+
instanceId: this.config.instanceId,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
logger.info('Audit logging service initialized successfully');
|
|
197
|
+
} catch (error) {
|
|
198
|
+
logger.error('Failed to initialize audit logging service', {
|
|
199
|
+
error: error.message,
|
|
200
|
+
stack: error.stack,
|
|
201
|
+
});
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Log a compliance audit event with full traceability.
|
|
208
|
+
*
|
|
209
|
+
* @param {Object} event - Audit event data
|
|
210
|
+
* @param {string} event.eventType - Type of event
|
|
211
|
+
* @param {string} event.category - Event category
|
|
212
|
+
* @param {string} event.userId - User identifier
|
|
213
|
+
* @param {string} event.resource - Resource accessed
|
|
214
|
+
* @param {string} event.action - Action performed
|
|
215
|
+
* @param {string} event.outcome - Event outcome (success/failure)
|
|
216
|
+
* @param {Object} event.details - Additional event details
|
|
217
|
+
* @returns {Promise<string>} Audit event ID
|
|
218
|
+
*/
|
|
219
|
+
async logAuditEvent(event) {
|
|
220
|
+
if (!this.isInitialized || !this.config.enabled) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const auditEvent = await this.createAuditEvent(event);
|
|
226
|
+
|
|
227
|
+
// Add to audit chain for immutability
|
|
228
|
+
await this.addToAuditChain(auditEvent);
|
|
229
|
+
|
|
230
|
+
// Store event
|
|
231
|
+
await this.storeAuditEvent(auditEvent);
|
|
232
|
+
|
|
233
|
+
// Update compliance tracking
|
|
234
|
+
this.updateComplianceTracking(auditEvent);
|
|
235
|
+
|
|
236
|
+
// Emit event for real-time monitoring
|
|
237
|
+
this.emit('auditEvent', auditEvent);
|
|
238
|
+
|
|
239
|
+
// Record telemetry
|
|
240
|
+
this.telemetry.recordMetric('audit_events_total', 1, {
|
|
241
|
+
category: auditEvent.category,
|
|
242
|
+
outcome: auditEvent.outcome,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
return auditEvent.id;
|
|
246
|
+
} catch (error) {
|
|
247
|
+
logger.error('Failed to log audit event', {
|
|
248
|
+
event,
|
|
249
|
+
error: error.message,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Log the failure itself as an audit event
|
|
253
|
+
await this.logSystemEvent('audit_failure', {
|
|
254
|
+
originalEvent: event,
|
|
255
|
+
error: error.message,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Execute function with audit context for correlation tracking.
|
|
264
|
+
*
|
|
265
|
+
* @param {string} auditEventId - Audit event ID for correlation
|
|
266
|
+
* @param {string} userId - User identifier
|
|
267
|
+
* @param {Function} fn - Function to execute
|
|
268
|
+
* @returns {Promise<any>} Function result
|
|
269
|
+
*/
|
|
270
|
+
async withAuditContext(auditEventId, userId, fn) {
|
|
271
|
+
const context = {
|
|
272
|
+
auditEventId,
|
|
273
|
+
userId,
|
|
274
|
+
timestamp: Date.now(),
|
|
275
|
+
correlationId: crypto.randomUUID(),
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
return auditContext.run(context, fn);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Get current audit context.
|
|
283
|
+
*
|
|
284
|
+
* @returns {Object|null} Current audit context
|
|
285
|
+
*/
|
|
286
|
+
getCurrentAuditContext() {
|
|
287
|
+
return auditContext.getStore() || null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Create a structured audit event.
|
|
292
|
+
*
|
|
293
|
+
* @private
|
|
294
|
+
* @param {Object} eventData - Raw event data
|
|
295
|
+
* @returns {Promise<Object>} Structured audit event
|
|
296
|
+
*/
|
|
297
|
+
async createAuditEvent(eventData) {
|
|
298
|
+
const timestamp = Date.now();
|
|
299
|
+
const eventId = crypto.randomUUID();
|
|
300
|
+
|
|
301
|
+
// Get current audit context
|
|
302
|
+
const context = this.getCurrentAuditContext();
|
|
303
|
+
|
|
304
|
+
// Validate required fields
|
|
305
|
+
this.validateEventData(eventData);
|
|
306
|
+
|
|
307
|
+
// Sanitize sensitive data
|
|
308
|
+
const sanitizedDetails = this.sanitizeSensitiveData(
|
|
309
|
+
eventData.details || {},
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
const auditEvent = {
|
|
313
|
+
// Core identifiers
|
|
314
|
+
id: eventId,
|
|
315
|
+
timestamp,
|
|
316
|
+
sequenceNumber: ++this.eventCounter,
|
|
317
|
+
|
|
318
|
+
// Service information
|
|
319
|
+
serviceName: this.config.serviceName,
|
|
320
|
+
serviceVersion: this.config.serviceVersion,
|
|
321
|
+
instanceId: this.config.instanceId,
|
|
322
|
+
|
|
323
|
+
// Event classification
|
|
324
|
+
eventType: eventData.eventType,
|
|
325
|
+
category: eventData.category,
|
|
326
|
+
severity: eventData.severity || this.calculateSeverity(eventData),
|
|
327
|
+
|
|
328
|
+
// Actor information
|
|
329
|
+
userId: eventData.userId,
|
|
330
|
+
sessionId: eventData.sessionId || context?.correlationId,
|
|
331
|
+
ipAddress: eventData.ipAddress,
|
|
332
|
+
userAgent: eventData.userAgent,
|
|
333
|
+
|
|
334
|
+
// Resource and action
|
|
335
|
+
resource: eventData.resource,
|
|
336
|
+
action: eventData.action,
|
|
337
|
+
outcome: eventData.outcome,
|
|
338
|
+
|
|
339
|
+
// Compliance context
|
|
340
|
+
compliance: {
|
|
341
|
+
frameworks: this.getApplicableFrameworks(eventData),
|
|
342
|
+
retentionRequired: this.calculateRetentionPeriod(eventData),
|
|
343
|
+
sensitivityLevel: this.calculateSensitivityLevel(eventData),
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
// Technical context
|
|
347
|
+
technical: {
|
|
348
|
+
correlationId: context?.correlationId || crypto.randomUUID(),
|
|
349
|
+
parentEventId: context?.auditEventId,
|
|
350
|
+
trace: this.telemetry.getCurrentTraceId?.() || null,
|
|
351
|
+
span: this.telemetry.getCurrentSpanId?.() || null,
|
|
352
|
+
},
|
|
353
|
+
|
|
354
|
+
// Event details (sanitized)
|
|
355
|
+
details: sanitizedDetails,
|
|
356
|
+
|
|
357
|
+
// Integrity information
|
|
358
|
+
integrity: {
|
|
359
|
+
checksum: null, // Will be calculated after event creation
|
|
360
|
+
signature: null, // Will be calculated after event creation
|
|
361
|
+
previousEventHash: this.getLastEventHash(),
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
// Calculate integrity checksum
|
|
366
|
+
auditEvent.integrity.checksum = this.calculateEventChecksum(auditEvent);
|
|
367
|
+
|
|
368
|
+
// Sign event if digital signatures are enabled
|
|
369
|
+
if (this.config.compliance.digitalSignatures) {
|
|
370
|
+
auditEvent.integrity.signature = await this.signEvent(auditEvent);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return auditEvent;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Validate audit event data against required fields.
|
|
378
|
+
*
|
|
379
|
+
* @private
|
|
380
|
+
* @param {Object} eventData - Event data to validate
|
|
381
|
+
* @throws {ValidationError} On validation failure
|
|
382
|
+
*/
|
|
383
|
+
validateEventData(eventData) {
|
|
384
|
+
const required = this.config.events.requiredFields;
|
|
385
|
+
|
|
386
|
+
for (const field of required) {
|
|
387
|
+
if (!eventData[field]) {
|
|
388
|
+
throw new ValidationError(`Required audit field missing: ${field}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Validate category
|
|
393
|
+
if (!this.config.events.categories.includes(eventData.category)) {
|
|
394
|
+
throw new ValidationError(
|
|
395
|
+
`Invalid event category: ${eventData.category}`,
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Validate outcome
|
|
400
|
+
const validOutcomes = ['success', 'failure', 'error', 'denied'];
|
|
401
|
+
if (!validOutcomes.includes(eventData.outcome)) {
|
|
402
|
+
throw new ValidationError(`Invalid event outcome: ${eventData.outcome}`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Sanitize sensitive data from event details.
|
|
408
|
+
*
|
|
409
|
+
* @private
|
|
410
|
+
* @param {Object} details - Event details
|
|
411
|
+
* @returns {Object} Sanitized details
|
|
412
|
+
*/
|
|
413
|
+
sanitizeSensitiveData(details) {
|
|
414
|
+
const sanitized = { ...details };
|
|
415
|
+
const sensitiveFields = this.config.events.sensitiveFields;
|
|
416
|
+
|
|
417
|
+
for (const field of sensitiveFields) {
|
|
418
|
+
if (sanitized[field]) {
|
|
419
|
+
sanitized[field] = '[REDACTED]';
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Deep sanitization for nested objects
|
|
424
|
+
this.sanitizeNestedObjects(sanitized, sensitiveFields);
|
|
425
|
+
|
|
426
|
+
return sanitized;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Add audit event to immutable chain.
|
|
431
|
+
*
|
|
432
|
+
* @private
|
|
433
|
+
* @param {Object} auditEvent - Audit event to add
|
|
434
|
+
*/
|
|
435
|
+
async addToAuditChain(auditEvent) {
|
|
436
|
+
if (!this.config.compliance.immutableStorage) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const chainEntry = {
|
|
441
|
+
eventId: auditEvent.id,
|
|
442
|
+
timestamp: auditEvent.timestamp,
|
|
443
|
+
hash: auditEvent.integrity.checksum,
|
|
444
|
+
previousHash: this.getLastEventHash(),
|
|
445
|
+
sequenceNumber: auditEvent.sequenceNumber,
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
this.auditChain.push(chainEntry);
|
|
449
|
+
|
|
450
|
+
// Persist chain state
|
|
451
|
+
await this.persistAuditChain();
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Store audit event to configured storage.
|
|
456
|
+
*
|
|
457
|
+
* @private
|
|
458
|
+
* @param {Object} auditEvent - Audit event to store
|
|
459
|
+
*/
|
|
460
|
+
async storeAuditEvent(auditEvent) {
|
|
461
|
+
switch (this.config.storage.type) {
|
|
462
|
+
case 'file':
|
|
463
|
+
await this.storeToFile(auditEvent);
|
|
464
|
+
break;
|
|
465
|
+
case 'database':
|
|
466
|
+
await this.storeToDatabase(auditEvent);
|
|
467
|
+
break;
|
|
468
|
+
case 's3':
|
|
469
|
+
await this.storeToS3(auditEvent);
|
|
470
|
+
break;
|
|
471
|
+
default:
|
|
472
|
+
throw new Error(
|
|
473
|
+
`Unsupported storage type: ${this.config.storage.type}`,
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Store audit event to file system.
|
|
480
|
+
*
|
|
481
|
+
* @private
|
|
482
|
+
* @param {Object} auditEvent - Audit event to store
|
|
483
|
+
*/
|
|
484
|
+
async storeToFile(auditEvent) {
|
|
485
|
+
const fileName = this.generateLogFileName(auditEvent.timestamp);
|
|
486
|
+
const filePath = path.join(this.config.storage.location, fileName);
|
|
487
|
+
|
|
488
|
+
let eventData = JSON.stringify(auditEvent) + '\n';
|
|
489
|
+
|
|
490
|
+
// Encrypt if enabled
|
|
491
|
+
if (this.config.storage.encryption) {
|
|
492
|
+
eventData = await this.encryptData(eventData);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Compress if enabled
|
|
496
|
+
if (this.config.storage.compression) {
|
|
497
|
+
eventData = await this.compressData(eventData);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
await fs.appendFile(filePath, eventData, { flag: 'a' });
|
|
501
|
+
|
|
502
|
+
// Check if file rotation is needed
|
|
503
|
+
await this.checkFileRotation(filePath);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Generate compliance report for audit trail.
|
|
508
|
+
*
|
|
509
|
+
* @param {Object} options - Report options
|
|
510
|
+
* @param {Date} options.startDate - Report start date
|
|
511
|
+
* @param {Date} options.endDate - Report end date
|
|
512
|
+
* @param {string[]} options.frameworks - Compliance frameworks to include
|
|
513
|
+
* @returns {Promise<Object>} Compliance report
|
|
514
|
+
*/
|
|
515
|
+
async generateComplianceReport(options = {}) {
|
|
516
|
+
const {
|
|
517
|
+
startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), // 30 days ago
|
|
518
|
+
endDate = new Date(),
|
|
519
|
+
frameworks = this.config.compliance.frameworks,
|
|
520
|
+
} = options;
|
|
521
|
+
|
|
522
|
+
logger.info('Generating compliance report', {
|
|
523
|
+
startDate: startDate.toISOString(),
|
|
524
|
+
endDate: endDate.toISOString(),
|
|
525
|
+
frameworks,
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
const report = {
|
|
529
|
+
id: crypto.randomUUID(),
|
|
530
|
+
timestamp: Date.now(),
|
|
531
|
+
period: {
|
|
532
|
+
start: startDate.toISOString(),
|
|
533
|
+
end: endDate.toISOString(),
|
|
534
|
+
},
|
|
535
|
+
frameworks,
|
|
536
|
+
summary: {
|
|
537
|
+
totalEvents: 0,
|
|
538
|
+
eventsByCategory: {},
|
|
539
|
+
eventsByOutcome: {},
|
|
540
|
+
violations: [],
|
|
541
|
+
recommendations: [],
|
|
542
|
+
},
|
|
543
|
+
details: {
|
|
544
|
+
events: [],
|
|
545
|
+
integrityStatus: await this.verifyAuditChainIntegrity(),
|
|
546
|
+
retentionCompliance: this.checkRetentionCompliance(),
|
|
547
|
+
securityEvents: [],
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
// Populate report with filtered events
|
|
552
|
+
const events = await this.getEventsInDateRange(startDate, endDate);
|
|
553
|
+
|
|
554
|
+
for (const event of events) {
|
|
555
|
+
// Check if event applies to requested frameworks
|
|
556
|
+
const applicableFrameworks = event.compliance.frameworks.filter((f) =>
|
|
557
|
+
frameworks.includes(f),
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
if (applicableFrameworks.length > 0) {
|
|
561
|
+
report.summary.totalEvents++;
|
|
562
|
+
|
|
563
|
+
// Update category counts
|
|
564
|
+
const category = event.category;
|
|
565
|
+
report.summary.eventsByCategory[category] =
|
|
566
|
+
(report.summary.eventsByCategory[category] || 0) + 1;
|
|
567
|
+
|
|
568
|
+
// Update outcome counts
|
|
569
|
+
const outcome = event.outcome;
|
|
570
|
+
report.summary.eventsByOutcome[outcome] =
|
|
571
|
+
(report.summary.eventsByOutcome[outcome] || 0) + 1;
|
|
572
|
+
|
|
573
|
+
// Add to detailed events
|
|
574
|
+
report.details.events.push({
|
|
575
|
+
id: event.id,
|
|
576
|
+
timestamp: event.timestamp,
|
|
577
|
+
eventType: event.eventType,
|
|
578
|
+
category: event.category,
|
|
579
|
+
outcome: event.outcome,
|
|
580
|
+
userId: event.userId,
|
|
581
|
+
resource: event.resource,
|
|
582
|
+
action: event.action,
|
|
583
|
+
frameworks: applicableFrameworks,
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Add compliance analysis
|
|
589
|
+
report.analysis = await this.analyzeCompliance(events, frameworks);
|
|
590
|
+
|
|
591
|
+
logger.info('Compliance report generated', {
|
|
592
|
+
reportId: report.id,
|
|
593
|
+
totalEvents: report.summary.totalEvents,
|
|
594
|
+
violations: report.summary.violations.length,
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
return report;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Verify audit chain integrity.
|
|
602
|
+
*
|
|
603
|
+
* @returns {Promise<Object>} Integrity verification result
|
|
604
|
+
*/
|
|
605
|
+
async verifyAuditChainIntegrity() {
|
|
606
|
+
if (!this.config.compliance.immutableStorage) {
|
|
607
|
+
return { enabled: false };
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
logger.info('Verifying audit chain integrity');
|
|
611
|
+
|
|
612
|
+
const result = {
|
|
613
|
+
enabled: true,
|
|
614
|
+
valid: true,
|
|
615
|
+
totalEvents: this.auditChain.length,
|
|
616
|
+
verifiedEvents: 0,
|
|
617
|
+
errors: [],
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
for (let i = 0; i < this.auditChain.length; i++) {
|
|
621
|
+
const entry = this.auditChain[i];
|
|
622
|
+
|
|
623
|
+
try {
|
|
624
|
+
// Verify hash chain
|
|
625
|
+
if (i > 0) {
|
|
626
|
+
const previousEntry = this.auditChain[i - 1];
|
|
627
|
+
if (entry.previousHash !== previousEntry.hash) {
|
|
628
|
+
result.valid = false;
|
|
629
|
+
result.errors.push({
|
|
630
|
+
eventId: entry.eventId,
|
|
631
|
+
error: 'Hash chain broken',
|
|
632
|
+
expected: previousEntry.hash,
|
|
633
|
+
actual: entry.previousHash,
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Verify event signature if available
|
|
639
|
+
if (this.config.compliance.digitalSignatures) {
|
|
640
|
+
const event = await this.getEventById(entry.eventId);
|
|
641
|
+
if (event && !(await this.verifyEventSignature(event))) {
|
|
642
|
+
result.valid = false;
|
|
643
|
+
result.errors.push({
|
|
644
|
+
eventId: entry.eventId,
|
|
645
|
+
error: 'Invalid digital signature',
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
result.verifiedEvents++;
|
|
651
|
+
} catch (error) {
|
|
652
|
+
result.valid = false;
|
|
653
|
+
result.errors.push({
|
|
654
|
+
eventId: entry.eventId,
|
|
655
|
+
error: error.message,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
this.lastIntegrityCheck = Date.now();
|
|
661
|
+
|
|
662
|
+
logger.info('Audit chain integrity verification completed', {
|
|
663
|
+
valid: result.valid,
|
|
664
|
+
totalEvents: result.totalEvents,
|
|
665
|
+
errors: result.errors.length,
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
return result;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Get audit logger health status.
|
|
673
|
+
*
|
|
674
|
+
* @returns {Object} Health status
|
|
675
|
+
*/
|
|
676
|
+
getHealth() {
|
|
677
|
+
return {
|
|
678
|
+
initialized: this.isInitialized,
|
|
679
|
+
enabled: this.config.enabled,
|
|
680
|
+
eventCounter: this.eventCounter,
|
|
681
|
+
auditChainLength: this.auditChain.length,
|
|
682
|
+
lastIntegrityCheck: this.lastIntegrityCheck,
|
|
683
|
+
compliance: {
|
|
684
|
+
frameworks: this.config.compliance.frameworks,
|
|
685
|
+
immutableStorage: this.config.compliance.immutableStorage,
|
|
686
|
+
digitalSignatures: this.config.compliance.digitalSignatures,
|
|
687
|
+
},
|
|
688
|
+
storage: {
|
|
689
|
+
type: this.config.storage.type,
|
|
690
|
+
location: this.config.storage.location,
|
|
691
|
+
},
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Additional helper methods would be implemented here...
|
|
696
|
+
// (initializeStorage, initializeSecurity, calculateSeverity, etc.)
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Validation error for audit events.
|
|
701
|
+
*/
|
|
702
|
+
class ValidationError extends Error {
|
|
703
|
+
constructor(message) {
|
|
704
|
+
super(message);
|
|
705
|
+
this.name = 'ValidationError';
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Singleton audit logger instance.
|
|
711
|
+
*/
|
|
712
|
+
let auditLoggerInstance = null;
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Get or create the global audit logger instance.
|
|
716
|
+
*
|
|
717
|
+
* @param {Object} options - Configuration options
|
|
718
|
+
* @returns {AuditLogger} Audit logger instance
|
|
719
|
+
*/
|
|
720
|
+
function getAuditLogger(options = {}) {
|
|
721
|
+
if (!auditLoggerInstance) {
|
|
722
|
+
auditLoggerInstance = new AuditLogger(options);
|
|
723
|
+
}
|
|
724
|
+
return auditLoggerInstance;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Initialize the global audit logging service.
|
|
729
|
+
*
|
|
730
|
+
* @param {Object} options - Configuration options
|
|
731
|
+
* @returns {Promise<AuditLogger>} Initialized audit logger
|
|
732
|
+
*/
|
|
733
|
+
async function initializeAuditLogging(options = {}) {
|
|
734
|
+
const auditLogger = getAuditLogger(options);
|
|
735
|
+
await auditLogger.initialize();
|
|
736
|
+
return auditLogger;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Log an audit event with the global audit logger.
|
|
741
|
+
*
|
|
742
|
+
* @param {Object} event - Audit event data
|
|
743
|
+
* @returns {Promise<string>} Audit event ID
|
|
744
|
+
*/
|
|
745
|
+
async function logAuditEvent(event) {
|
|
746
|
+
const auditLogger = getAuditLogger();
|
|
747
|
+
return auditLogger.logAuditEvent(event);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
module.exports = {
|
|
751
|
+
AuditLogger,
|
|
752
|
+
ValidationError,
|
|
753
|
+
getAuditLogger,
|
|
754
|
+
initializeAuditLogging,
|
|
755
|
+
logAuditEvent,
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
module.exports.default = module.exports;
|