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,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming Checks — stateless, pre-compiled pattern matchers for real-time verification.
|
|
3
|
+
*
|
|
4
|
+
* Extracts the regex-based formal verification checks from the existing
|
|
5
|
+
* formal-verifier.ts into standalone StreamingCheck objects. Also loads
|
|
6
|
+
* learned rules from the catalog and compiles them into the same format.
|
|
7
|
+
*
|
|
8
|
+
* All regex patterns are created once at module load time and reused across
|
|
9
|
+
* invocations. The `runChecks` function targets <10ms for the full check set
|
|
10
|
+
* against a single code unit.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
// ── Formal Checks (hand-crafted) ────────────────────────────────
|
|
15
|
+
const JS_LANGS = ['typescript', 'javascript', 'ts', 'js', 'tsx', 'jsx'];
|
|
16
|
+
const PY_LANGS = ['python', 'py'];
|
|
17
|
+
const ALL_LANGS = []; // empty = applies to all
|
|
18
|
+
/**
|
|
19
|
+
* Returns all hand-crafted formal checks as StreamingCheck objects.
|
|
20
|
+
*
|
|
21
|
+
* These cover the key vulnerability patterns from formal-verifier.ts,
|
|
22
|
+
* adapted for streaming (line/statement-level) detection during generation.
|
|
23
|
+
*/
|
|
24
|
+
export function getFormalChecks() {
|
|
25
|
+
return FORMAL_CHECKS;
|
|
26
|
+
}
|
|
27
|
+
const FORMAL_CHECKS = [
|
|
28
|
+
// 1. SQL injection — string concatenation in queries
|
|
29
|
+
{
|
|
30
|
+
id: 'sql_concat_injection',
|
|
31
|
+
name: 'SQL string concatenation',
|
|
32
|
+
languages: [...JS_LANGS, ...PY_LANGS],
|
|
33
|
+
pattern: /(?:SELECT|INSERT|UPDATE|DELETE)\s[^;]*["'`]\s*\+\s*\w+/i,
|
|
34
|
+
verdict: 'FAIL',
|
|
35
|
+
severity: 'critical',
|
|
36
|
+
evidenceTemplate: 'SQL query uses string concatenation: $0',
|
|
37
|
+
suggestion: 'Use parameterized queries ($1, ?, or :named placeholders) instead of string concatenation.',
|
|
38
|
+
source: 'formal',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'sql_template_injection',
|
|
42
|
+
name: 'SQL template literal injection',
|
|
43
|
+
languages: JS_LANGS,
|
|
44
|
+
pattern: /`[^`]*(?:SELECT|INSERT|UPDATE|DELETE)[^`]*\$\{(?!\d)/i,
|
|
45
|
+
verdict: 'FAIL',
|
|
46
|
+
severity: 'critical',
|
|
47
|
+
evidenceTemplate: 'SQL query uses template literal interpolation: $0',
|
|
48
|
+
suggestion: 'Use parameterized queries instead of template literal interpolation in SQL strings.',
|
|
49
|
+
source: 'formal',
|
|
50
|
+
},
|
|
51
|
+
// 2. Missing error handling — unhandled promise chains
|
|
52
|
+
{
|
|
53
|
+
id: 'unhandled_promise',
|
|
54
|
+
name: 'Unhandled promise (no .catch)',
|
|
55
|
+
languages: JS_LANGS,
|
|
56
|
+
pattern: /(?:fetch|axios\.\w+)\s*\([^)]*\)\s*\.then\s*\([^)]*\)(?![\s\S]*\.catch)/,
|
|
57
|
+
verdict: 'FAIL',
|
|
58
|
+
severity: 'high',
|
|
59
|
+
evidenceTemplate: 'Promise chain without .catch() handler: $0',
|
|
60
|
+
suggestion: 'Add a .catch() handler or use try/catch with await.',
|
|
61
|
+
source: 'formal',
|
|
62
|
+
},
|
|
63
|
+
// 3. Hardcoded credentials/secrets
|
|
64
|
+
{
|
|
65
|
+
id: 'hardcoded_secret',
|
|
66
|
+
name: 'Hardcoded secret or API key',
|
|
67
|
+
languages: ALL_LANGS,
|
|
68
|
+
pattern: /(?:const|let|var|=)\s*(?:\w+)?\s*(?:api[_-]?key|secret|password|token|auth)\s*=\s*["'`](?:sk-|pk-|ghp_|gho_|github_pat_|xox[bpors]-|AIza|AKIA|bearer\s).{8,}/i,
|
|
69
|
+
verdict: 'FAIL',
|
|
70
|
+
severity: 'critical',
|
|
71
|
+
evidenceTemplate: 'Hardcoded secret detected: $0',
|
|
72
|
+
suggestion: 'Use environment variables or a secrets manager instead of hardcoding credentials.',
|
|
73
|
+
source: 'formal',
|
|
74
|
+
},
|
|
75
|
+
// 4. Unsafe eval / Function constructor
|
|
76
|
+
{
|
|
77
|
+
id: 'unsafe_eval',
|
|
78
|
+
name: 'Unsafe eval() usage',
|
|
79
|
+
languages: JS_LANGS,
|
|
80
|
+
pattern: /\beval\s*\(\s*(?!\s*['"`][\s\S]*['"`]\s*\))/, // eval( but not eval("literal")
|
|
81
|
+
verdict: 'FAIL',
|
|
82
|
+
severity: 'critical',
|
|
83
|
+
evidenceTemplate: 'Unsafe eval() call detected: $0',
|
|
84
|
+
suggestion: 'Replace eval() with a safer alternative like JSON.parse() or a sandboxed evaluator.',
|
|
85
|
+
source: 'formal',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'unsafe_function_constructor',
|
|
89
|
+
name: 'Unsafe Function constructor',
|
|
90
|
+
languages: JS_LANGS,
|
|
91
|
+
pattern: /new\s+Function\s*\(/,
|
|
92
|
+
verdict: 'FAIL',
|
|
93
|
+
severity: 'critical',
|
|
94
|
+
evidenceTemplate: 'Unsafe new Function() call detected: $0',
|
|
95
|
+
suggestion: 'Avoid new Function(). Use static code paths or a sandboxed evaluator.',
|
|
96
|
+
source: 'formal',
|
|
97
|
+
},
|
|
98
|
+
// 5. Insecure randomness (Math.random for security)
|
|
99
|
+
{
|
|
100
|
+
id: 'insecure_random',
|
|
101
|
+
name: 'Math.random() used for security',
|
|
102
|
+
languages: JS_LANGS,
|
|
103
|
+
pattern: /(?:token|secret|key|nonce|csrf|session|password|salt|hash)\s*(?:=|:)\s*.*Math\.random/i,
|
|
104
|
+
verdict: 'FAIL',
|
|
105
|
+
severity: 'high',
|
|
106
|
+
evidenceTemplate: 'Math.random() used in security-sensitive context: $0',
|
|
107
|
+
suggestion: 'Use crypto.randomUUID() or crypto.getRandomValues() for security-sensitive random values.',
|
|
108
|
+
source: 'formal',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'insecure_random_token',
|
|
112
|
+
name: 'Math.random() token generation',
|
|
113
|
+
languages: JS_LANGS,
|
|
114
|
+
pattern: /Math\.random\(\)\.toString\(36\)/,
|
|
115
|
+
verdict: 'FAIL',
|
|
116
|
+
severity: 'high',
|
|
117
|
+
evidenceTemplate: 'Insecure token generation using Math.random(): $0',
|
|
118
|
+
suggestion: 'Use crypto.randomUUID() or crypto.randomBytes() for token generation.',
|
|
119
|
+
source: 'formal',
|
|
120
|
+
},
|
|
121
|
+
// 6. Prototype pollution patterns
|
|
122
|
+
{
|
|
123
|
+
id: 'prototype_pollution',
|
|
124
|
+
name: 'Prototype pollution risk',
|
|
125
|
+
languages: JS_LANGS,
|
|
126
|
+
pattern: /\w+\[(?:\w+|\w+\[\w+\])\]\s*=\s*(?!\s*(?:null|undefined|false|true|0|''|""|``)\s*[;,)])/,
|
|
127
|
+
verdict: 'FAIL',
|
|
128
|
+
severity: 'high',
|
|
129
|
+
evidenceTemplate: 'Dynamic property assignment may allow prototype pollution: $0',
|
|
130
|
+
suggestion: 'Validate property names against __proto__, constructor, and prototype before dynamic assignment.',
|
|
131
|
+
source: 'formal',
|
|
132
|
+
},
|
|
133
|
+
// 7. Path traversal
|
|
134
|
+
{
|
|
135
|
+
id: 'path_traversal',
|
|
136
|
+
name: 'Path traversal vulnerability',
|
|
137
|
+
languages: [...JS_LANGS, ...PY_LANGS],
|
|
138
|
+
pattern: /(?:readFile|readFileSync|createReadStream|writeFile|writeFileSync|open)\s*\(\s*(?:req\.(?:params|query|body)|request\.(?:args|form|json))\s*[\[.]/,
|
|
139
|
+
verdict: 'FAIL',
|
|
140
|
+
severity: 'critical',
|
|
141
|
+
evidenceTemplate: 'User input passed directly to filesystem operation: $0',
|
|
142
|
+
suggestion: 'Sanitize file paths with path.resolve() and verify they stay within the intended directory.',
|
|
143
|
+
source: 'formal',
|
|
144
|
+
},
|
|
145
|
+
// 8. Command injection
|
|
146
|
+
{
|
|
147
|
+
id: 'command_injection',
|
|
148
|
+
name: 'Command injection vulnerability',
|
|
149
|
+
languages: [...JS_LANGS, ...PY_LANGS],
|
|
150
|
+
pattern: /(?:exec|execSync|spawn|spawnSync|system|popen)\s*\(\s*(?:["'`][^"'`]*["'`]\s*\+|`[^`]*\$\{)/,
|
|
151
|
+
verdict: 'FAIL',
|
|
152
|
+
severity: 'critical',
|
|
153
|
+
evidenceTemplate: 'Command injection risk — shell command built with concatenation: $0',
|
|
154
|
+
suggestion: 'Use execFile() or spawn() with an argument array instead of exec() with string concatenation.',
|
|
155
|
+
source: 'formal',
|
|
156
|
+
},
|
|
157
|
+
// 9. Null/undefined access without check
|
|
158
|
+
{
|
|
159
|
+
id: 'unchecked_array_index',
|
|
160
|
+
name: 'Unchecked array index access',
|
|
161
|
+
languages: JS_LANGS,
|
|
162
|
+
pattern: /\w+\[0\]\.\w+(?!\s*\?\.)/, // arr[0].prop without optional chaining
|
|
163
|
+
verdict: 'FAIL',
|
|
164
|
+
severity: 'medium',
|
|
165
|
+
evidenceTemplate: 'Array element accessed without null check: $0',
|
|
166
|
+
suggestion: 'Check array length before accessing elements, or use optional chaining (arr[0]?.prop).',
|
|
167
|
+
source: 'formal',
|
|
168
|
+
},
|
|
169
|
+
// 10. Input validation missing — direct use of request params in DB queries
|
|
170
|
+
{
|
|
171
|
+
id: 'unvalidated_input_to_query',
|
|
172
|
+
name: 'Unvalidated input passed to database query',
|
|
173
|
+
languages: JS_LANGS,
|
|
174
|
+
pattern: /\.(?:query|execute|findOne|find|delete|update)\s*\(\s*\{[^}]*(?:req\.(?:params|query|body)|request\.\w+)/,
|
|
175
|
+
verdict: 'FAIL',
|
|
176
|
+
severity: 'high',
|
|
177
|
+
evidenceTemplate: 'Request input passed directly to database query without validation: $0',
|
|
178
|
+
suggestion: 'Validate and sanitize request input with zod, joi, or manual type checks before passing to queries.',
|
|
179
|
+
source: 'formal',
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
// ── Learned Rule Conversion ─────────────────────────────────────
|
|
183
|
+
/**
|
|
184
|
+
* Keyword map: maps keyword triggers found in rule name/description/category
|
|
185
|
+
* to context keywords that must appear in code for the rule to be relevant.
|
|
186
|
+
*
|
|
187
|
+
* When a rule's name, description, or category contains a trigger (left side),
|
|
188
|
+
* the associated keywords (right side) are assigned. The check only runs if
|
|
189
|
+
* at least one keyword is found in the code unit text.
|
|
190
|
+
*/
|
|
191
|
+
const CONTEXT_KEYWORD_MAP = [
|
|
192
|
+
// React / JSX
|
|
193
|
+
{
|
|
194
|
+
triggers: /\b(?:react|jsx|tsx|component|hook|use[A-Z]\w+|memo(?:iz)|useEffect|useState|useRef|useCallback|useMemo)\b/i,
|
|
195
|
+
keywords: ['React', 'useState', 'useEffect', 'useRef', 'useCallback', 'useMemo', 'jsx', 'tsx', 'import react', 'from \'react', 'from "react'],
|
|
196
|
+
},
|
|
197
|
+
// OpenAPI / Swagger / NestJS decorators
|
|
198
|
+
{
|
|
199
|
+
triggers: /\b(?:openapi|swagger|@Api\w*|@Controller|@Get|@Post|@Put|@Delete|@Patch|decorator|NestJS)\b/i,
|
|
200
|
+
keywords: ['@Api', '@Controller', '@Get(', '@Post(', '@Put(', '@Delete(', '@Patch(', 'swagger', 'openapi', '@nestjs'],
|
|
201
|
+
},
|
|
202
|
+
// Canvas / Drawing / 2D rendering
|
|
203
|
+
{
|
|
204
|
+
triggers: /\b(?:canvas|drawImage|getContext|2d\s*context|fillRect|strokeRect|beginPath|WebGL)\b/i,
|
|
205
|
+
keywords: ['canvas', 'drawImage', 'getContext', 'fillRect', 'strokeRect', 'beginPath', 'CanvasRenderingContext', 'webgl'],
|
|
206
|
+
},
|
|
207
|
+
// Stripe
|
|
208
|
+
{
|
|
209
|
+
triggers: /\b(?:stripe|payment.?intent|checkout.?session|subscription)\b/i,
|
|
210
|
+
keywords: ['stripe', 'Stripe', 'payment_intent', 'checkout.sessions', 'PaymentIntent'],
|
|
211
|
+
},
|
|
212
|
+
// GraphQL
|
|
213
|
+
{
|
|
214
|
+
triggers: /\b(?:graphql|resolver|mutation|gql`|@Query|@Mutation|@Resolver)\b/i,
|
|
215
|
+
keywords: ['graphql', 'GraphQL', 'gql`', '@Query', '@Mutation', '@Resolver', 'typeDefs', 'resolvers'],
|
|
216
|
+
},
|
|
217
|
+
// Docker / Container
|
|
218
|
+
{
|
|
219
|
+
triggers: /\b(?:docker|dockerfile|container|ENTRYPOINT|CMD\s)\b/i,
|
|
220
|
+
keywords: ['FROM ', 'ENTRYPOINT', 'CMD [', 'EXPOSE ', 'Dockerfile', 'docker-compose'],
|
|
221
|
+
},
|
|
222
|
+
// Redis
|
|
223
|
+
{
|
|
224
|
+
triggers: /\b(?:redis|HSET|HGET|ZADD|pub.?sub|ioredis)\b/i,
|
|
225
|
+
keywords: ['redis', 'Redis', 'ioredis', 'HSET', 'HGET', 'createClient'],
|
|
226
|
+
},
|
|
227
|
+
// MongoDB / Mongoose
|
|
228
|
+
{
|
|
229
|
+
triggers: /\b(?:mongo(?:db|ose)?|Schema\.Types|ObjectId|aggregate)\b/i,
|
|
230
|
+
keywords: ['mongoose', 'MongoDB', 'MongoClient', 'Schema.Types', 'ObjectId', '.aggregate('],
|
|
231
|
+
},
|
|
232
|
+
// Django
|
|
233
|
+
{
|
|
234
|
+
triggers: /\b(?:django|models\.Model|views\.py|urls\.py|INSTALLED_APPS)\b/i,
|
|
235
|
+
keywords: ['django', 'Django', 'models.Model', 'INSTALLED_APPS', 'urlpatterns', 'from django'],
|
|
236
|
+
},
|
|
237
|
+
// Flask
|
|
238
|
+
{
|
|
239
|
+
triggers: /\b(?:flask|@app\.route|Blueprint|Jinja)\b/i,
|
|
240
|
+
keywords: ['flask', 'Flask', '@app.route', 'Blueprint', 'from flask'],
|
|
241
|
+
},
|
|
242
|
+
// Vue
|
|
243
|
+
{
|
|
244
|
+
triggers: /\b(?:vue|v-model|v-bind|v-if|defineComponent|ref\(\)|computed\(\))\b/i,
|
|
245
|
+
keywords: ['vue', 'Vue', 'v-model', 'v-bind', 'defineComponent', 'from \'vue', 'from "vue'],
|
|
246
|
+
},
|
|
247
|
+
// Angular
|
|
248
|
+
{
|
|
249
|
+
triggers: /\b(?:angular|@Component|@Injectable|@NgModule|ngOnInit)\b/i,
|
|
250
|
+
keywords: ['@Component', '@Injectable', '@NgModule', 'ngOnInit', '@angular', 'from \'@angular'],
|
|
251
|
+
},
|
|
252
|
+
// WebSocket
|
|
253
|
+
{
|
|
254
|
+
triggers: /\b(?:websocket|ws:\/\/|wss:\/\/|socket\.io|onmessage)\b/i,
|
|
255
|
+
keywords: ['WebSocket', 'ws://', 'wss://', 'socket.io', 'onmessage', 'Socket('],
|
|
256
|
+
},
|
|
257
|
+
// AWS SDK
|
|
258
|
+
{
|
|
259
|
+
triggers: /\b(?:aws.?sdk|S3Client|DynamoDB|Lambda|SQS|SNS|@aws-sdk)\b/i,
|
|
260
|
+
keywords: ['aws-sdk', '@aws-sdk', 'S3Client', 'DynamoDB', 'LambdaClient', 'SQSClient'],
|
|
261
|
+
},
|
|
262
|
+
// Prisma
|
|
263
|
+
{
|
|
264
|
+
triggers: /\b(?:prisma|PrismaClient|prisma\.\$|findUnique|findMany)\b/i,
|
|
265
|
+
keywords: ['prisma', 'Prisma', 'PrismaClient', 'prisma.', '@prisma/client'],
|
|
266
|
+
},
|
|
267
|
+
];
|
|
268
|
+
/**
|
|
269
|
+
* Derive context keywords for a learned rule based on its name, description,
|
|
270
|
+
* and category. Returns undefined if no specific context can be inferred
|
|
271
|
+
* (the rule will run against all code units).
|
|
272
|
+
*/
|
|
273
|
+
function deriveContextKeywords(rule) {
|
|
274
|
+
const searchText = [
|
|
275
|
+
rule.pattern.description,
|
|
276
|
+
rule.pattern.claimCategory,
|
|
277
|
+
rule.id,
|
|
278
|
+
rule.fixDescription ?? '',
|
|
279
|
+
].join(' ');
|
|
280
|
+
for (const entry of CONTEXT_KEYWORD_MAP) {
|
|
281
|
+
if (entry.triggers.test(searchText)) {
|
|
282
|
+
return entry.keywords;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Fallback: try to extract literal strings from the regex pattern itself.
|
|
286
|
+
// Sequences of 4+ alphanumeric chars (likely meaningful identifiers).
|
|
287
|
+
if (rule.pattern.regexPattern) {
|
|
288
|
+
const literals = extractRegexLiterals(rule.pattern.regexPattern);
|
|
289
|
+
if (literals.length > 0) {
|
|
290
|
+
return literals;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Extract literal substrings (4+ alphanumeric chars) from a regex pattern.
|
|
297
|
+
* These are likely the actual identifiers the rule is looking for.
|
|
298
|
+
*/
|
|
299
|
+
function extractRegexLiterals(regexStr) {
|
|
300
|
+
// Match sequences of word chars that are at least 4 chars long,
|
|
301
|
+
// excluding common regex syntax fragments
|
|
302
|
+
const REGEX_NOISE = new Set([
|
|
303
|
+
'true', 'false', 'null', 'undefined', 'this', 'that',
|
|
304
|
+
'with', 'from', 'each', 'some', 'every', 'filter',
|
|
305
|
+
]);
|
|
306
|
+
const matches = regexStr.match(/[a-zA-Z_][a-zA-Z0-9_]{3,}/g) ?? [];
|
|
307
|
+
const unique = [...new Set(matches)].filter(m => !REGEX_NOISE.has(m.toLowerCase()));
|
|
308
|
+
return unique.length <= 10 ? unique : unique.slice(0, 10);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Load learned rules from the catalog and convert them to StreamingCheck format.
|
|
312
|
+
*
|
|
313
|
+
* Default path: `.assay/learned/rules.json` relative to process.cwd().
|
|
314
|
+
* Falls back to an empty set if the file doesn't exist (starter rules
|
|
315
|
+
* are loaded separately by getFormalChecks equivalent in the catalog).
|
|
316
|
+
*
|
|
317
|
+
* Each rule is assigned contextKeywords for relevance filtering — the check
|
|
318
|
+
* only runs on code units that contain at least one keyword.
|
|
319
|
+
*/
|
|
320
|
+
export function loadLearnedChecks(catalogPath) {
|
|
321
|
+
const filePath = catalogPath ?? join(process.cwd(), '.assay', 'learned', 'rules.json');
|
|
322
|
+
let rules;
|
|
323
|
+
try {
|
|
324
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
325
|
+
const parsed = JSON.parse(content);
|
|
326
|
+
rules = Array.isArray(parsed) ? parsed : [];
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
// No catalog on disk — return empty (starter rules are part of formal checks)
|
|
330
|
+
return [];
|
|
331
|
+
}
|
|
332
|
+
return rules
|
|
333
|
+
.filter(r => r.status === 'promoted' || r.status === 'validated')
|
|
334
|
+
.filter(r => r.pattern.kind === 'regex' && r.pattern.regexPattern)
|
|
335
|
+
.map(r => learnedRuleToCheck(r));
|
|
336
|
+
}
|
|
337
|
+
function learnedRuleToCheck(rule) {
|
|
338
|
+
let pattern;
|
|
339
|
+
try {
|
|
340
|
+
pattern = new RegExp(rule.pattern.regexPattern, 'i');
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
// Invalid regex — create a pattern that never matches
|
|
344
|
+
pattern = /(?!)/;
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
id: `learned_${rule.id}`,
|
|
348
|
+
name: rule.pattern.description.slice(0, 80),
|
|
349
|
+
languages: [...rule.pattern.languages],
|
|
350
|
+
pattern,
|
|
351
|
+
verdict: rule.pattern.matchBehavior === 'presence_is_bad' ? 'FAIL' : 'PASS',
|
|
352
|
+
severity: rule.pattern.severity,
|
|
353
|
+
evidenceTemplate: rule.pattern.evidenceTemplate,
|
|
354
|
+
suggestion: rule.fixDescription,
|
|
355
|
+
source: 'learned',
|
|
356
|
+
contextKeywords: deriveContextKeywords(rule),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
// Exported for testing
|
|
360
|
+
export { deriveContextKeywords as _deriveContextKeywords, extractRegexLiterals as _extractRegexLiterals };
|
|
361
|
+
// ── Compilation ─────────────────────────────────────────────────
|
|
362
|
+
/**
|
|
363
|
+
* Filter checks by language and return a pre-compiled set ready for fast execution.
|
|
364
|
+
*
|
|
365
|
+
* If no checks are provided, uses the built-in formal checks.
|
|
366
|
+
*/
|
|
367
|
+
export function compileCheckSet(language, checks) {
|
|
368
|
+
const start = performance.now();
|
|
369
|
+
const allChecks = checks ?? FORMAL_CHECKS;
|
|
370
|
+
const langLower = language.toLowerCase();
|
|
371
|
+
const filtered = allChecks.filter(check => {
|
|
372
|
+
if (check.languages.length === 0)
|
|
373
|
+
return true; // applies to all languages
|
|
374
|
+
return check.languages.some(l => l.toLowerCase() === langLower);
|
|
375
|
+
});
|
|
376
|
+
const compileTimeMs = performance.now() - start;
|
|
377
|
+
return {
|
|
378
|
+
checks: filtered,
|
|
379
|
+
language: langLower,
|
|
380
|
+
compileTimeMs,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
// ── Execution ───────────────────────────────────────────────────
|
|
384
|
+
/**
|
|
385
|
+
* Run all checks in the set against a code unit. Returns verification events.
|
|
386
|
+
*
|
|
387
|
+
* Designed to complete in <10ms for the full check set against a typical code unit.
|
|
388
|
+
*/
|
|
389
|
+
export function runChecks(unit, checkSet) {
|
|
390
|
+
const events = [];
|
|
391
|
+
const unitStart = performance.now();
|
|
392
|
+
const textLower = unit.text.toLowerCase();
|
|
393
|
+
for (const check of checkSet.checks) {
|
|
394
|
+
// Level 2 filtering: skip checks whose contextKeywords don't match the code
|
|
395
|
+
if (check.contextKeywords && check.contextKeywords.length > 0) {
|
|
396
|
+
const hasRelevantKeyword = check.contextKeywords.some(kw => textLower.includes(kw.toLowerCase()));
|
|
397
|
+
if (!hasRelevantKeyword)
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
const checkStart = performance.now();
|
|
401
|
+
// Reset lastIndex for patterns with the global flag
|
|
402
|
+
check.pattern.lastIndex = 0;
|
|
403
|
+
const match = check.pattern.exec(unit.text);
|
|
404
|
+
const latencyMs = performance.now() - checkStart;
|
|
405
|
+
if (match && check.verdict === 'FAIL') {
|
|
406
|
+
// Pattern matched and that means a failure
|
|
407
|
+
const evidence = formatEvidence(check.evidenceTemplate, match);
|
|
408
|
+
events.push({
|
|
409
|
+
type: 'finding',
|
|
410
|
+
codeUnit: unit,
|
|
411
|
+
checkId: check.id,
|
|
412
|
+
checkName: check.name,
|
|
413
|
+
verdict: 'FAIL',
|
|
414
|
+
evidence,
|
|
415
|
+
severity: check.severity,
|
|
416
|
+
suggestion: check.suggestion,
|
|
417
|
+
latencyMs,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
else if (!match && check.verdict === 'PASS') {
|
|
421
|
+
// Pattern was supposed to match (PASS means "match = good") but didn't
|
|
422
|
+
// This is the absence_is_bad case from learned rules
|
|
423
|
+
events.push({
|
|
424
|
+
type: 'finding',
|
|
425
|
+
codeUnit: unit,
|
|
426
|
+
checkId: check.id,
|
|
427
|
+
checkName: check.name,
|
|
428
|
+
verdict: 'FAIL',
|
|
429
|
+
evidence: formatEvidence(check.evidenceTemplate, null),
|
|
430
|
+
severity: check.severity,
|
|
431
|
+
suggestion: check.suggestion,
|
|
432
|
+
latencyMs,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
// Other cases: match+PASS (good) or no-match+FAIL (no problem found) — no event
|
|
436
|
+
}
|
|
437
|
+
return events;
|
|
438
|
+
}
|
|
439
|
+
// ── Helpers ─────────────────────────────────────────────────────
|
|
440
|
+
function formatEvidence(template, match) {
|
|
441
|
+
if (!match)
|
|
442
|
+
return template;
|
|
443
|
+
let result = template;
|
|
444
|
+
// Replace $0 with full match
|
|
445
|
+
result = result.replace(/\$0/g, match[0]);
|
|
446
|
+
// Replace $1, $2, etc. with capture groups
|
|
447
|
+
for (let i = 1; i < match.length; i++) {
|
|
448
|
+
result = result.replace(new RegExp(`\\$${i}`, 'g'), match[i] ?? '');
|
|
449
|
+
}
|
|
450
|
+
return result;
|
|
451
|
+
}
|
|
452
|
+
//# sourceMappingURL=streaming-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-checks.js","sourceRoot":"","sources":["../../src/realtime/streaming-checks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StreamingVerifier — orchestrator for the real-time verification pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Wires CodeBuffer (token accumulation + code unit detection) with
|
|
5
|
+
* StreamingChecks (pattern-based formal + learned checks) into a single
|
|
6
|
+
* stateful pipeline. Feed it tokens, it buffers them, detects completed
|
|
7
|
+
* code units, runs checks, and emits verification events.
|
|
8
|
+
*/
|
|
9
|
+
import type { CheckSeverity, StreamingVerifierStats, VerificationEvent } from './types.js';
|
|
10
|
+
export interface StreamingVerifierOptions {
|
|
11
|
+
language: string;
|
|
12
|
+
/** Path to project root for loading learned rules catalog */
|
|
13
|
+
projectPath?: string;
|
|
14
|
+
/** Callback fired for each verification event */
|
|
15
|
+
onEvent?: (event: VerificationEvent) => void;
|
|
16
|
+
/** Only auto-correct findings at or above this severity. Default: 'high' */
|
|
17
|
+
minCorrectionSeverity?: CheckSeverity;
|
|
18
|
+
}
|
|
19
|
+
export declare class StreamingVerifier {
|
|
20
|
+
private readonly codeBuffer;
|
|
21
|
+
private readonly checkSet;
|
|
22
|
+
private readonly onEvent?;
|
|
23
|
+
private events;
|
|
24
|
+
private unitsProcessed;
|
|
25
|
+
private checksRun;
|
|
26
|
+
private findingsCount;
|
|
27
|
+
private totalTimeMs;
|
|
28
|
+
private maxLatencyMs;
|
|
29
|
+
/**
|
|
30
|
+
* Tracks the highest endOffset from any code unit we have processed.
|
|
31
|
+
* Used by flush() to know where unchecked trailing code begins.
|
|
32
|
+
*/
|
|
33
|
+
private coveredOffset;
|
|
34
|
+
constructor(options: StreamingVerifierOptions);
|
|
35
|
+
/**
|
|
36
|
+
* Feed tokens from the LLM stream. Returns any verification events triggered.
|
|
37
|
+
*/
|
|
38
|
+
push(tokens: string): VerificationEvent[];
|
|
39
|
+
/**
|
|
40
|
+
* Flush the buffer — run checks on any remaining buffered code.
|
|
41
|
+
* Call at the end of the stream to verify trailing code that never
|
|
42
|
+
* reached a structural boundary (closing brace, semicolon, etc.).
|
|
43
|
+
*/
|
|
44
|
+
flush(): VerificationEvent[];
|
|
45
|
+
/** Get cumulative statistics. */
|
|
46
|
+
getStats(): StreamingVerifierStats;
|
|
47
|
+
/** Get all findings (FAIL events) accumulated so far. */
|
|
48
|
+
getFindings(): VerificationEvent[];
|
|
49
|
+
/** Get the full generated code accumulated so far. */
|
|
50
|
+
getGeneratedCode(): string;
|
|
51
|
+
/** Reset all state — buffer, events, stats. */
|
|
52
|
+
reset(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Run checks against a list of code units, accumulate stats, fire callbacks.
|
|
55
|
+
*/
|
|
56
|
+
private processUnits;
|
|
57
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StreamingVerifier — orchestrator for the real-time verification pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Wires CodeBuffer (token accumulation + code unit detection) with
|
|
5
|
+
* StreamingChecks (pattern-based formal + learned checks) into a single
|
|
6
|
+
* stateful pipeline. Feed it tokens, it buffers them, detects completed
|
|
7
|
+
* code units, runs checks, and emits verification events.
|
|
8
|
+
*/
|
|
9
|
+
import { CodeBuffer } from './code-buffer.js';
|
|
10
|
+
import { getFormalChecks, loadLearnedChecks, compileCheckSet, runChecks, } from './streaming-checks.js';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// StreamingVerifier
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
export class StreamingVerifier {
|
|
15
|
+
codeBuffer;
|
|
16
|
+
checkSet;
|
|
17
|
+
onEvent;
|
|
18
|
+
// Accumulated state
|
|
19
|
+
events = [];
|
|
20
|
+
unitsProcessed = 0;
|
|
21
|
+
checksRun = 0;
|
|
22
|
+
findingsCount = 0;
|
|
23
|
+
totalTimeMs = 0;
|
|
24
|
+
maxLatencyMs = 0;
|
|
25
|
+
/**
|
|
26
|
+
* Tracks the highest endOffset from any code unit we have processed.
|
|
27
|
+
* Used by flush() to know where unchecked trailing code begins.
|
|
28
|
+
*/
|
|
29
|
+
coveredOffset = 0;
|
|
30
|
+
constructor(options) {
|
|
31
|
+
this.codeBuffer = new CodeBuffer(options.language);
|
|
32
|
+
this.onEvent = options.onEvent;
|
|
33
|
+
// Load formal checks
|
|
34
|
+
const formal = getFormalChecks();
|
|
35
|
+
// Optionally load learned rules from the project catalog
|
|
36
|
+
let learned = [];
|
|
37
|
+
if (options.projectPath) {
|
|
38
|
+
const catalogPath = `${options.projectPath}/.assay/learned/rules.json`;
|
|
39
|
+
learned = loadLearnedChecks(catalogPath);
|
|
40
|
+
}
|
|
41
|
+
// Compile into a single check set filtered by language
|
|
42
|
+
this.checkSet = compileCheckSet(options.language, [...formal, ...learned]);
|
|
43
|
+
}
|
|
44
|
+
// -- Public API -----------------------------------------------------------
|
|
45
|
+
/**
|
|
46
|
+
* Feed tokens from the LLM stream. Returns any verification events triggered.
|
|
47
|
+
*/
|
|
48
|
+
push(tokens) {
|
|
49
|
+
const units = this.codeBuffer.push(tokens);
|
|
50
|
+
return this.processUnits(units);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Flush the buffer — run checks on any remaining buffered code.
|
|
54
|
+
* Call at the end of the stream to verify trailing code that never
|
|
55
|
+
* reached a structural boundary (closing brace, semicolon, etc.).
|
|
56
|
+
*/
|
|
57
|
+
flush() {
|
|
58
|
+
const fullBuffer = this.codeBuffer.getFullBuffer();
|
|
59
|
+
const remaining = fullBuffer.slice(this.coveredOffset).trim();
|
|
60
|
+
if (remaining.length === 0) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
const trailingUnit = {
|
|
64
|
+
text: remaining,
|
|
65
|
+
kind: 'line',
|
|
66
|
+
startOffset: this.coveredOffset,
|
|
67
|
+
endOffset: fullBuffer.length,
|
|
68
|
+
language: this.codeBuffer.getLanguage(),
|
|
69
|
+
};
|
|
70
|
+
return this.processUnits([trailingUnit]);
|
|
71
|
+
}
|
|
72
|
+
/** Get cumulative statistics. */
|
|
73
|
+
getStats() {
|
|
74
|
+
return {
|
|
75
|
+
unitsProcessed: this.unitsProcessed,
|
|
76
|
+
checksRun: this.checksRun,
|
|
77
|
+
findings: this.findingsCount,
|
|
78
|
+
avgLatencyMs: this.unitsProcessed > 0 ? this.totalTimeMs / this.unitsProcessed : 0,
|
|
79
|
+
maxLatencyMs: this.maxLatencyMs,
|
|
80
|
+
totalTimeMs: this.totalTimeMs,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Get all findings (FAIL events) accumulated so far. */
|
|
84
|
+
getFindings() {
|
|
85
|
+
return this.events.filter(e => e.verdict === 'FAIL');
|
|
86
|
+
}
|
|
87
|
+
/** Get the full generated code accumulated so far. */
|
|
88
|
+
getGeneratedCode() {
|
|
89
|
+
return this.codeBuffer.getFullBuffer();
|
|
90
|
+
}
|
|
91
|
+
/** Reset all state — buffer, events, stats. */
|
|
92
|
+
reset() {
|
|
93
|
+
this.codeBuffer.reset();
|
|
94
|
+
this.events = [];
|
|
95
|
+
this.unitsProcessed = 0;
|
|
96
|
+
this.checksRun = 0;
|
|
97
|
+
this.findingsCount = 0;
|
|
98
|
+
this.totalTimeMs = 0;
|
|
99
|
+
this.maxLatencyMs = 0;
|
|
100
|
+
this.coveredOffset = 0;
|
|
101
|
+
}
|
|
102
|
+
// -- Private helpers ------------------------------------------------------
|
|
103
|
+
/**
|
|
104
|
+
* Run checks against a list of code units, accumulate stats, fire callbacks.
|
|
105
|
+
*/
|
|
106
|
+
processUnits(units) {
|
|
107
|
+
const batchEvents = [];
|
|
108
|
+
for (const unit of units) {
|
|
109
|
+
const unitStart = performance.now();
|
|
110
|
+
const unitEvents = runChecks(unit, this.checkSet);
|
|
111
|
+
const unitLatency = performance.now() - unitStart;
|
|
112
|
+
// Track coverage regardless of whether events were produced
|
|
113
|
+
if (unit.endOffset > this.coveredOffset) {
|
|
114
|
+
this.coveredOffset = unit.endOffset;
|
|
115
|
+
}
|
|
116
|
+
this.unitsProcessed++;
|
|
117
|
+
this.checksRun += this.checkSet.checks.length;
|
|
118
|
+
this.totalTimeMs += unitLatency;
|
|
119
|
+
if (unitLatency > this.maxLatencyMs) {
|
|
120
|
+
this.maxLatencyMs = unitLatency;
|
|
121
|
+
}
|
|
122
|
+
for (const event of unitEvents) {
|
|
123
|
+
this.events.push(event);
|
|
124
|
+
batchEvents.push(event);
|
|
125
|
+
if (event.verdict === 'FAIL') {
|
|
126
|
+
this.findingsCount++;
|
|
127
|
+
}
|
|
128
|
+
this.onEvent?.(event);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return batchEvents;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=streaming-verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-verifier.js","sourceRoot":"","sources":["../../src/realtime/streaming-verifier.ts"],"names":[],"mappings":"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"}
|