tryassay 0.33.1 → 0.34.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/cli.js +20 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/hunt.d.ts +2 -0
- package/dist/commands/hunt.js +58 -7
- package/dist/commands/hunt.js.map +1 -1
- package/dist/commands/mcp.d.ts +14 -0
- package/dist/commands/mcp.js +18 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/watch.d.ts +19 -0
- package/dist/commands/watch.js +158 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/hunt/__tests__/finding-to-template.test.d.ts +1 -0
- package/dist/hunt/__tests__/finding-to-template.test.js +213 -0
- package/dist/hunt/__tests__/finding-to-template.test.js.map +1 -0
- package/dist/hunt/__tests__/parse-utils.test.js +28 -1
- package/dist/hunt/__tests__/parse-utils.test.js.map +1 -1
- package/dist/hunt/__tests__/taint-analysis.test.d.ts +1 -0
- package/dist/hunt/__tests__/taint-analysis.test.js +556 -0
- package/dist/hunt/__tests__/taint-analysis.test.js.map +1 -0
- package/dist/hunt/__tests__/templates.test.js +2 -2
- package/dist/hunt/__tests__/templates.test.js.map +1 -1
- package/dist/hunt/deep-dive.d.ts +2 -2
- package/dist/hunt/deep-dive.js +4 -4
- package/dist/hunt/deep-dive.js.map +1 -1
- package/dist/hunt/discovery.js +2 -2
- package/dist/hunt/discovery.js.map +1 -1
- package/dist/hunt/finding-to-template.d.ts +47 -0
- package/dist/hunt/finding-to-template.js +288 -0
- package/dist/hunt/finding-to-template.js.map +1 -0
- package/dist/hunt/orchestrator.d.ts +3 -0
- package/dist/hunt/orchestrator.js +20 -5
- package/dist/hunt/orchestrator.js.map +1 -1
- package/dist/hunt/taint-analysis.d.ts +49 -0
- package/dist/hunt/taint-analysis.js +429 -0
- package/dist/hunt/taint-analysis.js.map +1 -0
- package/dist/hunt/templates/csv-injection.d.ts +2 -0
- package/dist/hunt/templates/csv-injection.js +148 -0
- package/dist/hunt/templates/csv-injection.js.map +1 -0
- package/dist/hunt/templates/django-misconfig.d.ts +2 -0
- package/dist/hunt/templates/django-misconfig.js +172 -0
- package/dist/hunt/templates/django-misconfig.js.map +1 -0
- package/dist/hunt/templates/express-misconfig.d.ts +2 -0
- package/dist/hunt/templates/express-misconfig.js +156 -0
- package/dist/hunt/templates/express-misconfig.js.map +1 -0
- package/dist/hunt/templates/file-upload.d.ts +2 -0
- package/dist/hunt/templates/file-upload.js +131 -0
- package/dist/hunt/templates/file-upload.js.map +1 -0
- package/dist/hunt/templates/graphql-abuse.d.ts +2 -0
- package/dist/hunt/templates/graphql-abuse.js +161 -0
- package/dist/hunt/templates/graphql-abuse.js.map +1 -0
- package/dist/hunt/templates/hardcoded-credentials.d.ts +2 -0
- package/dist/hunt/templates/hardcoded-credentials.js +109 -0
- package/dist/hunt/templates/hardcoded-credentials.js.map +1 -0
- package/dist/hunt/templates/idor.d.ts +2 -0
- package/dist/hunt/templates/idor.js +102 -0
- package/dist/hunt/templates/idor.js.map +1 -0
- package/dist/hunt/templates/index.d.ts +2 -2
- package/dist/hunt/templates/index.js +38 -5
- package/dist/hunt/templates/index.js.map +1 -1
- package/dist/hunt/templates/insecure-deserialization.d.ts +2 -0
- package/dist/hunt/templates/insecure-deserialization.js +131 -0
- package/dist/hunt/templates/insecure-deserialization.js.map +1 -0
- package/dist/hunt/templates/mass-assignment.d.ts +2 -0
- package/dist/hunt/templates/mass-assignment.js +101 -0
- package/dist/hunt/templates/mass-assignment.js.map +1 -0
- package/dist/hunt/templates/nextjs-misconfig.d.ts +2 -0
- package/dist/hunt/templates/nextjs-misconfig.js +127 -0
- package/dist/hunt/templates/nextjs-misconfig.js.map +1 -0
- package/dist/hunt/templates/postmessage.d.ts +2 -0
- package/dist/hunt/templates/postmessage.js +180 -0
- package/dist/hunt/templates/postmessage.js.map +1 -0
- package/dist/hunt/templates/race-condition.d.ts +2 -0
- package/dist/hunt/templates/race-condition.js +138 -0
- package/dist/hunt/templates/race-condition.js.map +1 -0
- package/dist/hunt/templates/spring-misconfig.d.ts +2 -0
- package/dist/hunt/templates/spring-misconfig.js +177 -0
- package/dist/hunt/templates/spring-misconfig.js.map +1 -0
- package/dist/hunt/templates/xxe.d.ts +2 -0
- package/dist/hunt/templates/xxe.js +187 -0
- package/dist/hunt/templates/xxe.js.map +1 -0
- package/dist/hunt/triage.d.ts +2 -2
- package/dist/hunt/triage.js +4 -4
- package/dist/hunt/triage.js.map +1 -1
- package/dist/realtime/__tests__/catch-real-bugs.test.d.ts +9 -0
- package/dist/realtime/__tests__/catch-real-bugs.test.js +205 -0
- package/dist/realtime/__tests__/catch-real-bugs.test.js.map +1 -0
- package/dist/realtime/__tests__/code-buffer.test.d.ts +1 -0
- package/dist/realtime/__tests__/code-buffer.test.js +202 -0
- package/dist/realtime/__tests__/code-buffer.test.js.map +1 -0
- package/dist/realtime/__tests__/correction-injector.test.d.ts +1 -0
- package/dist/realtime/__tests__/correction-injector.test.js +168 -0
- package/dist/realtime/__tests__/correction-injector.test.js.map +1 -0
- package/dist/realtime/__tests__/stream-interceptor.test.d.ts +1 -0
- package/dist/realtime/__tests__/stream-interceptor.test.js +193 -0
- package/dist/realtime/__tests__/stream-interceptor.test.js.map +1 -0
- package/dist/realtime/__tests__/streaming-checks.test.d.ts +1 -0
- package/dist/realtime/__tests__/streaming-checks.test.js +479 -0
- package/dist/realtime/__tests__/streaming-checks.test.js.map +1 -0
- package/dist/realtime/__tests__/streaming-verifier.test.d.ts +1 -0
- package/dist/realtime/__tests__/streaming-verifier.test.js +157 -0
- package/dist/realtime/__tests__/streaming-verifier.test.js.map +1 -0
- package/dist/realtime/code-buffer.d.ts +52 -0
- package/dist/realtime/code-buffer.js +276 -0
- package/dist/realtime/code-buffer.js.map +1 -0
- package/dist/realtime/correction-injector.d.ts +56 -0
- package/dist/realtime/correction-injector.js +96 -0
- package/dist/realtime/correction-injector.js.map +1 -0
- package/dist/realtime/index.d.ts +14 -0
- package/dist/realtime/index.js +11 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/mcp-server.d.ts +14 -0
- package/dist/realtime/mcp-server.js +200 -0
- package/dist/realtime/mcp-server.js.map +1 -0
- package/dist/realtime/stream-interceptor.d.ts +65 -0
- package/dist/realtime/stream-interceptor.js +174 -0
- package/dist/realtime/stream-interceptor.js.map +1 -0
- package/dist/realtime/streaming-checks.d.ts +55 -0
- package/dist/realtime/streaming-checks.js +452 -0
- package/dist/realtime/streaming-checks.js.map +1 -0
- package/dist/realtime/streaming-verifier.d.ts +57 -0
- package/dist/realtime/streaming-verifier.js +134 -0
- package/dist/realtime/streaming-verifier.js.map +1 -0
- package/dist/realtime/types.d.ts +99 -0
- package/dist/realtime/types.js +8 -0
- package/dist/realtime/types.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdirSync, rmSync, existsSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { findingToTemplate, saveLearnedTemplate, loadLearnedTemplates, extractFilePatterns, extractBypasses, } from '../finding-to-template.js';
|
|
6
|
+
// ── Fixtures ─────────────────────────────────────────────────
|
|
7
|
+
function makeFinding(overrides = {}) {
|
|
8
|
+
return {
|
|
9
|
+
hypothesisId: 1,
|
|
10
|
+
templateId: 'csrf-bypass',
|
|
11
|
+
file: 'packages/next/src/server/csrf-protection.ts',
|
|
12
|
+
line: 42,
|
|
13
|
+
cwe: 'CWE-352',
|
|
14
|
+
severity: 'high',
|
|
15
|
+
title: 'CSRF wildcard domain bypass via TLD-level wildcards',
|
|
16
|
+
attackScenario: `An attacker can bypass CSRF protection by exploiting TLD-level wildcard matching.
|
|
17
|
+
1. Craft a request from evil.com with Origin header
|
|
18
|
+
2. The matchWildcardDomain() function accepts *.com as a valid wildcard
|
|
19
|
+
3. This bypasses the CSRF origin check for all .com domains`,
|
|
20
|
+
reproductionSteps: `1. Set allowedOrigins to ["*.com"]
|
|
21
|
+
2. Send POST with Origin: https://evil.com
|
|
22
|
+
3. Observe CSRF check passes when it should fail
|
|
23
|
+
|
|
24
|
+
curl -X POST https://target.com/api/action \\
|
|
25
|
+
-H "Origin: https://evil.com" \\
|
|
26
|
+
-H "Content-Type: application/json" \\
|
|
27
|
+
-d '{"action": "delete"}'`,
|
|
28
|
+
evidence: `function matchWildcardDomain(origin: string, pattern: string): boolean {
|
|
29
|
+
// Should reject TLD-level wildcards like *.com but doesn't
|
|
30
|
+
const regex = new RegExp(pattern.replace('*', '.*'));
|
|
31
|
+
return regex.test(origin);
|
|
32
|
+
}`,
|
|
33
|
+
recommendation: `Validate that wildcard patterns have at least two labels (e.g., *.example.com, not *.com).
|
|
34
|
+
Check RFC 6454 Section 5 for origin comparison rules.
|
|
35
|
+
See also OWASP CSRF Prevention Cheat Sheet.`,
|
|
36
|
+
confirmed: true,
|
|
37
|
+
...overrides,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// ── Test setup ───────────────────────────────────────────────
|
|
41
|
+
let testDir;
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
testDir = join(tmpdir(), `assay-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
44
|
+
mkdirSync(testDir, { recursive: true });
|
|
45
|
+
});
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
try {
|
|
48
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// cleanup best-effort
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// ── Tests ────────────────────────────────────────────────────
|
|
55
|
+
describe('findingToTemplate', () => {
|
|
56
|
+
it('creates a learned template with correct structure', () => {
|
|
57
|
+
const finding = makeFinding();
|
|
58
|
+
const learned = findingToTemplate(finding);
|
|
59
|
+
expect(learned.source).toBe('bounty-finding');
|
|
60
|
+
expect(learned.sourceFinding).toBe(finding.title);
|
|
61
|
+
expect(learned.id).toMatch(/^learned-/);
|
|
62
|
+
expect(learned.createdAt).toBeTruthy();
|
|
63
|
+
const t = learned.template;
|
|
64
|
+
expect(t.id).toBe(learned.id);
|
|
65
|
+
expect(t.name).toContain('[Learned]');
|
|
66
|
+
expect(t.name).toContain(finding.title);
|
|
67
|
+
expect(t.cwe).toBe('CWE-352');
|
|
68
|
+
expect(t.filePatterns.length).toBeGreaterThanOrEqual(2);
|
|
69
|
+
expect(t.triagePrompt).toContain(finding.attackScenario);
|
|
70
|
+
expect(t.deepDivePrompt).toContain(finding.reproductionSteps);
|
|
71
|
+
expect(t.severityRange).toEqual(['medium', 'critical']); // high -> [medium, critical]
|
|
72
|
+
expect(t.knownBypasses.length).toBeGreaterThan(0);
|
|
73
|
+
});
|
|
74
|
+
it('generates unique IDs for different findings', () => {
|
|
75
|
+
const f1 = makeFinding({ title: 'Finding One' });
|
|
76
|
+
const f2 = makeFinding({ title: 'Finding Two' });
|
|
77
|
+
const t1 = findingToTemplate(f1);
|
|
78
|
+
const t2 = findingToTemplate(f2);
|
|
79
|
+
expect(t1.id).not.toBe(t2.id);
|
|
80
|
+
});
|
|
81
|
+
it('maps severity ranges correctly', () => {
|
|
82
|
+
const cases = [
|
|
83
|
+
['critical', ['high', 'critical']],
|
|
84
|
+
['high', ['medium', 'critical']],
|
|
85
|
+
['medium', ['low', 'high']],
|
|
86
|
+
['low', ['low', 'medium']],
|
|
87
|
+
];
|
|
88
|
+
for (const [severity, expected] of cases) {
|
|
89
|
+
const t = findingToTemplate(makeFinding({ severity }));
|
|
90
|
+
expect(t.template.severityRange).toEqual(expected);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('extractFilePatterns', () => {
|
|
95
|
+
it('extracts path-derived keywords', () => {
|
|
96
|
+
const finding = makeFinding({ file: 'packages/next/src/server/csrf-protection.ts' });
|
|
97
|
+
const patterns = extractFilePatterns(finding);
|
|
98
|
+
expect(patterns).toContain('csrf-protection');
|
|
99
|
+
expect(patterns).toContain('server');
|
|
100
|
+
expect(patterns).toContain('next');
|
|
101
|
+
});
|
|
102
|
+
it('extracts technology keywords from attack scenario', () => {
|
|
103
|
+
const finding = makeFinding({
|
|
104
|
+
attackScenario: 'The attacker uses postMessage to send a crafted CSRF token via an iframe',
|
|
105
|
+
});
|
|
106
|
+
const patterns = extractFilePatterns(finding);
|
|
107
|
+
expect(patterns).toContain('postmessage');
|
|
108
|
+
expect(patterns).toContain('csrf');
|
|
109
|
+
expect(patterns).toContain('iframe');
|
|
110
|
+
expect(patterns).toContain('token');
|
|
111
|
+
});
|
|
112
|
+
it('extracts import names from evidence', () => {
|
|
113
|
+
const finding = makeFinding({
|
|
114
|
+
evidence: `import { validateOrigin } from '../utils/csrf-helpers';`,
|
|
115
|
+
});
|
|
116
|
+
const patterns = extractFilePatterns(finding);
|
|
117
|
+
expect(patterns).toContain('csrf-helpers');
|
|
118
|
+
});
|
|
119
|
+
it('returns at least 2 patterns', () => {
|
|
120
|
+
const finding = makeFinding({
|
|
121
|
+
file: 'a.ts',
|
|
122
|
+
attackScenario: '',
|
|
123
|
+
evidence: '',
|
|
124
|
+
title: '',
|
|
125
|
+
recommendation: '',
|
|
126
|
+
});
|
|
127
|
+
const patterns = extractFilePatterns(finding);
|
|
128
|
+
expect(patterns.length).toBeGreaterThanOrEqual(2);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('extractBypasses', () => {
|
|
132
|
+
it('extracts bypass steps from numbered list', () => {
|
|
133
|
+
const finding = makeFinding({
|
|
134
|
+
attackScenario: `The vulnerability allows:
|
|
135
|
+
1. Bypass CSRF check by sending null Origin
|
|
136
|
+
2. Exploit the wildcard matching to forge requests
|
|
137
|
+
3. Normal request that is not a bypass`,
|
|
138
|
+
});
|
|
139
|
+
const bypasses = extractBypasses(finding);
|
|
140
|
+
expect(bypasses.length).toBeGreaterThanOrEqual(2);
|
|
141
|
+
expect(bypasses.some(b => b.toLowerCase().includes('bypass'))).toBe(true);
|
|
142
|
+
expect(bypasses.some(b => b.toLowerCase().includes('exploit'))).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
it('falls back to first sentence when no structured bypasses', () => {
|
|
145
|
+
const finding = makeFinding({
|
|
146
|
+
attackScenario: 'The attacker sends a crafted request to bypass validation. This is a long explanation.',
|
|
147
|
+
reproductionSteps: 'Step one. Step two.',
|
|
148
|
+
});
|
|
149
|
+
const bypasses = extractBypasses(finding);
|
|
150
|
+
expect(bypasses.length).toBeGreaterThanOrEqual(1);
|
|
151
|
+
expect(bypasses[0]).toContain('crafted request');
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
describe('saveLearnedTemplate + loadLearnedTemplates', () => {
|
|
155
|
+
it('saves and loads a template (project-local)', () => {
|
|
156
|
+
const learned = findingToTemplate(makeFinding());
|
|
157
|
+
saveLearnedTemplate(learned, { projectRoot: testDir });
|
|
158
|
+
const storePath = join(testDir, '.assay', 'learned', 'templates.json');
|
|
159
|
+
expect(existsSync(storePath)).toBe(true);
|
|
160
|
+
const loaded = loadLearnedTemplates(testDir);
|
|
161
|
+
expect(loaded).toHaveLength(1);
|
|
162
|
+
expect(loaded[0].id).toBe(learned.id);
|
|
163
|
+
expect(loaded[0].cwe).toBe('CWE-352');
|
|
164
|
+
});
|
|
165
|
+
it('deduplicates by ID on save', () => {
|
|
166
|
+
const learned = findingToTemplate(makeFinding());
|
|
167
|
+
saveLearnedTemplate(learned, { projectRoot: testDir });
|
|
168
|
+
saveLearnedTemplate(learned, { projectRoot: testDir });
|
|
169
|
+
const loaded = loadLearnedTemplates(testDir);
|
|
170
|
+
expect(loaded).toHaveLength(1);
|
|
171
|
+
});
|
|
172
|
+
it('loads empty array when no store exists', () => {
|
|
173
|
+
const loaded = loadLearnedTemplates(testDir);
|
|
174
|
+
expect(loaded).toEqual([]);
|
|
175
|
+
});
|
|
176
|
+
it('handles corrupted store file gracefully', () => {
|
|
177
|
+
const storePath = join(testDir, '.assay', 'learned', 'templates.json');
|
|
178
|
+
mkdirSync(join(testDir, '.assay', 'learned'), { recursive: true });
|
|
179
|
+
const { writeFileSync } = require('node:fs');
|
|
180
|
+
writeFileSync(storePath, 'NOT JSON', 'utf-8');
|
|
181
|
+
const loaded = loadLearnedTemplates(testDir);
|
|
182
|
+
expect(loaded).toEqual([]);
|
|
183
|
+
});
|
|
184
|
+
it('multiple templates accumulate', () => {
|
|
185
|
+
const f1 = makeFinding({ title: 'Finding Alpha' });
|
|
186
|
+
const f2 = makeFinding({ title: 'Finding Beta' });
|
|
187
|
+
const t1 = findingToTemplate(f1);
|
|
188
|
+
const t2 = findingToTemplate(f2);
|
|
189
|
+
saveLearnedTemplate(t1, { projectRoot: testDir });
|
|
190
|
+
saveLearnedTemplate(t2, { projectRoot: testDir });
|
|
191
|
+
const loaded = loadLearnedTemplates(testDir);
|
|
192
|
+
expect(loaded).toHaveLength(2);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
describe('template registry integration', () => {
|
|
196
|
+
it('getAllTemplates includes learned templates', async () => {
|
|
197
|
+
// Import getAllTemplates dynamically to avoid circular dependency issues
|
|
198
|
+
const { getAllTemplates } = await import('../templates/index.js');
|
|
199
|
+
// Without any learned templates in a non-existent dir, should just return built-ins
|
|
200
|
+
const builtIn = getAllTemplates('/non-existent-path-for-test');
|
|
201
|
+
expect(builtIn.length).toBeGreaterThanOrEqual(10); // 10 built-in templates
|
|
202
|
+
// Save a learned template
|
|
203
|
+
const learned = findingToTemplate(makeFinding());
|
|
204
|
+
saveLearnedTemplate(learned, { projectRoot: testDir });
|
|
205
|
+
// Now getAllTemplates should include the learned one
|
|
206
|
+
const withLearned = getAllTemplates(testDir);
|
|
207
|
+
expect(withLearned.length).toBe(builtIn.length + 1);
|
|
208
|
+
const learnedTemplate = withLearned.find(t => t.id === learned.id);
|
|
209
|
+
expect(learnedTemplate).toBeDefined();
|
|
210
|
+
expect(learnedTemplate.name).toContain('[Learned]');
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
//# sourceMappingURL=finding-to-template.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding-to-template.test.js","sourceRoot":"","sources":["../../../src/hunt/__tests__/finding-to-template.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { stripCodeFences, safeParseJSON } from '../parse-utils.js';
|
|
2
|
+
import { stripCodeFences, extractJSON, safeParseJSON } from '../parse-utils.js';
|
|
3
3
|
describe('stripCodeFences', () => {
|
|
4
4
|
it('strips markdown code fences', () => {
|
|
5
5
|
expect(stripCodeFences('```json\n{"a":1}\n```')).toBe('{"a":1}');
|
|
@@ -11,6 +11,29 @@ describe('stripCodeFences', () => {
|
|
|
11
11
|
expect(stripCodeFences('```typescript\ncode\n```')).toBe('code');
|
|
12
12
|
});
|
|
13
13
|
});
|
|
14
|
+
describe('extractJSON', () => {
|
|
15
|
+
it('extracts JSON from code fences with trailing prose', () => {
|
|
16
|
+
const input = '```json\n{"vulnerable": false}\n```\n\n**Reasoning:**\n\nSome explanation...';
|
|
17
|
+
expect(extractJSON(input)).toBe('{"vulnerable": false}');
|
|
18
|
+
});
|
|
19
|
+
it('extracts JSON from code fences without trailing text', () => {
|
|
20
|
+
expect(extractJSON('```json\n{"a":1}\n```')).toBe('{"a":1}');
|
|
21
|
+
});
|
|
22
|
+
it('extracts plain JSON object', () => {
|
|
23
|
+
expect(extractJSON('{"a":1}')).toBe('{"a":1}');
|
|
24
|
+
});
|
|
25
|
+
it('extracts JSON with prefix text', () => {
|
|
26
|
+
const input = 'Here is my analysis:\n{"vulnerable": true}';
|
|
27
|
+
expect(extractJSON(input)).toBe('{"vulnerable": true}');
|
|
28
|
+
});
|
|
29
|
+
it('handles nested objects', () => {
|
|
30
|
+
const input = 'Result: {"a": {"b": 1}, "c": 2} done';
|
|
31
|
+
expect(extractJSON(input)).toBe('{"a": {"b": 1}, "c": 2}');
|
|
32
|
+
});
|
|
33
|
+
it('returns trimmed text when no JSON found', () => {
|
|
34
|
+
expect(extractJSON(' no json here ')).toBe('no json here');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
14
37
|
describe('safeParseJSON', () => {
|
|
15
38
|
it('parses valid JSON', () => {
|
|
16
39
|
expect(safeParseJSON('{"a":1}')).toEqual({ a: 1 });
|
|
@@ -18,6 +41,10 @@ describe('safeParseJSON', () => {
|
|
|
18
41
|
it('parses JSON inside code fences', () => {
|
|
19
42
|
expect(safeParseJSON('```json\n{"a":1}\n```')).toEqual({ a: 1 });
|
|
20
43
|
});
|
|
44
|
+
it('parses JSON from code fences with trailing reasoning', () => {
|
|
45
|
+
const input = '```json\n{"vulnerable": false, "confidence": "high"}\n```\n\n**Reasoning:**\n\nLong explanation here...';
|
|
46
|
+
expect(safeParseJSON(input)).toEqual({ vulnerable: false, confidence: 'high' });
|
|
47
|
+
});
|
|
21
48
|
it('returns null for invalid JSON', () => {
|
|
22
49
|
expect(safeParseJSON('not json')).toBeNull();
|
|
23
50
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-utils.test.js","sourceRoot":"","sources":["../../../src/hunt/__tests__/parse-utils.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"parse-utils.test.js","sourceRoot":"","sources":["../../../src/hunt/__tests__/parse-utils.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEhF,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,eAAe,CAAC,0BAA0B,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,KAAK,GAAG,8EAA8E,CAAC;QAC7F,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,KAAK,GAAG,4CAA4C,CAAC;QAC3D,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,KAAK,GAAG,sCAAsC,CAAC;QACrD,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,KAAK,GAAG,yGAAyG,CAAC;QACxH,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|