@indicated/vibeguard 1.2.0 → 1.2.1
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 +65 -9
- package/dist/mcp/server.js.map +1 -1
- package/package.json +1 -1
- package/src/mcp/server.ts +67 -14
- package/PROGRESS.md +0 -221
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":"AAoBA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAmOpD"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -40,6 +40,24 @@ const zod_1 = require("zod");
|
|
|
40
40
|
const path = __importStar(require("path"));
|
|
41
41
|
const scanner_1 = require("../scanner");
|
|
42
42
|
const definitions_1 = require("../scanner/rules/definitions");
|
|
43
|
+
const license_1 = require("../api/license");
|
|
44
|
+
function calculateGrade(counts) {
|
|
45
|
+
if (counts.critical > 0)
|
|
46
|
+
return 'F';
|
|
47
|
+
if (counts.high > 2)
|
|
48
|
+
return 'D';
|
|
49
|
+
if (counts.high > 0)
|
|
50
|
+
return 'C';
|
|
51
|
+
if (counts.medium > 3)
|
|
52
|
+
return 'C';
|
|
53
|
+
if (counts.medium > 0)
|
|
54
|
+
return 'B';
|
|
55
|
+
if (counts.low > 5)
|
|
56
|
+
return 'B';
|
|
57
|
+
if (counts.low > 0)
|
|
58
|
+
return 'A';
|
|
59
|
+
return 'A+';
|
|
60
|
+
}
|
|
43
61
|
async function startMcpServer() {
|
|
44
62
|
const server = new mcp_js_1.McpServer({
|
|
45
63
|
name: 'vibeguard',
|
|
@@ -51,24 +69,27 @@ async function startMcpServer() {
|
|
|
51
69
|
staged_only: zod_1.z.boolean().optional().describe('If true, only scan git staged files'),
|
|
52
70
|
}, async ({ paths, staged_only }) => {
|
|
53
71
|
try {
|
|
72
|
+
const licenseKey = (0, license_1.getLicenseKey)();
|
|
54
73
|
const scanner = new scanner_1.Scanner();
|
|
55
|
-
await scanner.initialize();
|
|
74
|
+
await scanner.initialize(licenseKey || undefined);
|
|
56
75
|
const cwd = process.cwd();
|
|
57
76
|
const targets = paths.map(p => path.resolve(cwd, p));
|
|
58
77
|
const result = staged_only
|
|
59
78
|
? await scanner.scanStaged()
|
|
60
79
|
: await scanner.scan(targets);
|
|
80
|
+
const userTier = scanner.getUserTier();
|
|
81
|
+
const tierLabel = userTier === 'pro' ? '🔓 Pro' : '🔒 Free';
|
|
61
82
|
if (result.findings.length === 0) {
|
|
62
83
|
return {
|
|
63
84
|
content: [
|
|
64
85
|
{
|
|
65
86
|
type: 'text',
|
|
66
|
-
text: `✅ No security issues found in ${result.files} file(s)
|
|
87
|
+
text: `✅ No security issues found in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
67
88
|
},
|
|
68
89
|
],
|
|
69
90
|
};
|
|
70
91
|
}
|
|
71
|
-
// Format findings
|
|
92
|
+
// Format findings with restriction info
|
|
72
93
|
const findings = result.findings.map(f => ({
|
|
73
94
|
severity: f.rule.severity,
|
|
74
95
|
rule: f.rule.id,
|
|
@@ -77,6 +98,7 @@ async function startMcpServer() {
|
|
|
77
98
|
line: f.line,
|
|
78
99
|
message: f.rule.description,
|
|
79
100
|
fix: f.rule.fix,
|
|
101
|
+
isRestricted: f.isRestricted,
|
|
80
102
|
}));
|
|
81
103
|
const counts = {
|
|
82
104
|
critical: findings.filter(f => f.severity === 'critical').length,
|
|
@@ -84,13 +106,25 @@ async function startMcpServer() {
|
|
|
84
106
|
medium: findings.filter(f => f.severity === 'medium').length,
|
|
85
107
|
low: findings.filter(f => f.severity === 'low').length,
|
|
86
108
|
};
|
|
109
|
+
const grade = calculateGrade(counts);
|
|
110
|
+
const restrictedCount = findings.filter(f => f.isRestricted).length;
|
|
87
111
|
const summary = `Found ${findings.length} issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low`;
|
|
88
|
-
const formattedFindings = findings.map(f =>
|
|
112
|
+
const formattedFindings = findings.map(f => {
|
|
113
|
+
const proTag = f.isRestricted ? ' [PRO]' : '';
|
|
114
|
+
const fixLine = f.isRestricted
|
|
115
|
+
? ' Fix: Upgrade to Pro to see fix details'
|
|
116
|
+
: ` Fix: ${f.fix}`;
|
|
117
|
+
return `[${f.severity.toUpperCase()}]${proTag} ${f.file}:${f.line}\n ${f.name}\n${fixLine}`;
|
|
118
|
+
}).join('\n\n');
|
|
119
|
+
let footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
|
|
120
|
+
if (restrictedCount > 0 && userTier === 'free') {
|
|
121
|
+
footer += `\n\n${restrictedCount} finding(s) require Pro to see fix details. Run 'vibeguard upgrade' to unlock.`;
|
|
122
|
+
}
|
|
89
123
|
return {
|
|
90
124
|
content: [
|
|
91
125
|
{
|
|
92
126
|
type: 'text',
|
|
93
|
-
text: `${summary}\n\n${formattedFindings}`,
|
|
127
|
+
text: `${summary}\n\n${formattedFindings}${footer}`,
|
|
94
128
|
},
|
|
95
129
|
],
|
|
96
130
|
};
|
|
@@ -137,9 +171,12 @@ async function startMcpServer() {
|
|
|
137
171
|
const ext = language === 'python' ? '.py' : language === 'typescript' ? '.ts' : '.js';
|
|
138
172
|
const tempFile = path.join(os.tmpdir(), `vibeguard-check-${Date.now()}${ext}`);
|
|
139
173
|
fs.writeFileSync(tempFile, code);
|
|
174
|
+
const licenseKey = (0, license_1.getLicenseKey)();
|
|
140
175
|
const scanner = new scanner_1.Scanner();
|
|
141
|
-
await scanner.initialize();
|
|
176
|
+
await scanner.initialize(licenseKey || undefined);
|
|
142
177
|
const result = await scanner.scan([tempFile]);
|
|
178
|
+
const userTier = scanner.getUserTier();
|
|
179
|
+
const tierLabel = userTier === 'pro' ? '🔓 Pro' : '🔒 Free';
|
|
143
180
|
// Clean up
|
|
144
181
|
fs.unlinkSync(tempFile);
|
|
145
182
|
if (result.findings.length === 0) {
|
|
@@ -147,7 +184,7 @@ async function startMcpServer() {
|
|
|
147
184
|
content: [
|
|
148
185
|
{
|
|
149
186
|
type: 'text',
|
|
150
|
-
text:
|
|
187
|
+
text: `✅ No security issues found in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
151
188
|
},
|
|
152
189
|
],
|
|
153
190
|
};
|
|
@@ -158,13 +195,32 @@ async function startMcpServer() {
|
|
|
158
195
|
name: f.rule.name,
|
|
159
196
|
line: f.line,
|
|
160
197
|
fix: f.rule.fix,
|
|
198
|
+
isRestricted: f.isRestricted,
|
|
161
199
|
}));
|
|
162
|
-
const
|
|
200
|
+
const counts = {
|
|
201
|
+
critical: findings.filter(f => f.severity === 'critical').length,
|
|
202
|
+
high: findings.filter(f => f.severity === 'high').length,
|
|
203
|
+
medium: findings.filter(f => f.severity === 'medium').length,
|
|
204
|
+
low: findings.filter(f => f.severity === 'low').length,
|
|
205
|
+
};
|
|
206
|
+
const grade = calculateGrade(counts);
|
|
207
|
+
const restrictedCount = findings.filter(f => f.isRestricted).length;
|
|
208
|
+
const formatted = findings.map(f => {
|
|
209
|
+
const proTag = f.isRestricted ? ' [PRO]' : '';
|
|
210
|
+
const fixLine = f.isRestricted
|
|
211
|
+
? ' Fix: Upgrade to Pro to see fix details'
|
|
212
|
+
: ` Fix: ${f.fix}`;
|
|
213
|
+
return `[${f.severity.toUpperCase()}]${proTag} Line ${f.line}: ${f.name}\n${fixLine}`;
|
|
214
|
+
}).join('\n\n');
|
|
215
|
+
let footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
|
|
216
|
+
if (restrictedCount > 0 && userTier === 'free') {
|
|
217
|
+
footer += `\n\n${restrictedCount} finding(s) require Pro to see fix details.`;
|
|
218
|
+
}
|
|
163
219
|
return {
|
|
164
220
|
content: [
|
|
165
221
|
{
|
|
166
222
|
type: 'text',
|
|
167
|
-
text: `Found ${findings.length} issue(s):\n\n${formatted}`,
|
|
223
|
+
text: `Found ${findings.length} issue(s):\n\n${formatted}${footer}`,
|
|
168
224
|
},
|
|
169
225
|
],
|
|
170
226
|
};
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
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
|
@@ -4,6 +4,19 @@ import { z } from 'zod';
|
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { Scanner } from '../scanner';
|
|
6
6
|
import { securityRules } from '../scanner/rules/definitions';
|
|
7
|
+
import { getLicenseKey } from '../api/license';
|
|
8
|
+
import { Severity, Tier } from '../types';
|
|
9
|
+
|
|
10
|
+
function calculateGrade(counts: Record<Severity, number>): string {
|
|
11
|
+
if (counts.critical > 0) return 'F';
|
|
12
|
+
if (counts.high > 2) return 'D';
|
|
13
|
+
if (counts.high > 0) return 'C';
|
|
14
|
+
if (counts.medium > 3) return 'C';
|
|
15
|
+
if (counts.medium > 0) return 'B';
|
|
16
|
+
if (counts.low > 5) return 'B';
|
|
17
|
+
if (counts.low > 0) return 'A';
|
|
18
|
+
return 'A+';
|
|
19
|
+
}
|
|
7
20
|
|
|
8
21
|
export async function startMcpServer(): Promise<void> {
|
|
9
22
|
const server = new McpServer({
|
|
@@ -21,8 +34,9 @@ export async function startMcpServer(): Promise<void> {
|
|
|
21
34
|
},
|
|
22
35
|
async ({ paths, staged_only }) => {
|
|
23
36
|
try {
|
|
37
|
+
const licenseKey = getLicenseKey();
|
|
24
38
|
const scanner = new Scanner();
|
|
25
|
-
await scanner.initialize();
|
|
39
|
+
await scanner.initialize(licenseKey || undefined);
|
|
26
40
|
|
|
27
41
|
const cwd = process.cwd();
|
|
28
42
|
const targets = paths.map(p => path.resolve(cwd, p));
|
|
@@ -31,18 +45,21 @@ export async function startMcpServer(): Promise<void> {
|
|
|
31
45
|
? await scanner.scanStaged()
|
|
32
46
|
: await scanner.scan(targets);
|
|
33
47
|
|
|
48
|
+
const userTier: Tier = scanner.getUserTier();
|
|
49
|
+
const tierLabel = userTier === 'pro' ? '🔓 Pro' : '🔒 Free';
|
|
50
|
+
|
|
34
51
|
if (result.findings.length === 0) {
|
|
35
52
|
return {
|
|
36
53
|
content: [
|
|
37
54
|
{
|
|
38
55
|
type: 'text' as const,
|
|
39
|
-
text: `✅ No security issues found in ${result.files} file(s)
|
|
56
|
+
text: `✅ No security issues found in ${result.files} file(s).\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
40
57
|
},
|
|
41
58
|
],
|
|
42
59
|
};
|
|
43
60
|
}
|
|
44
61
|
|
|
45
|
-
// Format findings
|
|
62
|
+
// Format findings with restriction info
|
|
46
63
|
const findings = result.findings.map(f => ({
|
|
47
64
|
severity: f.rule.severity,
|
|
48
65
|
rule: f.rule.id,
|
|
@@ -51,26 +68,39 @@ export async function startMcpServer(): Promise<void> {
|
|
|
51
68
|
line: f.line,
|
|
52
69
|
message: f.rule.description,
|
|
53
70
|
fix: f.rule.fix,
|
|
71
|
+
isRestricted: f.isRestricted,
|
|
54
72
|
}));
|
|
55
73
|
|
|
56
|
-
const counts = {
|
|
74
|
+
const counts: Record<Severity, number> = {
|
|
57
75
|
critical: findings.filter(f => f.severity === 'critical').length,
|
|
58
76
|
high: findings.filter(f => f.severity === 'high').length,
|
|
59
77
|
medium: findings.filter(f => f.severity === 'medium').length,
|
|
60
78
|
low: findings.filter(f => f.severity === 'low').length,
|
|
61
79
|
};
|
|
62
80
|
|
|
81
|
+
const grade = calculateGrade(counts);
|
|
82
|
+
const restrictedCount = findings.filter(f => f.isRestricted).length;
|
|
83
|
+
|
|
63
84
|
const summary = `Found ${findings.length} issue(s): ${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low`;
|
|
64
85
|
|
|
65
|
-
const formattedFindings = findings.map(f =>
|
|
66
|
-
|
|
67
|
-
|
|
86
|
+
const formattedFindings = findings.map(f => {
|
|
87
|
+
const proTag = f.isRestricted ? ' [PRO]' : '';
|
|
88
|
+
const fixLine = f.isRestricted
|
|
89
|
+
? ' Fix: Upgrade to Pro to see fix details'
|
|
90
|
+
: ` Fix: ${f.fix}`;
|
|
91
|
+
return `[${f.severity.toUpperCase()}]${proTag} ${f.file}:${f.line}\n ${f.name}\n${fixLine}`;
|
|
92
|
+
}).join('\n\n');
|
|
93
|
+
|
|
94
|
+
let footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
|
|
95
|
+
if (restrictedCount > 0 && userTier === 'free') {
|
|
96
|
+
footer += `\n\n${restrictedCount} finding(s) require Pro to see fix details. Run 'vibeguard upgrade' to unlock.`;
|
|
97
|
+
}
|
|
68
98
|
|
|
69
99
|
return {
|
|
70
100
|
content: [
|
|
71
101
|
{
|
|
72
102
|
type: 'text' as const,
|
|
73
|
-
text: `${summary}\n\n${formattedFindings}`,
|
|
103
|
+
text: `${summary}\n\n${formattedFindings}${footer}`,
|
|
74
104
|
},
|
|
75
105
|
],
|
|
76
106
|
};
|
|
@@ -136,10 +166,13 @@ export async function startMcpServer(): Promise<void> {
|
|
|
136
166
|
|
|
137
167
|
fs.writeFileSync(tempFile, code);
|
|
138
168
|
|
|
169
|
+
const licenseKey = getLicenseKey();
|
|
139
170
|
const scanner = new Scanner();
|
|
140
|
-
await scanner.initialize();
|
|
171
|
+
await scanner.initialize(licenseKey || undefined);
|
|
141
172
|
|
|
142
173
|
const result = await scanner.scan([tempFile]);
|
|
174
|
+
const userTier: Tier = scanner.getUserTier();
|
|
175
|
+
const tierLabel = userTier === 'pro' ? '🔓 Pro' : '🔒 Free';
|
|
143
176
|
|
|
144
177
|
// Clean up
|
|
145
178
|
fs.unlinkSync(tempFile);
|
|
@@ -149,7 +182,7 @@ export async function startMcpServer(): Promise<void> {
|
|
|
149
182
|
content: [
|
|
150
183
|
{
|
|
151
184
|
type: 'text' as const,
|
|
152
|
-
text:
|
|
185
|
+
text: `✅ No security issues found in this code snippet.\n\nGrade: A+ | Tier: ${tierLabel}`,
|
|
153
186
|
},
|
|
154
187
|
],
|
|
155
188
|
};
|
|
@@ -161,17 +194,37 @@ export async function startMcpServer(): Promise<void> {
|
|
|
161
194
|
name: f.rule.name,
|
|
162
195
|
line: f.line,
|
|
163
196
|
fix: f.rule.fix,
|
|
197
|
+
isRestricted: f.isRestricted,
|
|
164
198
|
}));
|
|
165
199
|
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
200
|
+
const counts: Record<Severity, number> = {
|
|
201
|
+
critical: findings.filter(f => f.severity === 'critical').length,
|
|
202
|
+
high: findings.filter(f => f.severity === 'high').length,
|
|
203
|
+
medium: findings.filter(f => f.severity === 'medium').length,
|
|
204
|
+
low: findings.filter(f => f.severity === 'low').length,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const grade = calculateGrade(counts);
|
|
208
|
+
const restrictedCount = findings.filter(f => f.isRestricted).length;
|
|
209
|
+
|
|
210
|
+
const formatted = findings.map(f => {
|
|
211
|
+
const proTag = f.isRestricted ? ' [PRO]' : '';
|
|
212
|
+
const fixLine = f.isRestricted
|
|
213
|
+
? ' Fix: Upgrade to Pro to see fix details'
|
|
214
|
+
: ` Fix: ${f.fix}`;
|
|
215
|
+
return `[${f.severity.toUpperCase()}]${proTag} Line ${f.line}: ${f.name}\n${fixLine}`;
|
|
216
|
+
}).join('\n\n');
|
|
217
|
+
|
|
218
|
+
let footer = `\nGrade: ${grade} | Tier: ${tierLabel}`;
|
|
219
|
+
if (restrictedCount > 0 && userTier === 'free') {
|
|
220
|
+
footer += `\n\n${restrictedCount} finding(s) require Pro to see fix details.`;
|
|
221
|
+
}
|
|
169
222
|
|
|
170
223
|
return {
|
|
171
224
|
content: [
|
|
172
225
|
{
|
|
173
226
|
type: 'text' as const,
|
|
174
|
-
text: `Found ${findings.length} issue(s):\n\n${formatted}`,
|
|
227
|
+
text: `Found ${findings.length} issue(s):\n\n${formatted}${footer}`,
|
|
175
228
|
},
|
|
176
229
|
],
|
|
177
230
|
};
|
package/PROGRESS.md
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
# VibeGuard Development Progress
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
VibeGuard is a local CLI security scanner for AI-generated code. This document tracks what has been implemented and what remains to be done.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## ✅ Completed
|
|
10
|
-
|
|
11
|
-
### Phase 1: Core Scanner
|
|
12
|
-
- [x] TypeScript project setup with npm package structure
|
|
13
|
-
- [x] Project structure following the planned architecture
|
|
14
|
-
- [x] JS/TS parser using @babel/parser for AST analysis
|
|
15
|
-
- [x] Pattern-based scanning with regex
|
|
16
|
-
- [x] Basic `scan` command with file/directory support
|
|
17
|
-
- [x] Finding output with file, line number, and severity
|
|
18
|
-
|
|
19
|
-
### Phase 2: Full Rule Set
|
|
20
|
-
- [x] 45 security rules implemented across all severity levels:
|
|
21
|
-
- **Critical (8):** hardcoded-secret, sql-injection, eval-usage, command-injection, insecure-deserialization, django-debug-true, django-secret-key-exposed, django-raw-sql
|
|
22
|
-
- **High (21):** missing-auth-route, xss-innerhtml, secrets-localstorage, supabase-no-rls, firebase-no-rules, idor-vulnerability, path-traversal, ssrf-vulnerability, open-redirect, insecure-cookie, missing-csrf, nextjs-exposed-server-action, nextjs-api-route-no-auth, nextjs-dangerouslySetInnerHTML, nextjs-exposed-env, django-no-csrf-exempt, fastapi-no-auth-dependency, nestjs-no-auth-guard, react-href-javascript, react-url-state-injection, express-session-insecure
|
|
23
|
-
- **Medium (10):** permissive-cors, http-not-https, weak-password, hardcoded-ip, xxe-vulnerability, jwt-none-algorithm, django-allowed-hosts-all, fastapi-cors-all-origins, express-helmet-missing, express-body-parser-limit
|
|
24
|
-
- **Low (6):** verbose-errors, missing-rate-limit, console-log-sensitive, debug-mode-enabled, prototype-pollution, nestjs-exposed-internal-exception
|
|
25
|
-
- [x] Python parser support (pattern-based)
|
|
26
|
-
- [x] Severity levels (critical, high, medium, low)
|
|
27
|
-
- [x] Letter grading system (A+ to F)
|
|
28
|
-
|
|
29
|
-
### Phase 3: CLI Polish
|
|
30
|
-
- [x] `vibeguard scan` - Main scan command
|
|
31
|
-
- [x] Directory scanning
|
|
32
|
-
- [x] File scanning
|
|
33
|
-
- [x] `--staged` flag for git staged files
|
|
34
|
-
- [x] `--json` output format
|
|
35
|
-
- [x] `--force` to ignore exit code
|
|
36
|
-
- [x] `--quiet` minimal output
|
|
37
|
-
- [x] `vibeguard init` - Pre-commit hook setup
|
|
38
|
-
- [x] Git hook creation
|
|
39
|
-
- [x] Husky detection and integration
|
|
40
|
-
- [x] `.vibeguardrc.json` config file creation
|
|
41
|
-
- [x] `vibeguard rules` - List security rules
|
|
42
|
-
- [x] `--severity` filter
|
|
43
|
-
- [x] `--language` filter
|
|
44
|
-
- [x] `--json` output
|
|
45
|
-
- [x] `vibeguard login` / `vibeguard logout` - License key management
|
|
46
|
-
- [x] `vibeguard upgrade` - Show Pro features and pricing
|
|
47
|
-
- [x] Pretty terminal output with colors
|
|
48
|
-
- [x] Config file support (`.vibeguardrc.json`)
|
|
49
|
-
|
|
50
|
-
### Phase 4: License System (CLI Side)
|
|
51
|
-
- [x] `login` command implemented
|
|
52
|
-
- [x] `logout` command implemented
|
|
53
|
-
- [x] License key storage in `~/.vibeguard/license.json`
|
|
54
|
-
- [x] Offline mode fallback (works without server)
|
|
55
|
-
- [x] API client stubs ready for server integration
|
|
56
|
-
|
|
57
|
-
### Phase 5: Free/Pro Tier System
|
|
58
|
-
- [x] `Tier` type added (`'free' | 'pro'`)
|
|
59
|
-
- [x] All 45 rules categorized by tier:
|
|
60
|
-
- **Free Tier (24 rules):** Basic vulnerabilities - hardcoded secrets, SQL injection, XSS, eval, command injection, CSRF, SSRF, path traversal, etc.
|
|
61
|
-
- **Pro Tier (21 rules):** Framework-specific - Next.js (4), Django (5), FastAPI (2), NestJS (2), React (2), Express (3), Supabase, Firebase, missing-auth-route
|
|
62
|
-
- [x] `isRestricted` field on findings for gated content
|
|
63
|
-
- [x] `[PRO]` badge display for restricted findings
|
|
64
|
-
- [x] Upgrade prompt showing count of restricted findings
|
|
65
|
-
- [x] `vibeguard upgrade` command with pricing and features
|
|
66
|
-
- [x] Tier info in JSON output (`tier`, `isRestricted` fields)
|
|
67
|
-
- [x] License tier caching for offline mode
|
|
68
|
-
- [x] `getUserTier()` and `getCachedTier()` functions
|
|
69
|
-
|
|
70
|
-
### Bonus: MCP Integration
|
|
71
|
-
- [x] `vibeguard mcp` command to start MCP server
|
|
72
|
-
- [x] `scan_code` tool - Scan files/directories
|
|
73
|
-
- [x] `list_security_rules` tool - List available rules
|
|
74
|
-
- [x] `check_code_snippet` tool - Validate code without saving
|
|
75
|
-
- [x] Documentation for Claude Code integration
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## 🔲 Not Yet Implemented
|
|
80
|
-
|
|
81
|
-
### Server-Side: Website + Backend (Phase 2 - Future Session)
|
|
82
|
-
- [ ] Next.js 14+ website on Vercel
|
|
83
|
-
- [ ] Landing page with feature showcase
|
|
84
|
-
- [ ] Pricing page (Monthly $9, Annual $79)
|
|
85
|
-
- [ ] Documentation site
|
|
86
|
-
- [ ] User dashboard (license management, usage stats)
|
|
87
|
-
- [ ] License validation API (`POST /v1/license/validate`)
|
|
88
|
-
- [ ] License activation API (`POST /v1/license/activate`)
|
|
89
|
-
- [ ] Rules API (`GET /v1/rules`) for auto-updates
|
|
90
|
-
- [ ] Vercel Postgres database (users, licenses, activations tables)
|
|
91
|
-
- [ ] NextAuth.js or Clerk authentication
|
|
92
|
-
|
|
93
|
-
### Server-Side: Stripe Integration (Phase 3 - Future Session)
|
|
94
|
-
- [ ] Stripe product setup (Pro Monthly, Pro Annual)
|
|
95
|
-
- [ ] Checkout flow
|
|
96
|
-
- [ ] Webhook handlers for payment events
|
|
97
|
-
- [ ] License key email delivery
|
|
98
|
-
- [ ] Subscription management
|
|
99
|
-
|
|
100
|
-
### CLI Enhancements
|
|
101
|
-
- [ ] `vibeguard update` - Manual rule update command
|
|
102
|
-
- [ ] `vibeguard ignore` - Add inline ignore comments
|
|
103
|
-
- [ ] `vibeguard fix` - Auto-fix certain issues (where safe)
|
|
104
|
-
- [ ] Watch mode (`--watch`) for continuous scanning
|
|
105
|
-
- [ ] SARIF output format for GitHub Advanced Security
|
|
106
|
-
- [ ] GitLab CI/CD integration format
|
|
107
|
-
|
|
108
|
-
### Additional Rules
|
|
109
|
-
- [x] Command injection detection
|
|
110
|
-
- [x] Path traversal detection
|
|
111
|
-
- [x] Insecure deserialization
|
|
112
|
-
- [x] Hardcoded IP addresses
|
|
113
|
-
- [x] Missing CSRF protection
|
|
114
|
-
- [x] Insecure cookie settings
|
|
115
|
-
- [x] Open redirect vulnerabilities
|
|
116
|
-
- [x] XXE (XML External Entity) detection
|
|
117
|
-
- [x] SSRF (Server-Side Request Forgery) patterns
|
|
118
|
-
- [x] JWT none algorithm vulnerability
|
|
119
|
-
- [x] Console logging sensitive data
|
|
120
|
-
- [x] Debug mode enabled
|
|
121
|
-
- [x] Prototype pollution
|
|
122
|
-
|
|
123
|
-
### Parser Improvements
|
|
124
|
-
- [ ] Tree-sitter Python parser (currently regex-only)
|
|
125
|
-
- [ ] Better AST-based SQL injection detection for JS
|
|
126
|
-
- [x] Framework-specific rules (Next.js, Django, FastAPI, NestJS, Express, React)
|
|
127
|
-
- [ ] JSX/TSX component-level analysis
|
|
128
|
-
|
|
129
|
-
### Testing
|
|
130
|
-
- [x] Unit tests for scanner (13 tests)
|
|
131
|
-
- [x] Unit tests for rule matching (186 tests across all 45 rules)
|
|
132
|
-
- [x] Rule definitions tests (47 tests)
|
|
133
|
-
- [x] Test coverage reporting (Vitest + v8)
|
|
134
|
-
- [x] CI/CD pipeline (GitHub Actions)
|
|
135
|
-
- [x] CI workflow: tests on Node 18, 20, 22
|
|
136
|
-
- [x] Release workflow: auto-publish to npm on tags
|
|
137
|
-
- [ ] Integration tests for CLI commands
|
|
138
|
-
|
|
139
|
-
### Documentation
|
|
140
|
-
- [ ] API documentation for server endpoints
|
|
141
|
-
- [ ] Contributing guide
|
|
142
|
-
- [ ] Rule authoring guide
|
|
143
|
-
- [ ] Examples for each vulnerability type
|
|
144
|
-
|
|
145
|
-
### Distribution
|
|
146
|
-
- [ ] Publish to npm
|
|
147
|
-
- [ ] Homebrew formula
|
|
148
|
-
- [ ] Binary releases (pkg)
|
|
149
|
-
- [ ] Docker image
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## 📁 Current Project Structure
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
vibeguard/
|
|
157
|
-
├── src/
|
|
158
|
-
│ ├── cli/
|
|
159
|
-
│ │ ├── index.ts # CLI entry point
|
|
160
|
-
│ │ ├── config.ts # Config file loading
|
|
161
|
-
│ │ ├── output.ts # Terminal formatting
|
|
162
|
-
│ │ └── commands/
|
|
163
|
-
│ │ ├── scan.ts # scan command
|
|
164
|
-
│ │ ├── init.ts # init command
|
|
165
|
-
│ │ ├── login.ts # login/logout commands
|
|
166
|
-
│ │ ├── rules.ts # rules command
|
|
167
|
-
│ │ ├── mcp.ts # mcp command
|
|
168
|
-
│ │ └── upgrade.ts # upgrade command (Pro features/pricing)
|
|
169
|
-
│ ├── scanner/
|
|
170
|
-
│ │ ├── index.ts # Main scanner logic
|
|
171
|
-
│ │ ├── parsers/
|
|
172
|
-
│ │ │ ├── javascript.ts # JS/TS AST + pattern scanning
|
|
173
|
-
│ │ │ └── python.ts # Python pattern scanning
|
|
174
|
-
│ │ └── rules/
|
|
175
|
-
│ │ ├── definitions.ts # 45 security rules (24 free, 21 pro)
|
|
176
|
-
│ │ ├── loader.ts # Rule loading (local + API)
|
|
177
|
-
│ │ └── matcher.ts # Pattern matching utilities
|
|
178
|
-
│ ├── mcp/
|
|
179
|
-
│ │ └── server.ts # MCP server for AI assistants
|
|
180
|
-
│ ├── api/
|
|
181
|
-
│ │ ├── license.ts # License management
|
|
182
|
-
│ │ └── rules.ts # Rules API client
|
|
183
|
-
│ └── types.ts # TypeScript types
|
|
184
|
-
├── dist/ # Compiled JavaScript
|
|
185
|
-
├── test-samples/ # Test files with vulnerabilities
|
|
186
|
-
├── package.json
|
|
187
|
-
├── tsconfig.json
|
|
188
|
-
├── README.md
|
|
189
|
-
└── PROGRESS.md # This file
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
## 🚀 Next Steps (Recommended Order)
|
|
195
|
-
|
|
196
|
-
1. **Website + Backend (Phase 2)** - Build vibeguard-web on Vercel with Next.js
|
|
197
|
-
- Landing page, pricing, docs
|
|
198
|
-
- License validation API
|
|
199
|
-
- Vercel Postgres database
|
|
200
|
-
2. **Stripe Integration (Phase 3)** - Payment flow and license delivery
|
|
201
|
-
3. **npm Publish** - Get it in users' hands
|
|
202
|
-
4. **CI Integration** - SARIF output for GitHub/GitLab
|
|
203
|
-
5. **More Rules** - Expand rule coverage based on user feedback
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
## 📊 Stats
|
|
208
|
-
|
|
209
|
-
| Metric | Count |
|
|
210
|
-
|--------|-------|
|
|
211
|
-
| Security Rules | 45 (24 free, 21 pro) |
|
|
212
|
-
| CLI Commands | 7 |
|
|
213
|
-
| MCP Tools | 3 |
|
|
214
|
-
| Supported Languages | 3 (JS, TS, Python) |
|
|
215
|
-
| Frameworks | 6 (Next.js, Django, FastAPI, NestJS, Express, React) |
|
|
216
|
-
| Unit Tests | 246 |
|
|
217
|
-
| Lines of TypeScript | ~2,200 |
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
|
-
*Last updated: January 30, 2026*
|