@jishankai/solid-cli 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/LICENSE +21 -0
- package/README.md +276 -0
- package/config/default.json +79 -0
- package/package.json +60 -0
- package/src/Orchestrator.js +482 -0
- package/src/agents/BaseAgent.js +35 -0
- package/src/agents/BlockchainAgent.js +453 -0
- package/src/agents/DeFiSecurityAgent.js +257 -0
- package/src/agents/NetworkAgent.js +341 -0
- package/src/agents/PermissionAgent.js +192 -0
- package/src/agents/PersistenceAgent.js +361 -0
- package/src/agents/ProcessAgent.js +572 -0
- package/src/agents/ResourceAgent.js +217 -0
- package/src/agents/SystemAgent.js +173 -0
- package/src/config/ConfigManager.js +446 -0
- package/src/index.js +629 -0
- package/src/llm/LLMAnalyzer.js +705 -0
- package/src/logging/Logger.js +352 -0
- package/src/report/ReportManager.js +445 -0
- package/src/report/generators/MarkdownGenerator.js +173 -0
- package/src/report/generators/PDFGenerator.js +616 -0
- package/src/report/templates/report.hbs +465 -0
- package/src/report/utils/formatter.js +426 -0
- package/src/report/utils/sanitizer.js +275 -0
- package/src/utils/commander.js +42 -0
- package/src/utils/signature.js +121 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import config from 'config';
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import Joi from 'joi';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Configuration Management System
|
|
8
|
+
*/
|
|
9
|
+
export class ConfigManager {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.schema = this.createSchema();
|
|
12
|
+
this.config = this.loadConfiguration();
|
|
13
|
+
this.watchers = [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create validation schema for configuration
|
|
18
|
+
*/
|
|
19
|
+
createSchema() {
|
|
20
|
+
return Joi.object({
|
|
21
|
+
analysis: Joi.object({
|
|
22
|
+
defaultDepth: Joi.string().valid('fast', 'comprehensive', 'deep').default('comprehensive'),
|
|
23
|
+
adaptiveMode: Joi.boolean().default(true),
|
|
24
|
+
blockchainDetection: Joi.boolean().default(true),
|
|
25
|
+
deepForensicsThreshold: Joi.string().valid('low', 'medium', 'high').default('medium'),
|
|
26
|
+
parallelExecution: Joi.boolean().default(true),
|
|
27
|
+
maxParallelAgents: Joi.number().integer().min(1).max(10).default(3)
|
|
28
|
+
}),
|
|
29
|
+
|
|
30
|
+
reports: Joi.object({
|
|
31
|
+
outputDir: Joi.string().default('./reports'),
|
|
32
|
+
retentionDays: Joi.number().integer().min(1).max(365).default(90),
|
|
33
|
+
defaultTemplate: Joi.string().default('executive'),
|
|
34
|
+
defaultFormats: Joi.array().items(Joi.string().valid('markdown', 'pdf', 'html')).default(['markdown', 'pdf']),
|
|
35
|
+
pdfOptions: Joi.object({
|
|
36
|
+
format: Joi.string().default('A4'),
|
|
37
|
+
margin: Joi.string().default('2cm'),
|
|
38
|
+
displayHeaderFooter: Joi.boolean().default(true),
|
|
39
|
+
printBackground: Joi.boolean().default(true)
|
|
40
|
+
}),
|
|
41
|
+
includeScreenshots: Joi.boolean().default(false),
|
|
42
|
+
compressOldReports: Joi.boolean().default(true)
|
|
43
|
+
}),
|
|
44
|
+
|
|
45
|
+
logging: Joi.object({
|
|
46
|
+
level: Joi.string().valid('error', 'warn', 'info', 'debug').default('info'),
|
|
47
|
+
consoleLevel: Joi.string().valid('error', 'warn', 'info', 'debug').default('warn'),
|
|
48
|
+
enableConsole: Joi.boolean().default(true),
|
|
49
|
+
enableFiles: Joi.boolean().default(true),
|
|
50
|
+
logDir: Joi.string().default('./logs'),
|
|
51
|
+
maxFileSize: Joi.string().default('20m'),
|
|
52
|
+
maxFiles: Joi.string().default('14d'),
|
|
53
|
+
securityLogRetention: Joi.string().default('30d')
|
|
54
|
+
}),
|
|
55
|
+
|
|
56
|
+
llm: Joi.object({
|
|
57
|
+
autoDetectProvider: Joi.boolean().default(true),
|
|
58
|
+
enableLogging: Joi.boolean().default(true),
|
|
59
|
+
logDir: Joi.string().default('./logs/llm-requests'),
|
|
60
|
+
privacyLevel: Joi.string().valid('low', 'medium', 'high').default('high'),
|
|
61
|
+
maxTokens: Joi.number().integer().min(100).max(8000).default(4000),
|
|
62
|
+
temperature: Joi.number().min(0).max(2).default(0.1),
|
|
63
|
+
minHighRiskFindings: Joi.number().integer().min(0).max(50).default(1),
|
|
64
|
+
minTotalFindings: Joi.number().integer().min(0).max(200).default(5),
|
|
65
|
+
skipWhenBelowThreshold: Joi.boolean().default(true)
|
|
66
|
+
}),
|
|
67
|
+
|
|
68
|
+
privacy: Joi.object({
|
|
69
|
+
redactUserPaths: Joi.boolean().default(true),
|
|
70
|
+
redactUsernames: Joi.boolean().default(true),
|
|
71
|
+
redactIPs: Joi.boolean().default(false),
|
|
72
|
+
preserveDomains: Joi.boolean().default(true),
|
|
73
|
+
sanitizationLevel: Joi.string().valid('low', 'medium', 'high').default('high')
|
|
74
|
+
}),
|
|
75
|
+
|
|
76
|
+
performance: Joi.object({
|
|
77
|
+
enableMetrics: Joi.boolean().default(true),
|
|
78
|
+
slowQueryThreshold: Joi.number().integer().min(100).default(5000),
|
|
79
|
+
memoryThreshold: Joi.number().integer().min(128).default(1024),
|
|
80
|
+
enableProfiling: Joi.boolean().default(false)
|
|
81
|
+
}),
|
|
82
|
+
|
|
83
|
+
security: Joi.object({
|
|
84
|
+
enableGeoLookup: Joi.boolean().default(true),
|
|
85
|
+
geoLookupLimit: Joi.number().integer().min(1).max(50).default(10),
|
|
86
|
+
trustedPaths: Joi.array().items(Joi.string()).default([
|
|
87
|
+
'/System', '/usr/bin', '/usr/sbin', '/bin', '/sbin', '/Applications'
|
|
88
|
+
]),
|
|
89
|
+
riskyPorts: Joi.array().items(Joi.number()).default([
|
|
90
|
+
22, 23, 135, 139, 445, 1433, 3389, 5432, 6379, 27017, 8080, 8443
|
|
91
|
+
])
|
|
92
|
+
}),
|
|
93
|
+
|
|
94
|
+
compliance: Joi.object({
|
|
95
|
+
frameworks: Joi.array().items(Joi.string()).default(['NIST CSF', 'ISO 27001', 'SOC 2']),
|
|
96
|
+
enableMapping: Joi.boolean().default(true),
|
|
97
|
+
reportCompliance: Joi.boolean().default(true)
|
|
98
|
+
})
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Load and validate configuration
|
|
104
|
+
*/
|
|
105
|
+
loadConfiguration() {
|
|
106
|
+
try {
|
|
107
|
+
// Use config library for environment-specific configs
|
|
108
|
+
let configData;
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
configData = config.util.toObject();
|
|
112
|
+
} catch (configError) {
|
|
113
|
+
console.warn(`Config library failed, using defaults: ${configError.message}`);
|
|
114
|
+
return this.getDefaultConfiguration();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Validate against schema
|
|
118
|
+
const { error, value } = this.schema.validate(configData, {
|
|
119
|
+
allowUnknown: true,
|
|
120
|
+
stripUnknown: false
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (error) {
|
|
124
|
+
console.warn(`Configuration validation warnings: ${error.message}`);
|
|
125
|
+
// Use defaults for invalid values
|
|
126
|
+
return this.getDefaultConfiguration();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return value;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error(`Failed to load configuration: ${error.message}`);
|
|
132
|
+
// Return hardcoded defaults as fallback
|
|
133
|
+
return this.getDefaultConfiguration();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get default configuration
|
|
139
|
+
*/
|
|
140
|
+
getDefaultConfiguration() {
|
|
141
|
+
return {
|
|
142
|
+
analysis: {
|
|
143
|
+
defaultDepth: 'comprehensive',
|
|
144
|
+
adaptiveMode: true,
|
|
145
|
+
blockchainDetection: true,
|
|
146
|
+
deepForensicsThreshold: 'medium',
|
|
147
|
+
parallelExecution: true,
|
|
148
|
+
maxParallelAgents: 3
|
|
149
|
+
},
|
|
150
|
+
reports: {
|
|
151
|
+
outputDir: './reports',
|
|
152
|
+
retentionDays: 90,
|
|
153
|
+
defaultTemplate: 'executive',
|
|
154
|
+
defaultFormats: ['markdown', 'pdf'],
|
|
155
|
+
pdfOptions: {
|
|
156
|
+
format: 'A4',
|
|
157
|
+
margin: '2cm',
|
|
158
|
+
displayHeaderFooter: true,
|
|
159
|
+
printBackground: true
|
|
160
|
+
},
|
|
161
|
+
includeScreenshots: false,
|
|
162
|
+
compressOldReports: true
|
|
163
|
+
},
|
|
164
|
+
logging: {
|
|
165
|
+
level: 'info',
|
|
166
|
+
consoleLevel: 'warn',
|
|
167
|
+
enableConsole: true,
|
|
168
|
+
enableFiles: true,
|
|
169
|
+
logDir: './logs',
|
|
170
|
+
maxFileSize: '20m',
|
|
171
|
+
maxFiles: '14d',
|
|
172
|
+
securityLogRetention: '30d'
|
|
173
|
+
},
|
|
174
|
+
llm: {
|
|
175
|
+
autoDetectProvider: true,
|
|
176
|
+
enableLogging: true,
|
|
177
|
+
logDir: './logs/llm-requests',
|
|
178
|
+
privacyLevel: 'high',
|
|
179
|
+
maxTokens: 4000,
|
|
180
|
+
temperature: 0.1,
|
|
181
|
+
minHighRiskFindings: 1,
|
|
182
|
+
minTotalFindings: 5,
|
|
183
|
+
skipWhenBelowThreshold: true
|
|
184
|
+
},
|
|
185
|
+
privacy: {
|
|
186
|
+
redactUserPaths: true,
|
|
187
|
+
redactUsernames: true,
|
|
188
|
+
redactIPs: false,
|
|
189
|
+
preserveDomains: true,
|
|
190
|
+
sanitizationLevel: 'high'
|
|
191
|
+
},
|
|
192
|
+
performance: {
|
|
193
|
+
enableMetrics: true,
|
|
194
|
+
slowQueryThreshold: 5000,
|
|
195
|
+
memoryThreshold: 1024,
|
|
196
|
+
enableProfiling: false
|
|
197
|
+
},
|
|
198
|
+
security: {
|
|
199
|
+
enableGeoLookup: true,
|
|
200
|
+
geoLookupLimit: 10,
|
|
201
|
+
trustedPaths: ['/System', '/usr/bin', '/usr/sbin', '/bin', '/sbin', '/Applications'],
|
|
202
|
+
riskyPorts: [22, 23, 135, 139, 445, 1433, 3389, 5432, 6379, 27017, 8080, 8443]
|
|
203
|
+
},
|
|
204
|
+
compliance: {
|
|
205
|
+
frameworks: ['NIST CSF', 'ISO 27001', 'SOC 2'],
|
|
206
|
+
enableMapping: true,
|
|
207
|
+
reportCompliance: true
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get configuration value by path
|
|
214
|
+
*/
|
|
215
|
+
get(path, defaultValue = undefined) {
|
|
216
|
+
if (!path || typeof path !== 'string') {
|
|
217
|
+
return defaultValue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const keys = path.split('.');
|
|
221
|
+
let value = this.config;
|
|
222
|
+
|
|
223
|
+
for (const key of keys) {
|
|
224
|
+
if (value && typeof value === 'object' && key in value) {
|
|
225
|
+
value = value[key];
|
|
226
|
+
} else {
|
|
227
|
+
return defaultValue;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return value;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Set configuration value by path
|
|
236
|
+
*/
|
|
237
|
+
set(path, value) {
|
|
238
|
+
const keys = path.split('.');
|
|
239
|
+
let current = this.config;
|
|
240
|
+
|
|
241
|
+
// Navigate to parent object
|
|
242
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
243
|
+
const key = keys[i];
|
|
244
|
+
if (!(key in current) || typeof current[key] !== 'object') {
|
|
245
|
+
current[key] = {};
|
|
246
|
+
}
|
|
247
|
+
current = current[key];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Set value
|
|
251
|
+
const finalKey = keys[keys.length - 1];
|
|
252
|
+
const oldValue = current[finalKey];
|
|
253
|
+
current[finalKey] = value;
|
|
254
|
+
|
|
255
|
+
// Validate the updated configuration
|
|
256
|
+
const { error } = this.schema.validate(this.config);
|
|
257
|
+
if (error) {
|
|
258
|
+
// Revert change if invalid
|
|
259
|
+
current[finalKey] = oldValue;
|
|
260
|
+
throw new Error(`Invalid configuration value for ${path}: ${error.message}`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Notify watchers
|
|
264
|
+
this.notifyWatchers(path, oldValue, value);
|
|
265
|
+
|
|
266
|
+
// Save to file if persistent
|
|
267
|
+
this.saveConfiguration();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Get entire configuration object
|
|
272
|
+
*/
|
|
273
|
+
getAll() {
|
|
274
|
+
return { ...this.config };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Watch for configuration changes
|
|
279
|
+
*/
|
|
280
|
+
watch(path, callback) {
|
|
281
|
+
this.watchers.push({ path, callback });
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Remove configuration watcher
|
|
286
|
+
*/
|
|
287
|
+
unwatch(path, callback) {
|
|
288
|
+
this.watchers = this.watchers.filter(w =>
|
|
289
|
+
!(w.path === path && w.callback === callback)
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Notify watchers of changes
|
|
295
|
+
*/
|
|
296
|
+
notifyWatchers(path, oldValue, newValue) {
|
|
297
|
+
this.watchers
|
|
298
|
+
.filter(w => w.path === path || w.path === '*')
|
|
299
|
+
.forEach(w => {
|
|
300
|
+
try {
|
|
301
|
+
w.callback(path, oldValue, newValue);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error(`Configuration watcher error: ${error.message}`);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Save configuration to file
|
|
310
|
+
*/
|
|
311
|
+
async saveConfiguration() {
|
|
312
|
+
try {
|
|
313
|
+
const configPath = join(process.cwd(), 'config', 'default.json');
|
|
314
|
+
writeFileSync(configPath, JSON.stringify(this.config, null, 2));
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error(`Failed to save configuration: ${error.message}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Load configuration from environment variables
|
|
322
|
+
*/
|
|
323
|
+
loadFromEnvironment() {
|
|
324
|
+
const envMappings = {
|
|
325
|
+
'ANALYSIS_DEPTH': 'analysis.defaultDepth',
|
|
326
|
+
'ANALYSIS_ADAPTIVE': 'analysis.adaptiveMode',
|
|
327
|
+
'ANALYSIS_BLOCKCHAIN': 'analysis.blockchainDetection',
|
|
328
|
+
'REPORTS_OUTPUT_DIR': 'reports.outputDir',
|
|
329
|
+
'REPORTS_RETENTION_DAYS': 'reports.retentionDays',
|
|
330
|
+
'LOG_LEVEL': 'logging.level',
|
|
331
|
+
'LOG_DIR': 'logging.logDir',
|
|
332
|
+
'LLM_MAX_TOKENS': 'llm.maxTokens',
|
|
333
|
+
'LLM_PRIVACY_LEVEL': 'llm.privacyLevel',
|
|
334
|
+
'LLM_MIN_HIGH_RISK': 'llm.minHighRiskFindings',
|
|
335
|
+
'LLM_MIN_TOTAL': 'llm.minTotalFindings',
|
|
336
|
+
'LLM_SKIP_BELOW_THRESHOLD': 'llm.skipWhenBelowThreshold',
|
|
337
|
+
'PRIVACY_REDACT_PATHS': 'privacy.redactUserPaths',
|
|
338
|
+
'PRIVACY_REDACT_USERNAMES': 'privacy.redactUsernames',
|
|
339
|
+
'SECURITY_GEO_LOOKUP': 'security.enableGeoLookup',
|
|
340
|
+
'SECURITY_GEO_LIMIT': 'security.geoLookupLimit'
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
for (const [envVar, configPath] of Object.entries(envMappings)) {
|
|
344
|
+
const value = process.env[envVar];
|
|
345
|
+
if (value !== undefined) {
|
|
346
|
+
// Convert string values to appropriate types
|
|
347
|
+
let parsedValue = value;
|
|
348
|
+
if (value === 'true') parsedValue = true;
|
|
349
|
+
else if (value === 'false') parsedValue = false;
|
|
350
|
+
else if (!isNaN(value) && value.includes('.')) parsedValue = parseFloat(value);
|
|
351
|
+
else if (!isNaN(value)) parsedValue = parseInt(value);
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
this.set(configPath, parsedValue);
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.warn(`Invalid environment variable ${envVar}: ${error.message}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Get configuration for a specific component
|
|
364
|
+
*/
|
|
365
|
+
getComponentConfig(component) {
|
|
366
|
+
return this.get(component, {});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Merge user configuration with defaults
|
|
371
|
+
*/
|
|
372
|
+
mergeWithUserConfig(userConfig) {
|
|
373
|
+
const merged = this.deepMerge(this.getDefaultConfiguration(), userConfig);
|
|
374
|
+
|
|
375
|
+
const { error, value } = this.schema.validate(merged);
|
|
376
|
+
if (error) {
|
|
377
|
+
console.warn(`Configuration merge warnings: ${error.message}`);
|
|
378
|
+
return value;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return value;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Deep merge objects
|
|
386
|
+
*/
|
|
387
|
+
deepMerge(target, source) {
|
|
388
|
+
const result = { ...target };
|
|
389
|
+
|
|
390
|
+
for (const key in source) {
|
|
391
|
+
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
392
|
+
result[key] = this.deepMerge(result[key] || {}, source[key]);
|
|
393
|
+
} else {
|
|
394
|
+
result[key] = source[key];
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return result;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Reset configuration to defaults
|
|
403
|
+
*/
|
|
404
|
+
reset() {
|
|
405
|
+
this.config = this.getDefaultConfiguration();
|
|
406
|
+
this.saveConfiguration();
|
|
407
|
+
this.notifyWatchers('*', null, this.config);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Validate current configuration
|
|
412
|
+
*/
|
|
413
|
+
validate() {
|
|
414
|
+
const { error, value } = this.schema.validate(this.config);
|
|
415
|
+
return { valid: !error, errors: error?.details || [], value };
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Global configuration manager instance
|
|
421
|
+
*/
|
|
422
|
+
let globalConfig = null;
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Get or create global configuration manager
|
|
426
|
+
*/
|
|
427
|
+
export function getConfigManager() {
|
|
428
|
+
if (!globalConfig) {
|
|
429
|
+
globalConfig = new ConfigManager();
|
|
430
|
+
}
|
|
431
|
+
return globalConfig;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Convenience function to get configuration value
|
|
436
|
+
*/
|
|
437
|
+
export function getConfig(path, defaultValue) {
|
|
438
|
+
return getConfigManager().get(path, defaultValue);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Convenience function to set configuration value
|
|
443
|
+
*/
|
|
444
|
+
export function setConfig(path, value) {
|
|
445
|
+
return getConfigManager().set(path, value);
|
|
446
|
+
}
|