kramscan 0.1.0 → 0.2.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/README.md +392 -87
- package/dist/agent/confirmation.d.ts +38 -0
- package/dist/agent/confirmation.js +210 -0
- package/dist/agent/context.d.ts +81 -0
- package/dist/agent/context.js +227 -0
- package/dist/agent/index.d.ts +10 -0
- package/dist/agent/index.js +32 -0
- package/dist/agent/orchestrator.d.ts +63 -0
- package/dist/agent/orchestrator.js +370 -0
- package/dist/agent/prompts/system.d.ts +6 -0
- package/dist/agent/prompts/system.js +116 -0
- package/dist/agent/skill-registry.d.ts +78 -0
- package/dist/agent/skill-registry.js +202 -0
- package/dist/agent/skills/analyze-findings.d.ts +22 -0
- package/dist/agent/skills/analyze-findings.js +191 -0
- package/dist/agent/skills/generate-report.d.ts +26 -0
- package/dist/agent/skills/generate-report.js +436 -0
- package/dist/agent/skills/health-check.d.ts +28 -0
- package/dist/agent/skills/health-check.js +344 -0
- package/dist/agent/skills/index.d.ts +9 -0
- package/dist/agent/skills/index.js +17 -0
- package/dist/agent/skills/verify-finding.d.ts +17 -0
- package/dist/agent/skills/verify-finding.js +91 -0
- package/dist/agent/skills/web-scan.d.ts +22 -0
- package/dist/agent/skills/web-scan.js +203 -0
- package/dist/agent/types.d.ts +141 -0
- package/dist/agent/types.js +16 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +176 -139
- package/dist/commands/agent.d.ts +6 -0
- package/dist/commands/agent.js +250 -0
- package/dist/commands/ai.d.ts +2 -0
- package/dist/commands/ai.js +112 -0
- package/dist/commands/analyze.js +104 -55
- package/dist/commands/config.js +63 -37
- package/dist/commands/doctor.js +22 -17
- package/dist/commands/onboard.js +190 -125
- package/dist/commands/report.js +69 -77
- package/dist/commands/scan.js +261 -81
- package/dist/commands/scans.d.ts +2 -0
- package/dist/commands/scans.js +51 -0
- package/dist/core/ai-client.d.ts +7 -2
- package/dist/core/ai-client.js +231 -20
- package/dist/core/ai-payloads.d.ts +17 -0
- package/dist/core/ai-payloads.js +54 -0
- package/dist/core/config-schema.d.ts +197 -0
- package/dist/core/config-schema.js +68 -0
- package/dist/core/config-schema.test.d.ts +1 -0
- package/dist/core/config-schema.test.js +151 -0
- package/dist/core/config.d.ts +17 -36
- package/dist/core/config.js +261 -20
- package/dist/core/errors.d.ts +71 -0
- package/dist/core/errors.js +162 -0
- package/dist/core/scan-index.d.ts +19 -0
- package/dist/core/scan-index.js +52 -0
- package/dist/core/scan-storage.d.ts +11 -0
- package/dist/core/scan-storage.js +69 -0
- package/dist/core/scanner.d.ts +101 -4
- package/dist/core/scanner.js +432 -63
- package/dist/core/vulnerability-detector.d.ts +18 -2
- package/dist/core/vulnerability-detector.js +349 -38
- package/dist/core/vulnerability-detector.test.d.ts +1 -0
- package/dist/core/vulnerability-detector.test.js +210 -0
- package/dist/index.js +3 -0
- package/dist/plugins/PluginManager.d.ts +27 -0
- package/dist/plugins/PluginManager.js +166 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.js +19 -0
- package/dist/plugins/types.d.ts +55 -0
- package/dist/plugins/types.js +25 -0
- package/dist/plugins/vulnerabilities/CSRFPlugin.d.ts +8 -0
- package/dist/plugins/vulnerabilities/CSRFPlugin.js +34 -0
- package/dist/plugins/vulnerabilities/SQLInjectionPlugin.d.ts +11 -0
- package/dist/plugins/vulnerabilities/SQLInjectionPlugin.js +109 -0
- package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.d.ts +11 -0
- package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.js +63 -0
- package/dist/plugins/vulnerabilities/SensitiveDataPlugin.d.ts +9 -0
- package/dist/plugins/vulnerabilities/SensitiveDataPlugin.js +32 -0
- package/dist/plugins/vulnerabilities/XSSPlugin.d.ts +15 -0
- package/dist/plugins/vulnerabilities/XSSPlugin.js +81 -0
- package/dist/reports/PdfGenerator.d.ts +36 -0
- package/dist/reports/PdfGenerator.js +379 -0
- package/dist/utils/logger.d.ts +33 -1
- package/dist/utils/logger.js +127 -8
- package/dist/utils/theme.d.ts +55 -0
- package/dist/utils/theme.js +195 -0
- package/package.json +27 -6
- package/dist/core/executor.d.ts +0 -2
- package/dist/core/executor.js +0 -74
- package/dist/core/logger.d.ts +0 -12
- package/dist/core/logger.js +0 -51
- package/dist/core/registry.d.ts +0 -3
- package/dist/core/registry.js +0 -35
- package/dist/core/storage.d.ts +0 -4
- package/dist/core/storage.js +0 -39
- package/dist/core/types.d.ts +0 -24
- package/dist/core/types.js +0 -2
- package/dist/skills/base.d.ts +0 -8
- package/dist/skills/base.js +0 -6
- package/dist/skills/builtin.d.ts +0 -4
- package/dist/skills/builtin.js +0 -71
- package/dist/skills/loader.d.ts +0 -2
- package/dist/skills/loader.js +0 -27
- package/dist/skills/types.d.ts +0 -46
- package/dist/skills/types.js +0 -2
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Generate Report Skill
|
|
4
|
+
* Creates professional security reports in multiple formats (DOCX, TXT, JSON)
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.GenerateReportSkill = void 0;
|
|
41
|
+
const logger_1 = require("../../utils/logger");
|
|
42
|
+
const fs = __importStar(require("fs/promises"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const os = __importStar(require("os"));
|
|
45
|
+
// Dynamic imports for report generation libraries
|
|
46
|
+
let docx;
|
|
47
|
+
try {
|
|
48
|
+
docx = require("docx");
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// docx not available
|
|
52
|
+
}
|
|
53
|
+
class GenerateReportSkill {
|
|
54
|
+
id = "generate_report";
|
|
55
|
+
name = "Generate Report";
|
|
56
|
+
description = "Creates a professional security report in DOCX, TXT, or JSON format based on scan results.";
|
|
57
|
+
tags = ["reporting", "documentation", "export"];
|
|
58
|
+
requiresConfirmation = false;
|
|
59
|
+
riskLevel = "low";
|
|
60
|
+
estimatedDuration = 10; // seconds
|
|
61
|
+
toolDefinition = {
|
|
62
|
+
name: "generate_report",
|
|
63
|
+
description: "Generate a professional security report from scan results in various formats",
|
|
64
|
+
parameters: [
|
|
65
|
+
{
|
|
66
|
+
name: "useLastScan",
|
|
67
|
+
type: "boolean",
|
|
68
|
+
description: "Use results from the most recent scan. If true, scanResults parameter is optional.",
|
|
69
|
+
required: false,
|
|
70
|
+
default: true,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "scanResults",
|
|
74
|
+
type: "object",
|
|
75
|
+
description: "Scan results to include in report (if not using last scan)",
|
|
76
|
+
required: false,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: "format",
|
|
80
|
+
type: "string",
|
|
81
|
+
description: "Report format: 'docx' (Word), 'txt' (text), or 'json'",
|
|
82
|
+
required: false,
|
|
83
|
+
default: "docx",
|
|
84
|
+
enum: ["docx", "txt", "json"],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "outputPath",
|
|
88
|
+
type: "string",
|
|
89
|
+
description: "Custom output path for the report. If not provided, saves to ~/.kramscan/reports/",
|
|
90
|
+
required: false,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "includeAnalysis",
|
|
94
|
+
type: "boolean",
|
|
95
|
+
description: "Include AI analysis in the report if available",
|
|
96
|
+
required: false,
|
|
97
|
+
default: true,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
validateParameters(params) {
|
|
102
|
+
const errors = [];
|
|
103
|
+
// Validate format
|
|
104
|
+
if (params.format) {
|
|
105
|
+
const validFormats = ["docx", "txt", "json"];
|
|
106
|
+
if (!validFormats.includes(params.format)) {
|
|
107
|
+
errors.push(`format must be one of: ${validFormats.join(", ")}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Check scan data availability
|
|
111
|
+
if (params.useLastScan === false && !params.scanResults) {
|
|
112
|
+
errors.push("scanResults is required when useLastScan is false");
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
valid: errors.length === 0,
|
|
116
|
+
errors,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
async execute(params, context) {
|
|
120
|
+
const useLastScan = params.useLastScan ?? true;
|
|
121
|
+
const format = params.format ?? "docx";
|
|
122
|
+
const customPath = params.outputPath;
|
|
123
|
+
const includeAnalysis = params.includeAnalysis ?? true;
|
|
124
|
+
let scanData;
|
|
125
|
+
// Get scan data
|
|
126
|
+
if (useLastScan) {
|
|
127
|
+
const lastResults = context.lastScanResults;
|
|
128
|
+
if (!lastResults) {
|
|
129
|
+
return {
|
|
130
|
+
skillId: this.id,
|
|
131
|
+
findings: [],
|
|
132
|
+
metadata: {
|
|
133
|
+
error: "No previous scan results found. Please run a scan first.",
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
scanData = lastResults;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
scanData = params.scanResults;
|
|
141
|
+
}
|
|
142
|
+
logger_1.logger.info(`Generating ${format.toUpperCase()} report`);
|
|
143
|
+
try {
|
|
144
|
+
// Determine output path
|
|
145
|
+
let outputPath;
|
|
146
|
+
if (customPath) {
|
|
147
|
+
outputPath = customPath;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const reportsDir = path.join(os.homedir(), ".kramscan", "reports");
|
|
151
|
+
await fs.mkdir(reportsDir, { recursive: true });
|
|
152
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
153
|
+
const targetName = scanData.target
|
|
154
|
+
? new URL(scanData.target).hostname
|
|
155
|
+
: "scan";
|
|
156
|
+
outputPath = path.join(reportsDir, `${targetName}-security-report-${timestamp}.${format}`);
|
|
157
|
+
}
|
|
158
|
+
// Generate report based on format
|
|
159
|
+
switch (format.toLowerCase()) {
|
|
160
|
+
case "docx":
|
|
161
|
+
await this.generateDocxReport(scanData, outputPath, includeAnalysis);
|
|
162
|
+
break;
|
|
163
|
+
case "txt":
|
|
164
|
+
await this.generateTxtReport(scanData, outputPath, includeAnalysis);
|
|
165
|
+
break;
|
|
166
|
+
case "json":
|
|
167
|
+
await this.generateJsonReport(scanData, outputPath);
|
|
168
|
+
break;
|
|
169
|
+
default:
|
|
170
|
+
throw new Error(`Unsupported format: ${format}`);
|
|
171
|
+
}
|
|
172
|
+
logger_1.logger.success(`Report saved to: ${outputPath}`);
|
|
173
|
+
return {
|
|
174
|
+
skillId: this.id,
|
|
175
|
+
findings: [],
|
|
176
|
+
metadata: {
|
|
177
|
+
outputPath,
|
|
178
|
+
format,
|
|
179
|
+
target: scanData.target,
|
|
180
|
+
totalFindings: scanData.findings?.length || 0,
|
|
181
|
+
timestamp: new Date().toISOString(),
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
187
|
+
logger_1.logger.error(`Report generation failed: ${errorMessage}`);
|
|
188
|
+
return {
|
|
189
|
+
skillId: this.id,
|
|
190
|
+
findings: [],
|
|
191
|
+
metadata: {
|
|
192
|
+
error: errorMessage,
|
|
193
|
+
target: scanData.target,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async generateDocxReport(scanData, outputPath, includeAnalysis) {
|
|
199
|
+
if (!docx) {
|
|
200
|
+
throw new Error("DOCX generation requires the 'docx' package. Please install it: npm install docx");
|
|
201
|
+
}
|
|
202
|
+
const { Document, Paragraph, TextRun, HeadingLevel, Table, TableCell, TableRow, WidthType, BorderStyle, } = docx;
|
|
203
|
+
const findings = scanData.findings || [];
|
|
204
|
+
const analysisFinding = includeAnalysis
|
|
205
|
+
? findings.find((f) => f.skillId === "analyze_findings")
|
|
206
|
+
: null;
|
|
207
|
+
const vulnerabilities = findings.filter((f) => f.skillId !== "analyze_findings");
|
|
208
|
+
// Create document sections
|
|
209
|
+
const children = [
|
|
210
|
+
new Paragraph({
|
|
211
|
+
text: "Security Assessment Report",
|
|
212
|
+
heading: HeadingLevel.TITLE,
|
|
213
|
+
}),
|
|
214
|
+
new Paragraph({
|
|
215
|
+
text: `Target: ${scanData.target || "N/A"}`,
|
|
216
|
+
spacing: { after: 200 },
|
|
217
|
+
}),
|
|
218
|
+
new Paragraph({
|
|
219
|
+
text: `Generated: ${new Date().toLocaleString()}`,
|
|
220
|
+
spacing: { after: 400 },
|
|
221
|
+
}),
|
|
222
|
+
];
|
|
223
|
+
// Executive Summary
|
|
224
|
+
children.push(new Paragraph({
|
|
225
|
+
text: "Executive Summary",
|
|
226
|
+
heading: HeadingLevel.HEADING_1,
|
|
227
|
+
}));
|
|
228
|
+
const severityCount = this.getSeverityCount(vulnerabilities);
|
|
229
|
+
children.push(new Paragraph({
|
|
230
|
+
children: [
|
|
231
|
+
new TextRun({
|
|
232
|
+
text: `Total Vulnerabilities Found: ${vulnerabilities.length}`,
|
|
233
|
+
bold: true,
|
|
234
|
+
}),
|
|
235
|
+
],
|
|
236
|
+
spacing: { after: 200 },
|
|
237
|
+
}));
|
|
238
|
+
if (severityCount.critical > 0) {
|
|
239
|
+
children.push(new Paragraph({
|
|
240
|
+
text: `Critical: ${severityCount.critical}`,
|
|
241
|
+
spacing: { after: 100 },
|
|
242
|
+
}));
|
|
243
|
+
}
|
|
244
|
+
if (severityCount.high > 0) {
|
|
245
|
+
children.push(new Paragraph({
|
|
246
|
+
text: `High: ${severityCount.high}`,
|
|
247
|
+
spacing: { after: 100 },
|
|
248
|
+
}));
|
|
249
|
+
}
|
|
250
|
+
if (severityCount.medium > 0) {
|
|
251
|
+
children.push(new Paragraph({
|
|
252
|
+
text: `Medium: ${severityCount.medium}`,
|
|
253
|
+
spacing: { after: 100 },
|
|
254
|
+
}));
|
|
255
|
+
}
|
|
256
|
+
if (severityCount.low > 0) {
|
|
257
|
+
children.push(new Paragraph({
|
|
258
|
+
text: `Low: ${severityCount.low}`,
|
|
259
|
+
spacing: { after: 100 },
|
|
260
|
+
}));
|
|
261
|
+
}
|
|
262
|
+
// AI Analysis section
|
|
263
|
+
if (analysisFinding) {
|
|
264
|
+
children.push(new Paragraph({
|
|
265
|
+
text: "AI Analysis",
|
|
266
|
+
heading: HeadingLevel.HEADING_1,
|
|
267
|
+
spacing: { before: 400 },
|
|
268
|
+
}));
|
|
269
|
+
children.push(new Paragraph({
|
|
270
|
+
text: analysisFinding.description,
|
|
271
|
+
spacing: { after: 400 },
|
|
272
|
+
}));
|
|
273
|
+
}
|
|
274
|
+
// Detailed Findings
|
|
275
|
+
if (vulnerabilities.length > 0) {
|
|
276
|
+
children.push(new Paragraph({
|
|
277
|
+
text: "Detailed Findings",
|
|
278
|
+
heading: HeadingLevel.HEADING_1,
|
|
279
|
+
spacing: { before: 400 },
|
|
280
|
+
}));
|
|
281
|
+
vulnerabilities.forEach((vuln, index) => {
|
|
282
|
+
children.push(new Paragraph({
|
|
283
|
+
text: `${index + 1}. ${vuln.title}`,
|
|
284
|
+
heading: HeadingLevel.HEADING_2,
|
|
285
|
+
spacing: { before: 300 },
|
|
286
|
+
}));
|
|
287
|
+
children.push(new Paragraph({
|
|
288
|
+
children: [
|
|
289
|
+
new TextRun({ text: "Severity: ", bold: true }),
|
|
290
|
+
new TextRun({
|
|
291
|
+
text: vuln.severity.toUpperCase(),
|
|
292
|
+
color: this.getSeverityColor(vuln.severity),
|
|
293
|
+
}),
|
|
294
|
+
],
|
|
295
|
+
spacing: { after: 100 },
|
|
296
|
+
}));
|
|
297
|
+
children.push(new Paragraph({
|
|
298
|
+
text: vuln.description,
|
|
299
|
+
spacing: { after: 200 },
|
|
300
|
+
}));
|
|
301
|
+
if (vuln.evidence) {
|
|
302
|
+
children.push(new Paragraph({
|
|
303
|
+
children: [new TextRun({ text: "Evidence:", bold: true })],
|
|
304
|
+
spacing: { before: 100 },
|
|
305
|
+
}));
|
|
306
|
+
children.push(new Paragraph({
|
|
307
|
+
text: vuln.evidence,
|
|
308
|
+
spacing: { after: 200 },
|
|
309
|
+
}));
|
|
310
|
+
}
|
|
311
|
+
if (vuln.recommendation) {
|
|
312
|
+
children.push(new Paragraph({
|
|
313
|
+
children: [
|
|
314
|
+
new TextRun({ text: "Recommendation:", bold: true }),
|
|
315
|
+
],
|
|
316
|
+
spacing: { before: 100 },
|
|
317
|
+
}));
|
|
318
|
+
children.push(new Paragraph({
|
|
319
|
+
text: vuln.recommendation,
|
|
320
|
+
spacing: { after: 200 },
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
if (vuln.references && vuln.references.length > 0) {
|
|
324
|
+
children.push(new Paragraph({
|
|
325
|
+
children: [new TextRun({ text: "References:", bold: true })],
|
|
326
|
+
spacing: { before: 100 },
|
|
327
|
+
}));
|
|
328
|
+
vuln.references.forEach((ref) => {
|
|
329
|
+
children.push(new Paragraph({
|
|
330
|
+
text: ref,
|
|
331
|
+
spacing: { after: 100 },
|
|
332
|
+
}));
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
const doc = new Document({
|
|
338
|
+
sections: [
|
|
339
|
+
{
|
|
340
|
+
properties: {},
|
|
341
|
+
children,
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
});
|
|
345
|
+
const buffer = await docx.Packer.toBuffer(doc);
|
|
346
|
+
await fs.writeFile(outputPath, buffer);
|
|
347
|
+
}
|
|
348
|
+
async generateTxtReport(scanData, outputPath, includeAnalysis) {
|
|
349
|
+
const findings = scanData.findings || [];
|
|
350
|
+
const analysisFinding = includeAnalysis
|
|
351
|
+
? findings.find((f) => f.skillId === "analyze_findings")
|
|
352
|
+
: null;
|
|
353
|
+
const vulnerabilities = findings.filter((f) => f.skillId !== "analyze_findings");
|
|
354
|
+
let content = "SECURITY ASSESSMENT REPORT\n";
|
|
355
|
+
content += "=".repeat(50) + "\n\n";
|
|
356
|
+
content += `Target: ${scanData.target || "N/A"}\n`;
|
|
357
|
+
content += `Generated: ${new Date().toLocaleString()}\n\n`;
|
|
358
|
+
content += "EXECUTIVE SUMMARY\n";
|
|
359
|
+
content += "-".repeat(50) + "\n";
|
|
360
|
+
content += `Total Vulnerabilities Found: ${vulnerabilities.length}\n`;
|
|
361
|
+
const severityCount = this.getSeverityCount(vulnerabilities);
|
|
362
|
+
if (severityCount.critical > 0)
|
|
363
|
+
content += `Critical: ${severityCount.critical}\n`;
|
|
364
|
+
if (severityCount.high > 0)
|
|
365
|
+
content += `High: ${severityCount.high}\n`;
|
|
366
|
+
if (severityCount.medium > 0)
|
|
367
|
+
content += `Medium: ${severityCount.medium}\n`;
|
|
368
|
+
if (severityCount.low > 0)
|
|
369
|
+
content += `Low: ${severityCount.low}\n`;
|
|
370
|
+
content += "\n";
|
|
371
|
+
if (analysisFinding) {
|
|
372
|
+
content += "AI ANALYSIS\n";
|
|
373
|
+
content += "-".repeat(50) + "\n";
|
|
374
|
+
content += analysisFinding.description + "\n\n";
|
|
375
|
+
}
|
|
376
|
+
if (vulnerabilities.length > 0) {
|
|
377
|
+
content += "DETAILED FINDINGS\n";
|
|
378
|
+
content += "-".repeat(50) + "\n\n";
|
|
379
|
+
vulnerabilities.forEach((vuln, index) => {
|
|
380
|
+
content += `${index + 1}. ${vuln.title}\n`;
|
|
381
|
+
content += ` Severity: ${vuln.severity.toUpperCase()}\n`;
|
|
382
|
+
content += ` Description: ${vuln.description}\n`;
|
|
383
|
+
if (vuln.evidence) {
|
|
384
|
+
content += ` Evidence: ${vuln.evidence}\n`;
|
|
385
|
+
}
|
|
386
|
+
if (vuln.recommendation) {
|
|
387
|
+
content += ` Recommendation: ${vuln.recommendation}\n`;
|
|
388
|
+
}
|
|
389
|
+
if (vuln.references && vuln.references.length > 0) {
|
|
390
|
+
content += ` References:\n`;
|
|
391
|
+
vuln.references.forEach((ref) => {
|
|
392
|
+
content += ` - ${ref}\n`;
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
content += "\n";
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
await fs.writeFile(outputPath, content);
|
|
399
|
+
}
|
|
400
|
+
async generateJsonReport(scanData, outputPath) {
|
|
401
|
+
const report = {
|
|
402
|
+
generatedAt: new Date().toISOString(),
|
|
403
|
+
target: scanData.target,
|
|
404
|
+
scanTimestamp: scanData.timestamp,
|
|
405
|
+
metadata: scanData.metadata,
|
|
406
|
+
findings: scanData.findings,
|
|
407
|
+
};
|
|
408
|
+
await fs.writeFile(outputPath, JSON.stringify(report, null, 2));
|
|
409
|
+
}
|
|
410
|
+
getSeverityCount(findings) {
|
|
411
|
+
return {
|
|
412
|
+
critical: findings.filter((f) => f.severity === "critical").length,
|
|
413
|
+
high: findings.filter((f) => f.severity === "high").length,
|
|
414
|
+
medium: findings.filter((f) => f.severity === "medium").length,
|
|
415
|
+
low: findings.filter((f) => f.severity === "low").length,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
getSeverityColor(severity) {
|
|
419
|
+
switch (severity) {
|
|
420
|
+
case "critical":
|
|
421
|
+
return "FF0000";
|
|
422
|
+
case "high":
|
|
423
|
+
return "FF4500";
|
|
424
|
+
case "medium":
|
|
425
|
+
return "FFA500";
|
|
426
|
+
case "low":
|
|
427
|
+
return "FFD700";
|
|
428
|
+
default:
|
|
429
|
+
return "808080";
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async run() {
|
|
433
|
+
throw new Error("Use execute() method with AgentContext for generate report skill");
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
exports.GenerateReportSkill = GenerateReportSkill;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Check Skill
|
|
3
|
+
* Verifies system configuration, dependencies, and environment setup
|
|
4
|
+
*/
|
|
5
|
+
import { AgentSkill, ToolDefinition, AgentContext, SkillResult } from "../types";
|
|
6
|
+
export declare class HealthCheckSkill implements AgentSkill {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
tags: string[];
|
|
11
|
+
requiresConfirmation: boolean;
|
|
12
|
+
riskLevel: "low";
|
|
13
|
+
estimatedDuration: number;
|
|
14
|
+
toolDefinition: ToolDefinition;
|
|
15
|
+
validateParameters(params: Record<string, unknown>): {
|
|
16
|
+
valid: boolean;
|
|
17
|
+
errors: string[];
|
|
18
|
+
};
|
|
19
|
+
execute(params: Record<string, unknown>, context: AgentContext): Promise<SkillResult>;
|
|
20
|
+
private checkNodeVersion;
|
|
21
|
+
private checkConfiguration;
|
|
22
|
+
private checkAIProvider;
|
|
23
|
+
private checkDependencies;
|
|
24
|
+
private checkDirectories;
|
|
25
|
+
private createFinding;
|
|
26
|
+
private getRecommendation;
|
|
27
|
+
run(): Promise<SkillResult>;
|
|
28
|
+
}
|