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,202 @@
1
+ "use strict";
2
+ /**
3
+ * Skill Registry and Execution System
4
+ * Manages AI-callable security skills with validation, confirmation, and execution
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.skillRegistry = exports.SkillRegistry = void 0;
8
+ const logger_1 = require("../utils/logger");
9
+ class SkillRegistry {
10
+ skills = new Map();
11
+ executionHistory = [];
12
+ /**
13
+ * Register a skill with the registry
14
+ */
15
+ register(skill) {
16
+ if (this.skills.has(skill.id)) {
17
+ logger_1.logger.warn(`Skill ${skill.id} is already registered. Overwriting.`);
18
+ }
19
+ this.skills.set(skill.id, skill);
20
+ logger_1.logger.debug(`Registered skill: ${skill.id}`);
21
+ }
22
+ /**
23
+ * Unregister a skill
24
+ */
25
+ unregister(skillId) {
26
+ return this.skills.delete(skillId);
27
+ }
28
+ /**
29
+ * Get a skill by ID
30
+ */
31
+ get(skillId) {
32
+ return this.skills.get(skillId);
33
+ }
34
+ /**
35
+ * Get all registered skills
36
+ */
37
+ getAll() {
38
+ return Array.from(this.skills.values());
39
+ }
40
+ /**
41
+ * Get all tool definitions for AI function calling
42
+ */
43
+ getToolDefinitions() {
44
+ return this.getAll().map((skill) => skill.toolDefinition);
45
+ }
46
+ /**
47
+ * Validate tool call parameters
48
+ */
49
+ validateToolCall(toolCall) {
50
+ const skill = this.get(toolCall.name);
51
+ if (!skill) {
52
+ return {
53
+ valid: false,
54
+ errors: [`Unknown skill: ${toolCall.name}`],
55
+ };
56
+ }
57
+ return skill.validateParameters(toolCall.arguments);
58
+ }
59
+ /**
60
+ * Check if a tool call requires confirmation
61
+ */
62
+ requiresConfirmation(toolName) {
63
+ const skill = this.get(toolName);
64
+ if (!skill)
65
+ return false;
66
+ return skill.requiresConfirmation;
67
+ }
68
+ /**
69
+ * Get confirmation prompt for a tool call
70
+ */
71
+ getConfirmationPrompt(toolCall) {
72
+ const skill = this.get(toolCall.name);
73
+ if (!skill)
74
+ return null;
75
+ return {
76
+ action: skill.name,
77
+ description: skill.description,
78
+ parameters: toolCall.arguments,
79
+ risk: skill.riskLevel,
80
+ estimatedTime: this.formatDuration(skill.estimatedDuration),
81
+ };
82
+ }
83
+ /**
84
+ * Execute a skill by tool call
85
+ */
86
+ async execute(toolCall, context) {
87
+ const skill = this.get(toolCall.name);
88
+ if (!skill) {
89
+ return {
90
+ toolCallId: toolCall.id,
91
+ success: false,
92
+ error: `Unknown skill: ${toolCall.name}`,
93
+ executionTime: 0,
94
+ };
95
+ }
96
+ // Validate parameters
97
+ const validation = skill.validateParameters(toolCall.arguments);
98
+ if (!validation.valid) {
99
+ return {
100
+ toolCallId: toolCall.id,
101
+ success: false,
102
+ error: `Validation failed: ${validation.errors.join(", ")}`,
103
+ executionTime: 0,
104
+ };
105
+ }
106
+ const startTime = Date.now();
107
+ let result;
108
+ let success = false;
109
+ let error;
110
+ try {
111
+ logger_1.logger.info(`Executing skill: ${skill.id}`);
112
+ result = await skill.execute(toolCall.arguments, context);
113
+ success = true;
114
+ logger_1.logger.success(`Skill ${skill.id} completed successfully`);
115
+ }
116
+ catch (err) {
117
+ error = err instanceof Error ? err.message : String(err);
118
+ logger_1.logger.error(`Skill ${skill.id} failed: ${error}`);
119
+ result = {
120
+ skillId: skill.id,
121
+ findings: [],
122
+ metadata: { error },
123
+ };
124
+ }
125
+ const executionTime = Date.now() - startTime;
126
+ // Record execution history
127
+ this.executionHistory.push({
128
+ timestamp: new Date(),
129
+ skillName: skill.id,
130
+ success,
131
+ duration: executionTime,
132
+ });
133
+ return {
134
+ toolCallId: toolCall.id,
135
+ success,
136
+ result,
137
+ error,
138
+ executionTime,
139
+ };
140
+ }
141
+ /**
142
+ * Execute multiple skills in parallel
143
+ */
144
+ async executeBatch(toolCalls, context) {
145
+ const promises = toolCalls.map((call) => this.execute(call, context));
146
+ return Promise.all(promises);
147
+ }
148
+ /**
149
+ * Get execution statistics
150
+ */
151
+ getStats() {
152
+ const total = this.executionHistory.length;
153
+ const successful = this.executionHistory.filter((e) => e.success).length;
154
+ const failed = total - successful;
155
+ const avgDuration = total > 0
156
+ ? this.executionHistory.reduce((sum, e) => sum + e.duration, 0) / total
157
+ : 0;
158
+ const skillUsage = {};
159
+ for (const entry of this.executionHistory) {
160
+ skillUsage[entry.skillName] = (skillUsage[entry.skillName] || 0) + 1;
161
+ }
162
+ return {
163
+ totalExecutions: total,
164
+ successfulExecutions: successful,
165
+ failedExecutions: failed,
166
+ averageDuration: Math.round(avgDuration),
167
+ skillUsage,
168
+ };
169
+ }
170
+ /**
171
+ * Clear execution history
172
+ */
173
+ clearHistory() {
174
+ this.executionHistory = [];
175
+ }
176
+ /**
177
+ * List available skills with descriptions
178
+ */
179
+ listSkills() {
180
+ return this.getAll().map((skill) => ({
181
+ id: skill.id,
182
+ name: skill.name,
183
+ description: skill.description,
184
+ risk: skill.riskLevel,
185
+ requiresConfirmation: skill.requiresConfirmation,
186
+ }));
187
+ }
188
+ formatDuration(seconds) {
189
+ if (seconds < 60) {
190
+ return `${seconds}s`;
191
+ }
192
+ const minutes = Math.floor(seconds / 60);
193
+ const remainingSeconds = seconds % 60;
194
+ if (remainingSeconds === 0) {
195
+ return `${minutes}m`;
196
+ }
197
+ return `${minutes}m ${remainingSeconds}s`;
198
+ }
199
+ }
200
+ exports.SkillRegistry = SkillRegistry;
201
+ // Global skill registry instance
202
+ exports.skillRegistry = new SkillRegistry();
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Analyze Findings Skill
3
+ * AI-powered analysis of security scan results with remediation recommendations
4
+ */
5
+ import { AgentSkill, ToolDefinition, AgentContext, SkillResult } from "../types";
6
+ export declare class AnalyzeFindingsSkill 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 buildAnalysisPrompt;
21
+ run(): Promise<SkillResult>;
22
+ }
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ /**
3
+ * Analyze Findings Skill
4
+ * AI-powered analysis of security scan results with remediation recommendations
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.AnalyzeFindingsSkill = void 0;
8
+ const ai_client_1 = require("../../core/ai-client");
9
+ const logger_1 = require("../../utils/logger");
10
+ class AnalyzeFindingsSkill {
11
+ id = "analyze_findings";
12
+ name = "Analyze Findings";
13
+ description = "Uses AI to analyze security scan results and provide expert insights, risk assessment, and remediation recommendations.";
14
+ tags = ["analysis", "ai", "reporting", "recommendations"];
15
+ requiresConfirmation = false;
16
+ riskLevel = "low";
17
+ estimatedDuration = 15; // seconds
18
+ toolDefinition = {
19
+ name: "analyze_findings",
20
+ description: "Analyze security scan findings using AI to provide expert insights and remediation recommendations",
21
+ parameters: [
22
+ {
23
+ name: "useLastScan",
24
+ type: "boolean",
25
+ description: "Use results from the most recent scan. If true, scanResults parameter is optional.",
26
+ required: false,
27
+ default: true,
28
+ },
29
+ {
30
+ name: "scanResults",
31
+ type: "object",
32
+ description: "Scan results to analyze (if not using last scan). Must contain findings array.",
33
+ required: false,
34
+ },
35
+ {
36
+ name: "focus",
37
+ type: "string",
38
+ description: "Optional focus area for analysis: 'executive', 'technical', 'remediation', or 'all'",
39
+ required: false,
40
+ default: "all",
41
+ enum: ["executive", "technical", "remediation", "all"],
42
+ },
43
+ ],
44
+ };
45
+ validateParameters(params) {
46
+ const errors = [];
47
+ // If not using last scan, must provide scanResults
48
+ if (params.useLastScan === false && !params.scanResults) {
49
+ errors.push("scanResults is required when useLastScan is false");
50
+ }
51
+ // Validate focus if provided
52
+ if (params.focus) {
53
+ const validFocus = ["executive", "technical", "remediation", "all"];
54
+ if (!validFocus.includes(params.focus)) {
55
+ errors.push(`focus must be one of: ${validFocus.join(", ")}`);
56
+ }
57
+ }
58
+ return {
59
+ valid: errors.length === 0,
60
+ errors,
61
+ };
62
+ }
63
+ async execute(params, context) {
64
+ const useLastScan = params.useLastScan ?? true;
65
+ const focus = params.focus ?? "all";
66
+ let scanData;
67
+ // Get scan data
68
+ if (useLastScan) {
69
+ const lastResults = context.lastScanResults;
70
+ if (!lastResults) {
71
+ return {
72
+ skillId: this.id,
73
+ findings: [],
74
+ metadata: {
75
+ error: "No previous scan results found. Please run a scan first.",
76
+ },
77
+ };
78
+ }
79
+ scanData = lastResults;
80
+ }
81
+ else {
82
+ scanData = params.scanResults;
83
+ }
84
+ if (!scanData.findings || scanData.findings.length === 0) {
85
+ return {
86
+ skillId: this.id,
87
+ findings: [],
88
+ metadata: {
89
+ message: "No vulnerabilities to analyze.",
90
+ target: scanData.target,
91
+ },
92
+ };
93
+ }
94
+ logger_1.logger.info(`Analyzing ${scanData.findings.length} findings with focus: ${focus}`);
95
+ try {
96
+ const aiClient = await (0, ai_client_1.createAIClient)();
97
+ const prompt = this.buildAnalysisPrompt(scanData, focus);
98
+ const response = await aiClient.analyze(prompt);
99
+ // Create a finding for the analysis itself
100
+ const analysisFinding = {
101
+ id: `analysis-${Date.now()}`,
102
+ skillId: this.id,
103
+ title: "AI Security Analysis",
104
+ severity: "info",
105
+ description: response.content,
106
+ metadata: {
107
+ focus,
108
+ target: scanData.target,
109
+ timestamp: new Date().toISOString(),
110
+ totalFindings: scanData.findings.length,
111
+ tokensUsed: response.usage,
112
+ },
113
+ };
114
+ logger_1.logger.success("Analysis complete");
115
+ return {
116
+ skillId: this.id,
117
+ findings: [analysisFinding],
118
+ metadata: {
119
+ target: scanData.target,
120
+ focus,
121
+ totalFindings: scanData.findings.length,
122
+ tokensUsed: response.usage,
123
+ timestamp: new Date().toISOString(),
124
+ },
125
+ };
126
+ }
127
+ catch (error) {
128
+ const errorMessage = error instanceof Error ? error.message : String(error);
129
+ logger_1.logger.error(`Analysis failed: ${errorMessage}`);
130
+ return {
131
+ skillId: this.id,
132
+ findings: [],
133
+ metadata: {
134
+ error: errorMessage,
135
+ target: scanData.target,
136
+ },
137
+ };
138
+ }
139
+ }
140
+ buildAnalysisPrompt(scanData, focus) {
141
+ const vulnList = scanData.findings
142
+ .map((f, i) => `${i + 1}. [${f.severity.toUpperCase()}] ${f.title}
143
+ Description: ${f.description}
144
+ ${f.evidence ? `Evidence: ${f.evidence}` : ""}
145
+ ${f.recommendation ? `Current recommendation: ${f.recommendation}` : ""}
146
+ ${f.metadata?.cwe ? `CWE: ${f.metadata.cwe}` : ""}`)
147
+ .join("\n\n");
148
+ let focusInstructions = "";
149
+ switch (focus) {
150
+ case "executive":
151
+ focusInstructions =
152
+ "Focus on business impact and high-level recommendations. Keep technical details minimal.";
153
+ break;
154
+ case "technical":
155
+ focusInstructions =
156
+ "Provide detailed technical analysis including root causes and specific code/configuration fixes.";
157
+ break;
158
+ case "remediation":
159
+ focusInstructions =
160
+ "Focus primarily on step-by-step remediation actions and prioritization.";
161
+ break;
162
+ default:
163
+ focusInstructions =
164
+ "Provide comprehensive analysis covering all aspects.";
165
+ }
166
+ return `You are a senior security analyst reviewing web application vulnerabilities.
167
+
168
+ Target: ${scanData.target || "Unknown"}
169
+ Scan Date: ${scanData.timestamp || new Date().toISOString()}
170
+ Total Vulnerabilities: ${scanData.findings.length}
171
+
172
+ Vulnerabilities Found:
173
+ ${vulnList}
174
+
175
+ Please provide a detailed analysis:
176
+
177
+ 1. **Executive Summary**: Brief overview of security posture and business risk
178
+ 2. **Risk Assessment**: Overall risk level with justification
179
+ 3. **Prioritized Recommendations**: Top 3-5 issues to fix first with specific actions
180
+ 4. **Attack Scenarios**: How vulnerabilities could be chained or exploited
181
+ 5. **Remediation Roadmap**: Step-by-step plan with effort estimates
182
+
183
+ ${focusInstructions}
184
+
185
+ Format in clear markdown with headers and bullet points.`;
186
+ }
187
+ async run() {
188
+ throw new Error("Use execute() method with AgentContext for analyze findings skill");
189
+ }
190
+ }
191
+ exports.AnalyzeFindingsSkill = AnalyzeFindingsSkill;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Generate Report Skill
3
+ * Creates professional security reports in multiple formats (DOCX, TXT, JSON)
4
+ */
5
+ import { AgentSkill, ToolDefinition, AgentContext, SkillResult } from "../types";
6
+ export declare class GenerateReportSkill 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 generateDocxReport;
21
+ private generateTxtReport;
22
+ private generateJsonReport;
23
+ private getSeverityCount;
24
+ private getSeverityColor;
25
+ run(): Promise<SkillResult>;
26
+ }