@sethdouglasford/claude-flow
Version:
Claude Code Flow - Advanced AI-powered development workflows with SPARC methodology
992 lines • 42 kB
JavaScript
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 class AuditManager extends EventEmitter {
auditTrails = new Map();
frameworks = new Map();
reports = new Map();
auditBuffer = [];
auditPath;
logger;
config;
configuration;
constructor(auditPath = "./audit", logger, config) {
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() {
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) {
const entry = {
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) {
const framework = {
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: {
...(req.automatedCheck || {}),
enabled: req.automatedCheck?.enabled ?? false,
frequency: req.automatedCheck?.frequency ?? "daily",
query: req.automatedCheck?.query ?? "",
},
})),
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) {
const report = {
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) {
const entries = await this.queryAuditEntries(exportConfig.scope);
let exportData;
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) {
const issues = [];
let totalEntries = 0;
let verifiedEntries = 0;
let corruptedEntries = 0;
const missingEntries = 0;
const trails = trailId ? [this.auditTrails.get(trailId)].filter(Boolean) :
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) {
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: {},
trending: "stable",
};
// 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
getDefaultConfiguration() {
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,
},
},
};
}
async loadConfigurations() {
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 = 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 = 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 = 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 });
}
}
async initializeDefaultFrameworks() {
const defaultFrameworks = [
{
name: "SOC 2 Type II",
version: "2017",
description: "Service Organization Control 2 Type II compliance framework",
type: "certification",
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",
status: "compliant",
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",
automationType: "automated",
effectiveness: "high",
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",
},
],
auditFrequency: "quarterly",
retentionPeriod: "7y",
responsible: "compliance-officer",
},
{
name: "GDPR",
version: "2018",
description: "General Data Protection Regulation compliance framework",
type: "regulatory",
requirements: [
{
title: "Data Processing Records",
description: "Maintain records of all data processing activities",
category: "data-protection",
priority: "critical",
status: "compliant",
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",
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);
}
}
}
async startAuditProcessing() {
// 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");
}
async flushAuditBuffer() {
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);
}
}
}
async processAuditEntry(entry) {
// 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);
}
determineAuditTrail(entry) {
// Use category and date for trail determination
const date = entry.timestamp.toISOString().split("T")[0];
return `${entry.category}-${date}`;
}
async createAuditTrail(id, category) {
const trail = {
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;
}
calculateHash(entry) {
// 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");
}
calculateTrailChecksum(trail) {
const data = trail.entries.map(e => e.integrity.hash).join("");
return createHash(this.configuration.integrity.checksumAlgorithm)
.update(data)
.digest("hex");
}
calculateRetentionPeriod(category, frameworks) {
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;
}
parseRetentionPeriod(period) {
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;
}
}
async queryAuditEntries(scope) {
let entries = [];
// 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());
}
async analyzeAuditEntries(entries, reportType) {
const findings = [];
// 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;
}
async calculateComplianceScore(frameworks, entries) {
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;
}
checkAutomatedRequirement(requirement, entries) {
// 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;
}
calculateRiskLevel(findings) {
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";
}
async generateRecommendations(findings, reportType) {
const recommendations = [];
// 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;
}
async checkComplianceViolations(entry) {
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,
});
}
}
}
}
}
async checkSecurityAlerts(entry) {
const { thresholds } = this.configuration.monitoring.alerting;
// 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",
});
}
}
async generateSecurityAlert(entry) {
this.emit("security:critical", {
entry,
message: `Critical security event: ${entry.eventType}`,
action: "immediate-review-required",
});
}
calculatePeakHourly(entries) {
const hourlyBuckets = {};
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);
}
groupBy(array, key) {
return array.reduce((groups, item) => {
const value = String(item[key]);
groups[value] = (groups[value] || 0) + 1;
return groups;
}, {});
}
convertToCSV(entries) {
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");
}
convertToXML(entries) {
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;
}
async convertToPDF(entries) {
// Would implement PDF generation
return "PDF generation not implemented";
}
async saveFramework(framework) {
const filePath = join(this.auditPath, "frameworks", `${framework.id}.json`);
await writeFile(filePath, JSON.stringify(framework, null, 2));
}
async saveAuditTrail(trail) {
const filePath = join(this.auditPath, "trails", `${trail.id}.json`);
await writeFile(filePath, JSON.stringify(trail, null, 2));
}
async saveReport(report) {
const filePath = join(this.auditPath, "reports", `${report.id}.json`);
await writeFile(filePath, JSON.stringify(report, null, 2));
}
}
//# sourceMappingURL=audit-manager.js.map