@expressots/studio-agent 4.0.0-preview.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.
Files changed (86) hide show
  1. package/README.md +143 -0
  2. package/dist/agent.d.ts +127 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +1031 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/discovery/index.d.ts +2 -0
  7. package/dist/discovery/index.d.ts.map +1 -0
  8. package/dist/discovery/index.js +2 -0
  9. package/dist/discovery/index.js.map +1 -0
  10. package/dist/discovery/route-scanner.d.ts +35 -0
  11. package/dist/discovery/route-scanner.d.ts.map +1 -0
  12. package/dist/discovery/route-scanner.js +385 -0
  13. package/dist/discovery/route-scanner.js.map +1 -0
  14. package/dist/index.d.ts +15 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +15 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/instrumentation/index.d.ts +2 -0
  19. package/dist/instrumentation/index.d.ts.map +1 -0
  20. package/dist/instrumentation/index.js +2 -0
  21. package/dist/instrumentation/index.js.map +1 -0
  22. package/dist/instrumentation/tracer.d.ts +40 -0
  23. package/dist/instrumentation/tracer.d.ts.map +1 -0
  24. package/dist/instrumentation/tracer.js +190 -0
  25. package/dist/instrumentation/tracer.js.map +1 -0
  26. package/dist/introspection/container-introspector.d.ts +81 -0
  27. package/dist/introspection/container-introspector.d.ts.map +1 -0
  28. package/dist/introspection/container-introspector.js +251 -0
  29. package/dist/introspection/container-introspector.js.map +1 -0
  30. package/dist/logging/log-capture.d.ts +58 -0
  31. package/dist/logging/log-capture.d.ts.map +1 -0
  32. package/dist/logging/log-capture.js +184 -0
  33. package/dist/logging/log-capture.js.map +1 -0
  34. package/dist/recording/index.d.ts +2 -0
  35. package/dist/recording/index.d.ts.map +1 -0
  36. package/dist/recording/index.js +2 -0
  37. package/dist/recording/index.js.map +1 -0
  38. package/dist/recording/request-recorder.d.ts +43 -0
  39. package/dist/recording/request-recorder.d.ts.map +1 -0
  40. package/dist/recording/request-recorder.js +373 -0
  41. package/dist/recording/request-recorder.js.map +1 -0
  42. package/dist/security/fix-resolver.d.ts +40 -0
  43. package/dist/security/fix-resolver.d.ts.map +1 -0
  44. package/dist/security/fix-resolver.js +283 -0
  45. package/dist/security/fix-resolver.js.map +1 -0
  46. package/dist/security/fix-runner.d.ts +60 -0
  47. package/dist/security/fix-runner.d.ts.map +1 -0
  48. package/dist/security/fix-runner.js +188 -0
  49. package/dist/security/fix-runner.js.map +1 -0
  50. package/dist/security/index.d.ts +140 -0
  51. package/dist/security/index.d.ts.map +1 -0
  52. package/dist/security/index.js +460 -0
  53. package/dist/security/index.js.map +1 -0
  54. package/dist/security/lockfile-graph.d.ts +69 -0
  55. package/dist/security/lockfile-graph.d.ts.map +1 -0
  56. package/dist/security/lockfile-graph.js +245 -0
  57. package/dist/security/lockfile-graph.js.map +1 -0
  58. package/dist/security/npm-audit.d.ts +67 -0
  59. package/dist/security/npm-audit.d.ts.map +1 -0
  60. package/dist/security/npm-audit.js +320 -0
  61. package/dist/security/npm-audit.js.map +1 -0
  62. package/dist/security/osv-cache.d.ts +51 -0
  63. package/dist/security/osv-cache.d.ts.map +1 -0
  64. package/dist/security/osv-cache.js +99 -0
  65. package/dist/security/osv-cache.js.map +1 -0
  66. package/dist/security/osv-client.d.ts +47 -0
  67. package/dist/security/osv-client.d.ts.map +1 -0
  68. package/dist/security/osv-client.js +247 -0
  69. package/dist/security/osv-client.js.map +1 -0
  70. package/dist/security/posture-analyzer.d.ts +44 -0
  71. package/dist/security/posture-analyzer.d.ts.map +1 -0
  72. package/dist/security/posture-analyzer.js +397 -0
  73. package/dist/security/posture-analyzer.js.map +1 -0
  74. package/dist/security/reachability.d.ts +59 -0
  75. package/dist/security/reachability.d.ts.map +1 -0
  76. package/dist/security/reachability.js +302 -0
  77. package/dist/security/reachability.js.map +1 -0
  78. package/dist/security/score.d.ts +36 -0
  79. package/dist/security/score.d.ts.map +1 -0
  80. package/dist/security/score.js +94 -0
  81. package/dist/security/score.js.map +1 -0
  82. package/dist/types/index.d.ts +587 -0
  83. package/dist/types/index.d.ts.map +1 -0
  84. package/dist/types/index.js +14 -0
  85. package/dist/types/index.js.map +1 -0
  86. package/package.json +75 -0
@@ -0,0 +1,397 @@
1
+ /**
2
+ * Runtime security posture analyzer.
3
+ *
4
+ * This is Studio's unique contribution: Snyk-style scanners only see
5
+ * `package.json`, but Studio has the recorded traffic, the routes, the
6
+ * DI graph and live logs. The analyzer turns all of that into a set
7
+ * of OWASP-mapped findings the user can act on directly from the UI.
8
+ *
9
+ * Rules implemented here are intentionally conservative — false
10
+ * positives erode trust quickly in a security tool. Every rule has
11
+ * either (a) a high-confidence runtime signal (e.g. literal
12
+ * `Access-Control-Allow-Origin: *`) or (b) an explicit "advisory"
13
+ * severity so users know the finding is heuristic.
14
+ *
15
+ * All passes are pure functions over a snapshot of in-memory state.
16
+ * The engine is responsible for debouncing and change detection.
17
+ */
18
+ import { createHash } from 'node:crypto';
19
+ /**
20
+ * Run every posture check over the given snapshot. Returns an
21
+ * unsorted list — the engine aggregates and dedupes by `id`.
22
+ */
23
+ export function analyzePosture(input) {
24
+ const findings = [];
25
+ findings.push(...checkSecurityHeaders(input));
26
+ findings.push(...checkPermissiveCors(input));
27
+ findings.push(...checkAuthGaps(input));
28
+ findings.push(...checkVerboseErrors(input));
29
+ findings.push(...checkSecretLeakage(input));
30
+ findings.push(...checkInputValidation(input));
31
+ return findings;
32
+ }
33
+ // ────────────────────────────────────────────────────────────────────
34
+ // Rule: missing standard security response headers
35
+ // ────────────────────────────────────────────────────────────────────
36
+ const REQUIRED_HEADERS = [
37
+ { name: 'content-security-policy', severity: 'MEDIUM', owasp: 'API8:2023' },
38
+ { name: 'strict-transport-security', severity: 'MEDIUM', owasp: 'API8:2023' },
39
+ { name: 'x-content-type-options', severity: 'LOW', owasp: 'API8:2023' },
40
+ { name: 'x-frame-options', severity: 'LOW', owasp: 'API8:2023' },
41
+ { name: 'referrer-policy', severity: 'LOW', owasp: 'API8:2023' },
42
+ ];
43
+ /**
44
+ * For each route observed in the recorded exchanges, check whether the
45
+ * most recent successful response carried the standard security
46
+ * headers. We pick the *last* 2xx response per route so transient
47
+ * misses on error paths don't flag every route.
48
+ */
49
+ function checkSecurityHeaders(input) {
50
+ const out = [];
51
+ const lastSuccessByRoute = mostRecentSuccessByRoute(input.exchanges);
52
+ for (const [, exchange] of lastSuccessByRoute) {
53
+ const headers = lowercaseHeaderKeys(exchange.response.headers);
54
+ for (const required of REQUIRED_HEADERS) {
55
+ if (headers[required.name])
56
+ continue;
57
+ out.push({
58
+ id: stableId('missing-header', required.name, exchange.request.path),
59
+ rule: `missing-${required.name}`,
60
+ owasp: required.owasp,
61
+ severity: required.severity,
62
+ title: `Missing ${prettyHeader(required.name)} header`,
63
+ description: `Responses to \`${exchange.request.method} ${exchange.request.path}\` ` +
64
+ `are not sending the \`${prettyHeader(required.name)}\` header. ` +
65
+ 'This relaxes browser-side defences against a range of common attacks.',
66
+ evidence: { kind: 'exchange', exchangeId: exchange.id },
67
+ fixHint: 'Register `helmet()` (or set the header explicitly in a response interceptor).',
68
+ });
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+ // ────────────────────────────────────────────────────────────────────
74
+ // Rule: permissive CORS
75
+ // ────────────────────────────────────────────────────────────────────
76
+ /**
77
+ * Flags responses that pair `Access-Control-Allow-Origin: *` with
78
+ * authenticated requests — that combination effectively turns CORS
79
+ * off for cross-origin attackers who can persuade a victim to issue
80
+ * a request bearing their own credentials.
81
+ */
82
+ function checkPermissiveCors(input) {
83
+ const out = [];
84
+ const seen = new Set();
85
+ for (const ex of input.exchanges) {
86
+ const headers = lowercaseHeaderKeys(ex.response.headers);
87
+ if (headers['access-control-allow-origin'] !== '*')
88
+ continue;
89
+ const reqHeaders = lowercaseHeaderKeys(ex.request.headers);
90
+ const hasAuth = Boolean(reqHeaders['authorization'] || reqHeaders['cookie']);
91
+ const key = `${ex.request.method}:${ex.request.path}:${hasAuth}`;
92
+ if (seen.has(key))
93
+ continue;
94
+ seen.add(key);
95
+ out.push({
96
+ id: stableId('permissive-cors', ex.request.method, ex.request.path, String(hasAuth)),
97
+ rule: 'permissive-cors',
98
+ owasp: 'API8:2023',
99
+ severity: hasAuth ? 'HIGH' : 'LOW',
100
+ title: hasAuth
101
+ ? 'Wildcard CORS on authenticated route'
102
+ : 'Wildcard CORS origin',
103
+ description: hasAuth
104
+ ? `\`${ex.request.method} ${ex.request.path}\` returns \`Access-Control-Allow-Origin: *\` ` +
105
+ 'while the client sends credentials. Browsers will refuse the response, but the ' +
106
+ 'configuration is a footgun — pin the origin to your front-end host instead.'
107
+ : `\`${ex.request.method} ${ex.request.path}\` returns \`Access-Control-Allow-Origin: *\`. ` +
108
+ 'Acceptable for fully public endpoints; replace with an explicit allow-list otherwise.',
109
+ evidence: { kind: 'exchange', exchangeId: ex.id },
110
+ fixHint: 'Configure CORS with a concrete `origin` list rather than `*`.',
111
+ });
112
+ }
113
+ return out;
114
+ }
115
+ // ────────────────────────────────────────────────────────────────────
116
+ // Rule: routes returning 2xx with no auth evidence
117
+ // ────────────────────────────────────────────────────────────────────
118
+ const PUBLIC_PATH_PATTERNS = [
119
+ /^\/?$/,
120
+ /^\/health/i,
121
+ /^\/healthz/i,
122
+ /^\/status/i,
123
+ /^\/metrics/i,
124
+ /^\/ready/i,
125
+ /^\/favicon/i,
126
+ ];
127
+ /**
128
+ * For each route, look at the most recent 2xx response: if no request
129
+ * we've seen against it carried an `Authorization` header or a session
130
+ * cookie, *and* the static / runtime middleware list shows no obvious
131
+ * auth interceptor, flag it as potentially unauthenticated.
132
+ *
133
+ * Intentionally LOW severity (not HIGH) because plenty of routes are
134
+ * legitimately public. Users skim the list and mute false positives.
135
+ */
136
+ function checkAuthGaps(input) {
137
+ const out = [];
138
+ const lastByRoute = mostRecentSuccessByRoute(input.exchanges);
139
+ const allByRoute = groupByRoute(input.exchanges);
140
+ const middlewareNames = (input.structure?.middleware ?? []).map((m) => m.toLowerCase());
141
+ const hasGlobalAuth = middlewareNames.some((n) => /auth|jwt|session|guard/.test(n));
142
+ for (const [routeKey, exchange] of lastByRoute) {
143
+ if (looksPublic(exchange.request.path))
144
+ continue;
145
+ if (hasGlobalAuth)
146
+ continue;
147
+ const everyExchange = allByRoute.get(routeKey) ?? [];
148
+ const sawCredentials = everyExchange.some((ex) => {
149
+ const h = lowercaseHeaderKeys(ex.request.headers);
150
+ return Boolean(h['authorization'] || h['cookie']);
151
+ });
152
+ if (sawCredentials)
153
+ continue;
154
+ out.push({
155
+ id: stableId('unauthenticated-route', exchange.request.method, exchange.request.path),
156
+ rule: 'unauthenticated-route',
157
+ owasp: 'API2:2023',
158
+ severity: 'LOW',
159
+ title: 'Route may be unauthenticated',
160
+ description: `\`${exchange.request.method} ${exchange.request.path}\` returned 2xx for every ` +
161
+ 'recorded request, and Studio never observed an `Authorization` header or session ' +
162
+ 'cookie. If this endpoint is meant to be private, add an auth interceptor.',
163
+ evidence: {
164
+ kind: 'route',
165
+ method: exchange.request.method,
166
+ path: exchange.request.path,
167
+ },
168
+ fixHint: 'Apply an auth interceptor on the controller or the route, or register one globally.',
169
+ });
170
+ }
171
+ return out;
172
+ }
173
+ // ────────────────────────────────────────────────────────────────────
174
+ // Rule: verbose error responses (stack trace leakage)
175
+ // ────────────────────────────────────────────────────────────────────
176
+ const STACK_REGEX = /at\s+[\w.<>$]+\s+\(.+:\d+:\d+\)/;
177
+ function checkVerboseErrors(input) {
178
+ const out = [];
179
+ const seen = new Set();
180
+ for (const ex of input.exchanges) {
181
+ if (ex.response.statusCode < 500)
182
+ continue;
183
+ const body = renderBody(ex.response.body);
184
+ if (!body)
185
+ continue;
186
+ if (!STACK_REGEX.test(body))
187
+ continue;
188
+ const key = `${ex.request.method}:${ex.request.path}`;
189
+ if (seen.has(key))
190
+ continue;
191
+ seen.add(key);
192
+ out.push({
193
+ id: stableId('verbose-error', ex.request.method, ex.request.path),
194
+ rule: 'verbose-error',
195
+ owasp: 'API8:2023',
196
+ severity: 'MEDIUM',
197
+ title: '5xx response includes a stack trace',
198
+ description: `\`${ex.request.method} ${ex.request.path}\` returned ${ex.response.statusCode} ` +
199
+ 'with a response body containing what looks like a stack trace. Production clients ' +
200
+ 'should never see implementation details from server-side errors.',
201
+ evidence: { kind: 'exchange', exchangeId: ex.id },
202
+ fixHint: 'Install a global error filter that strips stack frames from outbound responses.',
203
+ });
204
+ }
205
+ return out;
206
+ }
207
+ // ────────────────────────────────────────────────────────────────────
208
+ // Rule: likely secret leakage in responses or logs
209
+ // ────────────────────────────────────────────────────────────────────
210
+ /**
211
+ * High-precision patterns only. A single false positive on a secret
212
+ * scanner is much worse than a missed one — users learn to ignore the
213
+ * tool. We deliberately don't try to catch generic "long random string
214
+ * that might be a token". Adopt the [trufflehog / git-leaks] vocab.
215
+ */
216
+ const SECRET_PATTERNS = [
217
+ { name: 'AWS Access Key', regex: /AKIA[0-9A-Z]{16}/ },
218
+ { name: 'GitHub PAT', regex: /\bghp_[A-Za-z0-9]{36}\b/ },
219
+ { name: 'GitHub Fine-grained PAT', regex: /\bgithub_pat_[A-Za-z0-9_]{82}\b/ },
220
+ { name: 'Slack token', regex: /\bxox[abprs]-[A-Za-z0-9-]{10,48}\b/ },
221
+ { name: 'Stripe live key', regex: /\bsk_live_[A-Za-z0-9]{24,}\b/ },
222
+ { name: 'JWT', regex: /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/ },
223
+ ];
224
+ function checkSecretLeakage(input) {
225
+ const out = [];
226
+ for (const ex of input.exchanges) {
227
+ const body = renderBody(ex.response.body);
228
+ if (!body)
229
+ continue;
230
+ for (const pat of SECRET_PATTERNS) {
231
+ if (!pat.regex.test(body))
232
+ continue;
233
+ out.push({
234
+ id: stableId('response-secret', pat.name, ex.request.method, ex.request.path),
235
+ rule: 'response-secret',
236
+ owasp: 'API3:2023',
237
+ severity: 'HIGH',
238
+ title: `Response body matches a ${pat.name} pattern`,
239
+ description: `\`${ex.request.method} ${ex.request.path}\` returned a body containing what ` +
240
+ `looks like a ${pat.name}. Strip credentials from response payloads — they should ` +
241
+ 'never reach the client.',
242
+ evidence: { kind: 'exchange', exchangeId: ex.id },
243
+ });
244
+ }
245
+ }
246
+ for (let i = 0; i < input.logs.length; i++) {
247
+ const entry = input.logs[i];
248
+ for (const pat of SECRET_PATTERNS) {
249
+ if (!pat.regex.test(entry.message))
250
+ continue;
251
+ out.push({
252
+ id: stableId('log-secret', pat.name, entry.message.slice(0, 64)),
253
+ rule: 'log-secret',
254
+ owasp: 'API3:2023',
255
+ severity: 'MEDIUM',
256
+ title: `Log line matches a ${pat.name} pattern`,
257
+ description: `A captured log entry contains what looks like a ${pat.name}. Logs propagate to ` +
258
+ 'log aggregators and rotated files; treat them as untrusted destinations for secrets.',
259
+ evidence: { kind: 'log', logIndex: i },
260
+ });
261
+ // Don't double-report on the same line for multiple patterns.
262
+ break;
263
+ }
264
+ }
265
+ return out;
266
+ }
267
+ // ────────────────────────────────────────────────────────────────────
268
+ // Rule: controllers accepting bodies without validation
269
+ // ────────────────────────────────────────────────────────────────────
270
+ /**
271
+ * Heuristic check: any controller whose recorded requests carry a
272
+ * non-empty body, but whose source file doesn't import any of the
273
+ * canonical validation libraries we recognise. Marked INFO because
274
+ * it's the most heuristic of the rules — frameworks differ, and the
275
+ * controller might validate at a layer below our scanner.
276
+ */
277
+ function checkInputValidation(input) {
278
+ const out = [];
279
+ const seen = new Set();
280
+ const controllerByName = new Map();
281
+ for (const c of input.structure?.controllers ?? []) {
282
+ controllerByName.set(c.name, { filePath: c.filePath });
283
+ }
284
+ for (const ex of input.exchanges) {
285
+ if (!hasMeaningfulBody(ex.request.body))
286
+ continue;
287
+ const route = input.routes.find((r) => r.path === ex.request.path && r.method === ex.request.method);
288
+ if (!route)
289
+ continue;
290
+ const key = `${route.controller}.${route.controllerMethod}`;
291
+ if (seen.has(key))
292
+ continue;
293
+ seen.add(key);
294
+ const ctrl = controllerByName.get(route.controller);
295
+ if (!ctrl?.filePath)
296
+ continue;
297
+ // We can't reliably read the file here without async I/O; the engine
298
+ // does the file read once per scan and passes the import list via
299
+ // `srcRoot` (future enhancement). For now, surface the route and let
300
+ // the user verify — INFO severity reflects the uncertainty.
301
+ out.push({
302
+ id: stableId('unvalidated-body', route.controller, route.controllerMethod),
303
+ rule: 'unvalidated-body',
304
+ owasp: 'API4:2023',
305
+ severity: 'INFO',
306
+ title: `Verify request validation for ${route.controller}.${route.controllerMethod}`,
307
+ description: `\`${ex.request.method} ${ex.request.path}\` (handled by ` +
308
+ `\`${route.controller}.${route.controllerMethod}\`) accepts a body. Confirm that the ` +
309
+ 'handler validates it (zod, class-validator, or a project DTO) before use.',
310
+ evidence: { kind: 'file', filePath: ctrl.filePath, lineNumber: route.lineNumber },
311
+ fixHint: 'Wrap the body parameter in a typed DTO + validation pipe or use a runtime schema check.',
312
+ });
313
+ }
314
+ return out;
315
+ }
316
+ // ────────────────────────────────────────────────────────────────────
317
+ // Helpers
318
+ // ────────────────────────────────────────────────────────────────────
319
+ function lowercaseHeaderKeys(headers) {
320
+ const out = {};
321
+ if (!headers)
322
+ return out;
323
+ for (const [k, v] of Object.entries(headers)) {
324
+ out[k.toLowerCase()] = v;
325
+ }
326
+ return out;
327
+ }
328
+ function looksPublic(path) {
329
+ return PUBLIC_PATH_PATTERNS.some((p) => p.test(path));
330
+ }
331
+ function mostRecentSuccessByRoute(exchanges) {
332
+ const out = new Map();
333
+ for (const ex of exchanges) {
334
+ if (ex.response.statusCode < 200 || ex.response.statusCode >= 300)
335
+ continue;
336
+ const key = routeKey(ex.request.method, ex.request.path);
337
+ const existing = out.get(key);
338
+ if (!existing || ex.request.timestamp > existing.request.timestamp) {
339
+ out.set(key, ex);
340
+ }
341
+ }
342
+ return out;
343
+ }
344
+ function groupByRoute(exchanges) {
345
+ const out = new Map();
346
+ for (const ex of exchanges) {
347
+ const key = routeKey(ex.request.method, ex.request.path);
348
+ const list = out.get(key) ?? [];
349
+ list.push(ex);
350
+ out.set(key, list);
351
+ }
352
+ return out;
353
+ }
354
+ function routeKey(method, path) {
355
+ return `${method}:${path}`;
356
+ }
357
+ function renderBody(body) {
358
+ if (body == null)
359
+ return '';
360
+ if (typeof body === 'string')
361
+ return body;
362
+ try {
363
+ return JSON.stringify(body);
364
+ }
365
+ catch {
366
+ return '';
367
+ }
368
+ }
369
+ function hasMeaningfulBody(body) {
370
+ if (body == null)
371
+ return false;
372
+ if (typeof body === 'string')
373
+ return body.trim().length > 0;
374
+ if (typeof body === 'object') {
375
+ return Object.keys(body).length > 0;
376
+ }
377
+ return true;
378
+ }
379
+ function prettyHeader(headerName) {
380
+ return headerName
381
+ .split('-')
382
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
383
+ .join('-');
384
+ }
385
+ /**
386
+ * Build a deterministic id so re-runs of the analyzer produce the same
387
+ * id for the same finding — the engine relies on this for change
388
+ * detection (hash the id set; only broadcast on transition).
389
+ */
390
+ function stableId(...parts) {
391
+ const h = createHash('sha1');
392
+ for (const p of parts)
393
+ h.update(p);
394
+ h.update('\0');
395
+ return h.digest('hex').slice(0, 16);
396
+ }
397
+ //# sourceMappingURL=posture-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posture-analyzer.js","sourceRoot":"","sources":["../../src/security/posture-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Runtime reachability analysis for supply-chain findings.
3
+ *
4
+ * This is the single feature that justifies "why Studio over Snyk?". A
5
+ * static scanner can tell you that `lodash@4.17.10` has CVE-X; only a
6
+ * tool sitting inside the running app can tell you that:
7
+ *
8
+ * - `src/users/users.service.ts` actually imports lodash
9
+ * - that service is wired into `UsersController`, which owns `GET /users`
10
+ * - and `GET /users` has been hit 47 times in the last hour
11
+ *
12
+ * We combine three signals to land on one of four labels per finding:
13
+ *
14
+ * - **confirmed**: a route that imports (transitively) the vulnerable
15
+ * package has been exercised in the current session.
16
+ * - **likely**: the package is imported from `src/` but we haven't
17
+ * seen a request hit a route that reaches it yet.
18
+ * - **unreachable**: we have a complete import graph for `src/` and
19
+ * the package doesn't appear anywhere. Usually means it's only
20
+ * pulled in by a dev tool or another transitive dep.
21
+ * - **unknown**: we can't compute the graph (no src dir, scanning
22
+ * disabled). Default for transitive packages with no direct
23
+ * imports — we don't follow node_modules → node_modules edges.
24
+ *
25
+ * The analyzer is intentionally cheap: regex-based import extraction
26
+ * over the same source tree the route scanner already walked. We
27
+ * don't reach for a TypeScript AST — it'd be 100× slower for almost
28
+ * no precision gain at this granularity (we only need package names,
29
+ * not symbols).
30
+ */
31
+ import type { AppStructure, DependencyFinding, RecordedExchange, RouteInfo } from '../types/index.js';
32
+ /**
33
+ * Reachability snapshot built once per security scan. We compute it on
34
+ * the agent thread (synchronous file I/O, but only ~200 small files for
35
+ * a typical service) and pass it to `enrichWithReachability`, which is
36
+ * then a pure map.
37
+ */
38
+ export interface ReachabilitySnapshot {
39
+ /** package name → files in `src/` that import it. */
40
+ importedByPkg: Map<string, Set<string>>;
41
+ /** file path → routes whose handlers live in (or transitively reach) that file. */
42
+ routesByFile: Map<string, RouteInfo[]>;
43
+ }
44
+ /**
45
+ * Build a reachability snapshot for the host project. Returns an empty
46
+ * snapshot if `srcPath` doesn't exist — callers should treat that as
47
+ * "always emit `unknown`" rather than failing.
48
+ *
49
+ * Safe to call on every full scan; for a 1000-file project it usually
50
+ * completes in <100 ms.
51
+ */
52
+ export declare function buildReachabilitySnapshot(cwd: string, structure: AppStructure | null): Promise<ReachabilitySnapshot>;
53
+ /**
54
+ * Attach a `ReachabilityInfo` block to every finding in `findings`.
55
+ * Pure given the snapshot + exchanges; same call with the same inputs
56
+ * always produces the same output, which keeps hashing stable.
57
+ */
58
+ export declare function enrichWithReachability(findings: DependencyFinding[], snapshot: ReachabilitySnapshot, exchanges: RecordedExchange[]): DependencyFinding[];
59
+ //# sourceMappingURL=reachability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reachability.d.ts","sourceRoot":"","sources":["../../src/security/reachability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAKH,OAAO,KAAK,EACV,YAAY,EAEZ,iBAAiB,EAGjB,gBAAgB,EAChB,SAAS,EAEV,MAAM,mBAAmB,CAAC;AAE3B;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,qDAAqD;IACrD,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,mFAAmF;IACnF,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;CACxC;AAaD;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,YAAY,GAAG,IAAI,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAkC/B;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,QAAQ,EAAE,oBAAoB,EAC9B,SAAS,EAAE,gBAAgB,EAAE,GAC5B,iBAAiB,EAAE,CA0BrB"}