UNPKG

@iota-big3/sdk-security

Version:

Advanced security features including zero trust, quantum-safe crypto, and ML threat detection

352 lines 12.7 kB
"use strict"; /** * @iota-big3/sdk-security - Chaos Engineering Framework * Production readiness through controlled failure injection */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CHAOS_SCENARIOS = exports.ChaosEngine = void 0; const events_1 = require("events"); class ChaosEngine extends events_1.EventEmitter { constructor(config) { super(); this.isActive = false; this.failures = []; this.activeFailures = new Map(); this.originalMethods = new Map(); this.config = config; this.metrics = this.initializeMetrics(); } initializeMetrics() { return { totalFailures: 0, failuresByType: {}, failuresByComponent: {}, averageRecoveryTime: 0, systemAvailability: 100, lastFailureTime: 0 }; } async start() { if (!this.config.enabled || this.isActive) { return; } this.isActive = true; this.emit('chaos:started'); // Check safeguards before starting const safeToStart = await this.checkSafeguards(); if (!safeToStart) { this.isActive = false; this.emit('chaos:aborted', 'Safeguard conditions not met'); return; } // Start chaos injection this.startChaosInjection(); } async checkSafeguards() { for (const safeguard of this.config.safeguards) { const safe = await safeguard.condition(); if (!safe) { this.emit('chaos:safeguard:triggered', safeguard.name); switch (safeguard.action) { case 'abort': return false; case 'pause': await this.pause(); break; case 'notify': this.emit('chaos:safeguard:notification', safeguard.name); break; } } } return true; } startChaosInjection() { // Inject failures based on probability const interval = setInterval(async () => { if (!this.isActive) { clearInterval(interval); return; } if (Math.random() < this.config.probability) { await this.injectRandomFailure(); } }, 1000); // Check every second } async injectRandomFailure() { // Select random target const target = this.selectRandomTarget(); if (!target) return; // Select random failure type const failureType = this.selectRandomFailureType(target); // Create chaos event const event = { id: this.generateId(), timestamp: Date.now(), target: `${target.component}${target.method ? '.' + target.method : ''}`, failureType, recovered: false }; this.activeFailures.set(event.id, event); this.failures.push(event); this.updateMetrics(event); // Apply failure await this.applyFailure(target, failureType, event); // Schedule recovery if max duration is set if (this.config.maxDuration) { setTimeout(() => { this.recoverFailure(event.id); }, Math.random() * this.config.maxDuration); } this.emit('chaos:failure:injected', event); } selectRandomTarget() { const totalWeight = this.config.targets.reduce((sum, t) => sum + (t.weight || 1), 0); let random = Math.random() * totalWeight; for (const target of this.config.targets) { random -= (target.weight || 1); if (random <= 0) { return target; } } return this.config.targets[0] || null; } selectRandomFailureType(target) { const types = target.failureTypes; return types[Math.floor(Math.random() * types.length)]; } async applyFailure(target, type, event) { switch (type) { case 'latency': await this.injectLatency(target, event); break; case 'error': await this.injectError(target, event); break; case 'timeout': await this.injectTimeout(target, event); break; case 'resource_exhaustion': await this.injectResourceExhaustion(target, event); break; case 'network_partition': await this.injectNetworkPartition(target, event); break; case 'certificate_expiry': await this.injectCertificateExpiry(target, event); break; case 'permission_denied': await this.injectPermissionDenied(target, event); break; case 'data_corruption': await this.injectDataCorruption(target, event); break; } } async injectLatency(target, event) { const delay = 100 + Math.random() * 4900; // 100-5000ms event.duration = delay; // Add artificial delay to target component this.wrapMethod(target, async (original, ...args) => { await new Promise(resolve => setTimeout(resolve, delay)); return original.apply(this, args); }); } async injectError(target, event) { const errors = [ new Error('Chaos: Service temporarily unavailable'), new Error('Chaos: Authentication failed'), new Error('Chaos: Rate limit exceeded'), new Error('Chaos: Invalid security token') ]; event.error = errors[Math.floor(Math.random() * errors.length)]; this.wrapMethod(target, async (original, ...args) => { if (Math.random() > 0.5) { throw new Error('Chaos: Simulated random error'); } return original.apply(this, args); }); } async injectTimeout(target, event) { const timeout = 30000; // 30 second timeout event.duration = timeout; this.wrapMethod(target, async (original, ...args) => { await new Promise((_, reject) => { setTimeout(() => reject(new Error('Chaos: Operation timed out')), timeout); }); }); } async injectResourceExhaustion(target, event) { // Simulate memory pressure const arrays = []; const interval = setInterval(() => { if (!this.activeFailures.has(event.id)) { clearInterval(interval); return; } // Allocate 10MB arrays.push(new Array(10 * 1024 * 1024 / 8)); }, 100); event.error = new Error('Chaos: Resource exhaustion'); } async injectNetworkPartition(target, event) { event.error = new Error('Chaos: Network unreachable'); this.wrapMethod(target, async (original, ...args) => { throw event.error; }); } async injectCertificateExpiry(target, event) { event.error = new Error('Chaos: Certificate has expired'); this.wrapMethod(target, async (original, ...args) => { throw event.error; }); } async injectPermissionDenied(target, event) { event.error = new Error('Chaos: Permission denied'); this.wrapMethod(target, async (original, ...args) => { throw event.error; }); } async injectDataCorruption(target, event) { this.wrapMethod(target, async (original, ...args) => { const result = await original.apply(this, args); // Corrupt the result if (typeof result === 'object' && result !== null) { const keys = Object.keys(result); if (keys.length > 0) { const randomKey = keys[Math.floor(Math.random() * keys.length)]; result[randomKey] = ''.repeat(10); // Corrupted data } } return result; }); } wrapMethod(target, wrapper) { const key = `${target.component}.${target.method || 'default'}`; // Store original method if not already stored if (!this.originalMethods.has(key)) { // In real implementation, would use dependency injection or monkey patching // For now, we'll emit an event that the component can listen to this.emit('chaos:wrap:method', { component: target.component, method: target.method, wrapper }); } } async recoverFailure(eventId) { const event = this.activeFailures.get(eventId); if (!event) return; event.recovered = true; event.duration = Date.now() - event.timestamp; this.activeFailures.delete(eventId); // Restore original behavior const key = event.target; if (this.originalMethods.has(key)) { this.emit('chaos:restore:method', { component: event.target.split('.')[0], method: event.target.split('.')[1] }); } this.updateRecoveryMetrics(event); this.emit('chaos:failure:recovered', event); } async pause() { this.isActive = false; this.emit('chaos:paused'); } async resume() { if (this.config.enabled && !this.isActive) { await this.start(); } } async stop() { this.isActive = false; // Recover all active failures for (const [eventId] of this.activeFailures) { await this.recoverFailure(eventId); } this.emit('chaos:stopped'); } updateMetrics(event) { this.metrics.totalFailures++; this.metrics.failuresByType[event.failureType] = (this.metrics.failuresByType[event.failureType] || 0) + 1; const component = event.target.split('.')[0]; this.metrics.failuresByComponent[component] = (this.metrics.failuresByComponent[component] || 0) + 1; this.metrics.lastFailureTime = event.timestamp; this.calculateAvailability(); } updateRecoveryMetrics(event) { if (event.duration) { const totalRecoveryTime = this.metrics.averageRecoveryTime * (this.metrics.totalFailures - 1); this.metrics.averageRecoveryTime = (totalRecoveryTime + event.duration) / this.metrics.totalFailures; } this.calculateAvailability(); } calculateAvailability() { const totalTime = Date.now() - (this.failures[0]?.timestamp || Date.now()); const downtime = this.failures.reduce((sum, f) => sum + (f.duration || 0), 0); this.metrics.systemAvailability = ((totalTime - downtime) / totalTime) * 100; } getMetrics() { return { ...this.metrics }; } getFailureHistory(limit = 100) { return this.failures.slice(-limit); } getActiveFailures() { return Array.from(this.activeFailures.values()); } generateId() { return `chaos-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } } exports.ChaosEngine = ChaosEngine; // Chaos test scenarios exports.CHAOS_SCENARIOS = { AUTHENTICATION_STORM: { targets: [{ component: 'AccessControl', method: 'checkAccess', failureTypes: ['timeout', 'error'], weight: 3 }], probability: 0.8, maxDuration: 5000 }, CERTIFICATE_ROTATION: { targets: [{ component: 'ServiceMesh', method: 'registerService', failureTypes: ['certificate_expiry'], weight: 1 }], probability: 0.5, maxDuration: 10000 }, COMPLIANCE_DRIFT: { targets: [{ component: 'ComplianceAutomation', method: 'runAssessment', failureTypes: ['data_corruption', 'timeout'], weight: 1 }], probability: 0.3, maxDuration: 15000 }, SECURITY_SCAN_OVERLOAD: { targets: [{ component: 'SecurityScanner', method: 'startScan', failureTypes: ['resource_exhaustion', 'timeout'], weight: 2 }], probability: 0.6, maxDuration: 30000 } }; //# sourceMappingURL=chaos-engine.js.map