@indicated/vibeguard 1.4.0 → 1.5.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/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +247 -47
- package/dist/mcp/server.js.map +1 -1
- package/package.json +1 -1
- package/src/mcp/server.ts +289 -51
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAwQA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CA+OpD"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -38,6 +38,7 @@ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
|
38
38
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
39
39
|
const zod_1 = require("zod");
|
|
40
40
|
const path = __importStar(require("path"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
41
42
|
const scanner_1 = require("../scanner");
|
|
42
43
|
const definitions_1 = require("../scanner/rules/definitions");
|
|
43
44
|
const license_1 = require("../api/license");
|
|
@@ -58,13 +59,217 @@ function calculateGrade(counts) {
|
|
|
58
59
|
return 'A';
|
|
59
60
|
return 'A+';
|
|
60
61
|
}
|
|
62
|
+
function getCodeSnippet(filePath, line, contextLines = 3) {
|
|
63
|
+
try {
|
|
64
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
65
|
+
const lines = content.split('\n');
|
|
66
|
+
const startLine = Math.max(0, line - contextLines - 1);
|
|
67
|
+
const endLine = Math.min(lines.length, line + contextLines);
|
|
68
|
+
return lines.slice(startLine, endLine).map((l, i) => {
|
|
69
|
+
const lineNum = startLine + i + 1;
|
|
70
|
+
const marker = lineNum === line ? '→' : ' ';
|
|
71
|
+
return `${marker} ${lineNum.toString().padStart(4)}: ${l}`;
|
|
72
|
+
}).join('\n');
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return '(Could not read file)';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function analyzeContext(finding, cwd) {
|
|
79
|
+
const signals = [];
|
|
80
|
+
let confidence = 'high';
|
|
81
|
+
let question = '';
|
|
82
|
+
const filePath = finding.file;
|
|
83
|
+
const relativePath = path.relative(cwd, filePath).toLowerCase();
|
|
84
|
+
// Read file content for analysis
|
|
85
|
+
let fileContent = '';
|
|
86
|
+
try {
|
|
87
|
+
fileContent = fs.readFileSync(filePath, 'utf-8').toLowerCase();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Can't read file
|
|
91
|
+
}
|
|
92
|
+
// Analyze based on rule type
|
|
93
|
+
switch (finding.rule.id) {
|
|
94
|
+
case 'xss-innerhtml':
|
|
95
|
+
// Check for sanitizer imports
|
|
96
|
+
if (fileContent.includes('dompurify') || fileContent.includes('sanitize') ||
|
|
97
|
+
fileContent.includes('escapehtml') || fileContent.includes('escape-html')) {
|
|
98
|
+
signals.push({ signal: 'File imports sanitization library', type: 'positive' });
|
|
99
|
+
confidence = 'low';
|
|
100
|
+
}
|
|
101
|
+
// Check if it's static HTML
|
|
102
|
+
if (finding.code.includes("'<") || finding.code.includes('"<') || finding.code.includes('`<')) {
|
|
103
|
+
signals.push({ signal: 'Appears to be static HTML string', type: 'positive' });
|
|
104
|
+
confidence = 'low';
|
|
105
|
+
}
|
|
106
|
+
// Check for user input indicators
|
|
107
|
+
if (finding.code.includes('user') || finding.code.includes('input') ||
|
|
108
|
+
finding.code.includes('req.') || finding.code.includes('params')) {
|
|
109
|
+
signals.push({ signal: 'May contain user-controlled input', type: 'negative' });
|
|
110
|
+
confidence = 'high';
|
|
111
|
+
}
|
|
112
|
+
question = 'Is the data being inserted sanitized before this line? Check if escapeHtml() or similar is called on the variable.';
|
|
113
|
+
break;
|
|
114
|
+
case 'supabase-no-rls':
|
|
115
|
+
// Check if it's server-side
|
|
116
|
+
if (relativePath.includes('/api/') || relativePath.includes('/server/') ||
|
|
117
|
+
relativePath.includes('/routes/') || relativePath.includes('/backend/')) {
|
|
118
|
+
signals.push({ signal: 'File is in server-side directory', type: 'positive' });
|
|
119
|
+
confidence = 'low';
|
|
120
|
+
}
|
|
121
|
+
// Check for service role key
|
|
122
|
+
if (fileContent.includes('service_role') || fileContent.includes('servicerole') ||
|
|
123
|
+
fileContent.includes('supabase_service')) {
|
|
124
|
+
signals.push({ signal: 'Uses service role key (server-side pattern)', type: 'positive' });
|
|
125
|
+
confidence = 'low';
|
|
126
|
+
}
|
|
127
|
+
// Check for auth middleware
|
|
128
|
+
if (fileContent.includes('requireauth') || fileContent.includes('requireadmin') ||
|
|
129
|
+
fileContent.includes('middleware') || fileContent.includes('authenticate')) {
|
|
130
|
+
signals.push({ signal: 'File has authentication middleware', type: 'positive' });
|
|
131
|
+
confidence = 'low';
|
|
132
|
+
}
|
|
133
|
+
// Client-side indicators
|
|
134
|
+
if (relativePath.includes('/components/') || relativePath.includes('/pages/') ||
|
|
135
|
+
relativePath.includes('/app/') && !relativePath.includes('/api/')) {
|
|
136
|
+
signals.push({ signal: 'File appears to be client-side', type: 'negative' });
|
|
137
|
+
confidence = 'high';
|
|
138
|
+
}
|
|
139
|
+
question = 'Is this server-side code with proper auth middleware, or client-side code that should use RLS?';
|
|
140
|
+
break;
|
|
141
|
+
case 'secrets-localstorage':
|
|
142
|
+
// Check what's being stored
|
|
143
|
+
if (finding.code.includes('token') || finding.code.includes('jwt') ||
|
|
144
|
+
finding.code.includes('auth') || finding.code.includes('key')) {
|
|
145
|
+
signals.push({ signal: 'Storing authentication-related data', type: 'negative' });
|
|
146
|
+
confidence = 'high';
|
|
147
|
+
}
|
|
148
|
+
question = 'Is this storing actual auth tokens, or just non-sensitive data like UI preferences?';
|
|
149
|
+
break;
|
|
150
|
+
case 'ssrf-vulnerability':
|
|
151
|
+
// Check if URL is from env var
|
|
152
|
+
if (finding.code.includes('process.env') || finding.code.includes('env.')) {
|
|
153
|
+
signals.push({ signal: 'URL appears to come from environment variable', type: 'positive' });
|
|
154
|
+
confidence = 'low';
|
|
155
|
+
}
|
|
156
|
+
// Check for user input
|
|
157
|
+
if (finding.code.includes('req.') || finding.code.includes('body.') ||
|
|
158
|
+
finding.code.includes('params.') || finding.code.includes('query.')) {
|
|
159
|
+
signals.push({ signal: 'URL contains user-controlled input', type: 'negative' });
|
|
160
|
+
confidence = 'high';
|
|
161
|
+
}
|
|
162
|
+
question = 'Is the URL/host controlled by user input, or is it a fixed/environment-based URL?';
|
|
163
|
+
break;
|
|
164
|
+
case 'prototype-pollution':
|
|
165
|
+
// Check if it's just spread operator
|
|
166
|
+
if (finding.code.includes('...') && !finding.code.includes('merge')) {
|
|
167
|
+
signals.push({ signal: 'Uses spread operator (generally safe)', type: 'positive' });
|
|
168
|
+
confidence = 'low';
|
|
169
|
+
}
|
|
170
|
+
// Check for deep merge
|
|
171
|
+
if (finding.code.includes('merge') || finding.code.includes('deepmerge')) {
|
|
172
|
+
signals.push({ signal: 'Uses deep merge function', type: 'negative' });
|
|
173
|
+
confidence = 'high';
|
|
174
|
+
}
|
|
175
|
+
question = 'Is this using deep merge with user input, or just shallow spread/assign?';
|
|
176
|
+
break;
|
|
177
|
+
case 'missing-auth-route':
|
|
178
|
+
case 'nextjs-api-route-no-auth':
|
|
179
|
+
// Check for auth in file
|
|
180
|
+
if (fileContent.includes('getsession') || fileContent.includes('getserversession') ||
|
|
181
|
+
fileContent.includes('requireauth') || fileContent.includes('authenticate') ||
|
|
182
|
+
fileContent.includes('verifytoken') || fileContent.includes('middleware')) {
|
|
183
|
+
signals.push({ signal: 'File contains authentication logic', type: 'positive' });
|
|
184
|
+
confidence = 'low';
|
|
185
|
+
}
|
|
186
|
+
// Check if it's a public endpoint
|
|
187
|
+
if (relativePath.includes('login') || relativePath.includes('signup') ||
|
|
188
|
+
relativePath.includes('register') || relativePath.includes('public') ||
|
|
189
|
+
relativePath.includes('health') || relativePath.includes('webhook')) {
|
|
190
|
+
signals.push({ signal: 'Endpoint appears to be intentionally public', type: 'positive' });
|
|
191
|
+
confidence = 'low';
|
|
192
|
+
}
|
|
193
|
+
question = 'Is this endpoint intentionally public (login, webhook, health check) or should it require authentication?';
|
|
194
|
+
break;
|
|
195
|
+
case 'hardcoded-secret':
|
|
196
|
+
// Check if it's in a test/example file
|
|
197
|
+
if (relativePath.includes('test') || relativePath.includes('example') ||
|
|
198
|
+
relativePath.includes('sample') || relativePath.includes('mock')) {
|
|
199
|
+
signals.push({ signal: 'File appears to be test/example code', type: 'positive' });
|
|
200
|
+
confidence = 'low';
|
|
201
|
+
}
|
|
202
|
+
// Check for placeholder indicators
|
|
203
|
+
if (finding.code.includes('xxx') || finding.code.includes('example') ||
|
|
204
|
+
finding.code.includes('placeholder') || finding.code.includes('your-')) {
|
|
205
|
+
signals.push({ signal: 'Value appears to be a placeholder', type: 'positive' });
|
|
206
|
+
confidence = 'low';
|
|
207
|
+
}
|
|
208
|
+
question = 'Is this a real secret or a placeholder/example value? Check if this file is in version control.';
|
|
209
|
+
break;
|
|
210
|
+
default:
|
|
211
|
+
question = `Verify if this ${finding.rule.name} finding is a real security issue in your specific context.`;
|
|
212
|
+
}
|
|
213
|
+
// Add file path context
|
|
214
|
+
if (relativePath.includes('test') || relativePath.includes('spec') ||
|
|
215
|
+
relativePath.includes('mock') || relativePath.includes('fixture')) {
|
|
216
|
+
signals.push({ signal: 'File is in test/mock directory', type: 'positive' });
|
|
217
|
+
if (confidence === 'high')
|
|
218
|
+
confidence = 'medium';
|
|
219
|
+
}
|
|
220
|
+
if (signals.length === 0) {
|
|
221
|
+
signals.push({ signal: 'No additional context detected', type: 'neutral' });
|
|
222
|
+
}
|
|
223
|
+
return { signals, confidence, question };
|
|
224
|
+
}
|
|
225
|
+
function formatEnrichedFindings(findings) {
|
|
226
|
+
// Group by confidence
|
|
227
|
+
const highConf = findings.filter(f => f.confidence === 'high');
|
|
228
|
+
const medConf = findings.filter(f => f.confidence === 'medium');
|
|
229
|
+
const lowConf = findings.filter(f => f.confidence === 'low');
|
|
230
|
+
let output = '';
|
|
231
|
+
if (highConf.length > 0) {
|
|
232
|
+
output += `\n## 🔴 Likely Real Issues (${highConf.length})\nThese findings have high confidence and should be investigated:\n\n`;
|
|
233
|
+
output += highConf.map(f => formatSingleFinding(f)).join('\n---\n');
|
|
234
|
+
}
|
|
235
|
+
if (medConf.length > 0) {
|
|
236
|
+
output += `\n\n## 🟡 Needs Review (${medConf.length})\nThese findings need context to determine if they're issues:\n\n`;
|
|
237
|
+
output += medConf.map(f => formatSingleFinding(f)).join('\n---\n');
|
|
238
|
+
}
|
|
239
|
+
if (lowConf.length > 0) {
|
|
240
|
+
output += `\n\n## 🟢 Likely False Positives (${lowConf.length})\nThese findings appear safe based on context signals:\n\n`;
|
|
241
|
+
output += lowConf.map(f => formatSingleFinding(f)).join('\n---\n');
|
|
242
|
+
}
|
|
243
|
+
return output;
|
|
244
|
+
}
|
|
245
|
+
function formatSingleFinding(f) {
|
|
246
|
+
const signalIcons = f.contextSignals.map(s => {
|
|
247
|
+
const icon = s.type === 'positive' ? '✓' : s.type === 'negative' ? '⚠' : '•';
|
|
248
|
+
return ` ${icon} ${s.signal}`;
|
|
249
|
+
}).join('\n');
|
|
250
|
+
return `
|
|
251
|
+
**[${f.severity.toUpperCase()}] ${f.name}**
|
|
252
|
+
📍 ${f.file}:${f.line}
|
|
253
|
+
|
|
254
|
+
\`\`\`
|
|
255
|
+
${f.codeSnippet}
|
|
256
|
+
\`\`\`
|
|
257
|
+
|
|
258
|
+
**Context signals:**
|
|
259
|
+
${signalIcons}
|
|
260
|
+
|
|
261
|
+
**🤔 Analysis needed:** ${f.analysisQuestion}
|
|
262
|
+
|
|
263
|
+
**💡 Suggested fix:** ${f.fix}
|
|
264
|
+
`;
|
|
265
|
+
}
|
|
61
266
|
async function startMcpServer() {
|
|
62
267
|
const server = new mcp_js_1.McpServer({
|
|
63
268
|
name: 'vibeguard',
|
|
64
269
|
version: '1.0.0',
|
|
65
270
|
});
|
|
66
271
|
// Tool: scan_code
|
|
67
|
-
server.tool('scan_code', 'Scan files or directories for security vulnerabilities. Returns findings with
|
|
272
|
+
server.tool('scan_code', 'Scan files or directories for security vulnerabilities. Returns findings with context analysis to help determine real issues vs false positives. After receiving results, analyze each finding based on the context signals and code snippets provided.', {
|
|
68
273
|
paths: zod_1.z.array(zod_1.z.string()).describe('File or directory paths to scan (relative to current working directory)'),
|
|
69
274
|
staged_only: zod_1.z.boolean().optional().describe('If true, only scan git staged files'),
|
|
70
275
|
exclude: zod_1.z.array(zod_1.z.string()).optional().describe('Glob patterns to exclude (e.g., "**/vendor/**", "*.min.js")'),
|
|
@@ -85,7 +290,7 @@ async function startMcpServer() {
|
|
|
85
290
|
content: [
|
|
86
291
|
{
|
|
87
292
|
type: 'text',
|
|
88
|
-
text: `✅ No security issues found in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
293
|
+
text: `✅ **No security issues found** in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
89
294
|
},
|
|
90
295
|
],
|
|
91
296
|
};
|
|
@@ -97,42 +302,52 @@ async function startMcpServer() {
|
|
|
97
302
|
low: result.findings.filter(f => f.rule.severity === 'low').length,
|
|
98
303
|
};
|
|
99
304
|
const grade = calculateGrade(counts);
|
|
100
|
-
|
|
101
|
-
// Free tier: show counts only, no individual findings
|
|
305
|
+
// Free tier: show counts only
|
|
102
306
|
if (userTier === 'free') {
|
|
103
307
|
return {
|
|
104
308
|
content: [
|
|
105
309
|
{
|
|
106
310
|
type: 'text',
|
|
107
|
-
text:
|
|
311
|
+
text: `# Security Scan Results\n\n**Found ${result.findings.length} potential issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n\n**Grade: ${grade}** | Tier: ${tierLabel}\n\nUpgrade to Pro to see detailed findings with context analysis.\nRun \`vibeguard upgrade\` to unlock.`,
|
|
108
312
|
},
|
|
109
313
|
],
|
|
110
314
|
};
|
|
111
315
|
}
|
|
112
|
-
// Pro tier:
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
316
|
+
// Pro tier: enrich findings with context
|
|
317
|
+
const enrichedFindings = result.findings.map(f => {
|
|
318
|
+
const { signals, confidence, question } = analyzeContext(f, cwd);
|
|
319
|
+
return {
|
|
320
|
+
severity: f.rule.severity,
|
|
321
|
+
rule: f.rule.id,
|
|
322
|
+
name: f.rule.name,
|
|
323
|
+
file: path.relative(cwd, f.file),
|
|
324
|
+
line: f.line,
|
|
325
|
+
codeSnippet: getCodeSnippet(f.file, f.line),
|
|
326
|
+
contextSignals: signals,
|
|
327
|
+
analysisQuestion: question,
|
|
328
|
+
confidence,
|
|
329
|
+
fix: f.rule.fix || 'Review and fix as appropriate',
|
|
330
|
+
};
|
|
331
|
+
});
|
|
332
|
+
const highConfCount = enrichedFindings.filter(f => f.confidence === 'high').length;
|
|
333
|
+
const lowConfCount = enrichedFindings.filter(f => f.confidence === 'low').length;
|
|
334
|
+
const header = `# Security Scan Results
|
|
335
|
+
|
|
336
|
+
**Found ${result.findings.length} potential issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low
|
|
337
|
+
**Grade: ${grade}** | Tier: ${tierLabel}
|
|
338
|
+
|
|
339
|
+
**Confidence breakdown:**
|
|
340
|
+
- 🔴 ${highConfCount} likely real issues
|
|
341
|
+
- 🟢 ${lowConfCount} likely false positives
|
|
342
|
+
|
|
343
|
+
> **Instructions:** Review each finding below. Use the context signals and code snippets to determine if each is a real security issue. Focus on 🔴 high-confidence findings first.
|
|
344
|
+
`;
|
|
345
|
+
const formattedFindings = formatEnrichedFindings(enrichedFindings);
|
|
131
346
|
return {
|
|
132
347
|
content: [
|
|
133
348
|
{
|
|
134
349
|
type: 'text',
|
|
135
|
-
text:
|
|
350
|
+
text: header + formattedFindings,
|
|
136
351
|
},
|
|
137
352
|
],
|
|
138
353
|
};
|
|
@@ -173,7 +388,6 @@ async function startMcpServer() {
|
|
|
173
388
|
language: zod_1.z.enum(['javascript', 'typescript', 'python']).describe('The programming language'),
|
|
174
389
|
}, async ({ code, language }) => {
|
|
175
390
|
try {
|
|
176
|
-
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
177
391
|
const os = await Promise.resolve().then(() => __importStar(require('os')));
|
|
178
392
|
// Create temp file
|
|
179
393
|
const ext = language === 'python' ? '.py' : language === 'typescript' ? '.ts' : '.js';
|
|
@@ -192,7 +406,7 @@ async function startMcpServer() {
|
|
|
192
406
|
content: [
|
|
193
407
|
{
|
|
194
408
|
type: 'text',
|
|
195
|
-
text: `✅ No security issues found in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
409
|
+
text: `✅ **No security issues found** in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
196
410
|
},
|
|
197
411
|
],
|
|
198
412
|
};
|
|
@@ -204,40 +418,26 @@ async function startMcpServer() {
|
|
|
204
418
|
low: result.findings.filter(f => f.rule.severity === 'low').length,
|
|
205
419
|
};
|
|
206
420
|
const grade = calculateGrade(counts);
|
|
207
|
-
|
|
208
|
-
// Free tier: show counts only, no individual findings
|
|
421
|
+
// Free tier: show counts only
|
|
209
422
|
if (userTier === 'free') {
|
|
210
423
|
return {
|
|
211
424
|
content: [
|
|
212
425
|
{
|
|
213
426
|
type: 'text',
|
|
214
|
-
text:
|
|
427
|
+
text: `Found ${result.findings.length} potential issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n\nGrade: ${grade} | Tier: ${tierLabel}\n\nUpgrade to Pro to see details.`,
|
|
215
428
|
},
|
|
216
429
|
],
|
|
217
430
|
};
|
|
218
431
|
}
|
|
219
|
-
// Pro tier: show
|
|
220
|
-
const
|
|
221
|
-
severity: f.rule.
|
|
222
|
-
rule: f.rule.id,
|
|
223
|
-
name: f.rule.name,
|
|
224
|
-
line: f.line,
|
|
225
|
-
fix: f.rule.fix,
|
|
226
|
-
isRestricted: f.isRestricted,
|
|
227
|
-
}));
|
|
228
|
-
const formatted = findings.map(f => {
|
|
229
|
-
const proTag = f.isRestricted ? ' [PRO]' : '';
|
|
230
|
-
const fixLine = f.isRestricted
|
|
231
|
-
? ' Fix: Upgrade to Pro to see fix details'
|
|
232
|
-
: ` Fix: ${f.fix}`;
|
|
233
|
-
return `[${f.severity.toUpperCase()}]${proTag} Line ${f.line}: ${f.name}\n${fixLine}`;
|
|
432
|
+
// Pro tier: show findings with line numbers
|
|
433
|
+
const formatted = result.findings.map(f => {
|
|
434
|
+
return `**[${f.rule.severity.toUpperCase()}] Line ${f.line}: ${f.rule.name}**\n ${f.rule.description}\n 💡 Fix: ${f.rule.fix}`;
|
|
234
435
|
}).join('\n\n');
|
|
235
|
-
const footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
|
|
236
436
|
return {
|
|
237
437
|
content: [
|
|
238
438
|
{
|
|
239
439
|
type: 'text',
|
|
240
|
-
text:
|
|
440
|
+
text: `# Code Snippet Security Check\n\n**Found ${result.findings.length} issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n**Grade: ${grade}** | Tier: ${tierLabel}\n\n${formatted}`,
|
|
241
441
|
},
|
|
242
442
|
],
|
|
243
443
|
};
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/mcp/server.ts
CHANGED
|
@@ -2,10 +2,11 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import * as path from 'path';
|
|
5
|
+
import * as fs from 'fs';
|
|
5
6
|
import { Scanner } from '../scanner';
|
|
6
7
|
import { securityRules } from '../scanner/rules/definitions';
|
|
7
8
|
import { getLicenseKey } from '../api/license';
|
|
8
|
-
import { Severity, Tier } from '../types';
|
|
9
|
+
import { Severity, Tier, Finding } from '../types';
|
|
9
10
|
|
|
10
11
|
function calculateGrade(counts: Record<Severity, number>): string {
|
|
11
12
|
if (counts.critical > 0) return 'F';
|
|
@@ -18,6 +19,249 @@ function calculateGrade(counts: Record<Severity, number>): string {
|
|
|
18
19
|
return 'A+';
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
interface ContextSignal {
|
|
23
|
+
signal: string;
|
|
24
|
+
type: 'positive' | 'negative' | 'neutral';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface EnrichedFinding {
|
|
28
|
+
severity: string;
|
|
29
|
+
rule: string;
|
|
30
|
+
name: string;
|
|
31
|
+
file: string;
|
|
32
|
+
line: number;
|
|
33
|
+
codeSnippet: string;
|
|
34
|
+
contextSignals: ContextSignal[];
|
|
35
|
+
analysisQuestion: string;
|
|
36
|
+
confidence: 'high' | 'medium' | 'low';
|
|
37
|
+
fix: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getCodeSnippet(filePath: string, line: number, contextLines: number = 3): string {
|
|
41
|
+
try {
|
|
42
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
43
|
+
const lines = content.split('\n');
|
|
44
|
+
const startLine = Math.max(0, line - contextLines - 1);
|
|
45
|
+
const endLine = Math.min(lines.length, line + contextLines);
|
|
46
|
+
|
|
47
|
+
return lines.slice(startLine, endLine).map((l, i) => {
|
|
48
|
+
const lineNum = startLine + i + 1;
|
|
49
|
+
const marker = lineNum === line ? '→' : ' ';
|
|
50
|
+
return `${marker} ${lineNum.toString().padStart(4)}: ${l}`;
|
|
51
|
+
}).join('\n');
|
|
52
|
+
} catch {
|
|
53
|
+
return '(Could not read file)';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function analyzeContext(finding: Finding, cwd: string): { signals: ContextSignal[], confidence: 'high' | 'medium' | 'low', question: string } {
|
|
58
|
+
const signals: ContextSignal[] = [];
|
|
59
|
+
let confidence: 'high' | 'medium' | 'low' = 'high';
|
|
60
|
+
let question = '';
|
|
61
|
+
|
|
62
|
+
const filePath = finding.file;
|
|
63
|
+
const relativePath = path.relative(cwd, filePath).toLowerCase();
|
|
64
|
+
|
|
65
|
+
// Read file content for analysis
|
|
66
|
+
let fileContent = '';
|
|
67
|
+
try {
|
|
68
|
+
fileContent = fs.readFileSync(filePath, 'utf-8').toLowerCase();
|
|
69
|
+
} catch {
|
|
70
|
+
// Can't read file
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Analyze based on rule type
|
|
74
|
+
switch (finding.rule.id) {
|
|
75
|
+
case 'xss-innerhtml':
|
|
76
|
+
// Check for sanitizer imports
|
|
77
|
+
if (fileContent.includes('dompurify') || fileContent.includes('sanitize') ||
|
|
78
|
+
fileContent.includes('escapehtml') || fileContent.includes('escape-html')) {
|
|
79
|
+
signals.push({ signal: 'File imports sanitization library', type: 'positive' });
|
|
80
|
+
confidence = 'low';
|
|
81
|
+
}
|
|
82
|
+
// Check if it's static HTML
|
|
83
|
+
if (finding.code.includes("'<") || finding.code.includes('"<') || finding.code.includes('`<')) {
|
|
84
|
+
signals.push({ signal: 'Appears to be static HTML string', type: 'positive' });
|
|
85
|
+
confidence = 'low';
|
|
86
|
+
}
|
|
87
|
+
// Check for user input indicators
|
|
88
|
+
if (finding.code.includes('user') || finding.code.includes('input') ||
|
|
89
|
+
finding.code.includes('req.') || finding.code.includes('params')) {
|
|
90
|
+
signals.push({ signal: 'May contain user-controlled input', type: 'negative' });
|
|
91
|
+
confidence = 'high';
|
|
92
|
+
}
|
|
93
|
+
question = 'Is the data being inserted sanitized before this line? Check if escapeHtml() or similar is called on the variable.';
|
|
94
|
+
break;
|
|
95
|
+
|
|
96
|
+
case 'supabase-no-rls':
|
|
97
|
+
// Check if it's server-side
|
|
98
|
+
if (relativePath.includes('/api/') || relativePath.includes('/server/') ||
|
|
99
|
+
relativePath.includes('/routes/') || relativePath.includes('/backend/')) {
|
|
100
|
+
signals.push({ signal: 'File is in server-side directory', type: 'positive' });
|
|
101
|
+
confidence = 'low';
|
|
102
|
+
}
|
|
103
|
+
// Check for service role key
|
|
104
|
+
if (fileContent.includes('service_role') || fileContent.includes('servicerole') ||
|
|
105
|
+
fileContent.includes('supabase_service')) {
|
|
106
|
+
signals.push({ signal: 'Uses service role key (server-side pattern)', type: 'positive' });
|
|
107
|
+
confidence = 'low';
|
|
108
|
+
}
|
|
109
|
+
// Check for auth middleware
|
|
110
|
+
if (fileContent.includes('requireauth') || fileContent.includes('requireadmin') ||
|
|
111
|
+
fileContent.includes('middleware') || fileContent.includes('authenticate')) {
|
|
112
|
+
signals.push({ signal: 'File has authentication middleware', type: 'positive' });
|
|
113
|
+
confidence = 'low';
|
|
114
|
+
}
|
|
115
|
+
// Client-side indicators
|
|
116
|
+
if (relativePath.includes('/components/') || relativePath.includes('/pages/') ||
|
|
117
|
+
relativePath.includes('/app/') && !relativePath.includes('/api/')) {
|
|
118
|
+
signals.push({ signal: 'File appears to be client-side', type: 'negative' });
|
|
119
|
+
confidence = 'high';
|
|
120
|
+
}
|
|
121
|
+
question = 'Is this server-side code with proper auth middleware, or client-side code that should use RLS?';
|
|
122
|
+
break;
|
|
123
|
+
|
|
124
|
+
case 'secrets-localstorage':
|
|
125
|
+
// Check what's being stored
|
|
126
|
+
if (finding.code.includes('token') || finding.code.includes('jwt') ||
|
|
127
|
+
finding.code.includes('auth') || finding.code.includes('key')) {
|
|
128
|
+
signals.push({ signal: 'Storing authentication-related data', type: 'negative' });
|
|
129
|
+
confidence = 'high';
|
|
130
|
+
}
|
|
131
|
+
question = 'Is this storing actual auth tokens, or just non-sensitive data like UI preferences?';
|
|
132
|
+
break;
|
|
133
|
+
|
|
134
|
+
case 'ssrf-vulnerability':
|
|
135
|
+
// Check if URL is from env var
|
|
136
|
+
if (finding.code.includes('process.env') || finding.code.includes('env.')) {
|
|
137
|
+
signals.push({ signal: 'URL appears to come from environment variable', type: 'positive' });
|
|
138
|
+
confidence = 'low';
|
|
139
|
+
}
|
|
140
|
+
// Check for user input
|
|
141
|
+
if (finding.code.includes('req.') || finding.code.includes('body.') ||
|
|
142
|
+
finding.code.includes('params.') || finding.code.includes('query.')) {
|
|
143
|
+
signals.push({ signal: 'URL contains user-controlled input', type: 'negative' });
|
|
144
|
+
confidence = 'high';
|
|
145
|
+
}
|
|
146
|
+
question = 'Is the URL/host controlled by user input, or is it a fixed/environment-based URL?';
|
|
147
|
+
break;
|
|
148
|
+
|
|
149
|
+
case 'prototype-pollution':
|
|
150
|
+
// Check if it's just spread operator
|
|
151
|
+
if (finding.code.includes('...') && !finding.code.includes('merge')) {
|
|
152
|
+
signals.push({ signal: 'Uses spread operator (generally safe)', type: 'positive' });
|
|
153
|
+
confidence = 'low';
|
|
154
|
+
}
|
|
155
|
+
// Check for deep merge
|
|
156
|
+
if (finding.code.includes('merge') || finding.code.includes('deepmerge')) {
|
|
157
|
+
signals.push({ signal: 'Uses deep merge function', type: 'negative' });
|
|
158
|
+
confidence = 'high';
|
|
159
|
+
}
|
|
160
|
+
question = 'Is this using deep merge with user input, or just shallow spread/assign?';
|
|
161
|
+
break;
|
|
162
|
+
|
|
163
|
+
case 'missing-auth-route':
|
|
164
|
+
case 'nextjs-api-route-no-auth':
|
|
165
|
+
// Check for auth in file
|
|
166
|
+
if (fileContent.includes('getsession') || fileContent.includes('getserversession') ||
|
|
167
|
+
fileContent.includes('requireauth') || fileContent.includes('authenticate') ||
|
|
168
|
+
fileContent.includes('verifytoken') || fileContent.includes('middleware')) {
|
|
169
|
+
signals.push({ signal: 'File contains authentication logic', type: 'positive' });
|
|
170
|
+
confidence = 'low';
|
|
171
|
+
}
|
|
172
|
+
// Check if it's a public endpoint
|
|
173
|
+
if (relativePath.includes('login') || relativePath.includes('signup') ||
|
|
174
|
+
relativePath.includes('register') || relativePath.includes('public') ||
|
|
175
|
+
relativePath.includes('health') || relativePath.includes('webhook')) {
|
|
176
|
+
signals.push({ signal: 'Endpoint appears to be intentionally public', type: 'positive' });
|
|
177
|
+
confidence = 'low';
|
|
178
|
+
}
|
|
179
|
+
question = 'Is this endpoint intentionally public (login, webhook, health check) or should it require authentication?';
|
|
180
|
+
break;
|
|
181
|
+
|
|
182
|
+
case 'hardcoded-secret':
|
|
183
|
+
// Check if it's in a test/example file
|
|
184
|
+
if (relativePath.includes('test') || relativePath.includes('example') ||
|
|
185
|
+
relativePath.includes('sample') || relativePath.includes('mock')) {
|
|
186
|
+
signals.push({ signal: 'File appears to be test/example code', type: 'positive' });
|
|
187
|
+
confidence = 'low';
|
|
188
|
+
}
|
|
189
|
+
// Check for placeholder indicators
|
|
190
|
+
if (finding.code.includes('xxx') || finding.code.includes('example') ||
|
|
191
|
+
finding.code.includes('placeholder') || finding.code.includes('your-')) {
|
|
192
|
+
signals.push({ signal: 'Value appears to be a placeholder', type: 'positive' });
|
|
193
|
+
confidence = 'low';
|
|
194
|
+
}
|
|
195
|
+
question = 'Is this a real secret or a placeholder/example value? Check if this file is in version control.';
|
|
196
|
+
break;
|
|
197
|
+
|
|
198
|
+
default:
|
|
199
|
+
question = `Verify if this ${finding.rule.name} finding is a real security issue in your specific context.`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Add file path context
|
|
203
|
+
if (relativePath.includes('test') || relativePath.includes('spec') ||
|
|
204
|
+
relativePath.includes('mock') || relativePath.includes('fixture')) {
|
|
205
|
+
signals.push({ signal: 'File is in test/mock directory', type: 'positive' });
|
|
206
|
+
if (confidence === 'high') confidence = 'medium';
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (signals.length === 0) {
|
|
210
|
+
signals.push({ signal: 'No additional context detected', type: 'neutral' });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return { signals, confidence, question };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function formatEnrichedFindings(findings: EnrichedFinding[]): string {
|
|
217
|
+
// Group by confidence
|
|
218
|
+
const highConf = findings.filter(f => f.confidence === 'high');
|
|
219
|
+
const medConf = findings.filter(f => f.confidence === 'medium');
|
|
220
|
+
const lowConf = findings.filter(f => f.confidence === 'low');
|
|
221
|
+
|
|
222
|
+
let output = '';
|
|
223
|
+
|
|
224
|
+
if (highConf.length > 0) {
|
|
225
|
+
output += `\n## 🔴 Likely Real Issues (${highConf.length})\nThese findings have high confidence and should be investigated:\n\n`;
|
|
226
|
+
output += highConf.map(f => formatSingleFinding(f)).join('\n---\n');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (medConf.length > 0) {
|
|
230
|
+
output += `\n\n## 🟡 Needs Review (${medConf.length})\nThese findings need context to determine if they're issues:\n\n`;
|
|
231
|
+
output += medConf.map(f => formatSingleFinding(f)).join('\n---\n');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (lowConf.length > 0) {
|
|
235
|
+
output += `\n\n## 🟢 Likely False Positives (${lowConf.length})\nThese findings appear safe based on context signals:\n\n`;
|
|
236
|
+
output += lowConf.map(f => formatSingleFinding(f)).join('\n---\n');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return output;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function formatSingleFinding(f: EnrichedFinding): string {
|
|
243
|
+
const signalIcons = f.contextSignals.map(s => {
|
|
244
|
+
const icon = s.type === 'positive' ? '✓' : s.type === 'negative' ? '⚠' : '•';
|
|
245
|
+
return ` ${icon} ${s.signal}`;
|
|
246
|
+
}).join('\n');
|
|
247
|
+
|
|
248
|
+
return `
|
|
249
|
+
**[${f.severity.toUpperCase()}] ${f.name}**
|
|
250
|
+
📍 ${f.file}:${f.line}
|
|
251
|
+
|
|
252
|
+
\`\`\`
|
|
253
|
+
${f.codeSnippet}
|
|
254
|
+
\`\`\`
|
|
255
|
+
|
|
256
|
+
**Context signals:**
|
|
257
|
+
${signalIcons}
|
|
258
|
+
|
|
259
|
+
**🤔 Analysis needed:** ${f.analysisQuestion}
|
|
260
|
+
|
|
261
|
+
**💡 Suggested fix:** ${f.fix}
|
|
262
|
+
`;
|
|
263
|
+
}
|
|
264
|
+
|
|
21
265
|
export async function startMcpServer(): Promise<void> {
|
|
22
266
|
const server = new McpServer({
|
|
23
267
|
name: 'vibeguard',
|
|
@@ -27,7 +271,7 @@ export async function startMcpServer(): Promise<void> {
|
|
|
27
271
|
// Tool: scan_code
|
|
28
272
|
server.tool(
|
|
29
273
|
'scan_code',
|
|
30
|
-
'Scan files or directories for security vulnerabilities. Returns findings with
|
|
274
|
+
'Scan files or directories for security vulnerabilities. Returns findings with context analysis to help determine real issues vs false positives. After receiving results, analyze each finding based on the context signals and code snippets provided.',
|
|
31
275
|
{
|
|
32
276
|
paths: z.array(z.string()).describe('File or directory paths to scan (relative to current working directory)'),
|
|
33
277
|
staged_only: z.boolean().optional().describe('If true, only scan git staged files'),
|
|
@@ -54,7 +298,7 @@ export async function startMcpServer(): Promise<void> {
|
|
|
54
298
|
content: [
|
|
55
299
|
{
|
|
56
300
|
type: 'text' as const,
|
|
57
|
-
text: `✅ No security issues found in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
301
|
+
text: `✅ **No security issues found** in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
58
302
|
},
|
|
59
303
|
],
|
|
60
304
|
};
|
|
@@ -68,47 +312,58 @@ export async function startMcpServer(): Promise<void> {
|
|
|
68
312
|
};
|
|
69
313
|
|
|
70
314
|
const grade = calculateGrade(counts);
|
|
71
|
-
const summary = `Found ${result.findings.length} issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low`;
|
|
72
315
|
|
|
73
|
-
// Free tier: show counts only
|
|
316
|
+
// Free tier: show counts only
|
|
74
317
|
if (userTier === 'free') {
|
|
75
318
|
return {
|
|
76
319
|
content: [
|
|
77
320
|
{
|
|
78
321
|
type: 'text' as const,
|
|
79
|
-
text:
|
|
322
|
+
text: `# Security Scan Results\n\n**Found ${result.findings.length} potential issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n\n**Grade: ${grade}** | Tier: ${tierLabel}\n\nUpgrade to Pro to see detailed findings with context analysis.\nRun \`vibeguard upgrade\` to unlock.`,
|
|
80
323
|
},
|
|
81
324
|
],
|
|
82
325
|
};
|
|
83
326
|
}
|
|
84
327
|
|
|
85
|
-
// Pro tier:
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
: ` Fix: ${f.fix}`;
|
|
102
|
-
return `[${f.severity.toUpperCase()}]${proTag} ${f.file}:${f.line}\n ${f.name}\n${fixLine}`;
|
|
103
|
-
}).join('\n\n');
|
|
328
|
+
// Pro tier: enrich findings with context
|
|
329
|
+
const enrichedFindings: EnrichedFinding[] = result.findings.map(f => {
|
|
330
|
+
const { signals, confidence, question } = analyzeContext(f, cwd);
|
|
331
|
+
return {
|
|
332
|
+
severity: f.rule.severity,
|
|
333
|
+
rule: f.rule.id,
|
|
334
|
+
name: f.rule.name,
|
|
335
|
+
file: path.relative(cwd, f.file),
|
|
336
|
+
line: f.line,
|
|
337
|
+
codeSnippet: getCodeSnippet(f.file, f.line),
|
|
338
|
+
contextSignals: signals,
|
|
339
|
+
analysisQuestion: question,
|
|
340
|
+
confidence,
|
|
341
|
+
fix: f.rule.fix || 'Review and fix as appropriate',
|
|
342
|
+
};
|
|
343
|
+
});
|
|
104
344
|
|
|
105
|
-
const
|
|
345
|
+
const highConfCount = enrichedFindings.filter(f => f.confidence === 'high').length;
|
|
346
|
+
const lowConfCount = enrichedFindings.filter(f => f.confidence === 'low').length;
|
|
347
|
+
|
|
348
|
+
const header = `# Security Scan Results
|
|
349
|
+
|
|
350
|
+
**Found ${result.findings.length} potential issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low
|
|
351
|
+
**Grade: ${grade}** | Tier: ${tierLabel}
|
|
352
|
+
|
|
353
|
+
**Confidence breakdown:**
|
|
354
|
+
- 🔴 ${highConfCount} likely real issues
|
|
355
|
+
- 🟢 ${lowConfCount} likely false positives
|
|
356
|
+
|
|
357
|
+
> **Instructions:** Review each finding below. Use the context signals and code snippets to determine if each is a real security issue. Focus on 🔴 high-confidence findings first.
|
|
358
|
+
`;
|
|
359
|
+
|
|
360
|
+
const formattedFindings = formatEnrichedFindings(enrichedFindings);
|
|
106
361
|
|
|
107
362
|
return {
|
|
108
363
|
content: [
|
|
109
364
|
{
|
|
110
365
|
type: 'text' as const,
|
|
111
|
-
text:
|
|
366
|
+
text: header + formattedFindings,
|
|
112
367
|
},
|
|
113
368
|
],
|
|
114
369
|
};
|
|
@@ -165,7 +420,6 @@ export async function startMcpServer(): Promise<void> {
|
|
|
165
420
|
},
|
|
166
421
|
async ({ code, language }) => {
|
|
167
422
|
try {
|
|
168
|
-
const fs = await import('fs');
|
|
169
423
|
const os = await import('os');
|
|
170
424
|
|
|
171
425
|
// Create temp file
|
|
@@ -190,7 +444,7 @@ export async function startMcpServer(): Promise<void> {
|
|
|
190
444
|
content: [
|
|
191
445
|
{
|
|
192
446
|
type: 'text' as const,
|
|
193
|
-
text: `✅ No security issues found in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
447
|
+
text: `✅ **No security issues found** in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
194
448
|
},
|
|
195
449
|
],
|
|
196
450
|
};
|
|
@@ -204,45 +458,29 @@ export async function startMcpServer(): Promise<void> {
|
|
|
204
458
|
};
|
|
205
459
|
|
|
206
460
|
const grade = calculateGrade(counts);
|
|
207
|
-
const summary = `Found ${result.findings.length} issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low`;
|
|
208
461
|
|
|
209
|
-
// Free tier: show counts only
|
|
462
|
+
// Free tier: show counts only
|
|
210
463
|
if (userTier === 'free') {
|
|
211
464
|
return {
|
|
212
465
|
content: [
|
|
213
466
|
{
|
|
214
467
|
type: 'text' as const,
|
|
215
|
-
text:
|
|
468
|
+
text: `Found ${result.findings.length} potential issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n\nGrade: ${grade} | Tier: ${tierLabel}\n\nUpgrade to Pro to see details.`,
|
|
216
469
|
},
|
|
217
470
|
],
|
|
218
471
|
};
|
|
219
472
|
}
|
|
220
473
|
|
|
221
|
-
// Pro tier: show
|
|
222
|
-
const
|
|
223
|
-
severity: f.rule.
|
|
224
|
-
rule: f.rule.id,
|
|
225
|
-
name: f.rule.name,
|
|
226
|
-
line: f.line,
|
|
227
|
-
fix: f.rule.fix,
|
|
228
|
-
isRestricted: f.isRestricted,
|
|
229
|
-
}));
|
|
230
|
-
|
|
231
|
-
const formatted = findings.map(f => {
|
|
232
|
-
const proTag = f.isRestricted ? ' [PRO]' : '';
|
|
233
|
-
const fixLine = f.isRestricted
|
|
234
|
-
? ' Fix: Upgrade to Pro to see fix details'
|
|
235
|
-
: ` Fix: ${f.fix}`;
|
|
236
|
-
return `[${f.severity.toUpperCase()}]${proTag} Line ${f.line}: ${f.name}\n${fixLine}`;
|
|
474
|
+
// Pro tier: show findings with line numbers
|
|
475
|
+
const formatted = result.findings.map(f => {
|
|
476
|
+
return `**[${f.rule.severity.toUpperCase()}] Line ${f.line}: ${f.rule.name}**\n ${f.rule.description}\n 💡 Fix: ${f.rule.fix}`;
|
|
237
477
|
}).join('\n\n');
|
|
238
478
|
|
|
239
|
-
const footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
|
|
240
|
-
|
|
241
479
|
return {
|
|
242
480
|
content: [
|
|
243
481
|
{
|
|
244
482
|
type: 'text' as const,
|
|
245
|
-
text:
|
|
483
|
+
text: `# Code Snippet Security Check\n\n**Found ${result.findings.length} issue(s):** ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low\n**Grade: ${grade}** | Tier: ${tierLabel}\n\n${formatted}`,
|
|
246
484
|
},
|
|
247
485
|
],
|
|
248
486
|
};
|