claudify-agent 1.0.0 → 1.0.2
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/.claude/QUICK-REFERENCE.md +213 -213
- package/.claude/cost-dashboard.md +162 -162
- package/.claude/docs/COST-OPTIMIZATION.md +402 -403
- package/.claude/docs/MCP-INTEGRATION-GUIDE.md +348 -348
- package/.claude/docs/PLAN-MODE-OPTIMIZATION.md +835 -836
- package/.claude/hooks/auto-learning-review.ts +200 -195
- package/.claude/hooks/auto-lint-fix.ts +60 -104
- package/.claude/hooks/auto-security-review.ts +314 -354
- package/.claude/hooks/auto-validate.ts +249 -348
- package/.claude/hooks/lib/claude-hook.ts +168 -0
- package/.claude/hooks/plan-quality-tracker.ts +598 -719
- package/.claude/rules/anti-patterns.md +22 -22
- package/.claude/rules/context-tier-1.md +41 -41
- package/.claude/rules/context-tier-2.md +285 -285
- package/.claude/rules/general.md +25 -25
- package/.claude/rules/mcp-auto-use.md +46 -46
- package/.claude/rules/parallel-exploration-auto.md +30 -31
- package/.claude/rules/plan-mode-execution.md +289 -289
- package/.claude/rules/plan-mode-research.md +34 -34
- package/.claude/rules/plan-mode-structure.md +166 -166
- package/.claude/rules/plan-mode-validation.md +129 -130
- package/.claude/rules/security-critical.md +19 -19
- package/.claude/rules/tool-auto-selection.md +45 -45
- package/.claude/rules/tool-strategy.md +22 -22
- package/.claude/scripts/security-scan.js +1 -1
- package/.claude/security-dashboard.md +142 -142
- package/.claude/settings.json +50 -0
- package/.claude/skills/debug-optimizer/SKILL.md +420 -399
- package/.claude/skills/learning-loop/SKILL.md +313 -308
- package/.claude/skills/mcp-mastery/SKILL.md +218 -214
- package/.claude/skills/nextjs-guide/SKILL.md +687 -687
- package/.claude/skills/parallel-exploration/SKILL.md +197 -193
- package/.claude/skills/plan-mode-mastery/SKILL.md +268 -263
- package/.claude/skills/python-guide/SKILL.md +822 -822
- package/.claude/skills/react-guide/SKILL.md +762 -762
- package/.claude/skills/{security.md → security-guide/SKILL.md} +10 -0
- package/.claude/skills/solidity-guide/SKILL.md +5 -0
- package/.claude/skills/tool-selection/SKILL.md +433 -428
- package/.claude/skills/vite-guide/SKILL.md +445 -445
- package/CLAUDE.md +1 -0
- package/README.md +74 -35
- package/README.vi.md +106 -0
- package/bin/cli.js +13 -4
- package/package.json +9 -1
- package/.claude/skills/debug-optimizer.md +0 -12
- package/.claude/skills/nextjs.md +0 -13
- package/.claude/skills/react.md +0 -12
|
@@ -1,354 +1,314 @@
|
|
|
1
|
-
// .
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
5
|
-
import { join } from "path";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface SecurityFinding {
|
|
16
|
-
severity: "critical" | "high" | "medium" | "low";
|
|
17
|
-
type: string;
|
|
18
|
-
description: string;
|
|
19
|
-
location?: string;
|
|
20
|
-
suggestion: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
`).join('\n')}
|
|
316
|
-
|
|
317
|
-
## Security Checklist (OWASP Top 10)
|
|
318
|
-
|
|
319
|
-
- [ ] All user input validated and sanitized
|
|
320
|
-
- [ ] SQL injection prevented (parameterized queries)
|
|
321
|
-
- [ ] XSS prevented (escaping/sanitization)
|
|
322
|
-
- [ ] Authentication/authorization verified
|
|
323
|
-
- [ ] No hardcoded credentials or secrets
|
|
324
|
-
- [ ] Error handling doesn't leak sensitive info
|
|
325
|
-
- [ ] Rate limiting on auth endpoints
|
|
326
|
-
- [ ] Secure random number generation used
|
|
327
|
-
- [ ] Strong cryptographic algorithms used
|
|
328
|
-
- [ ] File paths validated and normalized
|
|
329
|
-
|
|
330
|
-
## Next Steps
|
|
331
|
-
|
|
332
|
-
${criticalCount > 0 ? '🚨 CRITICAL issues found! Address immediately before deployment.' :
|
|
333
|
-
highCount > 0 ? '⚠️ HIGH severity issues found. Review and fix before production.' :
|
|
334
|
-
mediumCount > 0 ? '📋 Medium severity issues found. Schedule for next sprint.' :
|
|
335
|
-
lowCount > 0 ? '💡 Low severity issues found. Consider fixing for best practices.' :
|
|
336
|
-
'✅ No security issues detected at current threshold.'}
|
|
337
|
-
`;
|
|
338
|
-
|
|
339
|
-
writeFileSync(reportPath, securityReport);
|
|
340
|
-
console.error(`[Security Review] Report saved to ${reportPath}`);
|
|
341
|
-
|
|
342
|
-
// Provide feedback to user
|
|
343
|
-
if (criticalCount > 0 || highCount > 0) {
|
|
344
|
-
const output = {
|
|
345
|
-
followup_message: `🚨 Security scan found ${criticalCount} critical and ${highCount} high severity issues. See \`.cursor/security-report.md\` for details.`,
|
|
346
|
-
};
|
|
347
|
-
console.log(JSON.stringify(output));
|
|
348
|
-
} else if (filteredFindings.length > 0) {
|
|
349
|
-
console.error(`[Security Review] ⚠️ Found ${filteredFindings.length} security finding(s). Report saved.`);
|
|
350
|
-
console.log(JSON.stringify({}));
|
|
351
|
-
} else {
|
|
352
|
-
console.error("[Security Review] ✓ No security issues found");
|
|
353
|
-
console.log(JSON.stringify({}));
|
|
354
|
-
}
|
|
1
|
+
// .claude/hooks/auto-security-review.ts
|
|
2
|
+
// Stop hook — scans code Claude wrote this turn for security vulnerabilities
|
|
3
|
+
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import {
|
|
7
|
+
readHookInput,
|
|
8
|
+
loadCurrentTurn,
|
|
9
|
+
writtenCode,
|
|
10
|
+
stateDir,
|
|
11
|
+
blockOrNotify,
|
|
12
|
+
done,
|
|
13
|
+
} from "./lib/claude-hook.ts";
|
|
14
|
+
|
|
15
|
+
interface SecurityFinding {
|
|
16
|
+
severity: "critical" | "high" | "medium" | "low";
|
|
17
|
+
type: string;
|
|
18
|
+
description: string;
|
|
19
|
+
location?: string;
|
|
20
|
+
suggestion: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Security settings live under "validation" in .claude/hooks.config.json
|
|
24
|
+
interface SecurityConfig {
|
|
25
|
+
validation?: {
|
|
26
|
+
enableSecurityReview?: boolean;
|
|
27
|
+
securitySeverityThreshold?: "critical" | "high" | "medium" | "low";
|
|
28
|
+
securityScanPatterns?: {
|
|
29
|
+
hardcodedCredentials?: boolean;
|
|
30
|
+
sqlInjection?: boolean;
|
|
31
|
+
xss?: boolean;
|
|
32
|
+
insecureCrypto?: boolean;
|
|
33
|
+
pathTraversal?: boolean;
|
|
34
|
+
commandInjection?: boolean;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Security pattern definitions (OWASP Top 10 inspired)
|
|
40
|
+
const SECURITY_PATTERNS = {
|
|
41
|
+
hardcodedCredentials: [
|
|
42
|
+
{
|
|
43
|
+
pattern: /(password|passwd|pwd)\s*[=:]\s*["'][^"']+["']/gi,
|
|
44
|
+
type: "Hardcoded Password",
|
|
45
|
+
severity: "critical" as const,
|
|
46
|
+
suggestion: "Use environment variables or secure secret management (e.g., AWS Secrets Manager, Azure Key Vault)"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
pattern: /(api[_-]?key|apikey)\s*[=:]\s*["'][^"']+["']/gi,
|
|
50
|
+
type: "Hardcoded API Key",
|
|
51
|
+
severity: "critical" as const,
|
|
52
|
+
suggestion: "Store API keys in environment variables or secure vault"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
pattern: /(secret|token|auth)\s*[=:]\s*["'][^"']+["']/gi,
|
|
56
|
+
type: "Hardcoded Secret/Token",
|
|
57
|
+
severity: "critical" as const,
|
|
58
|
+
suggestion: "Use environment variables for secrets"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
pattern: /AWS[_A-Z]*KEY|AWS[_A-Z]*SECRET/gi,
|
|
62
|
+
type: "AWS Credentials",
|
|
63
|
+
severity: "critical" as const,
|
|
64
|
+
suggestion: "Use IAM roles or AWS Secrets Manager"
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
sqlInjection: [
|
|
68
|
+
{
|
|
69
|
+
pattern: /(execute|query|raw)\s*\(\s*`[^`]*\$\{[^}]+\}/gi,
|
|
70
|
+
type: "Potential SQL Injection",
|
|
71
|
+
severity: "critical" as const,
|
|
72
|
+
suggestion: "Use parameterized queries or ORM methods instead of string interpolation"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
pattern: /execute\s*\(\s*["'][^"']*["']\s*\+/gi,
|
|
76
|
+
type: "SQL String Concatenation",
|
|
77
|
+
severity: "critical" as const,
|
|
78
|
+
suggestion: "Use parameterized queries"
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
xss: [
|
|
82
|
+
{
|
|
83
|
+
pattern: /dangerouslySetInnerHTML\s*=/gi,
|
|
84
|
+
type: "Dangerous HTML Rendering",
|
|
85
|
+
severity: "high" as const,
|
|
86
|
+
suggestion: "Avoid dangerouslySetInnerHTML or sanitize input with DOMPurify"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
pattern: /innerHTML\s*=/gi,
|
|
90
|
+
type: "Inner HTML Assignment",
|
|
91
|
+
severity: "high" as const,
|
|
92
|
+
suggestion: "Use textContent or sanitize HTML before assignment"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
pattern: /eval\s*\(/gi,
|
|
96
|
+
type: "Eval Usage",
|
|
97
|
+
severity: "high" as const,
|
|
98
|
+
suggestion: "Avoid eval() - use safer alternatives"
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
insecureCrypto: [
|
|
102
|
+
{
|
|
103
|
+
pattern: /crypto\s*\.\s*createHash\s*\(\s*["']md5["']/gi,
|
|
104
|
+
type: "Weak Hash Algorithm (MD5)",
|
|
105
|
+
severity: "high" as const,
|
|
106
|
+
suggestion: "Use SHA-256 or stronger (crypto.createHash('sha256'))"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
pattern: /crypto\s*\.\s*createHash\s*\(\s*["']sha1["']/gi,
|
|
110
|
+
type: "Weak Hash Algorithm (SHA1)",
|
|
111
|
+
severity: "medium" as const,
|
|
112
|
+
suggestion: "Use SHA-256 or stronger for security-critical applications"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
pattern: /Math\.random\s*\(/gi,
|
|
116
|
+
type: "Insecure Random Number Generator",
|
|
117
|
+
severity: "medium" as const,
|
|
118
|
+
suggestion: "Use crypto.randomBytes() for security-sensitive randomness"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
pathTraversal: [
|
|
122
|
+
{
|
|
123
|
+
pattern: /fs\s*\.\s*(readFile|writeFile|appendFile)\s*\([^)]*\+/gi,
|
|
124
|
+
type: "Potential Path Traversal",
|
|
125
|
+
severity: "high" as const,
|
|
126
|
+
suggestion: "Validate and sanitize file paths, use path.resolve() and path.normalize()"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
pattern: /require\s*\(\s*[^)]*\+/gi,
|
|
130
|
+
type: "Dynamic Require with User Input",
|
|
131
|
+
severity: "high" as const,
|
|
132
|
+
suggestion: "Avoid dynamic require with user-controlled paths"
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
commandInjection: [
|
|
136
|
+
{
|
|
137
|
+
pattern: /exec\s*\(\s*`[^`]*\$\{[^}]+\}/gi,
|
|
138
|
+
type: "Command Injection via Template Literal",
|
|
139
|
+
severity: "critical" as const,
|
|
140
|
+
suggestion: "Avoid shell commands with user input, use execFile with arguments array"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
pattern: /spawn\s*\(\s*[^)]*\+/gi,
|
|
144
|
+
type: "Command Injection via String Concatenation",
|
|
145
|
+
severity: "critical" as const,
|
|
146
|
+
suggestion: "Use spawn with arguments array instead of string concatenation"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
pattern: /child_process\s*\.\s*exec\s*\(/gi,
|
|
150
|
+
type: "Unsafe exec Usage",
|
|
151
|
+
severity: "medium" as const,
|
|
152
|
+
suggestion: "Prefer execFile or spawn with argument separation"
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const input = await readHookInput();
|
|
158
|
+
|
|
159
|
+
// Load configuration
|
|
160
|
+
const configPath = join(stateDir(input), 'hooks.config.json');
|
|
161
|
+
const config: SecurityConfig = existsSync(configPath)
|
|
162
|
+
? JSON.parse(readFileSync(configPath, 'utf-8'))
|
|
163
|
+
: {};
|
|
164
|
+
|
|
165
|
+
const securityConfig = {
|
|
166
|
+
enableSecurityReview: config.validation?.enableSecurityReview !== false,
|
|
167
|
+
severityThreshold: config.validation?.securitySeverityThreshold || "high",
|
|
168
|
+
scanPatterns: config.validation?.securityScanPatterns || {
|
|
169
|
+
hardcodedCredentials: true,
|
|
170
|
+
sqlInjection: true,
|
|
171
|
+
xss: true,
|
|
172
|
+
insecureCrypto: true,
|
|
173
|
+
pathTraversal: true,
|
|
174
|
+
commandInjection: true
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
if (!securityConfig.enableSecurityReview) {
|
|
179
|
+
console.error("[Security Review] ⚠ Security review disabled in config");
|
|
180
|
+
done();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
console.error("[Security Review] Running automatic security scan...");
|
|
184
|
+
|
|
185
|
+
const findings: SecurityFinding[] = [];
|
|
186
|
+
|
|
187
|
+
// Scan the code Claude wrote (Write/Edit/MultiEdit) in this turn
|
|
188
|
+
const turn = loadCurrentTurn(input.transcript_path);
|
|
189
|
+
const codeToScan = turn ? writtenCode(turn.toolUses) : [];
|
|
190
|
+
|
|
191
|
+
// Scan code for security issues
|
|
192
|
+
function scanCodeForSecurity(code: string, file: string, patternCategory: string): SecurityFinding[] {
|
|
193
|
+
const categoryFindings: SecurityFinding[] = [];
|
|
194
|
+
const patterns = SECURITY_PATTERNS[patternCategory as keyof typeof SECURITY_PATTERNS];
|
|
195
|
+
|
|
196
|
+
if (!patterns || !securityConfig.scanPatterns[patternCategory as keyof typeof securityConfig.scanPatterns]) {
|
|
197
|
+
return categoryFindings;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (const { pattern, type, severity, suggestion } of patterns) {
|
|
201
|
+
const matches = code.match(pattern);
|
|
202
|
+
if (matches) {
|
|
203
|
+
categoryFindings.push({
|
|
204
|
+
severity,
|
|
205
|
+
type,
|
|
206
|
+
description: `Found ${matches.length} occurrence(s) of potentially insecure pattern`,
|
|
207
|
+
location: file,
|
|
208
|
+
suggestion
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return categoryFindings;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// If no code was written, skip scan
|
|
217
|
+
if (codeToScan.length === 0) {
|
|
218
|
+
console.error("[Security Review] ⚠ No code changes found to scan");
|
|
219
|
+
done();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Run security scans on each written chunk
|
|
223
|
+
const patternCategories = Object.keys(SECURITY_PATTERNS);
|
|
224
|
+
for (const { file, code } of codeToScan) {
|
|
225
|
+
for (const category of patternCategories) {
|
|
226
|
+
findings.push(...scanCodeForSecurity(code, file, category));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Filter by severity threshold
|
|
231
|
+
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
232
|
+
const thresholdLevel = severityOrder[securityConfig.severityThreshold];
|
|
233
|
+
|
|
234
|
+
const filteredFindings = findings.filter(
|
|
235
|
+
finding => severityOrder[finding.severity] <= thresholdLevel
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
// Generate security report
|
|
239
|
+
const criticalCount = filteredFindings.filter(f => f.severity === "critical").length;
|
|
240
|
+
const highCount = filteredFindings.filter(f => f.severity === "high").length;
|
|
241
|
+
const mediumCount = filteredFindings.filter(f => f.severity === "medium").length;
|
|
242
|
+
const lowCount = filteredFindings.filter(f => f.severity === "low").length;
|
|
243
|
+
|
|
244
|
+
const reportPath = join(stateDir(input), 'security-report.md');
|
|
245
|
+
|
|
246
|
+
const securityReport = `## Security Scan Report
|
|
247
|
+
|
|
248
|
+
Generated: ${new Date().toISOString()}
|
|
249
|
+
Session: ${input.session_id}
|
|
250
|
+
Severity Threshold: ${securityConfig.severityThreshold}
|
|
251
|
+
|
|
252
|
+
## Summary
|
|
253
|
+
|
|
254
|
+
- 🔴 Critical: ${criticalCount}
|
|
255
|
+
- 🟠 High: ${highCount}
|
|
256
|
+
- 🟡 Medium: ${mediumCount}
|
|
257
|
+
- 🟢 Low: ${lowCount}
|
|
258
|
+
- **Total Findings**: ${filteredFindings.length}
|
|
259
|
+
|
|
260
|
+
## Findings
|
|
261
|
+
|
|
262
|
+
${filteredFindings.length === 0 ? '✅ No security issues found!' : filteredFindings.map((finding, i) => `
|
|
263
|
+
### ${i + 1}. ${finding.type}
|
|
264
|
+
|
|
265
|
+
**Severity**: ${finding.severity.toUpperCase()}
|
|
266
|
+
|
|
267
|
+
**File**: ${finding.location || 'unknown'}
|
|
268
|
+
|
|
269
|
+
**Description**: ${finding.description}
|
|
270
|
+
|
|
271
|
+
**Recommendation**: ${finding.suggestion}
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
`).join('\n')}
|
|
275
|
+
|
|
276
|
+
## Security Checklist (OWASP Top 10)
|
|
277
|
+
|
|
278
|
+
- [ ] All user input validated and sanitized
|
|
279
|
+
- [ ] SQL injection prevented (parameterized queries)
|
|
280
|
+
- [ ] XSS prevented (escaping/sanitization)
|
|
281
|
+
- [ ] Authentication/authorization verified
|
|
282
|
+
- [ ] No hardcoded credentials or secrets
|
|
283
|
+
- [ ] Error handling doesn't leak sensitive info
|
|
284
|
+
- [ ] Rate limiting on auth endpoints
|
|
285
|
+
- [ ] Secure random number generation used
|
|
286
|
+
- [ ] Strong cryptographic algorithms used
|
|
287
|
+
- [ ] File paths validated and normalized
|
|
288
|
+
|
|
289
|
+
## Next Steps
|
|
290
|
+
|
|
291
|
+
${criticalCount > 0 ? '🚨 CRITICAL issues found! Address immediately before deployment.' :
|
|
292
|
+
highCount > 0 ? '⚠️ HIGH severity issues found. Review and fix before production.' :
|
|
293
|
+
mediumCount > 0 ? '📋 Medium severity issues found. Schedule for next sprint.' :
|
|
294
|
+
lowCount > 0 ? '💡 Low severity issues found. Consider fixing for best practices.' :
|
|
295
|
+
'✅ No security issues detected at current threshold.'}
|
|
296
|
+
`;
|
|
297
|
+
|
|
298
|
+
writeFileSync(reportPath, securityReport);
|
|
299
|
+
console.error(`[Security Review] Report saved to ${reportPath}`);
|
|
300
|
+
|
|
301
|
+
// Provide feedback to user
|
|
302
|
+
if (criticalCount > 0 || highCount > 0) {
|
|
303
|
+
const summary = filteredFindings
|
|
304
|
+
.filter(f => f.severity === "critical" || f.severity === "high")
|
|
305
|
+
.map(f => `- [${f.severity.toUpperCase()}] ${f.type} in ${f.location}: ${f.suggestion}`)
|
|
306
|
+
.join('\n');
|
|
307
|
+
blockOrNotify(input, `🚨 Security scan found ${criticalCount} critical and ${highCount} high severity issues. Review and fix them (or confirm they are false positives). Full report: ${reportPath}\n\n${summary}`);
|
|
308
|
+
} else if (filteredFindings.length > 0) {
|
|
309
|
+
console.error(`[Security Review] ⚠️ Found ${filteredFindings.length} security finding(s). Report saved.`);
|
|
310
|
+
done();
|
|
311
|
+
} else {
|
|
312
|
+
console.error("[Security Review] ✓ No security issues found");
|
|
313
|
+
done();
|
|
314
|
+
}
|