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.
Files changed (105) hide show
  1. package/README.md +392 -87
  2. package/dist/agent/confirmation.d.ts +38 -0
  3. package/dist/agent/confirmation.js +210 -0
  4. package/dist/agent/context.d.ts +81 -0
  5. package/dist/agent/context.js +227 -0
  6. package/dist/agent/index.d.ts +10 -0
  7. package/dist/agent/index.js +32 -0
  8. package/dist/agent/orchestrator.d.ts +63 -0
  9. package/dist/agent/orchestrator.js +370 -0
  10. package/dist/agent/prompts/system.d.ts +6 -0
  11. package/dist/agent/prompts/system.js +116 -0
  12. package/dist/agent/skill-registry.d.ts +78 -0
  13. package/dist/agent/skill-registry.js +202 -0
  14. package/dist/agent/skills/analyze-findings.d.ts +22 -0
  15. package/dist/agent/skills/analyze-findings.js +191 -0
  16. package/dist/agent/skills/generate-report.d.ts +26 -0
  17. package/dist/agent/skills/generate-report.js +436 -0
  18. package/dist/agent/skills/health-check.d.ts +28 -0
  19. package/dist/agent/skills/health-check.js +344 -0
  20. package/dist/agent/skills/index.d.ts +9 -0
  21. package/dist/agent/skills/index.js +17 -0
  22. package/dist/agent/skills/verify-finding.d.ts +17 -0
  23. package/dist/agent/skills/verify-finding.js +91 -0
  24. package/dist/agent/skills/web-scan.d.ts +22 -0
  25. package/dist/agent/skills/web-scan.js +203 -0
  26. package/dist/agent/types.d.ts +141 -0
  27. package/dist/agent/types.js +16 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.js +176 -139
  30. package/dist/commands/agent.d.ts +6 -0
  31. package/dist/commands/agent.js +250 -0
  32. package/dist/commands/ai.d.ts +2 -0
  33. package/dist/commands/ai.js +112 -0
  34. package/dist/commands/analyze.js +104 -55
  35. package/dist/commands/config.js +63 -37
  36. package/dist/commands/doctor.js +22 -17
  37. package/dist/commands/onboard.js +190 -125
  38. package/dist/commands/report.js +69 -77
  39. package/dist/commands/scan.js +261 -81
  40. package/dist/commands/scans.d.ts +2 -0
  41. package/dist/commands/scans.js +51 -0
  42. package/dist/core/ai-client.d.ts +7 -2
  43. package/dist/core/ai-client.js +231 -20
  44. package/dist/core/ai-payloads.d.ts +17 -0
  45. package/dist/core/ai-payloads.js +54 -0
  46. package/dist/core/config-schema.d.ts +197 -0
  47. package/dist/core/config-schema.js +68 -0
  48. package/dist/core/config-schema.test.d.ts +1 -0
  49. package/dist/core/config-schema.test.js +151 -0
  50. package/dist/core/config.d.ts +17 -36
  51. package/dist/core/config.js +261 -20
  52. package/dist/core/errors.d.ts +71 -0
  53. package/dist/core/errors.js +162 -0
  54. package/dist/core/scan-index.d.ts +19 -0
  55. package/dist/core/scan-index.js +52 -0
  56. package/dist/core/scan-storage.d.ts +11 -0
  57. package/dist/core/scan-storage.js +69 -0
  58. package/dist/core/scanner.d.ts +101 -4
  59. package/dist/core/scanner.js +432 -63
  60. package/dist/core/vulnerability-detector.d.ts +18 -2
  61. package/dist/core/vulnerability-detector.js +349 -38
  62. package/dist/core/vulnerability-detector.test.d.ts +1 -0
  63. package/dist/core/vulnerability-detector.test.js +210 -0
  64. package/dist/index.js +3 -0
  65. package/dist/plugins/PluginManager.d.ts +27 -0
  66. package/dist/plugins/PluginManager.js +166 -0
  67. package/dist/plugins/index.d.ts +7 -0
  68. package/dist/plugins/index.js +19 -0
  69. package/dist/plugins/types.d.ts +55 -0
  70. package/dist/plugins/types.js +25 -0
  71. package/dist/plugins/vulnerabilities/CSRFPlugin.d.ts +8 -0
  72. package/dist/plugins/vulnerabilities/CSRFPlugin.js +34 -0
  73. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.d.ts +11 -0
  74. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.js +109 -0
  75. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.d.ts +11 -0
  76. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.js +63 -0
  77. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.d.ts +9 -0
  78. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.js +32 -0
  79. package/dist/plugins/vulnerabilities/XSSPlugin.d.ts +15 -0
  80. package/dist/plugins/vulnerabilities/XSSPlugin.js +81 -0
  81. package/dist/reports/PdfGenerator.d.ts +36 -0
  82. package/dist/reports/PdfGenerator.js +379 -0
  83. package/dist/utils/logger.d.ts +33 -1
  84. package/dist/utils/logger.js +127 -8
  85. package/dist/utils/theme.d.ts +55 -0
  86. package/dist/utils/theme.js +195 -0
  87. package/package.json +27 -6
  88. package/dist/core/executor.d.ts +0 -2
  89. package/dist/core/executor.js +0 -74
  90. package/dist/core/logger.d.ts +0 -12
  91. package/dist/core/logger.js +0 -51
  92. package/dist/core/registry.d.ts +0 -3
  93. package/dist/core/registry.js +0 -35
  94. package/dist/core/storage.d.ts +0 -4
  95. package/dist/core/storage.js +0 -39
  96. package/dist/core/types.d.ts +0 -24
  97. package/dist/core/types.js +0 -2
  98. package/dist/skills/base.d.ts +0 -8
  99. package/dist/skills/base.js +0 -6
  100. package/dist/skills/builtin.d.ts +0 -4
  101. package/dist/skills/builtin.js +0 -71
  102. package/dist/skills/loader.d.ts +0 -2
  103. package/dist/skills/loader.js +0 -27
  104. package/dist/skills/types.d.ts +0 -46
  105. 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
+ }