@goldensheepai/toknxr-cli 0.2.0 → 0.3.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/README.md +270 -9
- package/lib/audit-logger.js +500 -0
- package/lib/cli.js +1850 -129
- package/lib/cli.test.js +49 -0
- package/lib/code-analysis.js +349 -4
- package/lib/dashboard.js +4 -17
- package/lib/fixtures/canary-interaction.js +18 -0
- package/lib/plugin-system.js +266 -0
- package/lib/sync.js +27 -5
- package/lib/ui.js +129 -0
- package/lib/utils.js +117 -0
- package/package.json +51 -18
- package/.env +0 -21
- package/.env.example +0 -21
- package/interactions.log +0 -8
- package/src/ai-analytics.ts +0 -418
- package/src/auth.ts +0 -80
- package/src/cli.ts +0 -447
- package/src/code-analysis.ts +0 -365
- package/src/config.ts +0 -10
- package/src/dashboard.tsx +0 -391
- package/src/hallucination-detector.ts +0 -368
- package/src/policy.ts +0 -55
- package/src/pricing.ts +0 -21
- package/src/proxy.ts +0 -438
- package/src/sync.ts +0 -129
- package/start.sh +0 -56
- package/test-analysis.mjs +0 -77
- package/test-coding.mjs +0 -27
- package/test-generate-sample-data.js +0 -118
- package/test-proxy.mjs +0 -25
- package/toknxr.config.json +0 -63
- package/toknxr.policy.json +0 -18
- package/tsconfig.json +0 -19
@@ -0,0 +1,500 @@
|
|
1
|
+
/**
|
2
|
+
* Enterprise Audit Logging System for TokNxr
|
3
|
+
* Compliant audit trails for security monitoring and compliance
|
4
|
+
*/
|
5
|
+
import * as fs from 'node:fs';
|
6
|
+
import * as path from 'node:path';
|
7
|
+
import * as crypto from 'node:crypto';
|
8
|
+
import chalk from 'chalk';
|
9
|
+
// Audit event types for compliance monitoring
|
10
|
+
export var AuditEventType;
|
11
|
+
(function (AuditEventType) {
|
12
|
+
// Authentication & Authorization
|
13
|
+
AuditEventType["AUTH_LOGIN"] = "auth.login";
|
14
|
+
AuditEventType["AUTH_LOGOUT"] = "auth.logout";
|
15
|
+
AuditEventType["AUTH_FAILED"] = "auth.failed";
|
16
|
+
AuditEventType["AUTH_PASSWORD_CHANGE"] = "auth.password_change";
|
17
|
+
AuditEventType["AUTH_LOCKOUT"] = "auth.lockout";
|
18
|
+
AuditEventType["AUTH_SSO_ACCESS"] = "auth.sso_access";
|
19
|
+
// Data Access & Modification
|
20
|
+
AuditEventType["DATA_ACCESS"] = "data.access";
|
21
|
+
AuditEventType["DATA_MODIFY"] = "data.modify";
|
22
|
+
AuditEventType["DATA_DELETE"] = "data.delete";
|
23
|
+
AuditEventType["DATA_EXPORT"] = "data.export";
|
24
|
+
// AI Interaction Monitoring
|
25
|
+
AuditEventType["AI_REQUEST"] = "ai.request";
|
26
|
+
AuditEventType["AI_RESPONSE"] = "ai.response";
|
27
|
+
AuditEventType["AI_QUALITY_ANALYSIS"] = "ai.quality_analysis";
|
28
|
+
AuditEventType["AI_SECURITY_ALERT"] = "ai.security_alert";
|
29
|
+
AuditEventType["AI_PERFORMANCE_METRIC"] = "ai.performance_metric";
|
30
|
+
// System & Configuration Changes
|
31
|
+
AuditEventType["CONFIG_CHANGE"] = "config.change";
|
32
|
+
AuditEventType["POLICY_UPDATE"] = "policy.update";
|
33
|
+
AuditEventType["USER_MANAGEMENT"] = "user.management";
|
34
|
+
// Security Events
|
35
|
+
AuditEventType["SECURITY_VIOLATION"] = "security.violation";
|
36
|
+
AuditEventType["SECURITY_ANOMALY"] = "security.anomaly";
|
37
|
+
AuditEventType["INTEGRITY_CHECK"] = "security.integrity_check";
|
38
|
+
// Compliance Events
|
39
|
+
AuditEventType["COMPLIANCE_REPORT"] = "compliance.report";
|
40
|
+
AuditEventType["COMPLIANCE_VIOLATION"] = "compliance.violation";
|
41
|
+
AuditEventType["AUDIT_LOG_ACCESS"] = "audit.log_access";
|
42
|
+
// Error & System Events
|
43
|
+
AuditEventType["ERROR_OCCURRED"] = "error.occurred";
|
44
|
+
AuditEventType["SYSTEM_MAINTENANCE"] = "system.maintenance";
|
45
|
+
AuditEventType["PERFORMANCE_DEGRADATION"] = "performance.degradation";
|
46
|
+
})(AuditEventType || (AuditEventType = {}));
|
47
|
+
/**
|
48
|
+
* Enterprise Audit Logger with compliance and security features
|
49
|
+
*/
|
50
|
+
export class EnterpriseAuditLogger {
|
51
|
+
constructor(config = {}) {
|
52
|
+
this.eventBuffer = [];
|
53
|
+
this.bufferSize = 10; // Flush every 10 events
|
54
|
+
this.config = {
|
55
|
+
enabled: true,
|
56
|
+
logLevel: 'info',
|
57
|
+
retentionDays: 365, // 1 year retention
|
58
|
+
maxFileSize: 100, // 100MB per file
|
59
|
+
encryptionEnabled: false,
|
60
|
+
remoteSync: false,
|
61
|
+
complianceFrameworks: ['GDPR', 'SOX', 'HIPAA'],
|
62
|
+
alertThresholds: {
|
63
|
+
dailyEventLimit: 10000,
|
64
|
+
riskLevelThreshold: 'high'
|
65
|
+
},
|
66
|
+
...config
|
67
|
+
};
|
68
|
+
this.logFilePath = path.resolve(process.cwd(), 'audit.log');
|
69
|
+
if (this.config.encryptionEnabled) {
|
70
|
+
this.initializeEncryption();
|
71
|
+
}
|
72
|
+
// Initialize log file if it doesn't exist
|
73
|
+
this.initializeLogFile();
|
74
|
+
// Don't start maintenance immediately - only when audit logging is actively used
|
75
|
+
// this.scheduleMaintenance();
|
76
|
+
}
|
77
|
+
/**
|
78
|
+
* Log an audit event
|
79
|
+
*/
|
80
|
+
log(event) {
|
81
|
+
if (!this.config.enabled)
|
82
|
+
return;
|
83
|
+
// Start maintenance when audit logging is actively used
|
84
|
+
this.scheduleMaintenance();
|
85
|
+
const auditEvent = {
|
86
|
+
id: this.generateEventId(),
|
87
|
+
timestamp: new Date().toISOString(),
|
88
|
+
...event
|
89
|
+
};
|
90
|
+
// Check risk level for alerting
|
91
|
+
if (this.shouldAlert(auditEvent)) {
|
92
|
+
this.emitAlert(auditEvent);
|
93
|
+
}
|
94
|
+
// Add to buffer
|
95
|
+
this.eventBuffer.push(auditEvent);
|
96
|
+
// Flush if buffer is full or contains high-risk events
|
97
|
+
if (this.eventBuffer.length >= this.bufferSize ||
|
98
|
+
auditEvent.riskLevel === 'critical' ||
|
99
|
+
auditEvent.riskLevel === 'high') {
|
100
|
+
this.flushBuffer();
|
101
|
+
}
|
102
|
+
}
|
103
|
+
/**
|
104
|
+
* Quick logging methods for common events
|
105
|
+
*/
|
106
|
+
logAuthEvent(type, userId, success, details = {}) {
|
107
|
+
this.log({
|
108
|
+
eventType: type,
|
109
|
+
userId,
|
110
|
+
action: type.split('.')[1],
|
111
|
+
resource: 'authentication',
|
112
|
+
result: success ? 'success' : 'failure',
|
113
|
+
riskLevel: success ? 'low' : 'medium',
|
114
|
+
complianceTags: ['authentication', 'access_control'],
|
115
|
+
details: {
|
116
|
+
method: 'toknxr_cli',
|
117
|
+
...details
|
118
|
+
},
|
119
|
+
metadata: {
|
120
|
+
version: '1.0.0',
|
121
|
+
environment: process.env.NODE_ENV || 'development',
|
122
|
+
component: 'cli'
|
123
|
+
}
|
124
|
+
});
|
125
|
+
}
|
126
|
+
logAIEvent(type, userId, model, tokens, cost, quality) {
|
127
|
+
this.log({
|
128
|
+
eventType: type,
|
129
|
+
userId,
|
130
|
+
action: type.split('.')[1],
|
131
|
+
resource: 'ai_interaction',
|
132
|
+
resourceId: model,
|
133
|
+
result: 'success',
|
134
|
+
riskLevel: cost > 1.0 ? 'medium' : 'low', // Higher cost = higher risk
|
135
|
+
complianceTags: ['ai_usage', 'cost_tracking'],
|
136
|
+
details: {
|
137
|
+
model,
|
138
|
+
tokens,
|
139
|
+
cost_usd: cost,
|
140
|
+
quality_score: quality
|
141
|
+
},
|
142
|
+
metadata: {
|
143
|
+
version: '1.0.0',
|
144
|
+
environment: process.env.NODE_ENV || 'development',
|
145
|
+
component: 'ai_proxy'
|
146
|
+
}
|
147
|
+
});
|
148
|
+
}
|
149
|
+
logSecurityEvent(type, severity, details) {
|
150
|
+
this.log({
|
151
|
+
eventType: type,
|
152
|
+
action: 'security_monitoring',
|
153
|
+
resource: 'system_security',
|
154
|
+
result: 'warning',
|
155
|
+
riskLevel: severity,
|
156
|
+
complianceTags: ['security', 'monitoring'],
|
157
|
+
details,
|
158
|
+
metadata: {
|
159
|
+
version: '1.0.0',
|
160
|
+
environment: process.env.NODE_ENV || 'development',
|
161
|
+
component: 'security_monitor'
|
162
|
+
}
|
163
|
+
});
|
164
|
+
}
|
165
|
+
/**
|
166
|
+
* Query audit events with filtering
|
167
|
+
*/
|
168
|
+
query(options = {}) {
|
169
|
+
const events = this.loadAuditEvents();
|
170
|
+
return events.filter(event => {
|
171
|
+
if (options.eventType && event.eventType !== options.eventType)
|
172
|
+
return false;
|
173
|
+
if (options.userId && event.userId !== options.userId)
|
174
|
+
return false;
|
175
|
+
if (options.riskLevel && event.riskLevel !== options.riskLevel)
|
176
|
+
return false;
|
177
|
+
if (options.dateFrom && event.timestamp < options.dateFrom)
|
178
|
+
return false;
|
179
|
+
if (options.dateTo && event.timestamp > options.dateTo)
|
180
|
+
return false;
|
181
|
+
return true;
|
182
|
+
}).slice(0, options.limit || 1000);
|
183
|
+
}
|
184
|
+
/**
|
185
|
+
* Generate compliance report for specified period
|
186
|
+
*/
|
187
|
+
generateComplianceReport(startDate, endDate) {
|
188
|
+
const events = this.query({
|
189
|
+
dateFrom: startDate,
|
190
|
+
dateTo: endDate
|
191
|
+
});
|
192
|
+
const eventsByType = {};
|
193
|
+
const eventsByRiskLevel = {};
|
194
|
+
const complianceViolations = [];
|
195
|
+
events.forEach(event => {
|
196
|
+
// Count by type
|
197
|
+
eventsByType[event.eventType] = (eventsByType[event.eventType] || 0) + 1;
|
198
|
+
// Count by risk level
|
199
|
+
eventsByRiskLevel[event.riskLevel] = (eventsByRiskLevel[event.riskLevel] || 0) + 1;
|
200
|
+
// Check for compliance violations
|
201
|
+
if (this.isComplianceViolation(event)) {
|
202
|
+
complianceViolations.push(event);
|
203
|
+
}
|
204
|
+
});
|
205
|
+
const recommendations = this.generateRecommendations(events, complianceViolations);
|
206
|
+
return {
|
207
|
+
period: { start: startDate, end: endDate },
|
208
|
+
totalEvents: events.length,
|
209
|
+
eventsByType,
|
210
|
+
eventsByRiskLevel,
|
211
|
+
complianceViolations,
|
212
|
+
riskSummary: {
|
213
|
+
critical: eventsByRiskLevel.critical || 0,
|
214
|
+
high: eventsByRiskLevel.high || 0,
|
215
|
+
medium: eventsByRiskLevel.medium || 0,
|
216
|
+
low: eventsByRiskLevel.low || 0
|
217
|
+
},
|
218
|
+
recommendations
|
219
|
+
};
|
220
|
+
}
|
221
|
+
/**
|
222
|
+
* Export audit logs in various formats
|
223
|
+
*/
|
224
|
+
exportAuditData(format, options = {}) {
|
225
|
+
const events = this.query(options);
|
226
|
+
switch (format) {
|
227
|
+
case 'json':
|
228
|
+
return JSON.stringify(events, null, 2);
|
229
|
+
case 'csv':
|
230
|
+
return this.eventsToCSV(events);
|
231
|
+
case 'xml':
|
232
|
+
return this.eventsToXML(events);
|
233
|
+
default:
|
234
|
+
throw new Error(`Unsupported export format: ${format}`);
|
235
|
+
}
|
236
|
+
}
|
237
|
+
/**
|
238
|
+
* Private methods
|
239
|
+
*/
|
240
|
+
generateEventId() {
|
241
|
+
return crypto.randomUUID();
|
242
|
+
}
|
243
|
+
shouldAlert(event) {
|
244
|
+
return event.riskLevel === this.config.alertThresholds.riskLevelThreshold ||
|
245
|
+
event.riskLevel === 'critical';
|
246
|
+
}
|
247
|
+
emitAlert(event) {
|
248
|
+
console.warn(chalk.red.bold('🚨 AUDIT ALERT:'), chalk.yellow(event.eventType));
|
249
|
+
console.warn(chalk.gray(`Risk Level: ${event.riskLevel.toUpperCase()}`));
|
250
|
+
console.warn(chalk.gray(`Action: ${event.action}`));
|
251
|
+
console.warn(chalk.gray(`Resource: ${event.resource}`));
|
252
|
+
console.warn(chalk.gray(`Time: ${event.timestamp}`));
|
253
|
+
// In a real enterprise system, this would send alerts to:
|
254
|
+
// - SIEM systems
|
255
|
+
// - Email notifications
|
256
|
+
// - Incident response teams
|
257
|
+
// - Compliance dashboards
|
258
|
+
}
|
259
|
+
flushBuffer() {
|
260
|
+
if (this.eventBuffer.length === 0)
|
261
|
+
return;
|
262
|
+
try {
|
263
|
+
const eventsToWrite = [...this.eventBuffer];
|
264
|
+
this.eventBuffer = [];
|
265
|
+
const logEntries = eventsToWrite.map(event => {
|
266
|
+
const entry = JSON.stringify(event);
|
267
|
+
if (this.config.encryptionEnabled && this.encryptionKey) {
|
268
|
+
return this.encrypt(entry);
|
269
|
+
}
|
270
|
+
return entry;
|
271
|
+
}).join('\n') + '\n';
|
272
|
+
// Check file size before writing
|
273
|
+
this.checkFileSize();
|
274
|
+
fs.appendFileSync(this.logFilePath, logEntries);
|
275
|
+
}
|
276
|
+
catch (error) {
|
277
|
+
console.error('Failed to write audit logs:', error);
|
278
|
+
// Re-add failed events back to buffer
|
279
|
+
this.eventBuffer.unshift(...this.eventBuffer);
|
280
|
+
}
|
281
|
+
}
|
282
|
+
loadAuditEvents() {
|
283
|
+
try {
|
284
|
+
if (!fs.existsSync(this.logFilePath))
|
285
|
+
return [];
|
286
|
+
const content = fs.readFileSync(this.logFilePath, 'utf8');
|
287
|
+
const lines = content.trim().split('\n');
|
288
|
+
return lines.map(line => {
|
289
|
+
try {
|
290
|
+
let parsed;
|
291
|
+
if (this.config.encryptionEnabled && this.encryptionKey) {
|
292
|
+
parsed = this.decrypt(line);
|
293
|
+
}
|
294
|
+
else {
|
295
|
+
parsed = line;
|
296
|
+
}
|
297
|
+
return JSON.parse(parsed);
|
298
|
+
}
|
299
|
+
catch {
|
300
|
+
// Skip invalid lines but don't break the entire log
|
301
|
+
return null;
|
302
|
+
}
|
303
|
+
}).filter((event) => event !== null);
|
304
|
+
}
|
305
|
+
catch (error) {
|
306
|
+
console.error('Failed to load audit events:', error);
|
307
|
+
return [];
|
308
|
+
}
|
309
|
+
}
|
310
|
+
initializeLogFile() {
|
311
|
+
if (!fs.existsSync(this.logFilePath)) {
|
312
|
+
fs.writeFileSync(this.logFilePath, '');
|
313
|
+
}
|
314
|
+
}
|
315
|
+
checkFileSize() {
|
316
|
+
try {
|
317
|
+
const stats = fs.statSync(this.logFilePath);
|
318
|
+
const fileSizeMB = stats.size / (1024 * 1024);
|
319
|
+
if (fileSizeMB > this.config.maxFileSize) {
|
320
|
+
this.rotateLogFile();
|
321
|
+
}
|
322
|
+
}
|
323
|
+
catch {
|
324
|
+
// File might not exist, that's fine
|
325
|
+
}
|
326
|
+
}
|
327
|
+
rotateLogFile() {
|
328
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
329
|
+
const rotatedPath = `${this.logFilePath}.${timestamp}.rotated`;
|
330
|
+
try {
|
331
|
+
fs.renameSync(this.logFilePath, rotatedPath);
|
332
|
+
this.initializeLogFile();
|
333
|
+
// Log rotation event
|
334
|
+
this.log({
|
335
|
+
eventType: AuditEventType.SYSTEM_MAINTENANCE,
|
336
|
+
action: 'log_rotation',
|
337
|
+
resource: 'audit_system',
|
338
|
+
result: 'success',
|
339
|
+
riskLevel: 'low',
|
340
|
+
complianceTags: ['system_maintenance'],
|
341
|
+
details: { rotatedFile: rotatedPath },
|
342
|
+
metadata: {
|
343
|
+
version: '1.0.0',
|
344
|
+
environment: process.env.NODE_ENV || 'development',
|
345
|
+
component: 'audit_logger'
|
346
|
+
}
|
347
|
+
});
|
348
|
+
}
|
349
|
+
catch (error) {
|
350
|
+
console.error('Failed to rotate audit log:', error);
|
351
|
+
}
|
352
|
+
}
|
353
|
+
scheduleMaintenance() {
|
354
|
+
// Only start maintenance if not already running
|
355
|
+
if (this.maintenanceInterval)
|
356
|
+
return;
|
357
|
+
// Run maintenance every hour
|
358
|
+
this.maintenanceInterval = setInterval(() => {
|
359
|
+
try {
|
360
|
+
this.performMaintenance();
|
361
|
+
}
|
362
|
+
catch (error) {
|
363
|
+
console.error('Audit maintenance failed:', error);
|
364
|
+
}
|
365
|
+
}, 60 * 60 * 1000); // 1 hour
|
366
|
+
}
|
367
|
+
/**
|
368
|
+
* Stop maintenance interval (useful for CLI commands that don't need persistent logging)
|
369
|
+
*/
|
370
|
+
stopMaintenance() {
|
371
|
+
if (this.maintenanceInterval) {
|
372
|
+
clearInterval(this.maintenanceInterval);
|
373
|
+
this.maintenanceInterval = undefined;
|
374
|
+
}
|
375
|
+
}
|
376
|
+
performMaintenance() {
|
377
|
+
// Clean up old rotated files
|
378
|
+
const retentionMs = this.config.retentionDays * 24 * 60 * 60 * 1000;
|
379
|
+
try {
|
380
|
+
const files = fs.readdirSync(path.dirname(this.logFilePath))
|
381
|
+
.filter(file => file.startsWith(path.basename(this.logFilePath)) && file.includes('.rotated'));
|
382
|
+
files.forEach(file => {
|
383
|
+
const filePath = path.join(path.dirname(this.logFilePath), file);
|
384
|
+
const stats = fs.statSync(filePath);
|
385
|
+
if (Date.now() - stats.mtime.getTime() > retentionMs) {
|
386
|
+
fs.unlinkSync(filePath);
|
387
|
+
}
|
388
|
+
});
|
389
|
+
}
|
390
|
+
catch (error) {
|
391
|
+
console.error('Failed to perform audit maintenance:', error);
|
392
|
+
}
|
393
|
+
}
|
394
|
+
initializeEncryption() {
|
395
|
+
const keyEnv = process.env.AUDIT_ENCRYPTION_KEY;
|
396
|
+
if (keyEnv) {
|
397
|
+
this.encryptionKey = Buffer.from(keyEnv, 'hex');
|
398
|
+
}
|
399
|
+
else {
|
400
|
+
// Generate a new key (in production, this should be stored securely)
|
401
|
+
this.encryptionKey = crypto.randomBytes(32);
|
402
|
+
console.warn(chalk.yellow('⚠️ No AUDIT_ENCRYPTION_KEY found. Using generated key (not secure for production)'));
|
403
|
+
}
|
404
|
+
}
|
405
|
+
encrypt(text) {
|
406
|
+
if (!this.encryptionKey)
|
407
|
+
return text;
|
408
|
+
const iv = crypto.randomBytes(16);
|
409
|
+
const cipher = crypto.createCipheriv('aes-256-cbc', this.encryptionKey, iv);
|
410
|
+
let encrypted = cipher.update(text, 'utf8', 'hex');
|
411
|
+
encrypted += cipher.final('hex');
|
412
|
+
return iv.toString('hex') + ':' + encrypted;
|
413
|
+
}
|
414
|
+
decrypt(encryptedText) {
|
415
|
+
if (!this.encryptionKey)
|
416
|
+
return encryptedText;
|
417
|
+
const [ivHex, encrypted] = encryptedText.split(':');
|
418
|
+
const iv = Buffer.from(ivHex, 'hex');
|
419
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', this.encryptionKey, iv);
|
420
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
421
|
+
decrypted += decipher.final('utf8');
|
422
|
+
return decrypted;
|
423
|
+
}
|
424
|
+
isComplianceViolation(event) {
|
425
|
+
// Check for various compliance rule violations
|
426
|
+
const violations = [];
|
427
|
+
// GDPR: Data access without consent
|
428
|
+
if (event.eventType === AuditEventType.DATA_ACCESS &&
|
429
|
+
!event.details.consentObtained) {
|
430
|
+
violations.push('GDPR: Missing data consent');
|
431
|
+
}
|
432
|
+
// SOX: Unauthorized configuration changes
|
433
|
+
if (event.eventType === AuditEventType.CONFIG_CHANGE &&
|
434
|
+
event.result === 'failure') {
|
435
|
+
violations.push('SOX: Unauthorized config change');
|
436
|
+
}
|
437
|
+
// HIPAA: Access to sensitive health data
|
438
|
+
if (event.details.sensitiveDataType === 'health' &&
|
439
|
+
!event.details.accessAuthorized) {
|
440
|
+
violations.push('HIPAA: Unauthorized health data access');
|
441
|
+
}
|
442
|
+
return violations.length > 0;
|
443
|
+
}
|
444
|
+
generateRecommendations(events, violations) {
|
445
|
+
const recommendations = [];
|
446
|
+
const highRiskCount = events.filter(e => e.riskLevel === 'high' || e.riskLevel === 'critical').length;
|
447
|
+
if (highRiskCount > events.length * 0.1) {
|
448
|
+
recommendations.push('Implement additional access controls for high-risk operations');
|
449
|
+
}
|
450
|
+
if (violations.length > 0) {
|
451
|
+
recommendations.push('Review and address compliance violations in audit logs');
|
452
|
+
}
|
453
|
+
const authFailures = events.filter(e => e.eventType.includes('auth') && e.result === 'failure').length;
|
454
|
+
if (authFailures > events.length * 0.05) {
|
455
|
+
recommendations.push('Strengthen authentication controls and monitor for brute force attempts');
|
456
|
+
}
|
457
|
+
return recommendations;
|
458
|
+
}
|
459
|
+
eventsToCSV(events) {
|
460
|
+
if (events.length === 0)
|
461
|
+
return '';
|
462
|
+
const headers = Object.keys(events[0]).join(',');
|
463
|
+
const rows = events.map(event => Object.values(event).map(value => typeof value === 'object' ? JSON.stringify(value) : String(value)).join(','));
|
464
|
+
return [headers, ...rows].join('\n');
|
465
|
+
}
|
466
|
+
eventsToXML(events) {
|
467
|
+
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<audit-events>\n';
|
468
|
+
events.forEach(event => {
|
469
|
+
xml += ' <event>\n';
|
470
|
+
Object.entries(event).forEach(([key, value]) => {
|
471
|
+
const valueStr = typeof value === 'object' ? JSON.stringify(value) : String(value);
|
472
|
+
xml += ` <${key}>${this.escapeXml(valueStr)}</${key}>\n`;
|
473
|
+
});
|
474
|
+
xml += ' </event>\n';
|
475
|
+
});
|
476
|
+
xml += '</audit-events>';
|
477
|
+
return xml;
|
478
|
+
}
|
479
|
+
escapeXml(unsafe) {
|
480
|
+
return unsafe
|
481
|
+
.replace(/&/g, '&')
|
482
|
+
.replace(/</g, '<')
|
483
|
+
.replace(/>/g, '>')
|
484
|
+
.replace(/"/g, '"')
|
485
|
+
.replace(/'/g, ''');
|
486
|
+
}
|
487
|
+
}
|
488
|
+
// Export singleton instance for global use
|
489
|
+
export const auditLogger = new EnterpriseAuditLogger();
|
490
|
+
// Helper function to enable audit logging globally
|
491
|
+
export function initializeAuditLogging(config) {
|
492
|
+
// Re-initialize with new config if provided
|
493
|
+
if (config) {
|
494
|
+
Object.assign(auditLogger, config);
|
495
|
+
}
|
496
|
+
console.log(chalk.blue('📋 Enterprise audit logging initialized'));
|
497
|
+
console.log(chalk.gray(` Log file: ${auditLogger['logFilePath']}`));
|
498
|
+
console.log(chalk.gray(` Encryption: ${auditLogger['config'].encryptionEnabled ? 'enabled' : 'disabled'}`));
|
499
|
+
console.log(chalk.gray(` Remote sync: ${auditLogger['config'].remoteSync ? 'enabled' : 'disabled'}`));
|
500
|
+
}
|