vibecheck-mcp-server 3.5.0 → 3.5.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/__tests__/cache.test.d.ts +10 -0
- package/dist/__tests__/cache.test.d.ts.map +1 -0
- package/dist/__tests__/cache.test.js +239 -0
- package/dist/__tests__/cache.test.js.map +1 -0
- package/dist/__tests__/executor.test.d.ts +11 -0
- package/dist/__tests__/executor.test.d.ts.map +1 -0
- package/dist/__tests__/executor.test.js +198 -0
- package/dist/__tests__/executor.test.js.map +1 -0
- package/dist/__tests__/fixtures/exclusion-test/src/app.d.ts +5 -0
- package/dist/__tests__/fixtures/exclusion-test/src/app.d.ts.map +1 -0
- package/dist/__tests__/fixtures/exclusion-test/src/app.js +9 -0
- package/dist/__tests__/fixtures/exclusion-test/src/app.js.map +1 -0
- package/dist/__tests__/ids.test.d.ts +10 -0
- package/dist/__tests__/ids.test.d.ts.map +1 -0
- package/dist/__tests__/ids.test.js +262 -0
- package/dist/__tests__/ids.test.js.map +1 -0
- package/dist/__tests__/integration/tools.test.d.ts +10 -0
- package/dist/__tests__/integration/tools.test.d.ts.map +1 -0
- package/dist/__tests__/integration/tools.test.js +343 -0
- package/dist/__tests__/integration/tools.test.js.map +1 -0
- package/dist/__tests__/registry.test.d.ts +11 -0
- package/dist/__tests__/registry.test.d.ts.map +1 -0
- package/dist/__tests__/registry.test.js +289 -0
- package/dist/__tests__/registry.test.js.map +1 -0
- package/dist/__tests__/sandbox.test.d.ts +11 -0
- package/dist/__tests__/sandbox.test.d.ts.map +1 -0
- package/dist/__tests__/sandbox.test.js +257 -0
- package/dist/__tests__/sandbox.test.js.map +1 -0
- package/dist/__tests__/schemas.test.d.ts +7 -0
- package/dist/__tests__/schemas.test.d.ts.map +1 -0
- package/dist/__tests__/schemas.test.js +313 -0
- package/dist/__tests__/schemas.test.js.map +1 -0
- package/dist/benchmarks/run-benchmarks.d.ts +18 -0
- package/dist/benchmarks/run-benchmarks.d.ts.map +1 -0
- package/dist/benchmarks/run-benchmarks.js +245 -0
- package/dist/benchmarks/run-benchmarks.js.map +1 -0
- package/dist/handlers/tool-handler.d.ts +76 -0
- package/dist/handlers/tool-handler.d.ts.map +1 -0
- package/dist/handlers/tool-handler.js +522 -0
- package/dist/handlers/tool-handler.js.map +1 -0
- package/dist/index-v3.d.ts +18 -0
- package/dist/index-v3.d.ts.map +1 -0
- package/dist/index-v3.js +261 -0
- package/dist/index-v3.js.map +1 -0
- package/dist/lib/cache.d.ts +110 -0
- package/dist/lib/cache.d.ts.map +1 -0
- package/dist/lib/cache.js +273 -0
- package/dist/lib/cache.js.map +1 -0
- package/dist/lib/errors.d.ts +121 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +254 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/executor.d.ts +217 -0
- package/dist/lib/executor.d.ts.map +1 -0
- package/dist/lib/executor.js +676 -0
- package/dist/lib/executor.js.map +1 -0
- package/dist/lib/ids.d.ts +121 -0
- package/dist/lib/ids.d.ts.map +1 -0
- package/dist/lib/ids.js +192 -0
- package/dist/lib/ids.js.map +1 -0
- package/dist/lib/logger.d.ts +160 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +268 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/metrics.d.ts +146 -0
- package/dist/lib/metrics.d.ts.map +1 -0
- package/dist/lib/metrics.js +263 -0
- package/dist/lib/metrics.js.map +1 -0
- package/dist/lib/sandbox.d.ts +78 -0
- package/dist/lib/sandbox.d.ts.map +1 -0
- package/dist/lib/sandbox.js +277 -0
- package/dist/lib/sandbox.js.map +1 -0
- package/dist/lib/validator.d.ts +67 -0
- package/dist/lib/validator.d.ts.map +1 -0
- package/dist/lib/validator.js +178 -0
- package/dist/lib/validator.js.map +1 -0
- package/index-v1.js +698 -0
- package/index.js +1080 -1757
- package/index.old.js +4137 -0
- package/package.json +32 -7
- package/premium-tools.js +2 -2
- package/registry/tools.json +476 -0
- package/schemas/error-envelope.schema.json +125 -0
- package/schemas/finding.schema.json +167 -0
- package/schemas/report-artifact.schema.json +88 -0
- package/schemas/run-request.schema.json +75 -0
- package/schemas/verdict.schema.json +168 -0
- package/tier-auth.js +371 -183
- package/truth-context.js +90 -131
- package/truth-firewall-tools.js +1000 -1611
- package/vibecheck-tools.js +2 -2
- package/agent-firewall-interceptor.js +0 -500
- package/authority-tools.js +0 -569
- package/logger.js +0 -173
- package/tools-v3.js +0 -1039
- package/tools.js +0 -495
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic ID Generation Tests
|
|
3
|
+
*
|
|
4
|
+
* Ensures IDs are:
|
|
5
|
+
* - Deterministic (same inputs = same outputs)
|
|
6
|
+
* - Stable (consistent across runs)
|
|
7
|
+
* - Unique (different inputs = different outputs)
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect } from 'vitest';
|
|
10
|
+
import { generateFindingId, generateCacheKey, generateRequestId, generateRunId, generateProjectFingerprint, isValidFindingId, parseFindingId, compareFindingsForSort, sortFindings, SEVERITY_ORDER, } from '../lib/ids.js';
|
|
11
|
+
describe('Finding ID Generation', () => {
|
|
12
|
+
describe('generateFindingId()', () => {
|
|
13
|
+
it('should generate deterministic IDs', () => {
|
|
14
|
+
const evidence = { path: 'src/api.ts', lineStart: 42, message: 'test message' };
|
|
15
|
+
const id1 = generateFindingId('auth_gap', evidence);
|
|
16
|
+
const id2 = generateFindingId('auth_gap', evidence);
|
|
17
|
+
expect(id1).toBe(id2);
|
|
18
|
+
});
|
|
19
|
+
it('should match format category-8hexchars', () => {
|
|
20
|
+
const id = generateFindingId('auth_gap', { path: 'test.ts', lineStart: 1 });
|
|
21
|
+
expect(id).toMatch(/^auth_gap-[a-f0-9]{8}$/);
|
|
22
|
+
});
|
|
23
|
+
it('should produce different IDs for different paths', () => {
|
|
24
|
+
const id1 = generateFindingId('auth_gap', { path: 'a.ts', lineStart: 1 });
|
|
25
|
+
const id2 = generateFindingId('auth_gap', { path: 'b.ts', lineStart: 1 });
|
|
26
|
+
expect(id1).not.toBe(id2);
|
|
27
|
+
});
|
|
28
|
+
it('should produce different IDs for different lines', () => {
|
|
29
|
+
const id1 = generateFindingId('auth_gap', { path: 'test.ts', lineStart: 1 });
|
|
30
|
+
const id2 = generateFindingId('auth_gap', { path: 'test.ts', lineStart: 2 });
|
|
31
|
+
expect(id1).not.toBe(id2);
|
|
32
|
+
});
|
|
33
|
+
it('should produce different IDs for different categories', () => {
|
|
34
|
+
const evidence = { path: 'test.ts', lineStart: 1 };
|
|
35
|
+
const id1 = generateFindingId('auth_gap', evidence);
|
|
36
|
+
const id2 = generateFindingId('secrets', evidence);
|
|
37
|
+
expect(id1).not.toBe(id2);
|
|
38
|
+
});
|
|
39
|
+
it('should produce different IDs for different messages', () => {
|
|
40
|
+
const id1 = generateFindingId('auth_gap', { path: 'test.ts', lineStart: 1, message: 'msg1' });
|
|
41
|
+
const id2 = generateFindingId('auth_gap', { path: 'test.ts', lineStart: 1, message: 'msg2' });
|
|
42
|
+
expect(id1).not.toBe(id2);
|
|
43
|
+
});
|
|
44
|
+
it('should handle missing optional fields', () => {
|
|
45
|
+
const id1 = generateFindingId('auth_gap', {});
|
|
46
|
+
const id2 = generateFindingId('auth_gap', { path: undefined, lineStart: undefined });
|
|
47
|
+
expect(id1).toBe(id2);
|
|
48
|
+
expect(id1).toMatch(/^auth_gap-[a-f0-9]{8}$/);
|
|
49
|
+
});
|
|
50
|
+
it('should normalize category to lowercase snake_case', () => {
|
|
51
|
+
const id = generateFindingId('AUTH.GAP', { path: 'test.ts' });
|
|
52
|
+
expect(id).toMatch(/^auth_gap-[a-f0-9]{8}$/);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('isValidFindingId()', () => {
|
|
56
|
+
it('should validate correct IDs', () => {
|
|
57
|
+
expect(isValidFindingId('auth_gap-a1b2c3d4')).toBe(true);
|
|
58
|
+
expect(isValidFindingId('secrets-12345678')).toBe(true);
|
|
59
|
+
expect(isValidFindingId('dead_ui-abcdef12')).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
it('should reject invalid IDs', () => {
|
|
62
|
+
expect(isValidFindingId('invalid')).toBe(false);
|
|
63
|
+
expect(isValidFindingId('AUTH_GAP-123')).toBe(false);
|
|
64
|
+
expect(isValidFindingId('auth_gap_123')).toBe(false);
|
|
65
|
+
expect(isValidFindingId('auth-gap-12345678')).toBe(false);
|
|
66
|
+
expect(isValidFindingId('auth_gap-1234567')).toBe(false); // Too short
|
|
67
|
+
expect(isValidFindingId('auth_gap-123456789')).toBe(false); // Too long
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('parseFindingId()', () => {
|
|
71
|
+
it('should parse valid IDs', () => {
|
|
72
|
+
const result = parseFindingId('auth_gap-a1b2c3d4');
|
|
73
|
+
expect(result).toEqual({ category: 'auth_gap', hash: 'a1b2c3d4' });
|
|
74
|
+
});
|
|
75
|
+
it('should return null for invalid IDs', () => {
|
|
76
|
+
expect(parseFindingId('invalid')).toBeNull();
|
|
77
|
+
expect(parseFindingId('AUTH_GAP-123')).toBeNull();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('Cache Key Generation', () => {
|
|
82
|
+
describe('generateCacheKey()', () => {
|
|
83
|
+
it('should generate deterministic keys', () => {
|
|
84
|
+
const key1 = generateCacheKey('scan', 'fingerprint123', { profile: 'quick' });
|
|
85
|
+
const key2 = generateCacheKey('scan', 'fingerprint123', { profile: 'quick' });
|
|
86
|
+
expect(key1).toBe(key2);
|
|
87
|
+
});
|
|
88
|
+
it('should produce different keys for different tools', () => {
|
|
89
|
+
const key1 = generateCacheKey('scan', 'fingerprint123', {});
|
|
90
|
+
const key2 = generateCacheKey('ship', 'fingerprint123', {});
|
|
91
|
+
expect(key1).not.toBe(key2);
|
|
92
|
+
});
|
|
93
|
+
it('should produce different keys for different fingerprints', () => {
|
|
94
|
+
const key1 = generateCacheKey('scan', 'fingerprint123', {});
|
|
95
|
+
const key2 = generateCacheKey('scan', 'fingerprint456', {});
|
|
96
|
+
expect(key1).not.toBe(key2);
|
|
97
|
+
});
|
|
98
|
+
it('should produce different keys for different options', () => {
|
|
99
|
+
const key1 = generateCacheKey('scan', 'fingerprint123', { profile: 'quick' });
|
|
100
|
+
const key2 = generateCacheKey('scan', 'fingerprint123', { profile: 'full' });
|
|
101
|
+
expect(key1).not.toBe(key2);
|
|
102
|
+
});
|
|
103
|
+
it('should sort options for determinism', () => {
|
|
104
|
+
const key1 = generateCacheKey('scan', 'fp', { a: 1, b: 2 });
|
|
105
|
+
const key2 = generateCacheKey('scan', 'fp', { b: 2, a: 1 });
|
|
106
|
+
expect(key1).toBe(key2);
|
|
107
|
+
});
|
|
108
|
+
it('should include schema version', () => {
|
|
109
|
+
const key1 = generateCacheKey('scan', 'fp', {}, '1.0.0');
|
|
110
|
+
const key2 = generateCacheKey('scan', 'fp', {}, '2.0.0');
|
|
111
|
+
expect(key1).not.toBe(key2);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe('Request ID Generation', () => {
|
|
116
|
+
describe('generateRequestId()', () => {
|
|
117
|
+
it('should generate unique IDs', () => {
|
|
118
|
+
const ids = new Set();
|
|
119
|
+
for (let i = 0; i < 100; i++) {
|
|
120
|
+
ids.add(generateRequestId());
|
|
121
|
+
}
|
|
122
|
+
expect(ids.size).toBe(100);
|
|
123
|
+
});
|
|
124
|
+
it('should use default prefix', () => {
|
|
125
|
+
const id = generateRequestId();
|
|
126
|
+
expect(id).toMatch(/^req_/);
|
|
127
|
+
});
|
|
128
|
+
it('should use custom prefix', () => {
|
|
129
|
+
const id = generateRequestId('tool');
|
|
130
|
+
expect(id).toMatch(/^tool_/);
|
|
131
|
+
});
|
|
132
|
+
it('should include timestamp component', () => {
|
|
133
|
+
const id = generateRequestId();
|
|
134
|
+
// ID format: prefix_timestamp_random
|
|
135
|
+
const parts = id.split('_');
|
|
136
|
+
expect(parts.length).toBe(3);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
describe('generateRunId()', () => {
|
|
140
|
+
it('should generate unique run IDs', () => {
|
|
141
|
+
const ids = new Set();
|
|
142
|
+
for (let i = 0; i < 100; i++) {
|
|
143
|
+
ids.add(generateRunId());
|
|
144
|
+
}
|
|
145
|
+
expect(ids.size).toBe(100);
|
|
146
|
+
});
|
|
147
|
+
it('should match format', () => {
|
|
148
|
+
const id = generateRunId();
|
|
149
|
+
expect(id).toMatch(/^run_\d{14}_[a-f0-9]{8}$/);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe('Project Fingerprinting', () => {
|
|
154
|
+
describe('generateProjectFingerprint()', () => {
|
|
155
|
+
it('should generate deterministic fingerprints', () => {
|
|
156
|
+
const files = [
|
|
157
|
+
{ path: 'package.json', content: '{"name":"test"}' },
|
|
158
|
+
{ path: 'package-lock.json', content: '{}' },
|
|
159
|
+
];
|
|
160
|
+
const fp1 = generateProjectFingerprint(files);
|
|
161
|
+
const fp2 = generateProjectFingerprint(files);
|
|
162
|
+
expect(fp1).toBe(fp2);
|
|
163
|
+
});
|
|
164
|
+
it('should produce different fingerprints for different content', () => {
|
|
165
|
+
const files1 = [{ path: 'package.json', content: '{"name":"test1"}' }];
|
|
166
|
+
const files2 = [{ path: 'package.json', content: '{"name":"test2"}' }];
|
|
167
|
+
const fp1 = generateProjectFingerprint(files1);
|
|
168
|
+
const fp2 = generateProjectFingerprint(files2);
|
|
169
|
+
expect(fp1).not.toBe(fp2);
|
|
170
|
+
});
|
|
171
|
+
it('should be order-independent (sorted)', () => {
|
|
172
|
+
const files1 = [
|
|
173
|
+
{ path: 'a.json', content: '1' },
|
|
174
|
+
{ path: 'b.json', content: '2' },
|
|
175
|
+
];
|
|
176
|
+
const files2 = [
|
|
177
|
+
{ path: 'b.json', content: '2' },
|
|
178
|
+
{ path: 'a.json', content: '1' },
|
|
179
|
+
];
|
|
180
|
+
const fp1 = generateProjectFingerprint(files1);
|
|
181
|
+
const fp2 = generateProjectFingerprint(files2);
|
|
182
|
+
expect(fp1).toBe(fp2);
|
|
183
|
+
});
|
|
184
|
+
it('should produce 16-char hex fingerprint', () => {
|
|
185
|
+
const fp = generateProjectFingerprint([{ path: 'test', content: 'test' }]);
|
|
186
|
+
expect(fp).toMatch(/^[a-f0-9]{16}$/);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
describe('Finding Sorting', () => {
|
|
191
|
+
describe('SEVERITY_ORDER', () => {
|
|
192
|
+
it('should have correct priority order', () => {
|
|
193
|
+
expect(SEVERITY_ORDER.BLOCK).toBeLessThan(SEVERITY_ORDER.WARN);
|
|
194
|
+
expect(SEVERITY_ORDER.WARN).toBeLessThan(SEVERITY_ORDER.INFO);
|
|
195
|
+
expect(SEVERITY_ORDER.CRITICAL).toBe(SEVERITY_ORDER.BLOCK);
|
|
196
|
+
expect(SEVERITY_ORDER.HIGH).toBeLessThan(SEVERITY_ORDER.MEDIUM);
|
|
197
|
+
expect(SEVERITY_ORDER.MEDIUM).toBeLessThan(SEVERITY_ORDER.LOW);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
describe('compareFindingsForSort()', () => {
|
|
201
|
+
it('should sort by severity first (BLOCK before WARN)', () => {
|
|
202
|
+
const a = { severity: 'BLOCK', rule_id: 'a', evidence: [{ file: 'a.ts', line: 1 }] };
|
|
203
|
+
const b = { severity: 'WARN', rule_id: 'a', evidence: [{ file: 'a.ts', line: 1 }] };
|
|
204
|
+
expect(compareFindingsForSort(a, b)).toBeLessThan(0);
|
|
205
|
+
expect(compareFindingsForSort(b, a)).toBeGreaterThan(0);
|
|
206
|
+
});
|
|
207
|
+
it('should sort by rule_id when severity is same', () => {
|
|
208
|
+
const a = { severity: 'WARN', rule_id: 'aaa', evidence: [{ file: 'a.ts', line: 1 }] };
|
|
209
|
+
const b = { severity: 'WARN', rule_id: 'bbb', evidence: [{ file: 'a.ts', line: 1 }] };
|
|
210
|
+
expect(compareFindingsForSort(a, b)).toBeLessThan(0);
|
|
211
|
+
expect(compareFindingsForSort(b, a)).toBeGreaterThan(0);
|
|
212
|
+
});
|
|
213
|
+
it('should sort by path when severity and rule_id are same', () => {
|
|
214
|
+
const a = { severity: 'WARN', rule_id: 'test', evidence: [{ file: 'a.ts', line: 1 }] };
|
|
215
|
+
const b = { severity: 'WARN', rule_id: 'test', evidence: [{ file: 'b.ts', line: 1 }] };
|
|
216
|
+
expect(compareFindingsForSort(a, b)).toBeLessThan(0);
|
|
217
|
+
});
|
|
218
|
+
it('should sort by line when path is same', () => {
|
|
219
|
+
const a = { severity: 'WARN', rule_id: 'test', evidence: [{ file: 'test.ts', line: 1 }] };
|
|
220
|
+
const b = { severity: 'WARN', rule_id: 'test', evidence: [{ file: 'test.ts', line: 2 }] };
|
|
221
|
+
expect(compareFindingsForSort(a, b)).toBeLessThan(0);
|
|
222
|
+
});
|
|
223
|
+
it('should handle missing fields', () => {
|
|
224
|
+
const a = { severity: 'WARN' };
|
|
225
|
+
const b = { severity: 'WARN' };
|
|
226
|
+
expect(compareFindingsForSort(a, b)).toBe(0);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
describe('sortFindings()', () => {
|
|
230
|
+
it('should sort findings deterministically', () => {
|
|
231
|
+
const findings = [
|
|
232
|
+
{ severity: 'INFO', rule_id: 'c', evidence: [{ file: 'c.ts', line: 1 }] },
|
|
233
|
+
{ severity: 'BLOCK', rule_id: 'a', evidence: [{ file: 'a.ts', line: 1 }] },
|
|
234
|
+
{ severity: 'WARN', rule_id: 'b', evidence: [{ file: 'b.ts', line: 1 }] },
|
|
235
|
+
];
|
|
236
|
+
const sorted = sortFindings(findings);
|
|
237
|
+
expect(sorted[0].severity).toBe('BLOCK');
|
|
238
|
+
expect(sorted[1].severity).toBe('WARN');
|
|
239
|
+
expect(sorted[2].severity).toBe('INFO');
|
|
240
|
+
});
|
|
241
|
+
it('should not mutate original array', () => {
|
|
242
|
+
const findings = [
|
|
243
|
+
{ severity: 'INFO', rule_id: 'a' },
|
|
244
|
+
{ severity: 'BLOCK', rule_id: 'b' },
|
|
245
|
+
];
|
|
246
|
+
const sorted = sortFindings(findings);
|
|
247
|
+
expect(findings[0].severity).toBe('INFO');
|
|
248
|
+
expect(sorted[0].severity).toBe('BLOCK');
|
|
249
|
+
});
|
|
250
|
+
it('should produce same order on multiple runs', () => {
|
|
251
|
+
const findings = [
|
|
252
|
+
{ severity: 'WARN', rule_id: 'z', evidence: [{ file: 'z.ts', line: 3 }] },
|
|
253
|
+
{ severity: 'WARN', rule_id: 'a', evidence: [{ file: 'a.ts', line: 1 }] },
|
|
254
|
+
{ severity: 'WARN', rule_id: 'm', evidence: [{ file: 'm.ts', line: 2 }] },
|
|
255
|
+
];
|
|
256
|
+
const sorted1 = sortFindings([...findings]);
|
|
257
|
+
const sorted2 = sortFindings([...findings].reverse());
|
|
258
|
+
expect(sorted1.map((f) => f.rule_id).join(',')).toBe(sorted2.map((f) => f.rule_id).join(','));
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
//# sourceMappingURL=ids.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.test.js","sourceRoot":"","sources":["../../__tests__/ids.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.test.d.ts","sourceRoot":"","sources":["../../../__tests__/integration/tools.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration Tests for MCP Tools
|
|
3
|
+
*
|
|
4
|
+
* Tests tools against real fixtures, including:
|
|
5
|
+
* - venv/node_modules exclusion
|
|
6
|
+
* - Path sandboxing
|
|
7
|
+
* - Error handling
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
10
|
+
import { mkdirSync, writeFileSync, rmSync, existsSync } from 'fs';
|
|
11
|
+
import { join } from 'path';
|
|
12
|
+
import { tmpdir } from 'os';
|
|
13
|
+
import { handleTool } from '../../handlers/tool-handler.js';
|
|
14
|
+
describe('Tool Integration Tests', () => {
|
|
15
|
+
let testDir;
|
|
16
|
+
let projectPath;
|
|
17
|
+
beforeAll(() => {
|
|
18
|
+
// Create test fixture directory
|
|
19
|
+
testDir = join(tmpdir(), `vibecheck-test-${Date.now()}`);
|
|
20
|
+
projectPath = join(testDir, 'test-project');
|
|
21
|
+
mkdirSync(projectPath, { recursive: true });
|
|
22
|
+
// Create basic project structure
|
|
23
|
+
writeFileSync(join(projectPath, 'package.json'), JSON.stringify({
|
|
24
|
+
name: 'test-project',
|
|
25
|
+
version: '1.0.0',
|
|
26
|
+
dependencies: {},
|
|
27
|
+
}));
|
|
28
|
+
// Create source files
|
|
29
|
+
mkdirSync(join(projectPath, 'src'));
|
|
30
|
+
writeFileSync(join(projectPath, 'src', 'index.ts'), `
|
|
31
|
+
export function hello() {
|
|
32
|
+
return 'Hello, World!';
|
|
33
|
+
}
|
|
34
|
+
`);
|
|
35
|
+
// Create node_modules (should be excluded)
|
|
36
|
+
mkdirSync(join(projectPath, 'node_modules', 'fake-pkg'), { recursive: true });
|
|
37
|
+
writeFileSync(join(projectPath, 'node_modules', 'fake-pkg', 'index.js'), 'const secret = "sk-fake-key-in-node_modules";');
|
|
38
|
+
// Create venv (should be excluded)
|
|
39
|
+
mkdirSync(join(projectPath, 'venv', 'lib'), { recursive: true });
|
|
40
|
+
writeFileSync(join(projectPath, 'venv', 'lib', 'config.py'), 'API_KEY = "sk-fake-key-in-venv"');
|
|
41
|
+
// Create .vibecheck directory
|
|
42
|
+
mkdirSync(join(projectPath, '.vibecheck'), { recursive: true });
|
|
43
|
+
});
|
|
44
|
+
afterAll(() => {
|
|
45
|
+
// Clean up test directory
|
|
46
|
+
if (existsSync(testDir)) {
|
|
47
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
describe('Path Sandboxing', () => {
|
|
51
|
+
it('should reject paths outside workspace', async () => {
|
|
52
|
+
const request = {
|
|
53
|
+
tool: 'vibecheck.scan',
|
|
54
|
+
projectPath: '/etc/passwd',
|
|
55
|
+
};
|
|
56
|
+
const result = await handleTool(request);
|
|
57
|
+
expect(result.ok).toBe(false);
|
|
58
|
+
if (!result.ok) {
|
|
59
|
+
expect(result.error.code).toBe('PATH_OUTSIDE_SANDBOX');
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
it('should reject path traversal attempts', async () => {
|
|
63
|
+
const request = {
|
|
64
|
+
tool: 'vibecheck.scan',
|
|
65
|
+
projectPath: join(projectPath, '..', '..', 'etc'),
|
|
66
|
+
};
|
|
67
|
+
const result = await handleTool(request);
|
|
68
|
+
expect(result.ok).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
it('should accept valid project paths', async () => {
|
|
71
|
+
const request = {
|
|
72
|
+
tool: 'vibecheck.status',
|
|
73
|
+
projectPath: projectPath,
|
|
74
|
+
};
|
|
75
|
+
// This may fail if CLI is not available, but should not fail due to path validation
|
|
76
|
+
const result = await handleTool(request);
|
|
77
|
+
if (!result.ok) {
|
|
78
|
+
expect(result.error.code).not.toBe('PATH_OUTSIDE_SANDBOX');
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('Input Validation', () => {
|
|
83
|
+
it('should reject unknown tools', async () => {
|
|
84
|
+
const request = {
|
|
85
|
+
tool: 'vibecheck.nonexistent',
|
|
86
|
+
projectPath: projectPath,
|
|
87
|
+
};
|
|
88
|
+
const result = await handleTool(request);
|
|
89
|
+
expect(result.ok).toBe(false);
|
|
90
|
+
if (!result.ok) {
|
|
91
|
+
expect(result.error.code).toBe('INVALID_INPUT');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
it('should reject invalid options', async () => {
|
|
95
|
+
const request = {
|
|
96
|
+
tool: 'vibecheck.scan',
|
|
97
|
+
projectPath: projectPath,
|
|
98
|
+
options: {
|
|
99
|
+
profile: 'invalid_profile_name',
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
const result = await handleTool(request);
|
|
103
|
+
expect(result.ok).toBe(false);
|
|
104
|
+
if (!result.ok) {
|
|
105
|
+
expect(result.error.code).toBe('INVALID_INPUT');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
it('should accept valid options', async () => {
|
|
109
|
+
const request = {
|
|
110
|
+
tool: 'vibecheck.scan',
|
|
111
|
+
projectPath: projectPath,
|
|
112
|
+
options: {
|
|
113
|
+
profile: 'quick',
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
// May fail due to CLI not being available, but should pass validation
|
|
117
|
+
const result = await handleTool(request);
|
|
118
|
+
if (!result.ok) {
|
|
119
|
+
expect(['CLI_ERROR', 'INTERNAL_ERROR']).toContain(result.error.code);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
it('should require url for vibecheck.reality', async () => {
|
|
123
|
+
const request = {
|
|
124
|
+
tool: 'vibecheck.reality',
|
|
125
|
+
projectPath: projectPath,
|
|
126
|
+
options: {}, // Missing required url
|
|
127
|
+
};
|
|
128
|
+
const result = await handleTool(request);
|
|
129
|
+
expect(result.ok).toBe(false);
|
|
130
|
+
if (!result.ok) {
|
|
131
|
+
expect(result.error.code).toBe('INVALID_INPUT');
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('Tool Aliases', () => {
|
|
136
|
+
it('should resolve vibecheck.context to vibecheck.ctx', async () => {
|
|
137
|
+
const request = {
|
|
138
|
+
tool: 'vibecheck.context', // Alias
|
|
139
|
+
projectPath: projectPath,
|
|
140
|
+
};
|
|
141
|
+
// Should not fail with "unknown tool"
|
|
142
|
+
const result = await handleTool(request);
|
|
143
|
+
if (!result.ok) {
|
|
144
|
+
expect(result.error.code).not.toBe('INVALID_INPUT');
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
it('should resolve vibecheck.verify to vibecheck.reality', async () => {
|
|
148
|
+
const request = {
|
|
149
|
+
tool: 'vibecheck.verify', // Alias
|
|
150
|
+
projectPath: projectPath,
|
|
151
|
+
options: { url: 'http://localhost:3000' },
|
|
152
|
+
};
|
|
153
|
+
// Should not fail with "unknown tool"
|
|
154
|
+
const result = await handleTool(request);
|
|
155
|
+
if (!result.ok) {
|
|
156
|
+
expect(result.error.code).not.toBe('INVALID_INPUT');
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('Query Tools', () => {
|
|
161
|
+
it('vibecheck.get_truthpack should return error if no truthpack exists', async () => {
|
|
162
|
+
const request = {
|
|
163
|
+
tool: 'vibecheck.get_truthpack',
|
|
164
|
+
projectPath: projectPath,
|
|
165
|
+
};
|
|
166
|
+
const result = await handleTool(request);
|
|
167
|
+
// Should either succeed with data or fail gracefully
|
|
168
|
+
if (!result.ok) {
|
|
169
|
+
expect(result.error.message).toContain('truthpack');
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
it('vibecheck.validate_claim should handle missing truthpack', async () => {
|
|
173
|
+
const request = {
|
|
174
|
+
tool: 'vibecheck.validate_claim',
|
|
175
|
+
projectPath: projectPath,
|
|
176
|
+
options: {
|
|
177
|
+
claim: '/api/test',
|
|
178
|
+
type: 'route_exists',
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
const result = await handleTool(request);
|
|
182
|
+
// Should fail gracefully with message about truthpack
|
|
183
|
+
if (!result.ok) {
|
|
184
|
+
expect(result.error.message.toLowerCase()).toContain('truthpack');
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
it('vibecheck.search_evidence should handle missing truthpack', async () => {
|
|
188
|
+
const request = {
|
|
189
|
+
tool: 'vibecheck.search_evidence',
|
|
190
|
+
projectPath: projectPath,
|
|
191
|
+
options: {
|
|
192
|
+
query: 'test',
|
|
193
|
+
type: 'any',
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
const result = await handleTool(request);
|
|
197
|
+
if (!result.ok) {
|
|
198
|
+
expect(result.error.message.toLowerCase()).toContain('truthpack');
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
describe('Error Envelopes', () => {
|
|
203
|
+
it('should always return proper error envelope on failure', async () => {
|
|
204
|
+
const request = {
|
|
205
|
+
tool: 'vibecheck.unknown',
|
|
206
|
+
projectPath: '/invalid/path',
|
|
207
|
+
};
|
|
208
|
+
const result = await handleTool(request);
|
|
209
|
+
expect(result.ok).toBe(false);
|
|
210
|
+
if (!result.ok) {
|
|
211
|
+
expect(result.error).toBeDefined();
|
|
212
|
+
expect(result.error.code).toBeDefined();
|
|
213
|
+
expect(result.error.message).toBeDefined();
|
|
214
|
+
expect(result.requestId).toBeDefined();
|
|
215
|
+
expect(result.timestamp).toBeDefined();
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
it('should include requestId in all responses', async () => {
|
|
219
|
+
const request = {
|
|
220
|
+
tool: 'vibecheck.status',
|
|
221
|
+
projectPath: projectPath,
|
|
222
|
+
requestId: 'test_req_123',
|
|
223
|
+
};
|
|
224
|
+
const result = await handleTool(request);
|
|
225
|
+
if (result.ok) {
|
|
226
|
+
expect(result.meta?.requestId).toBe('test_req_123');
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
expect(result.requestId).toBe('test_req_123');
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
describe('Timeout Handling', () => {
|
|
234
|
+
it('should respect custom timeout', async () => {
|
|
235
|
+
const request = {
|
|
236
|
+
tool: 'vibecheck.scan',
|
|
237
|
+
projectPath: projectPath,
|
|
238
|
+
timeout: 1, // 1ms - should timeout
|
|
239
|
+
};
|
|
240
|
+
const result = await handleTool(request);
|
|
241
|
+
// Should either complete very fast or timeout
|
|
242
|
+
expect(result).toBeDefined();
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
describe('Cache Behavior', () => {
|
|
246
|
+
it('should cache results when cacheMode is auto', async () => {
|
|
247
|
+
const request = {
|
|
248
|
+
tool: 'vibecheck.status',
|
|
249
|
+
projectPath: projectPath,
|
|
250
|
+
cache: { mode: 'auto' },
|
|
251
|
+
};
|
|
252
|
+
// First call
|
|
253
|
+
const result1 = await handleTool(request);
|
|
254
|
+
// Second call should be faster (cached)
|
|
255
|
+
const result2 = await handleTool(request);
|
|
256
|
+
if (result1.ok && result2.ok) {
|
|
257
|
+
expect(result2.meta?.cached).toBe(true);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
it('should skip cache when cacheMode is skip', async () => {
|
|
261
|
+
const request = {
|
|
262
|
+
tool: 'vibecheck.status',
|
|
263
|
+
projectPath: projectPath,
|
|
264
|
+
cache: { mode: 'skip' },
|
|
265
|
+
};
|
|
266
|
+
const result = await handleTool(request);
|
|
267
|
+
if (result.ok) {
|
|
268
|
+
expect(result.meta?.cached).toBeFalsy();
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
describe('Exclusion Patterns', () => {
|
|
274
|
+
let testDir;
|
|
275
|
+
let projectPath;
|
|
276
|
+
beforeAll(() => {
|
|
277
|
+
testDir = join(tmpdir(), `vibecheck-exclusion-${Date.now()}`);
|
|
278
|
+
projectPath = join(testDir, 'exclusion-test');
|
|
279
|
+
mkdirSync(projectPath, { recursive: true });
|
|
280
|
+
// Create package.json
|
|
281
|
+
writeFileSync(join(projectPath, 'package.json'), JSON.stringify({
|
|
282
|
+
name: 'exclusion-test',
|
|
283
|
+
version: '1.0.0',
|
|
284
|
+
}));
|
|
285
|
+
// Source file with no issues
|
|
286
|
+
mkdirSync(join(projectPath, 'src'));
|
|
287
|
+
writeFileSync(join(projectPath, 'src', 'app.ts'), `
|
|
288
|
+
export const app = 'clean';
|
|
289
|
+
`);
|
|
290
|
+
// Files that should be excluded
|
|
291
|
+
const excludedDirs = [
|
|
292
|
+
'node_modules/pkg',
|
|
293
|
+
'venv/lib',
|
|
294
|
+
'.venv/lib',
|
|
295
|
+
'__pycache__',
|
|
296
|
+
'dist',
|
|
297
|
+
'build',
|
|
298
|
+
'.next',
|
|
299
|
+
];
|
|
300
|
+
for (const dir of excludedDirs) {
|
|
301
|
+
const fullDir = join(projectPath, dir);
|
|
302
|
+
mkdirSync(fullDir, { recursive: true });
|
|
303
|
+
writeFileSync(join(fullDir, 'secret.js'), 'const SECRET = "sk-should-not-be-found";');
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
afterAll(() => {
|
|
307
|
+
if (existsSync(testDir)) {
|
|
308
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
it('should not report findings from node_modules', async () => {
|
|
312
|
+
// This test verifies the sandbox exclusion patterns work
|
|
313
|
+
// In a real integration test, this would run the actual scan
|
|
314
|
+
const request = {
|
|
315
|
+
tool: 'vibecheck.scan',
|
|
316
|
+
projectPath: projectPath,
|
|
317
|
+
options: { profile: 'security' },
|
|
318
|
+
};
|
|
319
|
+
const result = await handleTool(request);
|
|
320
|
+
// If scan succeeds, verify no node_modules findings
|
|
321
|
+
if (result.ok) {
|
|
322
|
+
const data = result.data;
|
|
323
|
+
const findings = data.findings ?? [];
|
|
324
|
+
const nodeModulesFindings = findings.filter(f => f.file.includes('node_modules'));
|
|
325
|
+
expect(nodeModulesFindings.length).toBe(0);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
it('should not report findings from venv', async () => {
|
|
329
|
+
const request = {
|
|
330
|
+
tool: 'vibecheck.scan',
|
|
331
|
+
projectPath: projectPath,
|
|
332
|
+
options: { profile: 'security' },
|
|
333
|
+
};
|
|
334
|
+
const result = await handleTool(request);
|
|
335
|
+
if (result.ok) {
|
|
336
|
+
const data = result.data;
|
|
337
|
+
const findings = data.findings ?? [];
|
|
338
|
+
const venvFindings = findings.filter(f => f.file.includes('venv') || f.file.includes('.venv'));
|
|
339
|
+
expect(venvFindings.length).toBe(0);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
//# sourceMappingURL=tools.test.js.map
|