@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,608 @@
1
+ import * as path from 'node:path';
2
+ import { stableHash } from '../utils/hash.js';
3
+ import { trimSnippet, trimEnclosingSource } from '../utils/snippet.js';
4
+ import { Project, SyntaxKind, } from 'ts-morph';
5
+ import { buildCfg, blockOf, reachable } from '../graph/cfg.js';
6
+ // Tier-1 race detector. Three patterns:
7
+ // 1. read → await → write on `this.<id>` / module `let`/`var`
8
+ // 2. Promise.all/allSettled/race arms writing the same shared target
9
+ // 3. emitter.on/.addListener handler closing over outer mutable + read-modify-write across await
10
+ // Severity medium, confidence 0.7. `// rothunter:ignore-race` suppresses.
11
+ const PROMISE_PARALLEL_METHODS = new Set(['all', 'allSettled', 'race']);
12
+ const EMITTER_REGISTRATION_METHODS = new Set(['on', 'once', 'addListener', 'addEventListener']);
13
+ export function detectRaceConditions(input) {
14
+ let project;
15
+ if (input.project) {
16
+ project = input.project;
17
+ }
18
+ else {
19
+ project = new Project({
20
+ skipAddingFilesFromTsConfig: true,
21
+ skipFileDependencyResolution: true,
22
+ });
23
+ for (const rel of input.files) {
24
+ project.addSourceFileAtPathIfExists(path.join(input.workspaceRoot, rel));
25
+ }
26
+ }
27
+ const rmwCandidates = [];
28
+ const promiseAllRaces = [];
29
+ const findings = [];
30
+ for (const sf of project.getSourceFiles()) {
31
+ const relativeFile = path.relative(input.workspaceRoot, sf.getFilePath());
32
+ const moduleMutables = collectModuleMutables(sf);
33
+ // Pattern 1 — read-modify-write across await (every async callable).
34
+ for (const fn of sf.getFunctions()) {
35
+ rmwCandidates.push(...analyzeAsync(fn, relativeFile, moduleMutables));
36
+ }
37
+ for (const cls of sf.getClasses()) {
38
+ for (const m of cls.getMethods()) {
39
+ rmwCandidates.push(...analyzeAsync(m, relativeFile, moduleMutables));
40
+ }
41
+ }
42
+ for (const arrow of sf.getDescendantsOfKind(SyntaxKind.ArrowFunction)) {
43
+ rmwCandidates.push(...analyzeAsync(arrow, relativeFile, moduleMutables));
44
+ }
45
+ for (const expr of sf.getDescendantsOfKind(SyntaxKind.FunctionExpression)) {
46
+ rmwCandidates.push(...analyzeAsync(expr, relativeFile, moduleMutables));
47
+ }
48
+ // Pattern 2 — Promise.all siblings writing the same target.
49
+ for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
50
+ const race = analyzePromiseAll(call, relativeFile, moduleMutables);
51
+ if (race)
52
+ promiseAllRaces.push(...race);
53
+ }
54
+ // Pattern 3 — event-emitter handler closing over an outer mutable.
55
+ for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
56
+ const handlerRaces = analyzeEmitterHandler(call, relativeFile);
57
+ if (handlerRaces.length)
58
+ rmwCandidates.push(...handlerRaces);
59
+ }
60
+ }
61
+ // Pattern 1 + Pattern 3 share the same `analyzeAsync` engine: a handler that
62
+ // closes over a module-scope `let` is independently picked up by both the
63
+ // top-level arrow walker (anonymous arrow → no enclosingName) and the
64
+ // emitter-handler walker (carries the outer named function on its
65
+ // candidates). Sort so named candidates win the fingerprint dedup.
66
+ rmwCandidates.sort((a, b) => (b.enclosingName ? 1 : 0) - (a.enclosingName ? 1 : 0));
67
+ const seen = new Set();
68
+ for (const c of rmwCandidates) {
69
+ const f = toFinding(c);
70
+ if (seen.has(f.fingerprint))
71
+ continue;
72
+ seen.add(f.fingerprint);
73
+ findings.push(f);
74
+ }
75
+ for (const r of promiseAllRaces) {
76
+ const f = promiseAllToFinding(r);
77
+ if (seen.has(f.fingerprint))
78
+ continue;
79
+ seen.add(f.fingerprint);
80
+ findings.push(f);
81
+ }
82
+ return findings;
83
+ }
84
+ function collectModuleMutables(sf) {
85
+ const out = new Set();
86
+ const statements = sf.getVariableStatements();
87
+ for (const stmt of statements) {
88
+ const kind = stmt.getDeclarationKind();
89
+ if (kind !== 'let' && kind !== 'var')
90
+ continue;
91
+ for (const decl of stmt.getDeclarations()) {
92
+ if (decl.getNameNode().getKind() !== SyntaxKind.Identifier)
93
+ continue;
94
+ out.add(decl.getName());
95
+ }
96
+ }
97
+ return out;
98
+ }
99
+ function analyzeAsync(fn, file, moduleMutables) {
100
+ if (!fn.isAsync())
101
+ return [];
102
+ const body = fn.getBody?.();
103
+ if (!body)
104
+ return [];
105
+ const reads = [];
106
+ const awaits = [];
107
+ const writes = [];
108
+ // --- Reads: variable initialisers that pull from shared state -------------
109
+ for (const decl of body.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {
110
+ const init = decl.getInitializer();
111
+ if (!init)
112
+ continue;
113
+ const target = canonicalSharedTarget(init, moduleMutables);
114
+ if (!target)
115
+ continue;
116
+ reads.push({ target, line: decl.getStartLineNumber(), node: decl });
117
+ }
118
+ // Also: `const { x } = this`-style destructuring — treat as a read of `this`.
119
+ // For now we only emit if the destructured source itself is a shared target
120
+ // expression that maps to a canonical key (skipping deep-destructure for v0.1).
121
+ // --- Awaits ---------------------------------------------------------------
122
+ for (const aw of body.getDescendantsOfKind(SyntaxKind.AwaitExpression)) {
123
+ awaits.push({ line: aw.getStartLineNumber(), node: aw });
124
+ }
125
+ if (awaits.length === 0)
126
+ return [];
127
+ // --- Writes: assignment expressions whose LHS is shared state -------------
128
+ for (const bin of body.getDescendantsOfKind(SyntaxKind.BinaryExpression)) {
129
+ if (bin.getOperatorToken().getText() !== '=')
130
+ continue;
131
+ if (hasIgnoreAnnotation(bin))
132
+ continue;
133
+ const target = canonicalSharedTarget(bin.getLeft(), moduleMutables);
134
+ if (!target)
135
+ continue;
136
+ writes.push({
137
+ target,
138
+ line: bin.getStartLineNumber(),
139
+ endLine: bin.getEndLineNumber(),
140
+ source: bin.getText(),
141
+ node: bin,
142
+ });
143
+ }
144
+ if (writes.length === 0)
145
+ return [];
146
+ const enclosingName = fn.getName?.();
147
+ const enclosingSource = trimEnclosingSource(fn.getText());
148
+ // Build a CFG of the function body and use forward reachability to
149
+ // confirm that some execution path actually visits read → await → write
150
+ // in that order. Pure line-number ordering misfires on
151
+ // `if (cond) { read } await x; write` — `read` is conditional and may
152
+ // never execute on the path that reaches the write. The CFG resolves
153
+ // that ambiguity (the if-then block and the post-if join block are
154
+ // different CFG nodes, so the read is NOT reachable from the join
155
+ // entry without going through the then branch).
156
+ const cfg = buildCfg(body);
157
+ const blockCache = new Map();
158
+ const blockFor = (n) => {
159
+ const cached = blockCache.get(n);
160
+ if (cached !== undefined)
161
+ return cached;
162
+ const id = blockOf(cfg, n);
163
+ blockCache.set(n, id);
164
+ return id;
165
+ };
166
+ const orderedReach = (fromBlock, fromLine, toBlock, toLine) => {
167
+ if (fromBlock < 0 || toBlock < 0)
168
+ return false;
169
+ if (fromBlock === toBlock) {
170
+ // Same straight-line block — strict line ordering. Back-edges that
171
+ // loop the block to itself are picked up by reachable() below; the
172
+ // first-iteration ordering is what matters for the standard
173
+ // read-modify-write pattern.
174
+ return fromLine < toLine || reachable(cfg, fromBlock, toBlock);
175
+ }
176
+ return reachable(cfg, fromBlock, toBlock);
177
+ };
178
+ const out = [];
179
+ for (const r of reads) {
180
+ const rBlock = blockFor(r.node);
181
+ if (rBlock < 0)
182
+ continue;
183
+ let chosen = null;
184
+ for (const aw of awaits) {
185
+ const aBlock = blockFor(aw.node);
186
+ if (!orderedReach(rBlock, r.line, aBlock, aw.line))
187
+ continue;
188
+ for (const w of writes) {
189
+ if (w.target !== r.target)
190
+ continue;
191
+ const wBlock = blockFor(w.node);
192
+ if (!orderedReach(aBlock, aw.line, wBlock, w.line))
193
+ continue;
194
+ chosen = { aw, w };
195
+ break;
196
+ }
197
+ if (chosen)
198
+ break;
199
+ }
200
+ if (!chosen)
201
+ continue;
202
+ out.push({
203
+ file,
204
+ target: r.target,
205
+ readLine: r.line,
206
+ awaitLine: chosen.aw.line,
207
+ writeLine: chosen.w.line,
208
+ writeEndLine: chosen.w.endLine,
209
+ writeSnippet: trimSnippet(chosen.w.source),
210
+ enclosingName: enclosingName ?? undefined,
211
+ enclosingSource,
212
+ });
213
+ }
214
+ return out;
215
+ }
216
+ // Pattern 2: Promise.all/allSettled/race. Two shapes:
217
+ // (a) array-literal arms writing same target → cluster finding
218
+ // (b) .map(async ...) parallel callback with read→await→write → single finding
219
+ function analyzePromiseAll(call, file, moduleMutables) {
220
+ const callee = call.getExpression();
221
+ if (callee.getKind() !== SyntaxKind.PropertyAccessExpression)
222
+ return [];
223
+ const pa = callee.asKindOrThrow(SyntaxKind.PropertyAccessExpression);
224
+ const head = pa.getExpression().getText();
225
+ if (head !== 'Promise')
226
+ return [];
227
+ if (!PROMISE_PARALLEL_METHODS.has(pa.getName()))
228
+ return [];
229
+ const [arg] = call.getArguments();
230
+ if (!arg)
231
+ return [];
232
+ // (b) `.map(async ...)` parallel-callback shape.
233
+ if (arg.getKind() === SyntaxKind.CallExpression) {
234
+ return analyzeParallelMapCallback(call, arg, file, moduleMutables);
235
+ }
236
+ // (a) array-literal arms.
237
+ const arrayArg = arg.asKind(SyntaxKind.ArrayLiteralExpression);
238
+ if (!arrayArg)
239
+ return [];
240
+ const elements = arrayArg.getElements();
241
+ if (elements.length < 2)
242
+ return [];
243
+ const armWrites = [];
244
+ for (let i = 0; i < elements.length; i++) {
245
+ const armBody = resolveFunctionBody(elements[i]);
246
+ if (!armBody)
247
+ continue;
248
+ for (const bin of armBody.getDescendantsOfKind(SyntaxKind.BinaryExpression)) {
249
+ if (bin.getOperatorToken().getText() !== '=')
250
+ continue;
251
+ if (hasIgnoreAnnotation(bin))
252
+ continue;
253
+ const target = canonicalSharedTarget(bin.getLeft(), moduleMutables);
254
+ if (!target)
255
+ continue;
256
+ armWrites.push({
257
+ armIndex: i,
258
+ target,
259
+ line: bin.getStartLineNumber(),
260
+ snippet: trimSnippet(bin.getText()),
261
+ });
262
+ }
263
+ }
264
+ // Cluster by target — only emit when ≥ 2 distinct arms write.
265
+ const byTarget = new Map();
266
+ for (const w of armWrites) {
267
+ const list = byTarget.get(w.target) ?? [];
268
+ list.push(w);
269
+ byTarget.set(w.target, list);
270
+ }
271
+ const enclosingFn = findEnclosingNamedFunction(call);
272
+ const enclosingSource = enclosingFn
273
+ ? trimEnclosingSource(enclosingFn.getText())
274
+ : trimEnclosingSource(call.getText());
275
+ const enclosingName = enclosingFn
276
+ ? enclosingFn.getName?.()
277
+ : undefined;
278
+ const out = [];
279
+ for (const [target, list] of byTarget) {
280
+ const armIndices = new Set(list.map((w) => w.armIndex));
281
+ if (armIndices.size < 2)
282
+ continue;
283
+ out.push({
284
+ file,
285
+ callLine: call.getStartLineNumber(),
286
+ callEndLine: call.getEndLineNumber(),
287
+ target,
288
+ writes: list.map((w) => ({ line: w.line, snippet: w.snippet })),
289
+ enclosingSource,
290
+ enclosingName: enclosingName ?? undefined,
291
+ });
292
+ }
293
+ return out;
294
+ }
295
+ /**
296
+ * `Promise.all(<arr>.map(async (x) => { ... }))` — single async callback
297
+ * invoked once per element with full parallelism. Every read-modify-write
298
+ * across `await` on a shared target races with every other invocation.
299
+ */
300
+ function analyzeParallelMapCallback(promiseCall, arg, file, moduleMutables) {
301
+ // arg must be a `.map(<fn>)` / `.forEach(<fn>)` call. `.forEach` does NOT
302
+ // surface its returned promises so it cannot create races through
303
+ // Promise.all — only `.map` counts here.
304
+ if (arg.getKind() !== SyntaxKind.CallExpression)
305
+ return [];
306
+ const mapCall = arg;
307
+ const mapCallee = mapCall.getExpression();
308
+ if (mapCallee.getKind() !== SyntaxKind.PropertyAccessExpression)
309
+ return [];
310
+ const mapPa = mapCallee.asKindOrThrow(SyntaxKind.PropertyAccessExpression);
311
+ if (mapPa.getName() !== 'map')
312
+ return [];
313
+ const [cb] = mapCall.getArguments();
314
+ if (!cb)
315
+ return [];
316
+ if (cb.getKind() !== SyntaxKind.ArrowFunction &&
317
+ cb.getKind() !== SyntaxKind.FunctionExpression) {
318
+ return [];
319
+ }
320
+ const fn = cb;
321
+ // Only async callbacks can host the read-modify-write-across-await pattern.
322
+ if (!fn.isAsync?.())
323
+ return [];
324
+ const body = fn.getBody?.();
325
+ if (!body)
326
+ return [];
327
+ // Collect shared-target writes that follow an `await`.
328
+ const awaits = body.getDescendantsOfKind(SyntaxKind.AwaitExpression).map((a) => a.getStartLineNumber());
329
+ if (awaits.length === 0)
330
+ return [];
331
+ const firstAwait = Math.min(...awaits);
332
+ const enclosingFn = findEnclosingNamedFunction(promiseCall);
333
+ const enclosingSource = enclosingFn
334
+ ? trimEnclosingSource(enclosingFn.getText())
335
+ : trimEnclosingSource(promiseCall.getText());
336
+ const enclosingName = enclosingFn
337
+ ? enclosingFn.getName?.()
338
+ : undefined;
339
+ const writesByTarget = new Map();
340
+ for (const bin of body.getDescendantsOfKind(SyntaxKind.BinaryExpression)) {
341
+ if (bin.getOperatorToken().getText() !== '=')
342
+ continue;
343
+ if (hasIgnoreAnnotation(bin))
344
+ continue;
345
+ if (bin.getStartLineNumber() < firstAwait)
346
+ continue;
347
+ const target = canonicalSharedTarget(bin.getLeft(), moduleMutables);
348
+ if (!target)
349
+ continue;
350
+ const list = writesByTarget.get(target) ?? [];
351
+ list.push({ line: bin.getStartLineNumber(), snippet: trimSnippet(bin.getText()) });
352
+ writesByTarget.set(target, list);
353
+ }
354
+ const out = [];
355
+ for (const [target, writes] of writesByTarget) {
356
+ out.push({
357
+ file,
358
+ callLine: promiseCall.getStartLineNumber(),
359
+ callEndLine: promiseCall.getEndLineNumber(),
360
+ target,
361
+ writes,
362
+ enclosingSource,
363
+ enclosingName: enclosingName ?? undefined,
364
+ });
365
+ }
366
+ return out;
367
+ }
368
+ function resolveFunctionBody(node) {
369
+ let cur = node;
370
+ // Unwrap parens + IIFEs to land on the arrow/function-expression body.
371
+ for (let i = 0; i < 6; i++) {
372
+ const paren = cur.asKind(SyntaxKind.ParenthesizedExpression);
373
+ if (paren) {
374
+ cur = paren.getExpression();
375
+ continue;
376
+ }
377
+ const callShape = cur.asKind(SyntaxKind.CallExpression);
378
+ if (callShape) {
379
+ let inner = callShape.getExpression();
380
+ let innerParen = inner.asKind(SyntaxKind.ParenthesizedExpression);
381
+ while (innerParen) {
382
+ inner = innerParen.getExpression();
383
+ innerParen = inner.asKind(SyntaxKind.ParenthesizedExpression);
384
+ }
385
+ if (inner.getKind() === SyntaxKind.ArrowFunction ||
386
+ inner.getKind() === SyntaxKind.FunctionExpression) {
387
+ cur = inner;
388
+ continue;
389
+ }
390
+ return null;
391
+ }
392
+ break;
393
+ }
394
+ if (cur.getKind() === SyntaxKind.ArrowFunction ||
395
+ cur.getKind() === SyntaxKind.FunctionExpression) {
396
+ return cur.getBody?.() ?? null;
397
+ }
398
+ return null;
399
+ }
400
+ /**
401
+ * Walk ancestors until a named function-like is hit. Useful for surfacing
402
+ * the outer named function on findings whose immediate enclosing scope is
403
+ * an anonymous arrow/IIFE (Promise.all arms, emitter handlers). Falls back
404
+ * to the nearest function-like when no named ancestor exists.
405
+ */
406
+ function findEnclosingNamedFunction(node) {
407
+ let nearest = null;
408
+ let cur = node.getParent();
409
+ while (cur) {
410
+ const k = cur.getKind();
411
+ if (k === SyntaxKind.FunctionDeclaration ||
412
+ k === SyntaxKind.MethodDeclaration ||
413
+ k === SyntaxKind.ArrowFunction ||
414
+ k === SyntaxKind.FunctionExpression) {
415
+ if (!nearest)
416
+ nearest = cur;
417
+ const name = cur.getName?.();
418
+ if (name)
419
+ return cur;
420
+ }
421
+ cur = cur.getParent();
422
+ }
423
+ return nearest;
424
+ }
425
+ /**
426
+ * Pattern 3 — `emitter.on(event, handler)` where the handler closes over
427
+ * an outer `let`/`var` and performs a read-modify-write across `await`.
428
+ *
429
+ * We treat any `let`/`var` declared in an enclosing scope (function body,
430
+ * module top level) as a shared mutable. The same `analyzeAsync` engine
431
+ * then runs on the handler body — emitting the canonical read-modify-write
432
+ * race-condition finding.
433
+ */
434
+ function analyzeEmitterHandler(call, file) {
435
+ const callee = call.getExpression();
436
+ if (callee.getKind() !== SyntaxKind.PropertyAccessExpression)
437
+ return [];
438
+ const pa = callee.asKindOrThrow(SyntaxKind.PropertyAccessExpression);
439
+ if (!EMITTER_REGISTRATION_METHODS.has(pa.getName()))
440
+ return [];
441
+ const args = call.getArguments();
442
+ if (args.length < 2)
443
+ return [];
444
+ const handler = args[args.length - 1];
445
+ if (handler.getKind() !== SyntaxKind.ArrowFunction &&
446
+ handler.getKind() !== SyntaxKind.FunctionExpression) {
447
+ return [];
448
+ }
449
+ const fn = handler;
450
+ // Only async handlers can hit a read-modify-write race across `await`.
451
+ if (!fn.isAsync?.())
452
+ return [];
453
+ const outerMutables = collectOuterMutables(call, fn);
454
+ if (outerMutables.size === 0)
455
+ return [];
456
+ const candidates = analyzeAsync(fn, file, outerMutables);
457
+ // The handler itself is anonymous (arrow / function expression). Surface
458
+ // the outer named function that registered the listener so the finding
459
+ // has a useful enclosingName for downstream callers.
460
+ const outerNamed = findEnclosingNamedFunction(call);
461
+ const outerName = outerNamed
462
+ ? outerNamed.getName?.()
463
+ : undefined;
464
+ if (outerName) {
465
+ for (const c of candidates) {
466
+ if (!c.enclosingName)
467
+ c.enclosingName = outerName;
468
+ }
469
+ }
470
+ return candidates;
471
+ }
472
+ // let/var bindings the handler closes over. const skipped — mutable
473
+ // contents (Map/Set/Array) are tracked via member writes elsewhere.
474
+ function collectOuterMutables(call, handler) {
475
+ const out = new Set();
476
+ let cur = call.getParent();
477
+ while (cur) {
478
+ if (cur.getKind() === SyntaxKind.Block ||
479
+ cur.getKind() === SyntaxKind.SourceFile) {
480
+ const stmts = cur.getVariableStatements?.();
481
+ if (Array.isArray(stmts)) {
482
+ for (const stmt of stmts) {
483
+ const kind = stmt.getDeclarationKind();
484
+ if (kind !== 'let' && kind !== 'var')
485
+ continue;
486
+ for (const decl of stmt.getDeclarations()) {
487
+ if (decl.getNameNode().getKind() !== SyntaxKind.Identifier)
488
+ continue;
489
+ out.add(decl.getName());
490
+ }
491
+ }
492
+ }
493
+ }
494
+ if (cur === handler)
495
+ break;
496
+ cur = cur.getParent();
497
+ }
498
+ return out;
499
+ }
500
+ // Canonical key for shared state. this.foo[.bar] → "this.foo"; bare/elem-access
501
+ // → identifier only if it's a known module mutable. null otherwise.
502
+ function canonicalSharedTarget(expr, moduleMutables) {
503
+ let cur = expr;
504
+ // For PropertyAccessExpression chains, descend to the head identifier or `this`.
505
+ while (true) {
506
+ const propAccess = cur.asKind(SyntaxKind.PropertyAccessExpression);
507
+ const elemAccess = cur.asKind(SyntaxKind.ElementAccessExpression);
508
+ if (!propAccess && !elemAccess)
509
+ break;
510
+ const owner = (propAccess ?? elemAccess).getExpression();
511
+ if (propAccess && owner.getKind() === SyntaxKind.ThisKeyword) {
512
+ // `this.<name>` — canonical key.
513
+ return `this.${propAccess.getName()}`;
514
+ }
515
+ cur = owner;
516
+ }
517
+ if (cur.getKind() === SyntaxKind.Identifier) {
518
+ const name = cur.getText();
519
+ if (moduleMutables.has(name))
520
+ return name;
521
+ }
522
+ return null;
523
+ }
524
+ const IGNORE_ANNOTATION = 'rothunter:ignore-race';
525
+ function hasIgnoreAnnotation(node) {
526
+ for (const range of node.getLeadingCommentRanges()) {
527
+ if (range.getText().includes(IGNORE_ANNOTATION))
528
+ return true;
529
+ }
530
+ const fullStart = node.getFullStart();
531
+ const sf = node.getSourceFile();
532
+ const text = sf.getFullText().slice(Math.max(0, fullStart - 200), fullStart);
533
+ return text.includes(IGNORE_ANNOTATION);
534
+ }
535
+ function toFinding(c) {
536
+ const title = `Read-modify-write across \`await\` on ${c.target}`;
537
+ const description = [
538
+ `${title}.`,
539
+ `Two concurrent callers can both read \`${c.target}\` before either writes back. The second write overrides the first.`,
540
+ `Locations:`,
541
+ `- ${c.file}:${c.readLine} (read \`${c.target}\`)`,
542
+ `- ${c.file}:${c.awaitLine} (await yields control)`,
543
+ `- ${c.file}:${c.writeLine} (write \`${c.writeSnippet}\`)`,
544
+ '',
545
+ `If the function is invoked behind a mutex / queue / single-flight wrapper, OR the state is per-request and not shared between callers, add a \`// rothunter:ignore-race\` comment above the write OR document the synchronisation.`,
546
+ ].join('\n');
547
+ return {
548
+ detectorId: 'race-condition',
549
+ severity: 'medium',
550
+ confidence: 0.7,
551
+ layer: 1,
552
+ title,
553
+ description,
554
+ evidence: [
555
+ {
556
+ file: c.file,
557
+ range: { startLine: c.readLine, endLine: c.writeEndLine },
558
+ snippet: c.enclosingSource,
559
+ note: JSON.stringify({
560
+ target: c.target,
561
+ readLine: c.readLine,
562
+ awaitLine: c.awaitLine,
563
+ writeLine: c.writeLine,
564
+ enclosingName: c.enclosingName ?? '',
565
+ }),
566
+ },
567
+ ],
568
+ suggestion: 'Wrap the critical section in a mutex / single-flight / queue, OR fetch + update + write in one atomic transaction, OR re-fetch the value just before the write.',
569
+ fingerprint: `race:read-modify-write:${stableHash(`${c.file}::${c.target}::${c.readLine}::${c.writeLine}`)}`,
570
+ };
571
+ }
572
+ function promiseAllToFinding(r) {
573
+ const title = `Parallel \`Promise.all\` arms write the same shared target ${r.target}`;
574
+ const description = [
575
+ `${title}.`,
576
+ `Two or more sibling arms of the \`Promise.all\` (or \`Promise.allSettled\` / \`Promise.race\`) call write \`${r.target}\`. When both arms execute concurrently the second write overrides the first — guaranteed lost-update, no timing window required.`,
577
+ `Locations:`,
578
+ `- ${r.file}:${r.callLine} (parallel call)`,
579
+ ...r.writes.map((w) => `- ${r.file}:${w.line} (write \`${w.snippet}\`)`),
580
+ '',
581
+ 'If the arms must run in parallel, write to per-arm locals and merge afterwards, OR serialise the parallel arms, OR use an atomic counter (e.g. mutex / single-flight). Annotate with `// rothunter:ignore-race` on a write line if the parallel writes are mathematically commutative (e.g. set union with no read).',
582
+ ].join('\n');
583
+ return {
584
+ detectorId: 'race-condition',
585
+ severity: 'medium',
586
+ confidence: 0.75,
587
+ layer: 1,
588
+ title,
589
+ description,
590
+ evidence: [
591
+ {
592
+ file: r.file,
593
+ range: { startLine: r.callLine, endLine: r.callEndLine },
594
+ snippet: r.enclosingSource,
595
+ note: JSON.stringify({
596
+ pattern: 'promise-all',
597
+ target: r.target,
598
+ callLine: r.callLine,
599
+ writeLines: r.writes.map((w) => w.line),
600
+ enclosingName: r.enclosingName ?? '',
601
+ }),
602
+ },
603
+ ],
604
+ suggestion: 'Move the mutating writes out of parallel arms (compute into local results, merge after `await Promise.all`), OR serialise the writes through a single arm, OR wrap with a mutex / atomic primitive.',
605
+ fingerprint: `race:promise-all:${stableHash(`${r.file}::${r.target}::${r.callLine}`)}`,
606
+ };
607
+ }
608
+ //# sourceMappingURL=race-condition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"race-condition.js","sourceRoot":"","sources":["../../src/detectors/race-condition.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 SharedDbWriteDetectorInput extends FileWalkingDetectorInput {
4
+ }
5
+ export declare function detectSharedDbWrites(input: SharedDbWriteDetectorInput): Finding[];
6
+ //# sourceMappingURL=shared-db-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-db-write.d.ts","sourceRoot":"","sources":["../../src/detectors/shared-db-write.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAE3E,MAAM,WAAW,0BAA2B,SAAQ,wBAAwB;CAAG;AAsB/E,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,0BAA0B,GAAG,OAAO,EAAE,CAiGjF"}