@tamyla/clodo-framework 1.0.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/CHANGELOG.md +564 -0
- package/LICENSE +21 -0
- package/README.md +1393 -0
- package/bin/README.md +71 -0
- package/bin/clodo-service.js +416 -0
- package/bin/security/security-cli.js +96 -0
- package/bin/service-management/README.md +74 -0
- package/bin/service-management/create-service.js +129 -0
- package/bin/service-management/init-service.js +102 -0
- package/bin/service-management/init-service.js.backup +889 -0
- package/bin/shared/config/customer-cli.js +293 -0
- package/dist/config/ConfigurationManager.js +159 -0
- package/dist/config/CustomerConfigCLI.js +220 -0
- package/dist/config/FeatureManager.js +426 -0
- package/dist/config/customers.js +441 -0
- package/dist/config/domains.js +180 -0
- package/dist/config/features.js +225 -0
- package/dist/config/index.js +6 -0
- package/dist/database/database-orchestrator.js +730 -0
- package/dist/database/index.js +4 -0
- package/dist/deployment/auditor.js +971 -0
- package/dist/deployment/index.js +10 -0
- package/dist/deployment/rollback-manager.js +523 -0
- package/dist/deployment/testers/api-tester.js +80 -0
- package/dist/deployment/testers/auth-tester.js +129 -0
- package/dist/deployment/testers/core.js +217 -0
- package/dist/deployment/testers/database-tester.js +105 -0
- package/dist/deployment/testers/index.js +74 -0
- package/dist/deployment/testers/load-tester.js +120 -0
- package/dist/deployment/testers/performance-tester.js +105 -0
- package/dist/deployment/validator.js +558 -0
- package/dist/deployment/wrangler-deployer.js +574 -0
- package/dist/handlers/GenericRouteHandler.js +532 -0
- package/dist/index.js +39 -0
- package/dist/migration/MigrationAdapters.js +562 -0
- package/dist/modules/ModuleManager.js +668 -0
- package/dist/modules/security.js +98 -0
- package/dist/orchestration/cross-domain-coordinator.js +1083 -0
- package/dist/orchestration/index.js +5 -0
- package/dist/orchestration/modules/DeploymentCoordinator.js +258 -0
- package/dist/orchestration/modules/DomainResolver.js +196 -0
- package/dist/orchestration/modules/StateManager.js +332 -0
- package/dist/orchestration/multi-domain-orchestrator.js +255 -0
- package/dist/routing/EnhancedRouter.js +158 -0
- package/dist/schema/SchemaManager.js +778 -0
- package/dist/security/ConfigurationValidator.js +490 -0
- package/dist/security/DeploymentManager.js +208 -0
- package/dist/security/SecretGenerator.js +142 -0
- package/dist/security/SecurityCLI.js +228 -0
- package/dist/security/index.js +51 -0
- package/dist/security/patterns/environment-rules.js +66 -0
- package/dist/security/patterns/insecure-patterns.js +21 -0
- package/dist/service-management/ConfirmationEngine.js +411 -0
- package/dist/service-management/ErrorTracker.js +294 -0
- package/dist/service-management/GenerationEngine.js +3109 -0
- package/dist/service-management/InputCollector.js +237 -0
- package/dist/service-management/ServiceCreator.js +229 -0
- package/dist/service-management/ServiceInitializer.js +448 -0
- package/dist/service-management/ServiceOrchestrator.js +638 -0
- package/dist/service-management/handlers/ConfigMutator.js +130 -0
- package/dist/service-management/handlers/ConfirmationHandler.js +71 -0
- package/dist/service-management/handlers/GenerationHandler.js +80 -0
- package/dist/service-management/handlers/InputHandler.js +59 -0
- package/dist/service-management/handlers/ValidationHandler.js +203 -0
- package/dist/service-management/index.js +7 -0
- package/dist/services/GenericDataService.js +488 -0
- package/dist/shared/cloudflare/domain-discovery.js +562 -0
- package/dist/shared/cloudflare/domain-manager.js +912 -0
- package/dist/shared/cloudflare/index.js +8 -0
- package/dist/shared/cloudflare/ops.js +387 -0
- package/dist/shared/config/cache.js +1167 -0
- package/dist/shared/config/command-config-manager.js +174 -0
- package/dist/shared/config/customer-cli.js +258 -0
- package/dist/shared/config/index.js +9 -0
- package/dist/shared/config/manager.js +289 -0
- package/dist/shared/database/connection-manager.js +338 -0
- package/dist/shared/database/index.js +7 -0
- package/dist/shared/database/orchestrator.js +632 -0
- package/dist/shared/deployment/auditor.js +971 -0
- package/dist/shared/deployment/index.js +10 -0
- package/dist/shared/deployment/rollback-manager.js +523 -0
- package/dist/shared/deployment/validator.js +558 -0
- package/dist/shared/index.js +32 -0
- package/dist/shared/monitoring/health-checker.js +250 -0
- package/dist/shared/monitoring/index.js +8 -0
- package/dist/shared/monitoring/memory-manager.js +382 -0
- package/dist/shared/monitoring/production-monitor.js +390 -0
- package/dist/shared/production-tester/api-tester.js +80 -0
- package/dist/shared/production-tester/auth-tester.js +129 -0
- package/dist/shared/production-tester/core.js +217 -0
- package/dist/shared/production-tester/database-tester.js +105 -0
- package/dist/shared/production-tester/index.js +74 -0
- package/dist/shared/production-tester/load-tester.js +120 -0
- package/dist/shared/production-tester/performance-tester.js +105 -0
- package/dist/shared/security/api-token-manager.js +296 -0
- package/dist/shared/security/index.js +8 -0
- package/dist/shared/security/secret-generator.js +918 -0
- package/dist/shared/security/secure-token-manager.js +379 -0
- package/dist/shared/utils/error-recovery.js +240 -0
- package/dist/shared/utils/graceful-shutdown-manager.js +380 -0
- package/dist/shared/utils/index.js +9 -0
- package/dist/shared/utils/interactive-prompts.js +134 -0
- package/dist/shared/utils/rate-limiter.js +249 -0
- package/dist/utils/ErrorHandler.js +173 -0
- package/dist/utils/deployment/config-cache.js +1160 -0
- package/dist/utils/deployment/index.js +6 -0
- package/dist/utils/deployment/interactive-prompts.js +97 -0
- package/dist/utils/deployment/secret-generator.js +896 -0
- package/dist/utils/dirname-helper.js +35 -0
- package/dist/utils/domain-config.js +159 -0
- package/dist/utils/error-recovery.js +240 -0
- package/dist/utils/esm-helper.js +52 -0
- package/dist/utils/framework-config.js +481 -0
- package/dist/utils/graceful-shutdown-manager.js +379 -0
- package/dist/utils/health-checker.js +114 -0
- package/dist/utils/index.js +36 -0
- package/dist/utils/prompt-handler.js +98 -0
- package/dist/utils/usage-tracker.js +252 -0
- package/dist/utils/validation.js +112 -0
- package/dist/version/VersionDetector.js +723 -0
- package/dist/worker/index.js +4 -0
- package/dist/worker/integration.js +332 -0
- package/docs/FRAMEWORK-ARCHITECTURE-OVERVIEW.md +206 -0
- package/docs/INTEGRATION_GUIDE.md +2045 -0
- package/docs/README.md +82 -0
- package/docs/SECURITY.md +242 -0
- package/docs/deployment/deployment-guide.md +540 -0
- package/docs/overview.md +280 -0
- package/package.json +176 -0
- package/types/index.d.ts +575 -0
|
@@ -0,0 +1,971 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enterprise Deployment Audit System
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive audit and logging system for enterprise deployments with:
|
|
5
|
+
* - Structured deployment logging with multiple output formats
|
|
6
|
+
* - Comprehensive audit trails with compliance features
|
|
7
|
+
* - Deployment history tracking and analytics
|
|
8
|
+
* - Backup and recovery logging
|
|
9
|
+
* - Performance metrics and reporting
|
|
10
|
+
* - Cross-environment audit coordination
|
|
11
|
+
* - Real-time monitoring and alerting
|
|
12
|
+
* - Compliance reporting and retention policies
|
|
13
|
+
* - Advanced search and filtering capabilities
|
|
14
|
+
*
|
|
15
|
+
* @module deployment-auditor
|
|
16
|
+
* @version 2.0.0
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { existsSync, writeFileSync, appendFileSync, mkdirSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
20
|
+
import { join, dirname } from 'path';
|
|
21
|
+
import { execSync } from 'child_process';
|
|
22
|
+
export class DeploymentAuditor {
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
this.config = {
|
|
25
|
+
// Audit configuration
|
|
26
|
+
auditLevel: options.auditLevel || 'detailed',
|
|
27
|
+
// minimal, standard, detailed, verbose
|
|
28
|
+
retentionDays: options.retentionDays || 90,
|
|
29
|
+
maxLogSize: options.maxLogSize || 100 * 1024 * 1024,
|
|
30
|
+
// 100MB
|
|
31
|
+
|
|
32
|
+
// Output formats
|
|
33
|
+
formats: options.formats || ['json', 'csv', 'plain'],
|
|
34
|
+
includeMetrics: options.includeMetrics !== false,
|
|
35
|
+
includeBackups: options.includeBackups !== false,
|
|
36
|
+
// Paths
|
|
37
|
+
auditDir: options.auditDir || 'audit-logs',
|
|
38
|
+
backupDir: options.backupDir || 'audit-backups',
|
|
39
|
+
reportsDir: options.reportsDir || 'audit-reports',
|
|
40
|
+
// Real-time options
|
|
41
|
+
realTimeAlerts: options.realTimeAlerts || false,
|
|
42
|
+
alertWebhook: options.alertWebhook || null,
|
|
43
|
+
// Compliance
|
|
44
|
+
complianceMode: options.complianceMode || false,
|
|
45
|
+
encryptLogs: options.encryptLogs || false,
|
|
46
|
+
digitallySigned: options.digitallySigned || false,
|
|
47
|
+
// Environment tracking
|
|
48
|
+
environments: options.environments || ['development', 'staging', 'production'],
|
|
49
|
+
crossEnvironmentTracking: options.crossEnvironmentTracking !== false
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Audit state
|
|
53
|
+
this.currentSession = {
|
|
54
|
+
sessionId: this.generateSessionId(),
|
|
55
|
+
startTime: new Date(),
|
|
56
|
+
deployments: new Map(),
|
|
57
|
+
events: [],
|
|
58
|
+
metrics: {
|
|
59
|
+
totalEvents: 0,
|
|
60
|
+
errorCount: 0,
|
|
61
|
+
warningCount: 0,
|
|
62
|
+
deploymentCount: 0,
|
|
63
|
+
rollbackCount: 0
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Event types registry
|
|
68
|
+
this.eventTypes = {
|
|
69
|
+
DEPLOYMENT_START: {
|
|
70
|
+
level: 'info',
|
|
71
|
+
category: 'deployment',
|
|
72
|
+
retention: 'long'
|
|
73
|
+
},
|
|
74
|
+
DEPLOYMENT_END: {
|
|
75
|
+
level: 'info',
|
|
76
|
+
category: 'deployment',
|
|
77
|
+
retention: 'long'
|
|
78
|
+
},
|
|
79
|
+
DEPLOYMENT_ERROR: {
|
|
80
|
+
level: 'error',
|
|
81
|
+
category: 'deployment',
|
|
82
|
+
retention: 'permanent'
|
|
83
|
+
},
|
|
84
|
+
PHASE_START: {
|
|
85
|
+
level: 'debug',
|
|
86
|
+
category: 'phase',
|
|
87
|
+
retention: 'standard'
|
|
88
|
+
},
|
|
89
|
+
PHASE_END: {
|
|
90
|
+
level: 'debug',
|
|
91
|
+
category: 'phase',
|
|
92
|
+
retention: 'standard'
|
|
93
|
+
},
|
|
94
|
+
ROLLBACK_START: {
|
|
95
|
+
level: 'warn',
|
|
96
|
+
category: 'rollback',
|
|
97
|
+
retention: 'long'
|
|
98
|
+
},
|
|
99
|
+
ROLLBACK_END: {
|
|
100
|
+
level: 'warn',
|
|
101
|
+
category: 'rollback',
|
|
102
|
+
retention: 'long'
|
|
103
|
+
},
|
|
104
|
+
SECRET_GENERATED: {
|
|
105
|
+
level: 'info',
|
|
106
|
+
category: 'security',
|
|
107
|
+
retention: 'long'
|
|
108
|
+
},
|
|
109
|
+
SECRET_DEPLOYED: {
|
|
110
|
+
level: 'info',
|
|
111
|
+
category: 'security',
|
|
112
|
+
retention: 'long'
|
|
113
|
+
},
|
|
114
|
+
DATABASE_MIGRATION: {
|
|
115
|
+
level: 'info',
|
|
116
|
+
category: 'database',
|
|
117
|
+
retention: 'long'
|
|
118
|
+
},
|
|
119
|
+
VALIDATION_ERROR: {
|
|
120
|
+
level: 'error',
|
|
121
|
+
category: 'validation',
|
|
122
|
+
retention: 'long'
|
|
123
|
+
},
|
|
124
|
+
PERFORMANCE_METRIC: {
|
|
125
|
+
level: 'info',
|
|
126
|
+
category: 'performance',
|
|
127
|
+
retention: 'standard'
|
|
128
|
+
},
|
|
129
|
+
SECURITY_EVENT: {
|
|
130
|
+
level: 'warn',
|
|
131
|
+
category: 'security',
|
|
132
|
+
retention: 'permanent'
|
|
133
|
+
},
|
|
134
|
+
COMPLIANCE_VIOLATION: {
|
|
135
|
+
level: 'error',
|
|
136
|
+
category: 'compliance',
|
|
137
|
+
retention: 'permanent'
|
|
138
|
+
},
|
|
139
|
+
AUDIT_EVENT: {
|
|
140
|
+
level: 'info',
|
|
141
|
+
category: 'audit',
|
|
142
|
+
retention: 'permanent'
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Initialize audit system
|
|
147
|
+
this.initializeAuditSystem();
|
|
148
|
+
this.logAuditEvent('AUDIT_SYSTEM_INITIALIZED', 'SYSTEM', {
|
|
149
|
+
config: this.config,
|
|
150
|
+
sessionId: this.currentSession.sessionId
|
|
151
|
+
});
|
|
152
|
+
console.log('๐ Deployment Audit System initialized');
|
|
153
|
+
if (this.config.auditLevel === 'verbose') {
|
|
154
|
+
console.log(` ๐ Session ID: ${this.currentSession.sessionId}`);
|
|
155
|
+
console.log(` ๐ Audit Level: ${this.config.auditLevel}`);
|
|
156
|
+
console.log(` ๐พ Formats: ${this.config.formats.join(', ')}`);
|
|
157
|
+
console.log(` ๐ Audit Directory: ${this.config.auditDir}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Initialize audit system directories and files
|
|
163
|
+
*/
|
|
164
|
+
initializeAuditSystem() {
|
|
165
|
+
this.paths = {
|
|
166
|
+
audit: this.config.auditDir,
|
|
167
|
+
backup: this.config.backupDir,
|
|
168
|
+
reports: this.config.reportsDir,
|
|
169
|
+
daily: join(this.config.auditDir, 'daily'),
|
|
170
|
+
deployments: join(this.config.auditDir, 'deployments'),
|
|
171
|
+
security: join(this.config.auditDir, 'security'),
|
|
172
|
+
performance: join(this.config.auditDir, 'performance'),
|
|
173
|
+
compliance: join(this.config.auditDir, 'compliance')
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// Create directory structure
|
|
177
|
+
Object.values(this.paths).forEach(path => {
|
|
178
|
+
if (!existsSync(path)) {
|
|
179
|
+
mkdirSync(path, {
|
|
180
|
+
recursive: true
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Initialize log files
|
|
186
|
+
this.logFiles = {
|
|
187
|
+
main: join(this.paths.audit, 'deployment-audit.log'),
|
|
188
|
+
errors: join(this.paths.audit, 'deployment-errors.log'),
|
|
189
|
+
security: join(this.paths.security, 'security-audit.log'),
|
|
190
|
+
performance: join(this.paths.performance, 'performance-audit.log'),
|
|
191
|
+
compliance: join(this.paths.compliance, 'compliance-audit.log'),
|
|
192
|
+
daily: join(this.paths.daily, `audit-${this.getCurrentDateString()}.log`)
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// Initialize session log
|
|
196
|
+
this.sessionLogFile = join(this.paths.deployments, `session-${this.currentSession.sessionId}.log`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Generate unique session ID
|
|
201
|
+
* @returns {string} Session ID
|
|
202
|
+
*/
|
|
203
|
+
generateSessionId() {
|
|
204
|
+
const timestamp = Date.now().toString(36);
|
|
205
|
+
const random = Math.random().toString(36).substr(2, 9);
|
|
206
|
+
return `audit_${timestamp}_${random}`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get current date string for file naming
|
|
211
|
+
* @returns {string} Date string
|
|
212
|
+
*/
|
|
213
|
+
getCurrentDateString() {
|
|
214
|
+
return new Date().toISOString().split('T')[0];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Start deployment audit session
|
|
219
|
+
* @param {string} deploymentId - Deployment identifier
|
|
220
|
+
* @param {string} domain - Domain being deployed
|
|
221
|
+
* @param {Object} config - Deployment configuration
|
|
222
|
+
* @returns {Object} Deployment audit context
|
|
223
|
+
*/
|
|
224
|
+
startDeploymentAudit(deploymentId, domain, config = {}) {
|
|
225
|
+
const deploymentContext = {
|
|
226
|
+
deploymentId,
|
|
227
|
+
domain,
|
|
228
|
+
config,
|
|
229
|
+
startTime: new Date(),
|
|
230
|
+
phases: [],
|
|
231
|
+
events: [],
|
|
232
|
+
metrics: {
|
|
233
|
+
phaseCount: 0,
|
|
234
|
+
errorCount: 0,
|
|
235
|
+
warningCount: 0,
|
|
236
|
+
duration: 0
|
|
237
|
+
},
|
|
238
|
+
rollbacks: [],
|
|
239
|
+
status: 'in-progress'
|
|
240
|
+
};
|
|
241
|
+
this.currentSession.deployments.set(deploymentId, deploymentContext);
|
|
242
|
+
this.currentSession.metrics.deploymentCount++;
|
|
243
|
+
this.logAuditEvent('DEPLOYMENT_START', domain, {
|
|
244
|
+
deploymentId,
|
|
245
|
+
config,
|
|
246
|
+
sessionId: this.currentSession.sessionId,
|
|
247
|
+
environment: config.environment || 'unknown'
|
|
248
|
+
});
|
|
249
|
+
console.log(`๐ Deployment audit started: ${deploymentId}`);
|
|
250
|
+
if (this.config.auditLevel === 'verbose') {
|
|
251
|
+
console.log(` ๐ Domain: ${domain}`);
|
|
252
|
+
console.log(` ๐ Environment: ${config.environment || 'unknown'}`);
|
|
253
|
+
}
|
|
254
|
+
return deploymentContext;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* End deployment audit session
|
|
259
|
+
* @param {string} deploymentId - Deployment identifier
|
|
260
|
+
* @param {string} status - Final deployment status
|
|
261
|
+
* @param {Object} summary - Deployment summary
|
|
262
|
+
*/
|
|
263
|
+
endDeploymentAudit(deploymentId, status, summary = {}) {
|
|
264
|
+
const deployment = this.currentSession.deployments.get(deploymentId);
|
|
265
|
+
if (!deployment) {
|
|
266
|
+
this.logAuditEvent('AUDIT_ERROR', 'SYSTEM', {
|
|
267
|
+
error: `Deployment not found: ${deploymentId}`,
|
|
268
|
+
deploymentId
|
|
269
|
+
});
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
deployment.endTime = new Date();
|
|
273
|
+
deployment.duration = (deployment.endTime - deployment.startTime) / 1000;
|
|
274
|
+
deployment.status = status;
|
|
275
|
+
deployment.summary = summary;
|
|
276
|
+
this.logAuditEvent('DEPLOYMENT_END', deployment.domain, {
|
|
277
|
+
deploymentId,
|
|
278
|
+
status,
|
|
279
|
+
duration: deployment.duration,
|
|
280
|
+
phaseCount: deployment.phases.length,
|
|
281
|
+
errorCount: deployment.metrics.errorCount,
|
|
282
|
+
summary
|
|
283
|
+
});
|
|
284
|
+
console.log(`๐ Deployment audit completed: ${deploymentId} (${status})`);
|
|
285
|
+
if (this.config.auditLevel !== 'minimal') {
|
|
286
|
+
console.log(` โฑ๏ธ Duration: ${deployment.duration.toFixed(2)}s`);
|
|
287
|
+
console.log(` ๐ Phases: ${deployment.phases.length}`);
|
|
288
|
+
console.log(` โ Errors: ${deployment.metrics.errorCount}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Generate deployment report
|
|
292
|
+
this.generateDeploymentReport(deploymentId);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Log deployment phase start/end
|
|
297
|
+
* @param {string} deploymentId - Deployment identifier
|
|
298
|
+
* @param {string} phaseName - Phase name
|
|
299
|
+
* @param {string} action - 'start' or 'end'
|
|
300
|
+
* @param {Object} details - Phase details
|
|
301
|
+
*/
|
|
302
|
+
logPhase(deploymentId, phaseName, action, details = {}) {
|
|
303
|
+
const deployment = this.currentSession.deployments.get(deploymentId);
|
|
304
|
+
if (!deployment) {
|
|
305
|
+
console.warn(`โ ๏ธ Deployment not found for phase logging: ${deploymentId}`);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const phaseEvent = {
|
|
309
|
+
phase: phaseName,
|
|
310
|
+
action,
|
|
311
|
+
timestamp: new Date(),
|
|
312
|
+
details
|
|
313
|
+
};
|
|
314
|
+
deployment.phases.push(phaseEvent);
|
|
315
|
+
if (action === 'start') {
|
|
316
|
+
deployment.metrics.phaseCount++;
|
|
317
|
+
}
|
|
318
|
+
this.logAuditEvent(`PHASE_${action.toUpperCase()}`, deployment.domain, {
|
|
319
|
+
deploymentId,
|
|
320
|
+
phase: phaseName,
|
|
321
|
+
phaseNumber: deployment.phases.filter(p => p.action === 'start').length,
|
|
322
|
+
details
|
|
323
|
+
});
|
|
324
|
+
if (this.config.auditLevel === 'verbose') {
|
|
325
|
+
console.log(` ๐ Phase ${action}: ${phaseName}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Log deployment error with context
|
|
331
|
+
* @param {string} deploymentId - Deployment identifier
|
|
332
|
+
* @param {Error|string} error - Error object or message
|
|
333
|
+
* @param {Object} context - Additional context
|
|
334
|
+
*/
|
|
335
|
+
logError(deploymentId, error, context = {}) {
|
|
336
|
+
const deployment = this.currentSession.deployments.get(deploymentId);
|
|
337
|
+
if (deployment) {
|
|
338
|
+
deployment.metrics.errorCount++;
|
|
339
|
+
}
|
|
340
|
+
this.currentSession.metrics.errorCount++;
|
|
341
|
+
const errorDetails = {
|
|
342
|
+
deploymentId,
|
|
343
|
+
error: error instanceof Error ? {
|
|
344
|
+
message: error.message,
|
|
345
|
+
stack: error.stack,
|
|
346
|
+
name: error.name
|
|
347
|
+
} : {
|
|
348
|
+
message: error.toString()
|
|
349
|
+
},
|
|
350
|
+
context,
|
|
351
|
+
timestamp: new Date()
|
|
352
|
+
};
|
|
353
|
+
this.logAuditEvent('DEPLOYMENT_ERROR', deployment?.domain || 'UNKNOWN', errorDetails);
|
|
354
|
+
|
|
355
|
+
// Write to error log
|
|
356
|
+
this.writeToLogFile(this.logFiles.errors, {
|
|
357
|
+
type: 'error',
|
|
358
|
+
timestamp: new Date(),
|
|
359
|
+
deploymentId,
|
|
360
|
+
error: errorDetails.error,
|
|
361
|
+
context
|
|
362
|
+
});
|
|
363
|
+
console.error(`โ Deployment error logged: ${deploymentId}`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Log security-related events
|
|
368
|
+
* @param {string} deploymentId - Deployment identifier
|
|
369
|
+
* @param {string} eventType - Security event type
|
|
370
|
+
* @param {Object} details - Security event details
|
|
371
|
+
*/
|
|
372
|
+
logSecurityEvent(deploymentId, eventType, details = {}) {
|
|
373
|
+
const securityEvent = {
|
|
374
|
+
deploymentId,
|
|
375
|
+
eventType,
|
|
376
|
+
details,
|
|
377
|
+
timestamp: new Date(),
|
|
378
|
+
severity: details.severity || 'medium'
|
|
379
|
+
};
|
|
380
|
+
this.logAuditEvent('SECURITY_EVENT', details.domain || 'SYSTEM', securityEvent);
|
|
381
|
+
|
|
382
|
+
// Write to security log
|
|
383
|
+
this.writeToLogFile(this.logFiles.security, securityEvent);
|
|
384
|
+
if (this.config.auditLevel !== 'minimal') {
|
|
385
|
+
console.log(`๐ Security event: ${eventType} (${securityEvent.severity})`);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Alert on high severity events
|
|
389
|
+
if (securityEvent.severity === 'high' && this.config.realTimeAlerts) {
|
|
390
|
+
this.sendSecurityAlert(securityEvent);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Log performance metrics
|
|
396
|
+
* @param {string} deploymentId - Deployment identifier
|
|
397
|
+
* @param {string} metricName - Metric name
|
|
398
|
+
* @param {number} value - Metric value
|
|
399
|
+
* @param {Object} metadata - Additional metric metadata
|
|
400
|
+
*/
|
|
401
|
+
logPerformanceMetric(deploymentId, metricName, value, metadata = {}) {
|
|
402
|
+
const performanceEvent = {
|
|
403
|
+
deploymentId,
|
|
404
|
+
metric: metricName,
|
|
405
|
+
value,
|
|
406
|
+
metadata,
|
|
407
|
+
timestamp: new Date()
|
|
408
|
+
};
|
|
409
|
+
this.logAuditEvent('PERFORMANCE_METRIC', metadata.domain || 'SYSTEM', performanceEvent);
|
|
410
|
+
if (this.config.includeMetrics) {
|
|
411
|
+
this.writeToLogFile(this.logFiles.performance, performanceEvent);
|
|
412
|
+
}
|
|
413
|
+
if (this.config.auditLevel === 'verbose') {
|
|
414
|
+
console.log(`โก Performance: ${metricName} = ${value}${metadata.unit || ''}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Log rollback operations
|
|
420
|
+
* @param {string} deploymentId - Deployment identifier
|
|
421
|
+
* @param {string} action - Rollback action ('start' or 'end')
|
|
422
|
+
* @param {Object} rollbackData - Rollback details
|
|
423
|
+
*/
|
|
424
|
+
logRollback(deploymentId, action, rollbackData = {}) {
|
|
425
|
+
const deployment = this.currentSession.deployments.get(deploymentId);
|
|
426
|
+
if (deployment && action === 'start') {
|
|
427
|
+
deployment.rollbacks.push({
|
|
428
|
+
startTime: new Date(),
|
|
429
|
+
actions: rollbackData.actions || [],
|
|
430
|
+
reason: rollbackData.reason || 'deployment-failure'
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
if (action === 'start') {
|
|
434
|
+
this.currentSession.metrics.rollbackCount++;
|
|
435
|
+
}
|
|
436
|
+
this.logAuditEvent(`ROLLBACK_${action.toUpperCase()}`, deployment?.domain || 'SYSTEM', {
|
|
437
|
+
deploymentId,
|
|
438
|
+
rollbackData,
|
|
439
|
+
timestamp: new Date()
|
|
440
|
+
});
|
|
441
|
+
console.log(`๐ Rollback ${action}: ${deploymentId}`);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Log general audit event
|
|
446
|
+
* @param {string} eventType - Type of event
|
|
447
|
+
* @param {string} domain - Domain context
|
|
448
|
+
* @param {Object} details - Event details
|
|
449
|
+
*/
|
|
450
|
+
logAuditEvent(eventType, domain, details = {}) {
|
|
451
|
+
const eventConfig = this.eventTypes[eventType] || {
|
|
452
|
+
level: 'info',
|
|
453
|
+
category: 'general',
|
|
454
|
+
retention: 'standard'
|
|
455
|
+
};
|
|
456
|
+
const auditEvent = {
|
|
457
|
+
eventType,
|
|
458
|
+
level: eventConfig.level,
|
|
459
|
+
category: eventConfig.category,
|
|
460
|
+
retention: eventConfig.retention,
|
|
461
|
+
domain,
|
|
462
|
+
details,
|
|
463
|
+
timestamp: new Date(),
|
|
464
|
+
sessionId: this.currentSession.sessionId,
|
|
465
|
+
sequence: this.currentSession.metrics.totalEvents++
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
// Add to session events
|
|
469
|
+
this.currentSession.events.push(auditEvent);
|
|
470
|
+
|
|
471
|
+
// Write to main audit log
|
|
472
|
+
this.writeToLogFile(this.logFiles.main, auditEvent);
|
|
473
|
+
|
|
474
|
+
// Write to daily log
|
|
475
|
+
this.writeToLogFile(this.logFiles.daily, auditEvent);
|
|
476
|
+
|
|
477
|
+
// Write to session log
|
|
478
|
+
this.writeToLogFile(this.sessionLogFile, auditEvent);
|
|
479
|
+
|
|
480
|
+
// Category-specific logging
|
|
481
|
+
if (eventConfig.category === 'security') {
|
|
482
|
+
this.writeToLogFile(this.logFiles.security, auditEvent);
|
|
483
|
+
} else if (eventConfig.category === 'compliance') {
|
|
484
|
+
this.writeToLogFile(this.logFiles.compliance, auditEvent);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Update metrics
|
|
488
|
+
if (eventConfig.level === 'error') {
|
|
489
|
+
this.currentSession.metrics.errorCount++;
|
|
490
|
+
} else if (eventConfig.level === 'warn') {
|
|
491
|
+
this.currentSession.metrics.warningCount++;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Real-time processing
|
|
495
|
+
if (this.config.realTimeAlerts && eventConfig.level === 'error') {
|
|
496
|
+
this.sendAlert(auditEvent);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Write structured log entry to file
|
|
502
|
+
* @param {string} logFile - Log file path
|
|
503
|
+
* @param {Object} logEntry - Log entry object
|
|
504
|
+
*/
|
|
505
|
+
writeToLogFile(logFile, logEntry) {
|
|
506
|
+
try {
|
|
507
|
+
// Ensure directory exists
|
|
508
|
+
const dir = dirname(logFile);
|
|
509
|
+
if (!existsSync(dir)) {
|
|
510
|
+
mkdirSync(dir, {
|
|
511
|
+
recursive: true
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Check file size and rotate if needed
|
|
516
|
+
if (existsSync(logFile)) {
|
|
517
|
+
const stats = statSync(logFile);
|
|
518
|
+
if (stats.size > this.config.maxLogSize) {
|
|
519
|
+
this.rotateLogFile(logFile);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Write log entry based on format
|
|
524
|
+
if (this.config.formats.includes('json')) {
|
|
525
|
+
appendFileSync(logFile, JSON.stringify(logEntry) + '\n');
|
|
526
|
+
}
|
|
527
|
+
if (this.config.formats.includes('plain')) {
|
|
528
|
+
const plainEntry = `[${logEntry.timestamp?.toISOString() || new Date().toISOString()}] ${logEntry.eventType || 'LOG'}: ${JSON.stringify(logEntry.details || logEntry)}`;
|
|
529
|
+
const plainFile = logFile.replace('.log', '.txt');
|
|
530
|
+
appendFileSync(plainFile, plainEntry + '\n');
|
|
531
|
+
}
|
|
532
|
+
if (this.config.formats.includes('csv')) {
|
|
533
|
+
const csvFile = logFile.replace('.log', '.csv');
|
|
534
|
+
const csvHeaders = 'timestamp,eventType,level,category,domain,details\n';
|
|
535
|
+
if (!existsSync(csvFile)) {
|
|
536
|
+
writeFileSync(csvFile, csvHeaders);
|
|
537
|
+
}
|
|
538
|
+
const csvEntry = [logEntry.timestamp?.toISOString() || new Date().toISOString(), logEntry.eventType || 'LOG', logEntry.level || 'info', logEntry.category || 'general', logEntry.domain || '', JSON.stringify(logEntry.details || {}).replace(/"/g, '""')].join(',');
|
|
539
|
+
appendFileSync(csvFile, csvEntry + '\n');
|
|
540
|
+
}
|
|
541
|
+
} catch (error) {
|
|
542
|
+
console.error(`โ ๏ธ Failed to write audit log: ${error.message}`);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Rotate log file when it exceeds size limit
|
|
548
|
+
* @param {string} logFile - Log file to rotate
|
|
549
|
+
*/
|
|
550
|
+
rotateLogFile(logFile) {
|
|
551
|
+
try {
|
|
552
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
553
|
+
const rotatedFile = logFile.replace('.log', `-${timestamp}.log`);
|
|
554
|
+
|
|
555
|
+
// Move current file
|
|
556
|
+
execSync(`move "${logFile}" "${rotatedFile}"`, {
|
|
557
|
+
shell: true
|
|
558
|
+
});
|
|
559
|
+
this.logAuditEvent('AUDIT_LOG_ROTATED', 'SYSTEM', {
|
|
560
|
+
originalFile: logFile,
|
|
561
|
+
rotatedFile: rotatedFile,
|
|
562
|
+
timestamp: new Date()
|
|
563
|
+
});
|
|
564
|
+
} catch (error) {
|
|
565
|
+
console.error(`โ ๏ธ Failed to rotate log file: ${error.message}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Generate comprehensive deployment report
|
|
571
|
+
* @param {string} deploymentId - Deployment identifier
|
|
572
|
+
* @returns {Object} Generated report info
|
|
573
|
+
*/
|
|
574
|
+
generateDeploymentReport(deploymentId) {
|
|
575
|
+
const deployment = this.currentSession.deployments.get(deploymentId);
|
|
576
|
+
if (!deployment) {
|
|
577
|
+
console.warn(`โ ๏ธ Cannot generate report: deployment ${deploymentId} not found`);
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
const reportData = {
|
|
581
|
+
deploymentId,
|
|
582
|
+
domain: deployment.domain,
|
|
583
|
+
startTime: deployment.startTime,
|
|
584
|
+
endTime: deployment.endTime,
|
|
585
|
+
duration: deployment.duration,
|
|
586
|
+
status: deployment.status,
|
|
587
|
+
phases: deployment.phases,
|
|
588
|
+
metrics: deployment.metrics,
|
|
589
|
+
rollbacks: deployment.rollbacks,
|
|
590
|
+
events: deployment.events,
|
|
591
|
+
summary: deployment.summary || {},
|
|
592
|
+
generatedAt: new Date()
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
// Generate report files
|
|
596
|
+
const reportFiles = {
|
|
597
|
+
json: join(this.paths.reports, `deployment-${deploymentId}.json`),
|
|
598
|
+
html: join(this.paths.reports, `deployment-${deploymentId}.html`),
|
|
599
|
+
csv: join(this.paths.reports, `deployment-${deploymentId}.csv`)
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
// JSON report
|
|
603
|
+
writeFileSync(reportFiles.json, JSON.stringify(reportData, null, 2));
|
|
604
|
+
|
|
605
|
+
// HTML report
|
|
606
|
+
const htmlReport = this.generateHtmlReport(reportData);
|
|
607
|
+
writeFileSync(reportFiles.html, htmlReport);
|
|
608
|
+
|
|
609
|
+
// CSV report
|
|
610
|
+
const csvReport = this.generateCsvReport(reportData);
|
|
611
|
+
writeFileSync(reportFiles.csv, csvReport);
|
|
612
|
+
console.log(`๐ Deployment report generated: ${deploymentId}`);
|
|
613
|
+
if (this.config.auditLevel !== 'minimal') {
|
|
614
|
+
console.log(` ๐ JSON: ${reportFiles.json}`);
|
|
615
|
+
console.log(` ๐ HTML: ${reportFiles.html}`);
|
|
616
|
+
console.log(` ๐ CSV: ${reportFiles.csv}`);
|
|
617
|
+
}
|
|
618
|
+
return reportFiles;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Generate HTML deployment report
|
|
623
|
+
* @param {Object} reportData - Report data
|
|
624
|
+
* @returns {string} HTML content
|
|
625
|
+
*/
|
|
626
|
+
generateHtmlReport(reportData) {
|
|
627
|
+
return `<!DOCTYPE html>
|
|
628
|
+
<html lang="en">
|
|
629
|
+
<head>
|
|
630
|
+
<meta charset="UTF-8">
|
|
631
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
632
|
+
<title>Deployment Report - ${reportData.deploymentId}</title>
|
|
633
|
+
<style>
|
|
634
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }
|
|
635
|
+
.container { max-width: 1200px; margin: 0 auto; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
|
636
|
+
.header { background: ${reportData.status === 'success' ? '#059669' : '#dc2626'}; color: white; padding: 30px; border-radius: 8px 8px 0 0; }
|
|
637
|
+
.content { padding: 30px; }
|
|
638
|
+
.summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px; }
|
|
639
|
+
.summary-card { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; padding: 20px; text-align: center; }
|
|
640
|
+
.summary-card h3 { margin: 0 0 10px 0; font-size: 24px; }
|
|
641
|
+
.phases { background: #f1f5f9; border-radius: 6px; padding: 20px; margin-top: 20px; }
|
|
642
|
+
.phase { padding: 15px; border-left: 4px solid #3b82f6; margin-bottom: 10px; background: white; }
|
|
643
|
+
.phase.error { border-color: #dc2626; background: #fef2f2; }
|
|
644
|
+
.timeline { margin-top: 20px; }
|
|
645
|
+
.event { padding: 10px; border-left: 3px solid #e2e8f0; margin-bottom: 8px; font-size: 14px; }
|
|
646
|
+
.event.error { border-color: #dc2626; color: #dc2626; }
|
|
647
|
+
.event.warn { border-color: #f59e0b; color: #f59e0b; }
|
|
648
|
+
</style>
|
|
649
|
+
</head>
|
|
650
|
+
<body>
|
|
651
|
+
<div class="container">
|
|
652
|
+
<div class="header">
|
|
653
|
+
<h1>๐ Deployment Report</h1>
|
|
654
|
+
<p>Deployment: ${reportData.deploymentId}</p>
|
|
655
|
+
<p>Domain: ${reportData.domain}</p>
|
|
656
|
+
<p>Status: ${reportData.status.toUpperCase()}</p>
|
|
657
|
+
<p>Generated: ${reportData.generatedAt.toLocaleString()}</p>
|
|
658
|
+
</div>
|
|
659
|
+
|
|
660
|
+
<div class="content">
|
|
661
|
+
<div class="summary">
|
|
662
|
+
<div class="summary-card">
|
|
663
|
+
<h3>${reportData.duration?.toFixed(2) || 0}s</h3>
|
|
664
|
+
<p>Total Duration</p>
|
|
665
|
+
</div>
|
|
666
|
+
<div class="summary-card">
|
|
667
|
+
<h3>${reportData.phases.length}</h3>
|
|
668
|
+
<p>Phases Executed</p>
|
|
669
|
+
</div>
|
|
670
|
+
<div class="summary-card">
|
|
671
|
+
<h3>${reportData.metrics.errorCount}</h3>
|
|
672
|
+
<p>Errors</p>
|
|
673
|
+
</div>
|
|
674
|
+
<div class="summary-card">
|
|
675
|
+
<h3>${reportData.rollbacks.length}</h3>
|
|
676
|
+
<p>Rollbacks</p>
|
|
677
|
+
</div>
|
|
678
|
+
</div>
|
|
679
|
+
|
|
680
|
+
<div class="phases">
|
|
681
|
+
<h3>๐ Deployment Phases</h3>
|
|
682
|
+
${reportData.phases.map((phase, index) => `
|
|
683
|
+
<div class="phase ${phase.error ? 'error' : ''}">
|
|
684
|
+
<strong>${index + 1}. ${phase.phase} (${phase.action})</strong>
|
|
685
|
+
<div>Time: ${phase.timestamp.toLocaleString()}</div>
|
|
686
|
+
${phase.details ? `<div>Details: ${JSON.stringify(phase.details)}</div>` : ''}
|
|
687
|
+
</div>
|
|
688
|
+
`).join('')}
|
|
689
|
+
</div>
|
|
690
|
+
|
|
691
|
+
${reportData.events.length > 0 ? `
|
|
692
|
+
<div class="timeline">
|
|
693
|
+
<h3>๐ Event Timeline</h3>
|
|
694
|
+
${reportData.events.slice(-20).map(event => `
|
|
695
|
+
<div class="event ${event.level}">
|
|
696
|
+
<strong>${event.timestamp.toLocaleString()}</strong> - ${event.eventType}
|
|
697
|
+
${event.details ? `<div>${JSON.stringify(event.details)}</div>` : ''}
|
|
698
|
+
</div>
|
|
699
|
+
`).join('')}
|
|
700
|
+
</div>
|
|
701
|
+
` : ''}
|
|
702
|
+
</div>
|
|
703
|
+
</div>
|
|
704
|
+
</body>
|
|
705
|
+
</html>`;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Generate CSV deployment report
|
|
710
|
+
* @param {Object} reportData - Report data
|
|
711
|
+
* @returns {string} CSV content
|
|
712
|
+
*/
|
|
713
|
+
generateCsvReport(reportData) {
|
|
714
|
+
const headers = 'timestamp,phase,action,status,duration,details\n';
|
|
715
|
+
const rows = reportData.phases.map(phase => [phase.timestamp.toISOString(), phase.phase, phase.action, phase.error ? 'error' : 'success', reportData.duration || 0, JSON.stringify(phase.details || {}).replace(/"/g, '""')].join(',')).join('\n');
|
|
716
|
+
return headers + rows;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Search audit logs with filters
|
|
721
|
+
* @param {Object} filters - Search filters
|
|
722
|
+
* @returns {Array} Matching log entries
|
|
723
|
+
*/
|
|
724
|
+
searchAuditLogs(filters = {}) {
|
|
725
|
+
const results = [];
|
|
726
|
+
const {
|
|
727
|
+
eventType,
|
|
728
|
+
domain,
|
|
729
|
+
dateFrom,
|
|
730
|
+
dateTo,
|
|
731
|
+
level,
|
|
732
|
+
category,
|
|
733
|
+
deploymentId,
|
|
734
|
+
limit = 100
|
|
735
|
+
} = filters;
|
|
736
|
+
|
|
737
|
+
// Search current session events
|
|
738
|
+
let matchingEvents = this.currentSession.events.filter(event => {
|
|
739
|
+
if (eventType && event.eventType !== eventType) return false;
|
|
740
|
+
if (domain && event.domain !== domain) return false;
|
|
741
|
+
if (level && event.level !== level) return false;
|
|
742
|
+
if (category && event.category !== category) return false;
|
|
743
|
+
if (deploymentId && event.details?.deploymentId !== deploymentId) return false;
|
|
744
|
+
if (dateFrom && event.timestamp < new Date(dateFrom)) return false;
|
|
745
|
+
if (dateTo && event.timestamp > new Date(dateTo)) return false;
|
|
746
|
+
return true;
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
// Sort by timestamp (newest first)
|
|
750
|
+
matchingEvents.sort((a, b) => b.timestamp - a.timestamp);
|
|
751
|
+
|
|
752
|
+
// Apply limit
|
|
753
|
+
results.push(...matchingEvents.slice(0, limit));
|
|
754
|
+
this.logAuditEvent('AUDIT_SEARCH', 'SYSTEM', {
|
|
755
|
+
filters,
|
|
756
|
+
resultCount: results.length
|
|
757
|
+
});
|
|
758
|
+
return results;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Generate audit summary for current session
|
|
763
|
+
* @returns {Object} Audit summary
|
|
764
|
+
*/
|
|
765
|
+
generateAuditSummary() {
|
|
766
|
+
const sessionDuration = (new Date() - this.currentSession.startTime) / 1000;
|
|
767
|
+
const summary = {
|
|
768
|
+
sessionId: this.currentSession.sessionId,
|
|
769
|
+
sessionDuration,
|
|
770
|
+
metrics: {
|
|
771
|
+
...this.currentSession.metrics
|
|
772
|
+
},
|
|
773
|
+
deployments: Array.from(this.currentSession.deployments.entries()).map(([id, deployment]) => ({
|
|
774
|
+
deploymentId: id,
|
|
775
|
+
domain: deployment.domain,
|
|
776
|
+
status: deployment.status,
|
|
777
|
+
duration: deployment.duration,
|
|
778
|
+
phaseCount: deployment.phases.length,
|
|
779
|
+
errorCount: deployment.metrics.errorCount
|
|
780
|
+
})),
|
|
781
|
+
eventsByCategory: {},
|
|
782
|
+
eventsByLevel: {},
|
|
783
|
+
generatedAt: new Date()
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
// Categorize events
|
|
787
|
+
this.currentSession.events.forEach(event => {
|
|
788
|
+
// By category
|
|
789
|
+
if (!summary.eventsByCategory[event.category]) {
|
|
790
|
+
summary.eventsByCategory[event.category] = 0;
|
|
791
|
+
}
|
|
792
|
+
summary.eventsByCategory[event.category]++;
|
|
793
|
+
|
|
794
|
+
// By level
|
|
795
|
+
if (!summary.eventsByLevel[event.level]) {
|
|
796
|
+
summary.eventsByLevel[event.level] = 0;
|
|
797
|
+
}
|
|
798
|
+
summary.eventsByLevel[event.level]++;
|
|
799
|
+
});
|
|
800
|
+
console.log('\n๐ Audit Session Summary');
|
|
801
|
+
console.log(` ๐ Session: ${summary.sessionId}`);
|
|
802
|
+
console.log(` โฑ๏ธ Duration: ${sessionDuration.toFixed(2)}s`);
|
|
803
|
+
console.log(` ๐ Deployments: ${summary.metrics.deploymentCount}`);
|
|
804
|
+
console.log(` ๐ Total Events: ${summary.metrics.totalEvents}`);
|
|
805
|
+
console.log(` โ Errors: ${summary.metrics.errorCount}`);
|
|
806
|
+
console.log(` โ ๏ธ Warnings: ${summary.metrics.warningCount}`);
|
|
807
|
+
return summary;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Send real-time security alert
|
|
812
|
+
* @param {Object} securityEvent - Security event data
|
|
813
|
+
*/
|
|
814
|
+
async sendSecurityAlert(securityEvent) {
|
|
815
|
+
if (!this.config.alertWebhook) {
|
|
816
|
+
console.warn('โ ๏ธ Security alert webhook not configured');
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const alert = {
|
|
820
|
+
type: 'security_alert',
|
|
821
|
+
severity: securityEvent.severity,
|
|
822
|
+
event: securityEvent,
|
|
823
|
+
timestamp: new Date(),
|
|
824
|
+
sessionId: this.currentSession.sessionId
|
|
825
|
+
};
|
|
826
|
+
try {
|
|
827
|
+
// In a real implementation, this would send to a webhook
|
|
828
|
+
console.log(`๐จ Security Alert: ${securityEvent.eventType} (${securityEvent.severity})`);
|
|
829
|
+
this.logAuditEvent('SECURITY_ALERT_SENT', 'SYSTEM', {
|
|
830
|
+
alertId: Date.now().toString(),
|
|
831
|
+
event: securityEvent
|
|
832
|
+
});
|
|
833
|
+
} catch (error) {
|
|
834
|
+
console.error(`โ Failed to send security alert: ${error.message}`);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Send general alert
|
|
840
|
+
* @param {Object} auditEvent - Audit event to alert on
|
|
841
|
+
*/
|
|
842
|
+
async sendAlert(auditEvent) {
|
|
843
|
+
if (!this.config.realTimeAlerts) return;
|
|
844
|
+
console.log(`๐ Alert: ${auditEvent.eventType} (${auditEvent.level})`);
|
|
845
|
+
this.logAuditEvent('ALERT_SENT', 'SYSTEM', {
|
|
846
|
+
alertId: Date.now().toString(),
|
|
847
|
+
originalEvent: auditEvent.eventType
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Clean up old audit logs based on retention policy
|
|
853
|
+
* @returns {Object} Cleanup results
|
|
854
|
+
*/
|
|
855
|
+
cleanupAuditLogs() {
|
|
856
|
+
const cleanupResults = {
|
|
857
|
+
filesRemoved: 0,
|
|
858
|
+
spaceSaved: 0,
|
|
859
|
+
errors: []
|
|
860
|
+
};
|
|
861
|
+
try {
|
|
862
|
+
const cutoffDate = new Date();
|
|
863
|
+
cutoffDate.setDate(cutoffDate.getDate() - this.config.retentionDays);
|
|
864
|
+
|
|
865
|
+
// Scan audit directory for old files
|
|
866
|
+
const scanDirectory = dir => {
|
|
867
|
+
if (!existsSync(dir)) return;
|
|
868
|
+
const items = readdirSync(dir);
|
|
869
|
+
items.forEach(item => {
|
|
870
|
+
const itemPath = join(dir, item);
|
|
871
|
+
const stats = statSync(itemPath);
|
|
872
|
+
if (stats.isFile() && stats.mtime < cutoffDate) {
|
|
873
|
+
try {
|
|
874
|
+
cleanupResults.spaceSaved += stats.size;
|
|
875
|
+
execSync(`del "${itemPath}"`, {
|
|
876
|
+
shell: true
|
|
877
|
+
});
|
|
878
|
+
cleanupResults.filesRemoved++;
|
|
879
|
+
} catch (error) {
|
|
880
|
+
cleanupResults.errors.push({
|
|
881
|
+
file: itemPath,
|
|
882
|
+
error: error.message
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
};
|
|
888
|
+
scanDirectory(this.paths.daily);
|
|
889
|
+
scanDirectory(this.paths.deployments);
|
|
890
|
+
this.logAuditEvent('AUDIT_CLEANUP_COMPLETED', 'SYSTEM', cleanupResults);
|
|
891
|
+
console.log(`๐งน Audit cleanup completed: ${cleanupResults.filesRemoved} files removed`);
|
|
892
|
+
} catch (error) {
|
|
893
|
+
console.error(`โ Audit cleanup failed: ${error.message}`);
|
|
894
|
+
cleanupResults.errors.push({
|
|
895
|
+
general: error.message
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
return cleanupResults;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// Legacy function exports for backward compatibility
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Create simple audit logger
|
|
906
|
+
* @param {string} deploymentId - Deployment identifier
|
|
907
|
+
* @param {Object} options - Audit options
|
|
908
|
+
* @returns {DeploymentAuditor} Auditor instance
|
|
909
|
+
*/
|
|
910
|
+
export function createAuditLogger(deploymentId, options = {}) {
|
|
911
|
+
const auditor = new DeploymentAuditor(options);
|
|
912
|
+
return {
|
|
913
|
+
logPhase: (phase, action, details) => auditor.logPhase(deploymentId, phase, action, details),
|
|
914
|
+
logError: (error, context) => auditor.logError(deploymentId, error, context),
|
|
915
|
+
logEvent: (eventType, details) => auditor.logAuditEvent(eventType, details.domain || 'SYSTEM', details),
|
|
916
|
+
generateReport: () => auditor.generateDeploymentReport(deploymentId),
|
|
917
|
+
getSummary: () => auditor.generateAuditSummary()
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Simple deployment logging
|
|
923
|
+
* @param {string} deploymentId - Deployment identifier
|
|
924
|
+
* @param {string} message - Log message
|
|
925
|
+
* @param {Object} context - Additional context
|
|
926
|
+
*/
|
|
927
|
+
export function logDeployment(deploymentId, message, context = {}) {
|
|
928
|
+
const auditor = new DeploymentAuditor({
|
|
929
|
+
auditLevel: 'standard'
|
|
930
|
+
});
|
|
931
|
+
auditor.logAuditEvent('DEPLOYMENT_LOG', context.domain || 'SYSTEM', {
|
|
932
|
+
deploymentId,
|
|
933
|
+
message,
|
|
934
|
+
...context
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Log deployment phase with timing
|
|
940
|
+
* @param {string} deploymentId - Deployment identifier
|
|
941
|
+
* @param {string} phase - Phase name
|
|
942
|
+
* @param {Function} operation - Operation to execute
|
|
943
|
+
* @returns {Promise<*>} Operation result
|
|
944
|
+
*/
|
|
945
|
+
export async function auditPhase(deploymentId, phase, operation) {
|
|
946
|
+
const auditor = new DeploymentAuditor({
|
|
947
|
+
auditLevel: 'detailed'
|
|
948
|
+
});
|
|
949
|
+
auditor.logPhase(deploymentId, phase, 'start');
|
|
950
|
+
const startTime = Date.now();
|
|
951
|
+
try {
|
|
952
|
+
const result = await operation();
|
|
953
|
+
const duration = Date.now() - startTime;
|
|
954
|
+
auditor.logPhase(deploymentId, phase, 'end', {
|
|
955
|
+
duration,
|
|
956
|
+
success: true
|
|
957
|
+
});
|
|
958
|
+
return result;
|
|
959
|
+
} catch (error) {
|
|
960
|
+
const duration = Date.now() - startTime;
|
|
961
|
+
auditor.logPhase(deploymentId, phase, 'end', {
|
|
962
|
+
duration,
|
|
963
|
+
success: false,
|
|
964
|
+
error: error.message
|
|
965
|
+
});
|
|
966
|
+
auditor.logError(deploymentId, error, {
|
|
967
|
+
phase
|
|
968
|
+
});
|
|
969
|
+
throw error;
|
|
970
|
+
}
|
|
971
|
+
}
|