@lbroth/rothunter 1.0.0-rc.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 (269) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -0
  3. package/dist/adapters/llm.d.ts +68 -0
  4. package/dist/adapters/llm.d.ts.map +1 -0
  5. package/dist/adapters/llm.js +189 -0
  6. package/dist/adapters/llm.js.map +1 -0
  7. package/dist/config.d.ts +37 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +81 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/detector-registry.d.ts +32 -0
  12. package/dist/detector-registry.d.ts.map +1 -0
  13. package/dist/detector-registry.js +74 -0
  14. package/dist/detector-registry.js.map +1 -0
  15. package/dist/detectors/api-race.d.ts +6 -0
  16. package/dist/detectors/api-race.d.ts.map +1 -0
  17. package/dist/detectors/api-race.js +222 -0
  18. package/dist/detectors/api-race.js.map +1 -0
  19. package/dist/detectors/bad-config.d.ts +6 -0
  20. package/dist/detectors/bad-config.d.ts.map +1 -0
  21. package/dist/detectors/bad-config.js +529 -0
  22. package/dist/detectors/bad-config.js.map +1 -0
  23. package/dist/detectors/console-log-prod.d.ts +6 -0
  24. package/dist/detectors/console-log-prod.d.ts.map +1 -0
  25. package/dist/detectors/console-log-prod.js +72 -0
  26. package/dist/detectors/console-log-prod.js.map +1 -0
  27. package/dist/detectors/dead-api.d.ts +10 -0
  28. package/dist/detectors/dead-api.d.ts.map +1 -0
  29. package/dist/detectors/dead-api.js +115 -0
  30. package/dist/detectors/dead-api.js.map +1 -0
  31. package/dist/detectors/dead-export.d.ts +12 -0
  32. package/dist/detectors/dead-export.d.ts.map +1 -0
  33. package/dist/detectors/dead-export.js +140 -0
  34. package/dist/detectors/dead-export.js.map +1 -0
  35. package/dist/detectors/dead-handler.d.ts +12 -0
  36. package/dist/detectors/dead-handler.d.ts.map +1 -0
  37. package/dist/detectors/dead-handler.js +40 -0
  38. package/dist/detectors/dead-handler.js.map +1 -0
  39. package/dist/detectors/dead-module.d.ts +14 -0
  40. package/dist/detectors/dead-module.d.ts.map +1 -0
  41. package/dist/detectors/dead-module.js +50 -0
  42. package/dist/detectors/dead-module.js.map +1 -0
  43. package/dist/detectors/deep-nesting.d.ts +12 -0
  44. package/dist/detectors/deep-nesting.d.ts.map +1 -0
  45. package/dist/detectors/deep-nesting.js +133 -0
  46. package/dist/detectors/deep-nesting.js.map +1 -0
  47. package/dist/detectors/duplicate-function.d.ts +9 -0
  48. package/dist/detectors/duplicate-function.d.ts.map +1 -0
  49. package/dist/detectors/duplicate-function.js +199 -0
  50. package/dist/detectors/duplicate-function.js.map +1 -0
  51. package/dist/detectors/duplicate-type.d.ts +9 -0
  52. package/dist/detectors/duplicate-type.d.ts.map +1 -0
  53. package/dist/detectors/duplicate-type.js +166 -0
  54. package/dist/detectors/duplicate-type.js.map +1 -0
  55. package/dist/detectors/hot-hub-file.d.ts +11 -0
  56. package/dist/detectors/hot-hub-file.d.ts.map +1 -0
  57. package/dist/detectors/hot-hub-file.js +42 -0
  58. package/dist/detectors/hot-hub-file.js.map +1 -0
  59. package/dist/detectors/long-file.d.ts +12 -0
  60. package/dist/detectors/long-file.d.ts.map +1 -0
  61. package/dist/detectors/long-file.js +82 -0
  62. package/dist/detectors/long-file.js.map +1 -0
  63. package/dist/detectors/long-function.d.ts +12 -0
  64. package/dist/detectors/long-function.d.ts.map +1 -0
  65. package/dist/detectors/long-function.js +45 -0
  66. package/dist/detectors/long-function.js.map +1 -0
  67. package/dist/detectors/magic-numbers.d.ts +10 -0
  68. package/dist/detectors/magic-numbers.d.ts.map +1 -0
  69. package/dist/detectors/magic-numbers.js +332 -0
  70. package/dist/detectors/magic-numbers.js.map +1 -0
  71. package/dist/detectors/mutable-globals.d.ts +6 -0
  72. package/dist/detectors/mutable-globals.d.ts.map +1 -0
  73. package/dist/detectors/mutable-globals.js +95 -0
  74. package/dist/detectors/mutable-globals.js.map +1 -0
  75. package/dist/detectors/mutation.d.ts +11 -0
  76. package/dist/detectors/mutation.d.ts.map +1 -0
  77. package/dist/detectors/mutation.js +397 -0
  78. package/dist/detectors/mutation.js.map +1 -0
  79. package/dist/detectors/public-any.d.ts +6 -0
  80. package/dist/detectors/public-any.d.ts.map +1 -0
  81. package/dist/detectors/public-any.js +52 -0
  82. package/dist/detectors/public-any.js.map +1 -0
  83. package/dist/detectors/race-condition.d.ts +6 -0
  84. package/dist/detectors/race-condition.d.ts.map +1 -0
  85. package/dist/detectors/race-condition.js +608 -0
  86. package/dist/detectors/race-condition.js.map +1 -0
  87. package/dist/detectors/shared-db-write.d.ts +6 -0
  88. package/dist/detectors/shared-db-write.d.ts.map +1 -0
  89. package/dist/detectors/shared-db-write.js +656 -0
  90. package/dist/detectors/shared-db-write.js.map +1 -0
  91. package/dist/detectors/silent-catch.d.ts +6 -0
  92. package/dist/detectors/silent-catch.d.ts.map +1 -0
  93. package/dist/detectors/silent-catch.js +167 -0
  94. package/dist/detectors/silent-catch.js.map +1 -0
  95. package/dist/detectors/similar-functions.d.ts +15 -0
  96. package/dist/detectors/similar-functions.d.ts.map +1 -0
  97. package/dist/detectors/similar-functions.js +334 -0
  98. package/dist/detectors/similar-functions.js.map +1 -0
  99. package/dist/detectors/skip-tests.d.ts +6 -0
  100. package/dist/detectors/skip-tests.d.ts.map +1 -0
  101. package/dist/detectors/skip-tests.js +69 -0
  102. package/dist/detectors/skip-tests.js.map +1 -0
  103. package/dist/detectors/todo-comments.d.ts +29 -0
  104. package/dist/detectors/todo-comments.d.ts.map +1 -0
  105. package/dist/detectors/todo-comments.js +154 -0
  106. package/dist/detectors/todo-comments.js.map +1 -0
  107. package/dist/detectors/unused-deps.d.ts +8 -0
  108. package/dist/detectors/unused-deps.d.ts.map +1 -0
  109. package/dist/detectors/unused-deps.js +115 -0
  110. package/dist/detectors/unused-deps.js.map +1 -0
  111. package/dist/extraction/api-race-confirmer.d.ts +31 -0
  112. package/dist/extraction/api-race-confirmer.d.ts.map +1 -0
  113. package/dist/extraction/api-race-confirmer.js +110 -0
  114. package/dist/extraction/api-race-confirmer.js.map +1 -0
  115. package/dist/extraction/llm-confirmer.d.ts +25 -0
  116. package/dist/extraction/llm-confirmer.d.ts.map +1 -0
  117. package/dist/extraction/llm-confirmer.js +118 -0
  118. package/dist/extraction/llm-confirmer.js.map +1 -0
  119. package/dist/extraction/mutation-confirmer.d.ts +30 -0
  120. package/dist/extraction/mutation-confirmer.d.ts.map +1 -0
  121. package/dist/extraction/mutation-confirmer.js +73 -0
  122. package/dist/extraction/mutation-confirmer.js.map +1 -0
  123. package/dist/extraction/prompt-chunking.d.ts +37 -0
  124. package/dist/extraction/prompt-chunking.d.ts.map +1 -0
  125. package/dist/extraction/prompt-chunking.js +61 -0
  126. package/dist/extraction/prompt-chunking.js.map +1 -0
  127. package/dist/extraction/race-confirmer.d.ts +28 -0
  128. package/dist/extraction/race-confirmer.d.ts.map +1 -0
  129. package/dist/extraction/race-confirmer.js +68 -0
  130. package/dist/extraction/race-confirmer.js.map +1 -0
  131. package/dist/extraction/shared-db-write-confirmer.d.ts +31 -0
  132. package/dist/extraction/shared-db-write-confirmer.d.ts.map +1 -0
  133. package/dist/extraction/shared-db-write-confirmer.js +141 -0
  134. package/dist/extraction/shared-db-write-confirmer.js.map +1 -0
  135. package/dist/extraction/triage-confirmer.d.ts +59 -0
  136. package/dist/extraction/triage-confirmer.d.ts.map +1 -0
  137. package/dist/extraction/triage-confirmer.js +104 -0
  138. package/dist/extraction/triage-confirmer.js.map +1 -0
  139. package/dist/graph/cfg.d.ts +45 -0
  140. package/dist/graph/cfg.d.ts.map +1 -0
  141. package/dist/graph/cfg.js +198 -0
  142. package/dist/graph/cfg.js.map +1 -0
  143. package/dist/graph/decorator-entries.d.ts +2 -0
  144. package/dist/graph/decorator-entries.d.ts.map +1 -0
  145. package/dist/graph/decorator-entries.js +89 -0
  146. package/dist/graph/decorator-entries.js.map +1 -0
  147. package/dist/graph/entry-points.d.ts +12 -0
  148. package/dist/graph/entry-points.d.ts.map +1 -0
  149. package/dist/graph/entry-points.js +282 -0
  150. package/dist/graph/entry-points.js.map +1 -0
  151. package/dist/graph/handler-conventions.d.ts +2 -0
  152. package/dist/graph/handler-conventions.d.ts.map +1 -0
  153. package/dist/graph/handler-conventions.js +26 -0
  154. package/dist/graph/handler-conventions.js.map +1 -0
  155. package/dist/graph/iac-entries.d.ts +2 -0
  156. package/dist/graph/iac-entries.d.ts.map +1 -0
  157. package/dist/graph/iac-entries.js +123 -0
  158. package/dist/graph/iac-entries.js.map +1 -0
  159. package/dist/graph/import-graph.d.ts +48 -0
  160. package/dist/graph/import-graph.d.ts.map +1 -0
  161. package/dist/graph/import-graph.js +86 -0
  162. package/dist/graph/import-graph.js.map +1 -0
  163. package/dist/graph/monorepo-detect.d.ts +3 -0
  164. package/dist/graph/monorepo-detect.d.ts.map +1 -0
  165. package/dist/graph/monorepo-detect.js +166 -0
  166. package/dist/graph/monorepo-detect.js.map +1 -0
  167. package/dist/graph/tsconfig-paths.d.ts +23 -0
  168. package/dist/graph/tsconfig-paths.d.ts.map +1 -0
  169. package/dist/graph/tsconfig-paths.js +217 -0
  170. package/dist/graph/tsconfig-paths.js.map +1 -0
  171. package/dist/multi-workspace-scanner.d.ts +13 -0
  172. package/dist/multi-workspace-scanner.d.ts.map +1 -0
  173. package/dist/multi-workspace-scanner.js +130 -0
  174. package/dist/multi-workspace-scanner.js.map +1 -0
  175. package/dist/normalizers/type-normalizer.d.ts +16 -0
  176. package/dist/normalizers/type-normalizer.d.ts.map +1 -0
  177. package/dist/normalizers/type-normalizer.js +189 -0
  178. package/dist/normalizers/type-normalizer.js.map +1 -0
  179. package/dist/parsers/typescript-parser.d.ts +57 -0
  180. package/dist/parsers/typescript-parser.d.ts.map +1 -0
  181. package/dist/parsers/typescript-parser.js +502 -0
  182. package/dist/parsers/typescript-parser.js.map +1 -0
  183. package/dist/reporter/json-reporter.d.ts +12 -0
  184. package/dist/reporter/json-reporter.d.ts.map +1 -0
  185. package/dist/reporter/json-reporter.js +28 -0
  186. package/dist/reporter/json-reporter.js.map +1 -0
  187. package/dist/reporter/markdown-reporter.d.ts +11 -0
  188. package/dist/reporter/markdown-reporter.d.ts.map +1 -0
  189. package/dist/reporter/markdown-reporter.js +77 -0
  190. package/dist/reporter/markdown-reporter.js.map +1 -0
  191. package/dist/rothunter.d.ts +125 -0
  192. package/dist/rothunter.d.ts.map +1 -0
  193. package/dist/rothunter.js +1038 -0
  194. package/dist/rothunter.js.map +1 -0
  195. package/dist/server/false-positives.d.ts +34 -0
  196. package/dist/server/false-positives.d.ts.map +1 -0
  197. package/dist/server/false-positives.js +85 -0
  198. package/dist/server/false-positives.js.map +1 -0
  199. package/dist/server/index.d.ts +2 -0
  200. package/dist/server/index.d.ts.map +1 -0
  201. package/dist/server/index.js +1529 -0
  202. package/dist/server/index.js.map +1 -0
  203. package/dist/server/marked-to-fix.d.ts +16 -0
  204. package/dist/server/marked-to-fix.d.ts.map +1 -0
  205. package/dist/server/marked-to-fix.js +36 -0
  206. package/dist/server/marked-to-fix.js.map +1 -0
  207. package/dist/server/scan-store.d.ts +147 -0
  208. package/dist/server/scan-store.d.ts.map +1 -0
  209. package/dist/server/scan-store.js +291 -0
  210. package/dist/server/scan-store.js.map +1 -0
  211. package/dist/server/settings-store.d.ts +28 -0
  212. package/dist/server/settings-store.d.ts.map +1 -0
  213. package/dist/server/settings-store.js +46 -0
  214. package/dist/server/settings-store.js.map +1 -0
  215. package/dist/server/workspace-store.d.ts +39 -0
  216. package/dist/server/workspace-store.d.ts.map +1 -0
  217. package/dist/server/workspace-store.js +108 -0
  218. package/dist/server/workspace-store.js.map +1 -0
  219. package/dist/types/detector-input.d.ts +37 -0
  220. package/dist/types/detector-input.d.ts.map +1 -0
  221. package/dist/types/detector-input.js +2 -0
  222. package/dist/types/detector-input.js.map +1 -0
  223. package/dist/types.d.ts +110 -0
  224. package/dist/types.d.ts.map +1 -0
  225. package/dist/types.js +2 -0
  226. package/dist/types.js.map +1 -0
  227. package/dist/utils/clustering.d.ts +14 -0
  228. package/dist/utils/clustering.d.ts.map +1 -0
  229. package/dist/utils/clustering.js +56 -0
  230. package/dist/utils/clustering.js.map +1 -0
  231. package/dist/utils/gitignore.d.ts +32 -0
  232. package/dist/utils/gitignore.d.ts.map +1 -0
  233. package/dist/utils/gitignore.js +122 -0
  234. package/dist/utils/gitignore.js.map +1 -0
  235. package/dist/utils/hash.d.ts +11 -0
  236. package/dist/utils/hash.d.ts.map +1 -0
  237. package/dist/utils/hash.js +14 -0
  238. package/dist/utils/hash.js.map +1 -0
  239. package/dist/utils/ignore-annotation.d.ts +28 -0
  240. package/dist/utils/ignore-annotation.d.ts.map +1 -0
  241. package/dist/utils/ignore-annotation.js +46 -0
  242. package/dist/utils/ignore-annotation.js.map +1 -0
  243. package/dist/utils/llm-json.d.ts +2 -0
  244. package/dist/utils/llm-json.d.ts.map +1 -0
  245. package/dist/utils/llm-json.js +53 -0
  246. package/dist/utils/llm-json.js.map +1 -0
  247. package/dist/utils/logger.d.ts +3 -0
  248. package/dist/utils/logger.d.ts.map +1 -0
  249. package/dist/utils/logger.js +4 -0
  250. package/dist/utils/logger.js.map +1 -0
  251. package/dist/utils/project-conventions.d.ts +2 -0
  252. package/dist/utils/project-conventions.d.ts.map +1 -0
  253. package/dist/utils/project-conventions.js +108 -0
  254. package/dist/utils/project-conventions.js.map +1 -0
  255. package/dist/utils/regex.d.ts +9 -0
  256. package/dist/utils/regex.d.ts.map +1 -0
  257. package/dist/utils/regex.js +11 -0
  258. package/dist/utils/regex.js.map +1 -0
  259. package/dist/utils/snippet.d.ts +20 -0
  260. package/dist/utils/snippet.d.ts.map +1 -0
  261. package/dist/utils/snippet.js +28 -0
  262. package/dist/utils/snippet.js.map +1 -0
  263. package/dist/utils/source-reader.d.ts +19 -0
  264. package/dist/utils/source-reader.d.ts.map +1 -0
  265. package/dist/utils/source-reader.js +32 -0
  266. package/dist/utils/source-reader.js.map +1 -0
  267. package/logo.png +0 -0
  268. package/package.json +92 -0
  269. package/scripts/start-llm.mjs +161 -0
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Single source of truth for detector IDs.
3
+ *
4
+ * Anything that lists every detector (the server's settings UI, the CLI
5
+ * `--detectors` flag validation, future detector documentation) imports
6
+ * from here. Previously the server/index.ts hardcoded a parallel list
7
+ * that drifted when new detectors were wired into rothunter.ts.
8
+ *
9
+ * To register a new detector:
10
+ * 1. Add its id below.
11
+ * 2. Import + invoke it from rothunter.ts.
12
+ * 3. (Optional) Tag it as `singleWorkspaceOnly` if it can't run when
13
+ * multi-workspace-scanner is active — see the `MULTI_WORKSPACE_*`
14
+ * sets below for the current split.
15
+ */
16
+ export const DETECTOR_IDS = [
17
+ // Always-on (symbol/graph-only)
18
+ 'duplicate-type',
19
+ 'duplicate-function',
20
+ 'dead-module',
21
+ 'dead-export',
22
+ 'dead-api',
23
+ 'long-function',
24
+ 'deep-nesting',
25
+ 'public-any',
26
+ 'hot-hub-file',
27
+ // Single-workspace only (file-walking, git, or ts-morph Project-bound)
28
+ 'dead-handler',
29
+ 'mutation',
30
+ 'race-condition',
31
+ 'shared-db-write',
32
+ 'api-race',
33
+ 'bad-config',
34
+ 'silent-catch',
35
+ 'skip-tests',
36
+ 'long-file',
37
+ 'console-log-prod',
38
+ 'magic-numbers',
39
+ 'mutable-globals',
40
+ 'unused-deps',
41
+ 'similar-functions',
42
+ 'todo-comments',
43
+ ];
44
+ /**
45
+ * Detectors that need real workspace-root-relative file paths or git
46
+ * access on a single workspace. Multi-workspace mode skips these because
47
+ * multi-workspace-scanner prefixes paths with the workspace name (see
48
+ * the warn-log in rothunter.ts run()).
49
+ */
50
+ export const MULTI_WORKSPACE_SKIPPED = new Set([
51
+ 'dead-handler',
52
+ 'mutation',
53
+ 'race-condition',
54
+ 'shared-db-write',
55
+ 'api-race',
56
+ 'bad-config',
57
+ 'silent-catch',
58
+ 'skip-tests',
59
+ 'long-file',
60
+ 'console-log-prod',
61
+ 'magic-numbers',
62
+ 'mutable-globals',
63
+ 'unused-deps',
64
+ 'similar-functions',
65
+ 'todo-comments',
66
+ ]);
67
+ /**
68
+ * Cross-repo detector: only runs in multi-workspace mode (its whole
69
+ * purpose is to flag exported symbols that nobody imports across
70
+ * workspace boundaries — in single-workspace mode dead-export already
71
+ * covers that ground).
72
+ */
73
+ export const MULTI_WORKSPACE_ONLY = new Set(['dead-api']);
74
+ //# sourceMappingURL=detector-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector-registry.js","sourceRoot":"","sources":["../src/detector-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,gCAAgC;IAChC,gBAAgB;IAChB,oBAAoB;IACpB,aAAa;IACb,aAAa;IACb,UAAU;IACV,eAAe;IACf,cAAc;IACd,YAAY;IACZ,cAAc;IACd,uEAAuE;IACvE,cAAc;IACd,UAAU;IACV,gBAAgB;IAChB,iBAAiB;IACjB,UAAU;IACV,YAAY;IACZ,cAAc;IACd,YAAY;IACZ,WAAW;IACX,kBAAkB;IAClB,eAAe;IACf,iBAAiB;IACjB,aAAa;IACb,mBAAmB;IACnB,eAAe;CACP,CAAC;AAIX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAa;IACzD,cAAc;IACd,UAAU;IACV,gBAAgB;IAChB,iBAAiB;IACjB,UAAU;IACV,YAAY;IACZ,cAAc;IACd,YAAY;IACZ,WAAW;IACX,kBAAkB;IAClB,eAAe;IACf,iBAAiB;IACjB,aAAa;IACb,mBAAmB;IACnB,eAAe;CAChB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAa,CAAC,UAAU,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Finding } from '../types.js';
2
+ import type { FileWalkingDetectorInput } from '../types/detector-input.js';
3
+ export interface ApiRaceDetectorInput extends FileWalkingDetectorInput {
4
+ }
5
+ export declare function detectApiRaces(input: ApiRaceDetectorInput): Finding[];
6
+ //# sourceMappingURL=api-race.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-race.d.ts","sourceRoot":"","sources":["../../src/detectors/api-race.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAE3E,MAAM,WAAW,oBAAqB,SAAQ,wBAAwB;CAAG;AAiBzE,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,EAAE,CAwFrE"}
@@ -0,0 +1,222 @@
1
+ import * as path from 'node:path';
2
+ import { Project, SyntaxKind } from 'ts-morph';
3
+ import { stableHash } from '../utils/hash.js';
4
+ import { trimSnippet, trimEnclosingSource } from '../utils/snippet.js';
5
+ // Indexes PUT/PATCH/POST/DELETE calls by (method, normalized path); flags
6
+ // clusters touched by ≥2 caller files. Clients: fetch, axios, got, ky,
7
+ // superagent. GET excluded. Path interpolations + numeric segments → `:param`.
8
+ export function detectApiRaces(input) {
9
+ let project;
10
+ if (input.project) {
11
+ project = input.project;
12
+ }
13
+ else {
14
+ project = new Project({
15
+ skipAddingFilesFromTsConfig: true,
16
+ skipFileDependencyResolution: true,
17
+ });
18
+ for (const rel of input.files) {
19
+ project.addSourceFileAtPathIfExists(path.join(input.workspaceRoot, rel));
20
+ }
21
+ }
22
+ const calls = [];
23
+ for (const sf of project.getSourceFiles()) {
24
+ const relativeFile = path.relative(input.workspaceRoot, sf.getFilePath());
25
+ for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
26
+ const matched = matchHttpClient(call);
27
+ if (!matched)
28
+ continue;
29
+ const enclosing = findEnclosingFunction(call);
30
+ const enclosingSource = enclosing
31
+ ? trimEnclosingSource(enclosing.getText())
32
+ : trimSnippet(call.getText());
33
+ const enclosingName = enclosing?.getName?.() ?? undefined;
34
+ calls.push({
35
+ method: matched.method,
36
+ pathPattern: matched.pathPattern,
37
+ file: relativeFile,
38
+ line: call.getStartLineNumber(),
39
+ endLine: call.getEndLineNumber(),
40
+ snippet: trimSnippet(call.getText()),
41
+ enclosingName,
42
+ enclosingSource,
43
+ client: matched.client,
44
+ });
45
+ }
46
+ }
47
+ const byKey = new Map();
48
+ for (const c of calls) {
49
+ const key = `${c.method} ${c.pathPattern}`;
50
+ const list = byKey.get(key) ?? [];
51
+ list.push(c);
52
+ byKey.set(key, list);
53
+ }
54
+ const findings = [];
55
+ for (const [key, list] of byKey) {
56
+ const distinctFiles = new Set(list.map((c) => c.file));
57
+ if (distinctFiles.size < 2)
58
+ continue;
59
+ const clients = [...new Set(list.map((c) => c.client))];
60
+ const exampleFiles = [...distinctFiles].slice(0, 6).join(', ');
61
+ findings.push({
62
+ detectorId: 'api-race',
63
+ severity: 'medium',
64
+ confidence: 0.65,
65
+ layer: 1,
66
+ title: `Shared API write: \`${key}\` called from ${distinctFiles.size} files (${list.length} call sites, clients: ${clients.join('+')})`,
67
+ description: [
68
+ `Multiple functions issue mutating HTTP calls against \`${key}\`.`,
69
+ `If any two of these can execute concurrently (browser + worker, two services, a job that retries while the user hits PATCH), the server may see two writes against the same resource — lost update if the server has no optimistic-locking version.`,
70
+ ``,
71
+ `Locations:`,
72
+ ...list.map((c) => `- ${c.file}:${c.line} (${c.client}) \`${c.snippet}\``),
73
+ ``,
74
+ `Files involved: ${exampleFiles}${distinctFiles.size > 6 ? ', …' : ''}`,
75
+ ].join('\n'),
76
+ evidence: list.slice(0, 8).map((c) => ({
77
+ file: c.file,
78
+ range: { startLine: c.line, endLine: c.endLine },
79
+ snippet: c.enclosingSource,
80
+ note: JSON.stringify({
81
+ method: c.method,
82
+ pathPattern: c.pathPattern,
83
+ client: c.client,
84
+ enclosingName: c.enclosingName ?? '',
85
+ }),
86
+ })),
87
+ suggestion: 'Add an `If-Match` / version-aware update on the server, single-flight the client calls, or merge the duplicated callers into one. If the calls are guaranteed serialised by a queue, document the synchronisation and mark this finding as a false positive.',
88
+ fingerprint: `api-race:${stableHash(key)}`,
89
+ });
90
+ }
91
+ return findings;
92
+ }
93
+ const FETCH_LIKE = new Set(['fetch']);
94
+ const HTTP_CLIENTS = new Set(['axios', 'got', 'ky', 'superagent', 'request', 'apiClient', 'http']);
95
+ const WRITE_VERBS = new Set(['put', 'patch', 'post', 'delete']);
96
+ function matchHttpClient(call) {
97
+ const callee = call.getExpression();
98
+ // fetch(url, { method: 'PUT', ... })
99
+ if (callee.getKind() === SyntaxKind.Identifier && FETCH_LIKE.has(callee.getText())) {
100
+ const args = call.getArguments();
101
+ if (args.length < 2)
102
+ return null;
103
+ const url = extractUrlLiteral(args[0]);
104
+ if (!url)
105
+ return null;
106
+ const method = extractFetchMethod(args[1]);
107
+ if (!method || method === 'GET')
108
+ return null;
109
+ return { method, pathPattern: normalisePath(url), client: 'fetch' };
110
+ }
111
+ // axios/got/ky/superagent/...method(url, ...)
112
+ if (callee.getKind() === SyntaxKind.PropertyAccessExpression) {
113
+ const pa = callee.asKindOrThrow(SyntaxKind.PropertyAccessExpression);
114
+ const verb = pa.getName().toLowerCase();
115
+ if (!WRITE_VERBS.has(verb))
116
+ return null;
117
+ const head = pa.getExpression();
118
+ if (head.getKind() !== SyntaxKind.Identifier)
119
+ return null;
120
+ const clientName = head.getText();
121
+ if (!HTTP_CLIENTS.has(clientName))
122
+ return null;
123
+ const args = call.getArguments();
124
+ if (args.length === 0)
125
+ return null;
126
+ const url = extractUrlLiteral(args[0]);
127
+ if (!url)
128
+ return null;
129
+ return { method: verb.toUpperCase(), pathPattern: normalisePath(url), client: clientName };
130
+ }
131
+ // axios({ url, method: 'put' })
132
+ if (callee.getKind() === SyntaxKind.Identifier && callee.getText() === 'axios') {
133
+ const args = call.getArguments();
134
+ if (args.length === 0)
135
+ return null;
136
+ const obj = args[0];
137
+ if (obj.getKind() !== SyntaxKind.ObjectLiteralExpression)
138
+ return null;
139
+ const urlNode = pickObjectProperty(obj, 'url');
140
+ const methodNode = pickObjectProperty(obj, 'method');
141
+ if (!urlNode || !methodNode)
142
+ return null;
143
+ const url = extractUrlLiteral(urlNode);
144
+ const method = extractStringFromNode(methodNode);
145
+ if (!url || !method)
146
+ return null;
147
+ const upper = method.toUpperCase();
148
+ if (upper === 'GET' || !WRITE_VERBS.has(upper.toLowerCase()))
149
+ return null;
150
+ return { method: upper, pathPattern: normalisePath(url), client: 'axios' };
151
+ }
152
+ return null;
153
+ }
154
+ function extractUrlLiteral(node) {
155
+ const strLit = node.asKind(SyntaxKind.StringLiteral) ?? node.asKind(SyntaxKind.NoSubstitutionTemplateLiteral);
156
+ if (strLit)
157
+ return strLit.getLiteralText();
158
+ if (node.getKind() === SyntaxKind.TemplateExpression) {
159
+ // Reconstruct path with `:param` placeholders for each interpolation.
160
+ const text = node.getText();
161
+ return text
162
+ .slice(1, -1) // strip the backticks
163
+ .replace(/\$\{[^}]+\}/g, ':param');
164
+ }
165
+ return null;
166
+ }
167
+ function extractFetchMethod(optsNode) {
168
+ if (optsNode.getKind() !== SyntaxKind.ObjectLiteralExpression)
169
+ return null;
170
+ const methodInit = pickObjectProperty(optsNode, 'method');
171
+ if (!methodInit)
172
+ return null;
173
+ const m = extractStringFromNode(methodInit);
174
+ return m ? m.toUpperCase() : null;
175
+ }
176
+ function extractStringFromNode(node) {
177
+ const lit = node.asKind(SyntaxKind.StringLiteral) ?? node.asKind(SyntaxKind.NoSubstitutionTemplateLiteral);
178
+ return lit ? lit.getLiteralText() : null;
179
+ }
180
+ /**
181
+ * Normalise a raw URL string into a comparable path pattern:
182
+ * - Strip protocol/host (`https://api.example.com/users/123` → `/users/123`)
183
+ * - Replace numeric segments with `:id`
184
+ * - Replace `:param` interpolation markers (already placed by extractor)
185
+ * - Trim trailing slash
186
+ */
187
+ function normalisePath(raw) {
188
+ let s = raw;
189
+ s = s.replace(/^https?:\/\/[^/]+/, '');
190
+ s = s.replace(/\?.*$/, ''); // drop query string
191
+ s = s.replace(/\/+\d+(?=\/|$)/g, '/:id');
192
+ s = s.replace(/\/+/g, '/');
193
+ if (s.length > 1 && s.endsWith('/'))
194
+ s = s.slice(0, -1);
195
+ if (!s.startsWith('/'))
196
+ s = `/${s}`;
197
+ return s;
198
+ }
199
+ function pickObjectProperty(obj, name) {
200
+ const olit = obj.asKind(SyntaxKind.ObjectLiteralExpression);
201
+ if (!olit)
202
+ return null;
203
+ const prop = olit.getProperty(name);
204
+ if (!prop || prop.getKind() !== SyntaxKind.PropertyAssignment)
205
+ return null;
206
+ return prop.getInitializer() ?? null;
207
+ }
208
+ function findEnclosingFunction(node) {
209
+ let cur = node.getParent();
210
+ while (cur) {
211
+ const k = cur.getKind();
212
+ if (k === SyntaxKind.FunctionDeclaration ||
213
+ k === SyntaxKind.MethodDeclaration ||
214
+ k === SyntaxKind.ArrowFunction ||
215
+ k === SyntaxKind.FunctionExpression) {
216
+ return cur;
217
+ }
218
+ cur = cur.getParent();
219
+ }
220
+ return null;
221
+ }
222
+ //# sourceMappingURL=api-race.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-race.js","sourceRoot":"","sources":["../../src/detectors/api-race.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Finding } from '../types.js';
2
+ import type { FileWalkingDetectorInput } from '../types/detector-input.js';
3
+ export interface BadConfigDetectorInput extends FileWalkingDetectorInput {
4
+ }
5
+ export declare function detectBadConfig(input: BadConfigDetectorInput): Finding[];
6
+ //# sourceMappingURL=bad-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bad-config.d.ts","sourceRoot":"","sources":["../../src/detectors/bad-config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAE3E,MAAM,WAAW,sBAAuB,SAAQ,wBAAwB;CAAG;AAK3E,wBAAgB,eAAe,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,EAAE,CAgCxE"}