claude-flow-tbowman01
Version:
Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)
1,604 lines (1,457 loc) • 50.2 kB
text/typescript
import { EventEmitter } from 'events';
import { writeFile, readFile, mkdir, readdir } from 'fs/promises';
import { join } from 'path';
import { createHash } from 'crypto';
import { Logger } from '../core/logger.js';
import { ConfigManager } from '../core/config.js';
export interface AuditEntry {
id: string;
timestamp: Date;
eventType: string;
category:
| 'authentication'
| 'authorization'
| 'data-access'
| 'system-change'
| 'security'
| 'compliance'
| 'business';
severity: 'low' | 'medium' | 'high' | 'critical';
userId?: string;
sessionId?: string;
resource: {
type: string;
id: string;
name?: string;
path?: string;
};
action: string;
outcome: 'success' | 'failure' | 'partial' | 'denied';
details: Record<string, any>;
context: {
ipAddress?: string;
userAgent?: string;
location?: string;
source: string;
requestId?: string;
};
compliance: {
frameworks: string[];
controls: string[];
retention: string;
classification: 'public' | 'internal' | 'confidential' | 'restricted';
};
integrity: {
hash: string;
signature?: string;
verified: boolean;
};
metadata: Record<string, any>;
}
export interface ComplianceFramework {
id: string;
name: string;
version: string;
description: string;
type: 'regulatory' | 'industry' | 'internal' | 'certification';
requirements: ComplianceRequirement[];
auditFrequency: 'continuous' | 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'annually';
retentionPeriod: string;
reportingRequirements: {
frequency: string;
recipients: string[];
format: string[];
automated: boolean;
};
controls: ComplianceControl[];
status: 'active' | 'inactive' | 'pending' | 'deprecated';
implementationDate: Date;
nextReview: Date;
responsible: string;
}
export interface ComplianceRequirement {
id: string;
title: string;
description: string;
category: string;
priority: 'low' | 'medium' | 'high' | 'critical';
status: 'compliant' | 'non-compliant' | 'partial' | 'not-applicable' | 'pending';
evidence: string[];
gaps: string[];
remediation: {
actions: string[];
owner: string;
dueDate: Date;
cost?: number;
effort?: string;
};
lastAssessed: Date;
nextAssessment: Date;
automatedCheck: {
enabled: boolean;
frequency: string;
query: string;
threshold?: any;
};
}
export interface ComplianceControl {
id: string;
name: string;
description: string;
type: 'preventive' | 'detective' | 'corrective' | 'compensating';
automationType: 'manual' | 'semi-automated' | 'automated';
effectiveness: 'low' | 'medium' | 'high';
frequency: string;
owner: string;
evidence: string[];
testingProcedure: string;
lastTested: Date;
nextTest: Date;
status: 'effective' | 'ineffective' | 'needs-improvement' | 'not-tested';
}
export interface AuditReport {
id: string;
title: string;
description: string;
type: 'compliance' | 'security' | 'operational' | 'financial' | 'investigation' | 'custom';
scope: {
timeRange: { start: Date; end: Date };
systems: string[];
users: string[];
events: string[];
compliance: string[];
};
findings: AuditFinding[];
recommendations: AuditRecommendation[];
summary: {
totalEvents: number;
criticalFindings: number;
complianceScore: number;
riskLevel: 'low' | 'medium' | 'high' | 'critical';
};
methodology: string;
limitations: string[];
reviewers: string[];
approvers: string[];
status: 'draft' | 'under-review' | 'approved' | 'published' | 'archived';
confidentiality: 'public' | 'internal' | 'confidential' | 'restricted';
createdAt: Date;
updatedAt: Date;
createdBy: string;
publishedAt?: Date;
}
export interface AuditFinding {
id: string;
title: string;
description: string;
severity: 'low' | 'medium' | 'high' | 'critical';
category: string;
risk: string;
impact: string;
likelihood: string;
evidence: AuditEvidence[];
relatedEvents: string[];
complianceImpact: {
frameworks: string[];
violations: string[];
penalties?: string[];
};
remediation: {
priority: 'low' | 'medium' | 'high' | 'immediate';
owner: string;
actions: string[];
timeline: string;
cost?: number;
};
status: 'open' | 'in-progress' | 'resolved' | 'accepted-risk' | 'false-positive';
}
export interface AuditEvidence {
id: string;
type:
| 'log-entry'
| 'screenshot'
| 'document'
| 'system-output'
| 'witness-statement'
| 'data-export';
description: string;
source: string;
timestamp: Date;
hash: string;
location: string;
preservationStatus: 'intact' | 'modified' | 'corrupted' | 'missing';
chainOfCustody: ChainOfCustodyEntry[];
}
export interface ChainOfCustodyEntry {
timestamp: Date;
action: 'collected' | 'accessed' | 'analyzed' | 'transferred' | 'stored' | 'destroyed';
user: string;
reason: string;
hash: string;
}
export interface AuditRecommendation {
id: string;
title: string;
description: string;
priority: 'low' | 'medium' | 'high' | 'critical';
category: 'policy' | 'process' | 'technology' | 'training' | 'governance';
implementation: {
effort: 'low' | 'medium' | 'high';
cost: 'low' | 'medium' | 'high';
timeline: string;
dependencies: string[];
risks: string[];
};
expectedBenefit: string;
owner: string;
status: 'proposed' | 'approved' | 'in-progress' | 'completed' | 'rejected';
tracking: {
milestones: string[];
progress: number;
nextReview: Date;
};
}
export interface AuditTrail {
id: string;
name: string;
description: string;
category: string;
entries: AuditEntry[];
configuration: {
retention: string;
compression: boolean;
encryption: boolean;
archival: {
enabled: boolean;
location: string;
schedule: string;
};
monitoring: {
realTime: boolean;
alerting: boolean;
dashboards: string[];
};
};
integrity: {
verified: boolean;
lastVerification: Date;
checksum: string;
tamperEvidence: TamperEvidence[];
};
access: {
viewers: string[];
admins: string[];
readonly: boolean;
auditAccess: boolean;
};
compliance: {
frameworks: string[];
retention: string;
exportRequirements: string[];
immutable: boolean;
};
createdAt: Date;
updatedAt: Date;
}
export interface TamperEvidence {
timestamp: Date;
type: 'checksum-mismatch' | 'unauthorized-access' | 'missing-entries' | 'timestamp-anomaly';
description: string;
severity: 'low' | 'medium' | 'high' | 'critical';
investigationStatus: 'pending' | 'investigating' | 'resolved' | 'false-alarm';
evidence: string[];
}
export interface AuditConfiguration {
general: {
enabled: boolean;
defaultRetention: string;
compressionEnabled: boolean;
encryptionEnabled: boolean;
realTimeProcessing: boolean;
};
collection: {
automaticCapture: boolean;
bufferSize: number;
batchSize: number;
flushInterval: number;
failureHandling: 'ignore' | 'retry' | 'alert' | 'stop';
};
storage: {
primaryLocation: string;
backupLocation?: string;
archivalLocation?: string;
partitioning: 'daily' | 'weekly' | 'monthly';
indexing: boolean;
};
integrity: {
checksumAlgorithm: 'sha256' | 'sha512' | 'blake2b';
verificationFrequency: string;
digitalSignatures: boolean;
immutableStorage: boolean;
};
compliance: {
frameworks: string[];
automaticClassification: boolean;
retentionPolicies: Record<string, string>;
exportFormats: string[];
};
monitoring: {
alerting: {
enabled: boolean;
channels: string[];
thresholds: {
failedLogins: number;
privilegedAccess: number;
dataExfiltration: number;
configChanges: number;
};
};
reporting: {
automated: boolean;
frequency: string;
recipients: string[];
dashboards: string[];
};
};
privacy: {
piiDetection: boolean;
anonymization: boolean;
masking: {
enabled: boolean;
patterns: string[];
};
consent: {
required: boolean;
tracking: boolean;
};
};
}
export interface AuditMetrics {
volume: {
totalEntries: number;
dailyAverage: number;
peakHourly: number;
byCategory: Record<string, number>;
bySeverity: Record<string, number>;
};
compliance: {
overallScore: number;
byFramework: Record<
string,
{
score: number;
compliant: number;
nonCompliant: number;
total: number;
}
>;
trending: 'improving' | 'stable' | 'declining';
};
integrity: {
verificationSuccess: number;
tamperAttempts: number;
dataLoss: number;
corruptionEvents: number;
};
performance: {
ingestionRate: number;
queryResponseTime: number;
storageEfficiency: number;
availabilityPercentage: number;
};
security: {
unauthorizedAccess: number;
privilegedActions: number;
suspiciousPatterns: number;
escalatedIncidents: number;
};
}
export class AuditManager extends EventEmitter {
private auditTrails: Map<string, AuditTrail> = new Map();
private frameworks: Map<string, ComplianceFramework> = new Map();
private reports: Map<string, AuditReport> = new Map();
private auditBuffer: AuditEntry[] = [];
private auditPath: string;
private logger: Logger;
private config: ConfigManager;
private configuration: AuditConfiguration;
constructor(auditPath: string = './audit', logger?: Logger, config?: ConfigManager) {
super();
this.auditPath = auditPath;
this.logger = logger || new Logger({ level: 'info', format: 'text', destination: 'console' });
this.config = config || ConfigManager.getInstance();
this.configuration = this.getDefaultConfiguration();
}
async initialize(): Promise<void> {
try {
await mkdir(this.auditPath, { recursive: true });
await mkdir(join(this.auditPath, 'trails'), { recursive: true });
await mkdir(join(this.auditPath, 'frameworks'), { recursive: true });
await mkdir(join(this.auditPath, 'reports'), { recursive: true });
await mkdir(join(this.auditPath, 'evidence'), { recursive: true });
await mkdir(join(this.auditPath, 'exports'), { recursive: true });
await this.loadConfigurations();
await this.initializeDefaultFrameworks();
await this.startAuditProcessing();
this.logger.info('Audit Manager initialized successfully');
} catch (error) {
this.logger.error('Failed to initialize Audit Manager', { error });
throw error;
}
}
async logAuditEvent(eventData: {
eventType: string;
category: AuditEntry['category'];
severity?: AuditEntry['severity'];
userId?: string;
sessionId?: string;
resource: AuditEntry['resource'];
action: string;
outcome: AuditEntry['outcome'];
details: Record<string, any>;
context: Partial<AuditEntry['context']>;
compliance?: {
frameworks?: string[];
controls?: string[];
classification?: AuditEntry['compliance']['classification'];
};
}): Promise<AuditEntry> {
const entry: AuditEntry = {
id: `audit-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
timestamp: new Date(),
eventType: eventData.eventType,
category: eventData.category,
severity: eventData.severity || 'medium',
userId: eventData.userId,
sessionId: eventData.sessionId,
resource: eventData.resource,
action: eventData.action,
outcome: eventData.outcome,
details: eventData.details,
context: {
source: 'system',
...eventData.context,
},
compliance: {
frameworks: eventData.compliance?.frameworks || [],
controls: eventData.compliance?.controls || [],
retention: this.calculateRetentionPeriod(
eventData.category,
eventData.compliance?.frameworks,
),
classification: eventData.compliance?.classification || 'internal',
},
integrity: {
hash: '',
verified: false,
},
metadata: {},
};
// Calculate integrity hash
entry.integrity.hash = this.calculateHash(entry);
entry.integrity.verified = true;
// Add to buffer for batch processing
this.auditBuffer.push(entry);
// Immediate processing for critical events
if (entry.severity === 'critical') {
await this.processAuditEntry(entry);
await this.generateSecurityAlert(entry);
}
// Batch process if buffer is full
if (this.auditBuffer.length >= this.configuration.collection.batchSize) {
await this.flushAuditBuffer();
}
this.emit('audit:logged', entry);
return entry;
}
async createComplianceFramework(frameworkData: {
name: string;
version: string;
description: string;
type: ComplianceFramework['type'];
requirements: Omit<ComplianceRequirement, 'id'>[];
controls: Omit<ComplianceControl, 'id'>[];
auditFrequency: ComplianceFramework['auditFrequency'];
retentionPeriod: string;
responsible: string;
}): Promise<ComplianceFramework> {
const framework: ComplianceFramework = {
id: `framework-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
name: frameworkData.name,
version: frameworkData.version,
description: frameworkData.description,
type: frameworkData.type,
requirements: frameworkData.requirements.map((req, index) => ({
id: `req-${Date.now()}-${index}`,
...req,
automatedCheck: {
enabled: false,
frequency: 'daily',
query: '',
...req.automatedCheck,
},
})),
auditFrequency: frameworkData.auditFrequency,
retentionPeriod: frameworkData.retentionPeriod,
reportingRequirements: {
frequency: 'quarterly',
recipients: [],
format: ['pdf', 'json'],
automated: false,
},
controls: frameworkData.controls.map((control, index) => ({
id: `control-${Date.now()}-${index}`,
...control,
})),
status: 'active',
implementationDate: new Date(),
nextReview: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 year
responsible: frameworkData.responsible,
};
this.frameworks.set(framework.id, framework);
await this.saveFramework(framework);
await this.logAuditEvent({
eventType: 'compliance_framework_created',
category: 'compliance',
severity: 'medium',
resource: { type: 'compliance-framework', id: framework.id, name: framework.name },
action: 'create',
outcome: 'success',
details: { frameworkType: framework.type, requirementsCount: framework.requirements.length },
context: { source: 'audit-manager' },
compliance: { frameworks: [framework.id] },
});
this.emit('framework:created', framework);
this.logger.info(`Compliance framework created: ${framework.name} (${framework.id})`);
return framework;
}
async generateAuditReport(reportConfig: {
title: string;
description: string;
type: AuditReport['type'];
scope: AuditReport['scope'];
includeRecommendations?: boolean;
confidentiality?: AuditReport['confidentiality'];
}): Promise<AuditReport> {
const report: AuditReport = {
id: `report-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
title: reportConfig.title,
description: reportConfig.description,
type: reportConfig.type,
scope: reportConfig.scope,
findings: [],
recommendations: [],
summary: {
totalEvents: 0,
criticalFindings: 0,
complianceScore: 0,
riskLevel: 'low',
},
methodology: 'Automated analysis of audit trail data with manual review of findings',
limitations: [],
reviewers: [],
approvers: [],
status: 'draft',
confidentiality: reportConfig.confidentiality || 'internal',
createdAt: new Date(),
updatedAt: new Date(),
createdBy: 'audit-manager',
};
// Collect relevant audit entries
const auditEntries = await this.queryAuditEntries(reportConfig.scope);
report.summary.totalEvents = auditEntries.length;
// Analyze entries for findings
const findings = await this.analyzeAuditEntries(auditEntries, reportConfig.type);
report.findings = findings;
report.summary.criticalFindings = findings.filter((f) => f.severity === 'critical').length;
// Calculate compliance score
if (reportConfig.scope.compliance && reportConfig.scope.compliance.length > 0) {
report.summary.complianceScore = await this.calculateComplianceScore(
reportConfig.scope.compliance,
auditEntries,
);
}
// Determine risk level
report.summary.riskLevel = this.calculateRiskLevel(findings);
// Generate recommendations
if (reportConfig.includeRecommendations !== false) {
report.recommendations = await this.generateRecommendations(findings, reportConfig.type);
}
this.reports.set(report.id, report);
await this.saveReport(report);
await this.logAuditEvent({
eventType: 'audit_report_generated',
category: 'compliance',
severity: 'medium',
resource: { type: 'audit-report', id: report.id, name: report.title },
action: 'generate',
outcome: 'success',
details: {
reportType: report.type,
totalEvents: report.summary.totalEvents,
findingsCount: report.findings.length,
complianceScore: report.summary.complianceScore,
},
context: { source: 'audit-manager' },
compliance: { frameworks: reportConfig.scope.compliance || [] },
});
this.emit('report:generated', report);
this.logger.info(`Audit report generated: ${report.title} (${report.id})`);
return report;
}
async exportAuditData(exportConfig: {
format: 'json' | 'csv' | 'xml' | 'pdf';
scope: {
timeRange: { start: Date; end: Date };
categories?: string[];
severity?: string[];
users?: string[];
};
destination: string;
encryption?: boolean;
compression?: boolean;
}): Promise<string> {
const entries = await this.queryAuditEntries(exportConfig.scope);
let exportData: string;
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `audit-export-${timestamp}.${exportConfig.format}`;
const filepath = join(this.auditPath, 'exports', filename);
switch (exportConfig.format) {
case 'json':
exportData = JSON.stringify(entries, null, 2);
break;
case 'csv':
exportData = this.convertToCSV(entries);
break;
case 'xml':
exportData = this.convertToXML(entries);
break;
case 'pdf':
exportData = await this.convertToPDF(entries);
break;
default:
throw new Error(`Unsupported export format: ${exportConfig.format}`);
}
// Apply compression if requested
if (exportConfig.compression) {
// Would implement compression here
}
// Apply encryption if requested
if (exportConfig.encryption) {
// Would implement encryption here
}
await writeFile(filepath, exportData);
await this.logAuditEvent({
eventType: 'audit_data_exported',
category: 'data-access',
severity: 'medium',
resource: { type: 'audit-data', id: 'export', path: filepath },
action: 'export',
outcome: 'success',
details: {
format: exportConfig.format,
recordCount: entries.length,
timeRange: exportConfig.scope.timeRange,
compressed: exportConfig.compression || false,
encrypted: exportConfig.encryption || false,
},
context: { source: 'audit-manager' },
});
this.emit('data:exported', {
filepath,
format: exportConfig.format,
recordCount: entries.length,
});
this.logger.info(`Audit data exported: ${filename} (${entries.length} records)`);
return filepath;
}
async verifyAuditIntegrity(trailId?: string): Promise<{
verified: boolean;
issues: TamperEvidence[];
summary: {
totalEntries: number;
verifiedEntries: number;
corruptedEntries: number;
missingEntries: number;
};
}> {
const issues: TamperEvidence[] = [];
let totalEntries = 0;
let verifiedEntries = 0;
let corruptedEntries = 0;
let missingEntries = 0;
const trails = trailId
? ([this.auditTrails.get(trailId)].filter(Boolean) as AuditTrail[])
: Array.from(this.auditTrails.values());
for (const trail of trails) {
for (const entry of trail.entries) {
totalEntries++;
// Verify hash
const calculatedHash = this.calculateHash(entry);
if (calculatedHash === entry.integrity.hash) {
verifiedEntries++;
} else {
corruptedEntries++;
issues.push({
timestamp: new Date(),
type: 'checksum-mismatch',
description: `Hash mismatch for audit entry ${entry.id}`,
severity: 'high',
investigationStatus: 'pending',
evidence: [`Expected: ${entry.integrity.hash}`, `Calculated: ${calculatedHash}`],
});
}
}
// Update trail integrity status
trail.integrity.verified = issues.length === 0;
trail.integrity.lastVerification = new Date();
trail.integrity.tamperEvidence = issues;
await this.saveAuditTrail(trail);
}
const verified = issues.length === 0;
await this.logAuditEvent({
eventType: 'audit_integrity_verification',
category: 'security',
severity: verified ? 'low' : 'high',
resource: { type: 'audit-trail', id: trailId || 'all' },
action: 'verify',
outcome: verified ? 'success' : 'failure',
details: {
totalEntries,
verifiedEntries,
corruptedEntries,
issuesFound: issues.length,
},
context: { source: 'audit-manager' },
});
if (!verified) {
this.emit('integrity:compromised', {
issues,
summary: { totalEntries, verifiedEntries, corruptedEntries, missingEntries },
});
this.logger.error(`Audit integrity verification failed: ${issues.length} issues found`);
} else {
this.logger.info(`Audit integrity verification successful: ${totalEntries} entries verified`);
}
return {
verified,
issues,
summary: { totalEntries, verifiedEntries, corruptedEntries, missingEntries },
};
}
async getAuditMetrics(timeRange?: { start: Date; end: Date }): Promise<AuditMetrics> {
const range = timeRange || {
start: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), // Last 30 days
end: new Date(),
};
const entries = await this.queryAuditEntries({ timeRange: range });
// Volume metrics
const volumeMetrics = {
totalEntries: entries.length,
dailyAverage: entries.length / 30,
peakHourly: this.calculatePeakHourly(entries),
byCategory: this.groupBy(entries, 'category'),
bySeverity: this.groupBy(entries, 'severity'),
};
// Compliance metrics
const complianceMetrics = {
overallScore: 85, // Would be calculated from actual compliance data
byFramework: {} as Record<string, any>,
trending: 'stable' as const,
};
// Calculate compliance scores by framework
for (const framework of this.frameworks.values()) {
const score = await this.calculateComplianceScore([framework.id], entries);
complianceMetrics.byFramework[framework.id] = {
score,
compliant: framework.requirements.filter((r) => r.status === 'compliant').length,
nonCompliant: framework.requirements.filter((r) => r.status === 'non-compliant').length,
total: framework.requirements.length,
};
}
// Integrity metrics
const integrityMetrics = {
verificationSuccess: 99.5,
tamperAttempts: entries.filter((e) => e.eventType === 'unauthorized_access').length,
dataLoss: 0,
corruptionEvents: 0,
};
// Performance metrics
const performanceMetrics = {
ingestionRate: entries.length / 24, // entries per hour
queryResponseTime: 150, // ms
storageEfficiency: 85, // percentage
availabilityPercentage: 99.9,
};
// Security metrics
const securityMetrics = {
unauthorizedAccess: entries.filter(
(e) => e.outcome === 'denied' || e.eventType === 'unauthorized_access',
).length,
privilegedActions: entries.filter((e) => e.details.privileged === true).length,
suspiciousPatterns: entries.filter((e) => e.severity === 'critical').length,
escalatedIncidents: entries.filter(
(e) => e.category === 'security' && e.severity === 'critical',
).length,
};
return {
volume: volumeMetrics,
compliance: complianceMetrics,
integrity: integrityMetrics,
performance: performanceMetrics,
security: securityMetrics,
};
}
// Private helper methods
private getDefaultConfiguration(): AuditConfiguration {
return {
general: {
enabled: true,
defaultRetention: '7y',
compressionEnabled: true,
encryptionEnabled: true,
realTimeProcessing: true,
},
collection: {
automaticCapture: true,
bufferSize: 10000,
batchSize: 1000,
flushInterval: 60000,
failureHandling: 'retry',
},
storage: {
primaryLocation: join(this.auditPath, 'trails'),
partitioning: 'daily',
indexing: true,
},
integrity: {
checksumAlgorithm: 'sha256',
verificationFrequency: 'daily',
digitalSignatures: false,
immutableStorage: true,
},
compliance: {
frameworks: [],
automaticClassification: true,
retentionPolicies: {
authentication: '3y',
'data-access': '7y',
'system-change': '5y',
security: '7y',
compliance: '10y',
},
exportFormats: ['json', 'csv', 'pdf'],
},
monitoring: {
alerting: {
enabled: true,
channels: ['email', 'webhook'],
thresholds: {
failedLogins: 5,
privilegedAccess: 10,
dataExfiltration: 1,
configChanges: 20,
},
},
reporting: {
automated: true,
frequency: 'weekly',
recipients: [],
dashboards: [],
},
},
privacy: {
piiDetection: true,
anonymization: false,
masking: {
enabled: true,
patterns: ['\\b\\d{4}[- ]?\\d{4}[- ]?\\d{4}[- ]?\\d{4}\\b'], // Credit card pattern
},
consent: {
required: false,
tracking: false,
},
},
};
}
private async loadConfigurations(): Promise<void> {
try {
// Load frameworks
const frameworkFiles = await readdir(join(this.auditPath, 'frameworks'));
for (const file of frameworkFiles.filter((f) => f.endsWith('.json'))) {
const content = await readFile(join(this.auditPath, 'frameworks', file), 'utf-8');
const framework: ComplianceFramework = JSON.parse(content);
this.frameworks.set(framework.id, framework);
}
// Load audit trails
const trailFiles = await readdir(join(this.auditPath, 'trails'));
for (const file of trailFiles.filter((f) => f.endsWith('.json'))) {
const content = await readFile(join(this.auditPath, 'trails', file), 'utf-8');
const trail: AuditTrail = JSON.parse(content);
this.auditTrails.set(trail.id, trail);
}
// Load reports
const reportFiles = await readdir(join(this.auditPath, 'reports'));
for (const file of reportFiles.filter((f) => f.endsWith('.json'))) {
const content = await readFile(join(this.auditPath, 'reports', file), 'utf-8');
const report: AuditReport = JSON.parse(content);
this.reports.set(report.id, report);
}
this.logger.info(
`Loaded ${this.frameworks.size} frameworks, ${this.auditTrails.size} trails, ${this.reports.size} reports`,
);
} catch (error) {
this.logger.warn('Failed to load some audit configurations', { error });
}
}
private async initializeDefaultFrameworks(): Promise<void> {
const defaultFrameworks = [
{
name: 'SOC 2 Type II',
version: '2017',
description: 'Service Organization Control 2 Type II compliance framework',
type: 'certification' as const,
requirements: [
{
title: 'Security Principle - Logical and Physical Access Controls',
description: 'The entity restricts logical and physical access to the system',
category: 'access-control',
priority: 'high' as const,
status: 'compliant' as const,
evidence: [],
gaps: [],
remediation: {
actions: [],
owner: 'security-team',
dueDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
},
lastAssessed: new Date(),
nextAssessment: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
automatedCheck: {
enabled: true,
frequency: 'daily',
query: 'category:authentication AND outcome:failure',
threshold: 10,
},
},
],
controls: [
{
name: 'Multi-Factor Authentication',
description: 'MFA is required for all user accounts',
type: 'preventive' as const,
automationType: 'automated' as const,
effectiveness: 'high' as const,
frequency: 'continuous',
owner: 'security-team',
evidence: [],
testingProcedure: 'Verify MFA is enabled for all user accounts',
lastTested: new Date(),
nextTest: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
status: 'effective' as const,
},
],
auditFrequency: 'quarterly' as const,
retentionPeriod: '7y',
responsible: 'compliance-officer',
},
{
name: 'GDPR',
version: '2018',
description: 'General Data Protection Regulation compliance framework',
type: 'regulatory' as const,
requirements: [
{
title: 'Data Processing Records',
description: 'Maintain records of all data processing activities',
category: 'data-protection',
priority: 'critical' as const,
status: 'compliant' as const,
evidence: [],
gaps: [],
remediation: {
actions: [],
owner: 'data-protection-officer',
dueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
},
lastAssessed: new Date(),
nextAssessment: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
automatedCheck: {
enabled: true,
frequency: 'daily',
query: 'category:data-access AND details.pii:true',
},
},
],
controls: [],
auditFrequency: 'annually' as const,
retentionPeriod: '6y',
responsible: 'data-protection-officer',
},
];
for (const frameworkData of defaultFrameworks) {
if (!Array.from(this.frameworks.values()).some((f) => f.name === frameworkData.name)) {
await this.createComplianceFramework(frameworkData);
}
}
}
private async startAuditProcessing(): Promise<void> {
// Start buffer flush timer
setInterval(async () => {
if (this.auditBuffer.length > 0) {
await this.flushAuditBuffer();
}
}, this.configuration.collection.flushInterval);
// Start integrity verification timer
setInterval(
async () => {
await this.verifyAuditIntegrity();
},
24 * 60 * 60 * 1000,
); // Daily
this.logger.info('Started audit processing timers');
}
private async flushAuditBuffer(): Promise<void> {
if (this.auditBuffer.length === 0) return;
const entries = [...this.auditBuffer];
this.auditBuffer = [];
try {
for (const entry of entries) {
await this.processAuditEntry(entry);
}
this.logger.debug(`Flushed ${entries.length} audit entries`);
} catch (error) {
this.logger.error('Failed to flush audit buffer', { error });
// Re-add entries to buffer for retry if configured
if (this.configuration.collection.failureHandling === 'retry') {
this.auditBuffer.unshift(...entries);
}
}
}
private async processAuditEntry(entry: AuditEntry): Promise<void> {
// Determine which trail to add the entry to
const trailId = this.determineAuditTrail(entry);
let trail = this.auditTrails.get(trailId);
if (!trail) {
trail = await this.createAuditTrail(trailId, entry.category);
}
// Add entry to trail
trail.entries.push(entry);
trail.updatedAt = new Date();
// Update trail integrity
trail.integrity.checksum = this.calculateTrailChecksum(trail);
trail.integrity.lastVerification = new Date();
await this.saveAuditTrail(trail);
// Check for compliance violations
await this.checkComplianceViolations(entry);
// Check for security alerts
await this.checkSecurityAlerts(entry);
}
private determineAuditTrail(entry: AuditEntry): string {
// Use category and date for trail determination
const date = entry.timestamp.toISOString().split('T')[0];
return `${entry.category}-${date}`;
}
private async createAuditTrail(id: string, category: string): Promise<AuditTrail> {
const trail: AuditTrail = {
id,
name: `${category} audit trail`,
description: `Audit trail for ${category} events`,
category,
entries: [],
configuration: {
retention:
this.configuration.compliance.retentionPolicies[category] ||
this.configuration.general.defaultRetention,
compression: this.configuration.general.compressionEnabled,
encryption: this.configuration.general.encryptionEnabled,
archival: {
enabled: true,
location: join(this.auditPath, 'archive'),
schedule: 'yearly',
},
monitoring: {
realTime: this.configuration.general.realTimeProcessing,
alerting: this.configuration.monitoring.alerting.enabled,
dashboards: [],
},
},
integrity: {
verified: true,
lastVerification: new Date(),
checksum: '',
tamperEvidence: [],
},
access: {
viewers: [],
admins: ['audit-admin'],
readonly: false,
auditAccess: true,
},
compliance: {
frameworks: [],
retention:
this.configuration.compliance.retentionPolicies[category] ||
this.configuration.general.defaultRetention,
exportRequirements: [],
immutable: this.configuration.integrity.immutableStorage,
},
createdAt: new Date(),
updatedAt: new Date(),
};
this.auditTrails.set(trail.id, trail);
await this.saveAuditTrail(trail);
return trail;
}
private calculateHash(entry: AuditEntry): string {
// Create a deterministic string representation of the entry
const data = {
timestamp: entry.timestamp.toISOString(),
eventType: entry.eventType,
category: entry.category,
userId: entry.userId,
resource: entry.resource,
action: entry.action,
outcome: entry.outcome,
details: entry.details,
};
return createHash(this.configuration.integrity.checksumAlgorithm)
.update(JSON.stringify(data))
.digest('hex');
}
private calculateTrailChecksum(trail: AuditTrail): string {
const data = trail.entries.map((e) => e.integrity.hash).join('');
return createHash(this.configuration.integrity.checksumAlgorithm).update(data).digest('hex');
}
private calculateRetentionPeriod(category: string, frameworks?: string[]): string {
const categoryRetention = this.configuration.compliance.retentionPolicies[category];
if (categoryRetention) return categoryRetention;
// Check framework requirements
if (frameworks) {
let maxRetention = this.configuration.general.defaultRetention;
for (const frameworkId of frameworks) {
const framework = this.frameworks.get(frameworkId);
if (
framework &&
this.parseRetentionPeriod(framework.retentionPeriod) >
this.parseRetentionPeriod(maxRetention)
) {
maxRetention = framework.retentionPeriod;
}
}
return maxRetention;
}
return this.configuration.general.defaultRetention;
}
private parseRetentionPeriod(period: string): number {
const match = period.match(/(\d+)([ymd])/);
if (!match) return 0;
const value = parseInt(match[1]);
const unit = match[2];
switch (unit) {
case 'y':
return value * 365;
case 'm':
return value * 30;
case 'd':
return value;
default:
return 0;
}
}
private async queryAuditEntries(scope: {
timeRange?: { start: Date; end: Date };
categories?: string[];
severity?: string[];
users?: string[];
events?: string[];
compliance?: string[];
}): Promise<AuditEntry[]> {
let entries: AuditEntry[] = [];
// Collect entries from all trails
for (const trail of this.auditTrails.values()) {
entries.push(...trail.entries);
}
// Apply filters
if (scope.timeRange) {
entries = entries.filter(
(e) => e.timestamp >= scope.timeRange!.start && e.timestamp <= scope.timeRange!.end,
);
}
if (scope.categories) {
entries = entries.filter((e) => scope.categories!.includes(e.category));
}
if (scope.severity) {
entries = entries.filter((e) => scope.severity!.includes(e.severity));
}
if (scope.users) {
entries = entries.filter((e) => e.userId && scope.users!.includes(e.userId));
}
if (scope.events) {
entries = entries.filter((e) => scope.events!.includes(e.eventType));
}
if (scope.compliance) {
entries = entries.filter((e) =>
e.compliance.frameworks.some((f) => scope.compliance!.includes(f)),
);
}
return entries.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
}
private async analyzeAuditEntries(
entries: AuditEntry[],
reportType: string,
): Promise<AuditFinding[]> {
const findings: AuditFinding[] = [];
// Security-focused analysis
if (reportType === 'security') {
// Check for failed login patterns
const failedLogins = entries.filter(
(e) => e.eventType === 'user_login' && e.outcome === 'failure',
);
if (failedLogins.length > 10) {
findings.push({
id: `finding-${Date.now()}-1`,
title: 'Excessive Failed Login Attempts',
description: `${failedLogins.length} failed login attempts detected`,
severity: 'high',
category: 'authentication',
risk: 'Potential brute force attack',
impact: 'Unauthorized access attempt',
likelihood: 'medium',
evidence: [],
relatedEvents: failedLogins.map((e) => e.id),
complianceImpact: {
frameworks: ['SOC2'],
violations: ['Access Control'],
penalties: [],
},
remediation: {
priority: 'high',
owner: 'security-team',
actions: ['Implement account lockout', 'Enable MFA', 'Review access logs'],
timeline: '7 days',
},
status: 'open',
});
}
}
// Compliance-focused analysis
if (reportType === 'compliance') {
// Check for data access patterns
const dataAccess = entries.filter(
(e) => e.category === 'data-access' && e.details.pii === true,
);
if (dataAccess.length > 0) {
findings.push({
id: `finding-${Date.now()}-2`,
title: 'PII Data Access Events',
description: `${dataAccess.length} events involving PII data access`,
severity: 'medium',
category: 'data-protection',
risk: 'Privacy compliance risk',
impact: 'Potential GDPR violation',
likelihood: 'low',
evidence: [],
relatedEvents: dataAccess.map((e) => e.id),
complianceImpact: {
frameworks: ['GDPR'],
violations: ['Data Processing'],
penalties: ['Administrative fine'],
},
remediation: {
priority: 'medium',
owner: 'data-protection-officer',
actions: ['Review data access justification', 'Update privacy notices'],
timeline: '30 days',
},
status: 'open',
});
}
}
return findings;
}
private async calculateComplianceScore(
frameworks: string[],
entries: AuditEntry[],
): Promise<number> {
let totalRequirements = 0;
let metRequirements = 0;
for (const frameworkId of frameworks) {
const framework = this.frameworks.get(frameworkId);
if (!framework) continue;
for (const requirement of framework.requirements) {
totalRequirements++;
if (requirement.status === 'compliant') {
metRequirements++;
} else if (requirement.automatedCheck.enabled) {
// Check if automated requirement is met based on audit data
const violations = this.checkAutomatedRequirement(requirement, entries);
if (violations.length === 0) {
metRequirements++;
}
}
}
}
return totalRequirements > 0 ? (metRequirements / totalRequirements) * 100 : 0;
}
private checkAutomatedRequirement(
requirement: ComplianceRequirement,
entries: AuditEntry[],
): AuditEntry[] {
// Simplified automated compliance checking
// In a real implementation, this would parse the query and evaluate against entries
const violations = entries.filter((e) => {
if (requirement.automatedCheck.query.includes('outcome:failure')) {
return e.outcome === 'failure';
}
return false;
});
return violations;
}
private calculateRiskLevel(findings: AuditFinding[]): 'low' | 'medium' | 'high' | 'critical' {
const criticalFindings = findings.filter((f) => f.severity === 'critical').length;
const highFindings = findings.filter((f) => f.severity === 'high').length;
if (criticalFindings > 0) return 'critical';
if (highFindings > 2) return 'high';
if (findings.length > 5) return 'medium';
return 'low';
}
private async generateRecommendations(
findings: AuditFinding[],
reportType: string,
): Promise<AuditRecommendation[]> {
const recommendations: AuditRecommendation[] = [];
// Generic security recommendations
if (findings.some((f) => f.category === 'authentication')) {
recommendations.push({
id: `rec-${Date.now()}-1`,
title: 'Strengthen Authentication Controls',
description: 'Implement additional authentication security measures',
priority: 'high',
category: 'technology',
implementation: {
effort: 'medium',
cost: 'medium',
timeline: '30 days',
dependencies: ['Identity Provider Integration'],
risks: ['User experience impact'],
},
expectedBenefit: 'Reduced risk of unauthorized access',
owner: 'security-team',
status: 'proposed',
tracking: {
milestones: ['MFA deployment', 'Policy update', 'User training'],
progress: 0,
nextReview: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
},
});
}
return recommendations;
}
private async checkComplianceViolations(entry: AuditEntry): Promise<void> {
for (const frameworkId of entry.compliance.frameworks) {
const framework = this.frameworks.get(frameworkId);
if (!framework) continue;
for (const requirement of framework.requirements) {
if (requirement.automatedCheck.enabled) {
const violations = this.checkAutomatedRequirement(requirement, [entry]);
if (violations.length > 0) {
this.emit('compliance:violation', {
framework: frameworkId,
requirement: requirement.id,
entry,
severity: requirement.priority,
});
}
}
}
}
}
private async checkSecurityAlerts(entry: AuditEntry): Promise<void> {
const thresholds = this.configuration.monitoring.alerting.thresholds;
// Check for specific alert conditions
if (entry.eventType === 'user_login' && entry.outcome === 'failure') {
// Would implement failed login threshold checking
}
if (entry.category === 'data-access' && entry.details.privileged) {
this.emit('security:alert', {
type: 'privileged-access',
entry,
severity: 'medium',
});
}
}
private async generateSecurityAlert(entry: AuditEntry): Promise<void> {
this.emit('security:critical', {
entry,
message: `Critical security event: ${entry.eventType}`,
action: 'immediate-review-required',
});
}
private calculatePeakHourly(entries: AuditEntry[]): number {
const hourlyBuckets: Record<string, number> = {};
for (const entry of entries) {
const hour = entry.timestamp.toISOString().substr(0, 13); // YYYY-MM-DDTHH
hourlyBuckets[hour] = (hourlyBuckets[hour] || 0) + 1;
}
return Math.max(...Object.values(hourlyBuckets), 0);
}
private groupBy<T>(array: T[], key: keyof T): Record<string, number> {
return array.reduce(
(groups, item) => {
const value = String(item[key]);
groups[value] = (groups[value] || 0) + 1;
return groups;
},
{} as Record<string, number>,
);
}
private convertToCSV(entries: AuditEntry[]): string {
const headers = [
'timestamp',
'eventType',
'category',
'severity',
'userId',
'action',
'outcome',
'resource',
];
const rows = entries.map((entry) => [
entry.timestamp.toISOString(),
entry.eventType,
entry.category,
entry.severity,
entry.userId || '',
entry.action,
entry.outcome,
`${entry.resource.type}:${entry.resource.id}`,
]);
return [headers, ...rows].map((row) => row.join(',')).join('\n');
}
private convertToXML(entries: AuditEntry[]): string {
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<auditEntries>\n';
for (const entry of entries) {
xml += ` <entry id="${entry.id}">\n`;
xml += ` <timestamp>${entry.timestamp.toISOString()}</timestamp>\n`;
xml += ` <eventType>${entry.eventType}</eventType>\n`;
xml += ` <category>${entry.category}</category>\n`;
xml += ` <severity>${entry.severity}</severity>\n`;
xml += ` <action>${entry.action}</action>\n`;
xml += ` <outcome>${entry.outcome}</outcome>\n`;
xml += ` </entry>\n`;
}
xml += '</auditEntries>';
return xml;
}
private async convertToPDF(entries: AuditEntry[]): Promise<string> {
// Would implement PDF generation
return 'PDF generation not implemented';
}
private async saveFramework(framework: ComplianceFramework): Promise<void> {
const filePath = join(this.auditPath, 'frameworks', `${framework.id}.json`);
await writeFile(filePath, JSON.stringify(framework, null, 2));
}
private async saveAuditTrail(trail: AuditTrail): Promise<void> {
const filePath = join(this.auditPath, 'trails', `${trail.id}.json`);
await writeFile(filePath, JSON.stringify(trail, null, 2));