codesift-mcp 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (454) hide show
  1. package/README.md +5 -1
  2. package/dist/cli/commands-admin.d.ts +18 -0
  3. package/dist/cli/commands-admin.d.ts.map +1 -0
  4. package/dist/cli/commands-admin.js +187 -0
  5. package/dist/cli/commands-admin.js.map +1 -0
  6. package/dist/cli/commands-daemon.d.ts +42 -0
  7. package/dist/cli/commands-daemon.d.ts.map +1 -0
  8. package/dist/cli/commands-daemon.js +163 -0
  9. package/dist/cli/commands-daemon.js.map +1 -0
  10. package/dist/cli/commands-index.d.ts +12 -0
  11. package/dist/cli/commands-index.d.ts.map +1 -0
  12. package/dist/cli/commands-index.js +133 -0
  13. package/dist/cli/commands-index.js.map +1 -0
  14. package/dist/cli/commands-maintenance.d.ts +12 -0
  15. package/dist/cli/commands-maintenance.d.ts.map +1 -0
  16. package/dist/cli/commands-maintenance.js +409 -0
  17. package/dist/cli/commands-maintenance.js.map +1 -0
  18. package/dist/cli/commands-query.d.ts +21 -0
  19. package/dist/cli/commands-query.d.ts.map +1 -0
  20. package/dist/cli/commands-query.js +270 -0
  21. package/dist/cli/commands-query.js.map +1 -0
  22. package/dist/cli/commands.d.ts +2 -36
  23. package/dist/cli/commands.d.ts.map +1 -1
  24. package/dist/cli/commands.js +8 -867
  25. package/dist/cli/commands.js.map +1 -1
  26. package/dist/cli/embed-child.js +13 -2
  27. package/dist/cli/embed-child.js.map +1 -1
  28. package/dist/instructions.d.ts +1 -1
  29. package/dist/instructions.d.ts.map +1 -1
  30. package/dist/instructions.js +5 -2
  31. package/dist/instructions.js.map +1 -1
  32. package/dist/parser/extractors/php-class-metadata.d.ts +10 -0
  33. package/dist/parser/extractors/php-class-metadata.d.ts.map +1 -0
  34. package/dist/parser/extractors/php-class-metadata.js +65 -0
  35. package/dist/parser/extractors/php-class-metadata.js.map +1 -0
  36. package/dist/parser/extractors/php-doc.d.ts +13 -0
  37. package/dist/parser/extractors/php-doc.d.ts.map +1 -0
  38. package/dist/parser/extractors/php-doc.js +39 -0
  39. package/dist/parser/extractors/php-doc.js.map +1 -0
  40. package/dist/parser/extractors/php-node-metadata.d.ts +26 -0
  41. package/dist/parser/extractors/php-node-metadata.d.ts.map +1 -0
  42. package/dist/parser/extractors/php-node-metadata.js +132 -0
  43. package/dist/parser/extractors/php-node-metadata.js.map +1 -0
  44. package/dist/parser/extractors/php-symbol-builders.d.ts +13 -0
  45. package/dist/parser/extractors/php-symbol-builders.d.ts.map +1 -0
  46. package/dist/parser/extractors/php-symbol-builders.js +58 -0
  47. package/dist/parser/extractors/php-symbol-builders.js.map +1 -0
  48. package/dist/parser/extractors/php-walker.d.ts +4 -0
  49. package/dist/parser/extractors/php-walker.d.ts.map +1 -0
  50. package/dist/parser/extractors/php-walker.js +238 -0
  51. package/dist/parser/extractors/php-walker.js.map +1 -0
  52. package/dist/parser/extractors/php.d.ts +2 -33
  53. package/dist/parser/extractors/php.d.ts.map +1 -1
  54. package/dist/parser/extractors/php.js +2 -747
  55. package/dist/parser/extractors/php.js.map +1 -1
  56. package/dist/register-tool-loaders.d.ts +11 -11
  57. package/dist/register-tool-loaders.d.ts.map +1 -1
  58. package/dist/register-tools/runtime.d.ts +11 -0
  59. package/dist/register-tools/runtime.d.ts.map +1 -1
  60. package/dist/register-tools/runtime.js +40 -0
  61. package/dist/register-tools/runtime.js.map +1 -1
  62. package/dist/register-tools.d.ts.map +1 -1
  63. package/dist/register-tools.js +5 -1
  64. package/dist/register-tools.js.map +1 -1
  65. package/dist/retrieval/semantic-handlers.d.ts.map +1 -1
  66. package/dist/retrieval/semantic-handlers.js +10 -3
  67. package/dist/retrieval/semantic-handlers.js.map +1 -1
  68. package/dist/search/semantic.d.ts +2 -0
  69. package/dist/search/semantic.d.ts.map +1 -1
  70. package/dist/search/semantic.js +41 -9
  71. package/dist/search/semantic.js.map +1 -1
  72. package/dist/storage/chunk-store.d.ts +14 -2
  73. package/dist/storage/chunk-store.d.ts.map +1 -1
  74. package/dist/storage/chunk-store.js +214 -34
  75. package/dist/storage/chunk-store.js.map +1 -1
  76. package/dist/storage/embedding-store.d.ts +0 -12
  77. package/dist/storage/embedding-store.d.ts.map +1 -1
  78. package/dist/storage/embedding-store.js +69 -9
  79. package/dist/storage/embedding-store.js.map +1 -1
  80. package/dist/storage/index-cache.d.ts +12 -0
  81. package/dist/storage/index-cache.d.ts.map +1 -0
  82. package/dist/storage/index-cache.js +89 -0
  83. package/dist/storage/index-cache.js.map +1 -0
  84. package/dist/storage/index-json-mutations.d.ts +11 -0
  85. package/dist/storage/index-json-mutations.d.ts.map +1 -0
  86. package/dist/storage/index-json-mutations.js +93 -0
  87. package/dist/storage/index-json-mutations.js.map +1 -0
  88. package/dist/storage/index-migration.d.ts +22 -0
  89. package/dist/storage/index-migration.d.ts.map +1 -0
  90. package/dist/storage/index-migration.js +80 -0
  91. package/dist/storage/index-migration.js.map +1 -0
  92. package/dist/storage/index-store.d.ts +5 -61
  93. package/dist/storage/index-store.d.ts.map +1 -1
  94. package/dist/storage/index-store.js +33 -414
  95. package/dist/storage/index-store.js.map +1 -1
  96. package/dist/storage/index-version.d.ts +39 -0
  97. package/dist/storage/index-version.d.ts.map +1 -0
  98. package/dist/storage/index-version.js +87 -0
  99. package/dist/storage/index-version.js.map +1 -0
  100. package/dist/storage/registry.d.ts +9 -1
  101. package/dist/storage/registry.d.ts.map +1 -1
  102. package/dist/storage/registry.js +169 -8
  103. package/dist/storage/registry.js.map +1 -1
  104. package/dist/storage/shared-embedding-cache.d.ts +23 -3
  105. package/dist/storage/shared-embedding-cache.d.ts.map +1 -1
  106. package/dist/storage/shared-embedding-cache.js +300 -45
  107. package/dist/storage/shared-embedding-cache.js.map +1 -1
  108. package/dist/storage/telemetry/config.d.ts.map +1 -1
  109. package/dist/storage/telemetry/config.js +3 -2
  110. package/dist/storage/telemetry/config.js.map +1 -1
  111. package/dist/storage/telemetry/retro-aggregator.d.ts +21 -0
  112. package/dist/storage/telemetry/retro-aggregator.d.ts.map +1 -1
  113. package/dist/storage/telemetry/retro-aggregator.js +58 -16
  114. package/dist/storage/telemetry/retro-aggregator.js.map +1 -1
  115. package/dist/storage/telemetry/sanitizer.d.ts +16 -0
  116. package/dist/storage/telemetry/sanitizer.d.ts.map +1 -1
  117. package/dist/storage/telemetry/sanitizer.js +2 -0
  118. package/dist/storage/telemetry/sanitizer.js.map +1 -1
  119. package/dist/storage/telemetry/uploader.d.ts +3 -1
  120. package/dist/storage/telemetry/uploader.d.ts.map +1 -1
  121. package/dist/storage/telemetry/uploader.js +158 -21
  122. package/dist/storage/telemetry/uploader.js.map +1 -1
  123. package/dist/tools/cross-repo-contract-adapters.d.ts +39 -0
  124. package/dist/tools/cross-repo-contract-adapters.d.ts.map +1 -0
  125. package/dist/tools/cross-repo-contract-adapters.js +70 -0
  126. package/dist/tools/cross-repo-contract-adapters.js.map +1 -0
  127. package/dist/tools/cross-repo-contract-group.d.ts +17 -0
  128. package/dist/tools/cross-repo-contract-group.d.ts.map +1 -0
  129. package/dist/tools/cross-repo-contract-group.js +89 -0
  130. package/dist/tools/cross-repo-contract-group.js.map +1 -0
  131. package/dist/tools/cross-repo-contract-matcher.d.ts +24 -0
  132. package/dist/tools/cross-repo-contract-matcher.d.ts.map +1 -0
  133. package/dist/tools/cross-repo-contract-matcher.js +134 -0
  134. package/dist/tools/cross-repo-contract-matcher.js.map +1 -0
  135. package/dist/tools/cross-repo-contract-resolver.d.ts +9 -0
  136. package/dist/tools/cross-repo-contract-resolver.d.ts.map +1 -0
  137. package/dist/tools/cross-repo-contract-resolver.js +86 -0
  138. package/dist/tools/cross-repo-contract-resolver.js.map +1 -0
  139. package/dist/tools/cross-repo-contract-tools.d.ts +12 -135
  140. package/dist/tools/cross-repo-contract-tools.d.ts.map +1 -1
  141. package/dist/tools/cross-repo-contract-tools.js +8 -589
  142. package/dist/tools/cross-repo-contract-tools.js.map +1 -1
  143. package/dist/tools/cross-repo-contract-types.d.ts +30 -0
  144. package/dist/tools/cross-repo-contract-types.d.ts.map +1 -0
  145. package/dist/tools/cross-repo-contract-types.js +3 -0
  146. package/dist/tools/cross-repo-contract-types.js.map +1 -0
  147. package/dist/tools/cross-repo-outbound-calls.d.ts +28 -0
  148. package/dist/tools/cross-repo-outbound-calls.d.ts.map +1 -0
  149. package/dist/tools/cross-repo-outbound-calls.js +347 -0
  150. package/dist/tools/cross-repo-outbound-calls.js.map +1 -0
  151. package/dist/tools/cross-repo-outbound-lexer/call-detectors.d.ts.map +1 -1
  152. package/dist/tools/cross-repo-outbound-lexer/call-detectors.js +2 -0
  153. package/dist/tools/cross-repo-outbound-lexer/call-detectors.js.map +1 -1
  154. package/dist/tools/cross-repo-outbound-lexer/types.d.ts +2 -0
  155. package/dist/tools/cross-repo-outbound-lexer/types.d.ts.map +1 -1
  156. package/dist/tools/index-tools/file-indexer.js +3 -3
  157. package/dist/tools/index-tools/file-indexer.js.map +1 -1
  158. package/dist/tools/index-tools/folder-indexer.d.ts.map +1 -1
  159. package/dist/tools/index-tools/folder-indexer.js +47 -2
  160. package/dist/tools/index-tools/folder-indexer.js.map +1 -1
  161. package/dist/tools/index-tools/parse.d.ts +12 -3
  162. package/dist/tools/index-tools/parse.d.ts.map +1 -1
  163. package/dist/tools/index-tools/parse.js +33 -8
  164. package/dist/tools/index-tools/parse.js.map +1 -1
  165. package/dist/tools/index-tools/registry.d.ts +19 -0
  166. package/dist/tools/index-tools/registry.d.ts.map +1 -1
  167. package/dist/tools/index-tools/registry.js +88 -2
  168. package/dist/tools/index-tools/registry.js.map +1 -1
  169. package/dist/tools/index-tools/state.d.ts +31 -0
  170. package/dist/tools/index-tools/state.d.ts.map +1 -1
  171. package/dist/tools/index-tools/state.js +53 -0
  172. package/dist/tools/index-tools/state.js.map +1 -1
  173. package/dist/tools/index-tools/types.d.ts +9 -0
  174. package/dist/tools/index-tools/types.d.ts.map +1 -1
  175. package/dist/tools/index-tools/watcher.js +3 -3
  176. package/dist/tools/index-tools/watcher.js.map +1 -1
  177. package/dist/tools/index-tools/worktree-seed.d.ts +44 -0
  178. package/dist/tools/index-tools/worktree-seed.d.ts.map +1 -0
  179. package/dist/tools/index-tools/worktree-seed.js +302 -0
  180. package/dist/tools/index-tools/worktree-seed.js.map +1 -0
  181. package/dist/tools/index-tools.d.ts.map +1 -1
  182. package/dist/tools/index-tools.js +3 -1
  183. package/dist/tools/index-tools.js.map +1 -1
  184. package/dist/tools/nest-ext-tools/graphql.d.ts +17 -0
  185. package/dist/tools/nest-ext-tools/graphql.d.ts.map +1 -0
  186. package/dist/tools/nest-ext-tools/graphql.js +54 -0
  187. package/dist/tools/nest-ext-tools/graphql.js.map +1 -0
  188. package/dist/tools/nest-ext-tools/microservice.d.ts +17 -0
  189. package/dist/tools/nest-ext-tools/microservice.d.ts.map +1 -0
  190. package/dist/tools/nest-ext-tools/microservice.js +51 -0
  191. package/dist/tools/nest-ext-tools/microservice.js.map +1 -0
  192. package/dist/tools/nest-ext-tools/openapi.d.ts +81 -0
  193. package/dist/tools/nest-ext-tools/openapi.d.ts.map +1 -0
  194. package/dist/tools/nest-ext-tools/openapi.js +254 -0
  195. package/dist/tools/nest-ext-tools/openapi.js.map +1 -0
  196. package/dist/tools/nest-ext-tools/queue.d.ts +27 -0
  197. package/dist/tools/nest-ext-tools/queue.d.ts.map +1 -0
  198. package/dist/tools/nest-ext-tools/queue.js +95 -0
  199. package/dist/tools/nest-ext-tools/queue.js.map +1 -0
  200. package/dist/tools/nest-ext-tools/schedule.d.ts +19 -0
  201. package/dist/tools/nest-ext-tools/schedule.d.ts.map +1 -0
  202. package/dist/tools/nest-ext-tools/schedule.js +89 -0
  203. package/dist/tools/nest-ext-tools/schedule.js.map +1 -0
  204. package/dist/tools/nest-ext-tools/scope.d.ts +19 -0
  205. package/dist/tools/nest-ext-tools/scope.d.ts.map +1 -0
  206. package/dist/tools/nest-ext-tools/scope.js +151 -0
  207. package/dist/tools/nest-ext-tools/scope.js.map +1 -0
  208. package/dist/tools/nest-ext-tools/shared.d.ts +33 -0
  209. package/dist/tools/nest-ext-tools/shared.d.ts.map +1 -0
  210. package/dist/tools/nest-ext-tools/shared.js +279 -0
  211. package/dist/tools/nest-ext-tools/shared.js.map +1 -0
  212. package/dist/tools/nest-ext-tools/typeorm.d.ts +22 -0
  213. package/dist/tools/nest-ext-tools/typeorm.d.ts.map +1 -0
  214. package/dist/tools/nest-ext-tools/typeorm.js +59 -0
  215. package/dist/tools/nest-ext-tools/typeorm.js.map +1 -0
  216. package/dist/tools/nest-ext-tools/websocket.d.ts +21 -0
  217. package/dist/tools/nest-ext-tools/websocket.d.ts.map +1 -0
  218. package/dist/tools/nest-ext-tools/websocket.js +70 -0
  219. package/dist/tools/nest-ext-tools/websocket.js.map +1 -0
  220. package/dist/tools/nest-ext-tools.d.ts +10 -204
  221. package/dist/tools/nest-ext-tools.d.ts.map +1 -1
  222. package/dist/tools/nest-ext-tools.js +10 -749
  223. package/dist/tools/nest-ext-tools.js.map +1 -1
  224. package/dist/tools/perf-tools.js +2 -2
  225. package/dist/tools/python-audit/checks/dead-code.d.ts +1 -1
  226. package/dist/tools/python-audit/checks/dead-code.d.ts.map +1 -1
  227. package/dist/tools/python-constants/constant-match.d.ts +5 -0
  228. package/dist/tools/python-constants/constant-match.d.ts.map +1 -0
  229. package/dist/tools/python-constants/constant-match.js +24 -0
  230. package/dist/tools/python-constants/constant-match.js.map +1 -0
  231. package/dist/tools/python-constants/file-context.d.ts +5 -0
  232. package/dist/tools/python-constants/file-context.d.ts.map +1 -0
  233. package/dist/tools/python-constants/file-context.js +91 -0
  234. package/dist/tools/python-constants/file-context.js.map +1 -0
  235. package/dist/tools/python-constants/function-defaults.d.ts +5 -0
  236. package/dist/tools/python-constants/function-defaults.d.ts.map +1 -0
  237. package/dist/tools/python-constants/function-defaults.js +98 -0
  238. package/dist/tools/python-constants/function-defaults.js.map +1 -0
  239. package/dist/tools/python-constants/model.d.ts +78 -0
  240. package/dist/tools/python-constants/model.d.ts.map +1 -0
  241. package/dist/tools/python-constants/model.js +2 -0
  242. package/dist/tools/python-constants/model.js.map +1 -0
  243. package/dist/tools/python-constants/syntax.d.ts +22 -0
  244. package/dist/tools/python-constants/syntax.d.ts.map +1 -0
  245. package/dist/tools/python-constants/syntax.js +93 -0
  246. package/dist/tools/python-constants/syntax.js.map +1 -0
  247. package/dist/tools/python-constants/value-resolver.d.ts +6 -0
  248. package/dist/tools/python-constants/value-resolver.d.ts.map +1 -0
  249. package/dist/tools/python-constants/value-resolver.js +320 -0
  250. package/dist/tools/python-constants/value-resolver.js.map +1 -0
  251. package/dist/tools/python-constants-tools.d.ts +3 -45
  252. package/dist/tools/python-constants-tools.d.ts.map +1 -1
  253. package/dist/tools/python-constants-tools.js +2 -505
  254. package/dist/tools/python-constants-tools.js.map +1 -1
  255. package/dist/tools/route-tools/django.d.ts +8 -0
  256. package/dist/tools/route-tools/django.d.ts.map +1 -0
  257. package/dist/tools/route-tools/django.js +52 -0
  258. package/dist/tools/route-tools/django.js.map +1 -0
  259. package/dist/tools/route-tools/express.d.ts +5 -0
  260. package/dist/tools/route-tools/express.d.ts.map +1 -0
  261. package/dist/tools/route-tools/express.js +33 -0
  262. package/dist/tools/route-tools/express.js.map +1 -0
  263. package/dist/tools/route-tools/file-sources.d.ts +7 -0
  264. package/dist/tools/route-tools/file-sources.d.ts.map +1 -0
  265. package/dist/tools/route-tools/file-sources.js +15 -0
  266. package/dist/tools/route-tools/file-sources.js.map +1 -0
  267. package/dist/tools/route-tools/handler-discovery.d.ts +4 -0
  268. package/dist/tools/route-tools/handler-discovery.d.ts.map +1 -0
  269. package/dist/tools/route-tools/handler-discovery.js +38 -0
  270. package/dist/tools/route-tools/handler-discovery.js.map +1 -0
  271. package/dist/tools/route-tools/hono.d.ts +5 -0
  272. package/dist/tools/route-tools/hono.d.ts.map +1 -0
  273. package/dist/tools/route-tools/hono.js +61 -0
  274. package/dist/tools/route-tools/hono.js.map +1 -0
  275. package/dist/tools/route-tools/ktor.d.ts +5 -0
  276. package/dist/tools/route-tools/ktor.d.ts.map +1 -0
  277. package/dist/tools/route-tools/ktor.js +76 -0
  278. package/dist/tools/route-tools/ktor.js.map +1 -0
  279. package/dist/tools/route-tools/laravel.d.ts +5 -0
  280. package/dist/tools/route-tools/laravel.d.ts.map +1 -0
  281. package/dist/tools/route-tools/laravel.js +45 -0
  282. package/dist/tools/route-tools/laravel.js.map +1 -0
  283. package/dist/tools/route-tools/mermaid-call-chain.d.ts +3 -0
  284. package/dist/tools/route-tools/mermaid-call-chain.d.ts.map +1 -0
  285. package/dist/tools/route-tools/mermaid-call-chain.js +50 -0
  286. package/dist/tools/route-tools/mermaid-call-chain.js.map +1 -0
  287. package/dist/tools/route-tools/nest.d.ts +5 -0
  288. package/dist/tools/route-tools/nest.d.ts.map +1 -0
  289. package/dist/tools/route-tools/nest.js +75 -0
  290. package/dist/tools/route-tools/nest.js.map +1 -0
  291. package/dist/tools/route-tools/next-trace.d.ts +4 -0
  292. package/dist/tools/route-tools/next-trace.d.ts.map +1 -0
  293. package/dist/tools/route-tools/next-trace.js +48 -0
  294. package/dist/tools/route-tools/next-trace.js.map +1 -0
  295. package/dist/tools/route-tools/next.d.ts +7 -0
  296. package/dist/tools/route-tools/next.d.ts.map +1 -0
  297. package/dist/tools/route-tools/next.js +77 -0
  298. package/dist/tools/route-tools/next.js.map +1 -0
  299. package/dist/tools/route-tools/python-decorators.d.ts +7 -0
  300. package/dist/tools/route-tools/python-decorators.d.ts.map +1 -0
  301. package/dist/tools/route-tools/python-decorators.js +53 -0
  302. package/dist/tools/route-tools/python-decorators.js.map +1 -0
  303. package/dist/tools/route-tools/route-mermaid.d.ts +4 -0
  304. package/dist/tools/route-tools/route-mermaid.d.ts.map +1 -0
  305. package/dist/tools/route-tools/route-mermaid.js +53 -0
  306. package/dist/tools/route-tools/route-mermaid.js.map +1 -0
  307. package/dist/tools/route-tools/spring-kotlin.d.ts +5 -0
  308. package/dist/tools/route-tools/spring-kotlin.d.ts.map +1 -0
  309. package/dist/tools/route-tools/spring-kotlin.js +52 -0
  310. package/dist/tools/route-tools/spring-kotlin.js.map +1 -0
  311. package/dist/tools/route-tools/trace-analysis.d.ts +4 -0
  312. package/dist/tools/route-tools/trace-analysis.d.ts.map +1 -0
  313. package/dist/tools/route-tools/trace-analysis.js +37 -0
  314. package/dist/tools/route-tools/trace-analysis.js.map +1 -0
  315. package/dist/tools/route-tools/trace-route.d.ts +6 -0
  316. package/dist/tools/route-tools/trace-route.d.ts.map +1 -0
  317. package/dist/tools/route-tools/trace-route.js +53 -0
  318. package/dist/tools/route-tools/trace-route.js.map +1 -0
  319. package/dist/tools/route-tools/types.d.ts +35 -0
  320. package/dist/tools/route-tools/types.d.ts.map +1 -0
  321. package/dist/tools/route-tools/types.js +2 -0
  322. package/dist/tools/route-tools/types.js.map +1 -0
  323. package/dist/tools/route-tools/yii2.d.ts +5 -0
  324. package/dist/tools/route-tools/yii2.d.ts.map +1 -0
  325. package/dist/tools/route-tools/yii2.js +73 -0
  326. package/dist/tools/route-tools/yii2.js.map +1 -0
  327. package/dist/tools/route-tools.d.ts +7 -49
  328. package/dist/tools/route-tools.d.ts.map +1 -1
  329. package/dist/tools/route-tools.js +5 -978
  330. package/dist/tools/route-tools.js.map +1 -1
  331. package/dist/tools/symbol-analysis-tools.d.ts +81 -0
  332. package/dist/tools/symbol-analysis-tools.d.ts.map +1 -0
  333. package/dist/tools/symbol-analysis-tools.js +327 -0
  334. package/dist/tools/symbol-analysis-tools.js.map +1 -0
  335. package/dist/tools/symbol-context-tools.d.ts +68 -0
  336. package/dist/tools/symbol-context-tools.d.ts.map +1 -0
  337. package/dist/tools/symbol-context-tools.js +232 -0
  338. package/dist/tools/symbol-context-tools.js.map +1 -0
  339. package/dist/tools/symbol-lookup-tools.d.ts +77 -0
  340. package/dist/tools/symbol-lookup-tools.d.ts.map +1 -0
  341. package/dist/tools/symbol-lookup-tools.js +305 -0
  342. package/dist/tools/symbol-lookup-tools.js.map +1 -0
  343. package/dist/tools/symbol-reference-tools.d.ts +38 -0
  344. package/dist/tools/symbol-reference-tools.d.ts.map +1 -0
  345. package/dist/tools/symbol-reference-tools.js +253 -0
  346. package/dist/tools/symbol-reference-tools.js.map +1 -0
  347. package/dist/tools/symbol-tool-internals.d.ts +9 -0
  348. package/dist/tools/symbol-tool-internals.d.ts.map +1 -0
  349. package/dist/tools/symbol-tool-internals.js +47 -0
  350. package/dist/tools/symbol-tool-internals.js.map +1 -0
  351. package/dist/tools/symbol-tools.d.ts +11 -270
  352. package/dist/tools/symbol-tools.d.ts.map +1 -1
  353. package/dist/tools/symbol-tools.js +7 -1131
  354. package/dist/tools/symbol-tools.js.map +1 -1
  355. package/dist/tools/taint/python-context.d.ts +10 -0
  356. package/dist/tools/taint/python-context.d.ts.map +1 -0
  357. package/dist/tools/taint/python-context.js +150 -0
  358. package/dist/tools/taint/python-context.js.map +1 -0
  359. package/dist/tools/taint/taint-analyzer.d.ts +2 -0
  360. package/dist/tools/taint/taint-analyzer.d.ts.map +1 -0
  361. package/dist/tools/taint/taint-analyzer.js +2 -0
  362. package/dist/tools/taint/taint-analyzer.js.map +1 -0
  363. package/dist/tools/taint/taint-expression.d.ts +18 -0
  364. package/dist/tools/taint/taint-expression.d.ts.map +1 -0
  365. package/dist/tools/taint/taint-expression.js +265 -0
  366. package/dist/tools/taint/taint-expression.js.map +1 -0
  367. package/dist/tools/taint/taint-flow.d.ts +10 -0
  368. package/dist/tools/taint/taint-flow.d.ts.map +1 -0
  369. package/dist/tools/taint/taint-flow.js +178 -0
  370. package/dist/tools/taint/taint-flow.js.map +1 -0
  371. package/dist/tools/taint/taint-model.d.ts +113 -0
  372. package/dist/tools/taint/taint-model.d.ts.map +1 -0
  373. package/dist/tools/taint/taint-model.js +277 -0
  374. package/dist/tools/taint/taint-model.js.map +1 -0
  375. package/dist/tools/taint-tools.d.ts +2 -34
  376. package/dist/tools/taint-tools.d.ts.map +1 -1
  377. package/dist/tools/taint-tools.js +2 -852
  378. package/dist/tools/taint-tools.js.map +1 -1
  379. package/dist/tools/typescript-constants/file-context.d.ts +7 -0
  380. package/dist/tools/typescript-constants/file-context.d.ts.map +1 -0
  381. package/dist/tools/typescript-constants/file-context.js +219 -0
  382. package/dist/tools/typescript-constants/file-context.js.map +1 -0
  383. package/dist/tools/typescript-constants/symbol-resolver.d.ts +7 -0
  384. package/dist/tools/typescript-constants/symbol-resolver.d.ts.map +1 -0
  385. package/dist/tools/typescript-constants/symbol-resolver.js +165 -0
  386. package/dist/tools/typescript-constants/symbol-resolver.js.map +1 -0
  387. package/dist/tools/typescript-constants/types.d.ts +44 -0
  388. package/dist/tools/typescript-constants/types.d.ts.map +1 -0
  389. package/dist/tools/typescript-constants/types.js +2 -0
  390. package/dist/tools/typescript-constants/types.js.map +1 -0
  391. package/dist/tools/typescript-constants/value-evaluator.d.ts +8 -0
  392. package/dist/tools/typescript-constants/value-evaluator.d.ts.map +1 -0
  393. package/dist/tools/typescript-constants/value-evaluator.js +404 -0
  394. package/dist/tools/typescript-constants/value-evaluator.js.map +1 -0
  395. package/dist/tools/typescript-constants-tools.d.ts.map +1 -1
  396. package/dist/tools/typescript-constants-tools.js +19 -709
  397. package/dist/tools/typescript-constants-tools.js.map +1 -1
  398. package/dist/utils/import-graph/collect.d.ts +5 -0
  399. package/dist/utils/import-graph/collect.d.ts.map +1 -0
  400. package/dist/utils/import-graph/collect.js +47 -0
  401. package/dist/utils/import-graph/collect.js.map +1 -0
  402. package/dist/utils/import-graph/edge-accumulator.d.ts +7 -0
  403. package/dist/utils/import-graph/edge-accumulator.d.ts.map +1 -0
  404. package/dist/utils/import-graph/edge-accumulator.js +47 -0
  405. package/dist/utils/import-graph/edge-accumulator.js.map +1 -0
  406. package/dist/utils/import-graph/language-imports.d.ts +6 -0
  407. package/dist/utils/import-graph/language-imports.d.ts.map +1 -0
  408. package/dist/utils/import-graph/language-imports.js +84 -0
  409. package/dist/utils/import-graph/language-imports.js.map +1 -0
  410. package/dist/utils/import-graph/metrics.d.ts +6 -0
  411. package/dist/utils/import-graph/metrics.d.ts.map +1 -0
  412. package/dist/utils/import-graph/metrics.js +51 -0
  413. package/dist/utils/import-graph/metrics.js.map +1 -0
  414. package/dist/utils/import-graph/path-map.d.ts +7 -0
  415. package/dist/utils/import-graph/path-map.d.ts.map +1 -0
  416. package/dist/utils/import-graph/path-map.js +56 -0
  417. package/dist/utils/import-graph/path-map.js.map +1 -0
  418. package/dist/utils/import-graph/python-php-edge-collectors.d.ts +5 -0
  419. package/dist/utils/import-graph/python-php-edge-collectors.d.ts.map +1 -0
  420. package/dist/utils/import-graph/python-php-edge-collectors.js +56 -0
  421. package/dist/utils/import-graph/python-php-edge-collectors.js.map +1 -0
  422. package/dist/utils/import-graph/source-edge-collector.d.ts +13 -0
  423. package/dist/utils/import-graph/source-edge-collector.d.ts.map +1 -0
  424. package/dist/utils/import-graph/source-edge-collector.js +42 -0
  425. package/dist/utils/import-graph/source-edge-collector.js.map +1 -0
  426. package/dist/utils/import-graph/source-imports.d.ts +5 -0
  427. package/dist/utils/import-graph/source-imports.d.ts.map +1 -0
  428. package/dist/utils/import-graph/source-imports.js +33 -0
  429. package/dist/utils/import-graph/source-imports.js.map +1 -0
  430. package/dist/utils/import-graph/types.d.ts +15 -0
  431. package/dist/utils/import-graph/types.d.ts.map +1 -0
  432. package/dist/utils/import-graph/types.js +2 -0
  433. package/dist/utils/import-graph/types.js.map +1 -0
  434. package/dist/utils/import-graph/typescript-edge-collector.d.ts +7 -0
  435. package/dist/utils/import-graph/typescript-edge-collector.d.ts.map +1 -0
  436. package/dist/utils/import-graph/typescript-edge-collector.js +58 -0
  437. package/dist/utils/import-graph/typescript-edge-collector.js.map +1 -0
  438. package/dist/utils/import-graph/workspace-alias.d.ts +7 -0
  439. package/dist/utils/import-graph/workspace-alias.d.ts.map +1 -0
  440. package/dist/utils/import-graph/workspace-alias.js +95 -0
  441. package/dist/utils/import-graph/workspace-alias.js.map +1 -0
  442. package/dist/utils/import-graph/workspace-entry.d.ts +3 -0
  443. package/dist/utils/import-graph/workspace-entry.d.ts.map +1 -0
  444. package/dist/utils/import-graph/workspace-entry.js +81 -0
  445. package/dist/utils/import-graph/workspace-entry.js.map +1 -0
  446. package/dist/utils/import-graph.d.ts +10 -94
  447. package/dist/utils/import-graph.d.ts.map +1 -1
  448. package/dist/utils/import-graph.js +6 -702
  449. package/dist/utils/import-graph.js.map +1 -1
  450. package/package.json +1 -1
  451. package/rules/codesift.md +11 -2
  452. package/rules/codesift.mdc +11 -2
  453. package/rules/codex.md +11 -2
  454. package/rules/gemini.md +11 -2
@@ -1,857 +1,7 @@
1
- import { readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
1
  import { getParser } from "../parser/parser-manager.js";
4
- import { detectSrcLayout, resolvePythonImport } from "../utils/python-import-resolver.js";
5
2
  import { getCodeIndex } from "./index-tools.js";
6
- const DEFAULT_MAX_DEPTH = 4;
7
- const DEFAULT_MAX_TRACES = 50;
8
- const DEFAULT_SOURCE_PATTERNS = [
9
- "request.GET",
10
- "request.POST",
11
- "request.body",
12
- "request.data",
13
- "request.headers",
14
- "request.COOKIES",
15
- "request.META",
16
- ];
17
- const DEFAULT_SINK_PATTERNS = [
18
- "redirect",
19
- "mark_safe",
20
- "cursor.execute",
21
- "subprocess",
22
- "requests",
23
- "httpx",
24
- "open",
25
- "session-write",
26
- ];
27
- const KNOWN_SANITIZERS = new Set([
28
- "escape",
29
- "conditional_escape",
30
- "urlquote",
31
- "quote",
32
- "quote_plus",
33
- ]);
34
- function clonePath(path) {
35
- return {
36
- source: { ...path.source },
37
- hops: path.hops.map((hop) => ({ ...hop })),
38
- heuristic: path.heuristic,
39
- };
40
- }
41
- function pathKey(path) {
42
- return JSON.stringify({
43
- source: path.source,
44
- hops: path.hops,
45
- heuristic: path.heuristic,
46
- });
47
- }
48
- function dedupePaths(paths) {
49
- const seen = new Set();
50
- const result = [];
51
- for (const path of paths) {
52
- const key = pathKey(path);
53
- if (seen.has(key))
54
- continue;
55
- seen.add(key);
56
- result.push(path);
57
- }
58
- return result;
59
- }
60
- function cloneEnv(env) {
61
- const next = new Map();
62
- for (const [name, paths] of env.entries()) {
63
- next.set(name, paths.map(clonePath));
64
- }
65
- return next;
66
- }
67
- function mergeEnvs(...envs) {
68
- const merged = new Map();
69
- for (const env of envs) {
70
- for (const [name, paths] of env.entries()) {
71
- const existing = merged.get(name) ?? [];
72
- merged.set(name, dedupePaths([...existing, ...paths.map(clonePath)]));
73
- }
74
- }
75
- return merged;
76
- }
77
- function appendHop(paths, hop, options) {
78
- return dedupePaths(paths.map((path) => ({
79
- source: { ...path.source },
80
- hops: [...path.hops.map((entry) => ({ ...entry })), { ...hop }],
81
- heuristic: path.heuristic || Boolean(options?.heuristic),
82
- })));
83
- }
84
- function computeConfidence(path) {
85
- if (path.heuristic)
86
- return "medium";
87
- if (path.hops.length >= 4)
88
- return "medium";
89
- return "high";
90
- }
91
- function lineForNode(symbol, node) {
92
- return symbol.start_line + node.startPosition.row;
93
- }
94
- function codeForNode(node) {
95
- return node.text.split("\n")[0]?.trim() ?? node.text.trim();
96
- }
97
- function getAttributePath(node) {
98
- if (!node)
99
- return null;
100
- if (node.type === "identifier")
101
- return node.text;
102
- if (node.type === "attribute") {
103
- const objectNode = node.childForFieldName("object") ?? node.namedChild(0);
104
- const attributeNode = node.childForFieldName("attribute") ?? node.namedChild(1);
105
- const objectPath = getAttributePath(objectNode);
106
- const attributePath = getAttributePath(attributeNode);
107
- if (!objectPath || !attributePath)
108
- return null;
109
- return `${objectPath}.${attributePath}`;
110
- }
111
- return null;
112
- }
113
- function getCallArguments(argsNode) {
114
- if (!argsNode)
115
- return [];
116
- const args = [];
117
- let index = 0;
118
- for (const child of argsNode.namedChildren) {
119
- if (child.type === "keyword_argument") {
120
- const keywordNode = child.namedChildren[0];
121
- const valueNode = child.namedChildren[1];
122
- if (!valueNode)
123
- continue;
124
- const arg = {
125
- node: valueNode,
126
- index,
127
- };
128
- if (keywordNode?.text)
129
- arg.keyword = keywordNode.text;
130
- args.push(arg);
131
- index += 1;
132
- continue;
133
- }
134
- args.push({
135
- node: child,
136
- index,
137
- });
138
- index += 1;
139
- }
140
- return args;
141
- }
142
- function getParameterName(node) {
143
- switch (node.type) {
144
- case "identifier":
145
- return node.text;
146
- case "default_parameter":
147
- case "typed_parameter":
148
- case "typed_default_parameter":
149
- case "list_splat_pattern":
150
- case "dictionary_splat_pattern":
151
- return node.namedChildren[0]?.text ?? null;
152
- default:
153
- return null;
154
- }
155
- }
156
- function findFunctionNode(node) {
157
- if (node.type === "function_definition" || node.type === "async_function_definition") {
158
- return node;
159
- }
160
- for (const child of node.namedChildren) {
161
- const found = findFunctionNode(child);
162
- if (found)
163
- return found;
164
- }
165
- return null;
166
- }
167
- function createSourcePath(sourceKind, symbol, node) {
168
- return {
169
- source: {
170
- kind: sourceKind,
171
- label: node.text,
172
- file: symbol.file,
173
- line: lineForNode(symbol, node),
174
- symbol_name: symbol.name,
175
- code: codeForNode(node),
176
- },
177
- hops: [],
178
- heuristic: false,
179
- };
180
- }
181
- function identifierPaths(env, name) {
182
- return (env.get(name) ?? []).map(clonePath);
183
- }
184
- function isAllowedPattern(allowed, kind, label) {
185
- if (allowed.length === 0)
186
- return true;
187
- return allowed.some((pattern) => pattern === kind
188
- || label === pattern
189
- || label.includes(pattern)
190
- || kind.includes(pattern));
191
- }
192
- function buildSinkDescriptors() {
193
- return [
194
- {
195
- kind: "redirect",
196
- matches: (calleeText) => calleeText === "redirect"
197
- || calleeText.endsWith(".redirect")
198
- || calleeText === "HttpResponseRedirect"
199
- || calleeText === "HttpResponsePermanentRedirect",
200
- pickArgs: (args) => args[0] ? [args[0]] : [],
201
- },
202
- {
203
- kind: "mark_safe",
204
- matches: (calleeText) => calleeText === "mark_safe" || calleeText.endsWith(".mark_safe"),
205
- pickArgs: (args) => args[0] ? [args[0]] : [],
206
- },
207
- {
208
- kind: "cursor.execute",
209
- matches: (calleeText) => calleeText === "cursor.execute" || calleeText.endsWith(".execute"),
210
- pickArgs: (args) => args[0] ? [args[0]] : [],
211
- },
212
- {
213
- kind: "subprocess",
214
- matches: (calleeText) => calleeText.startsWith("subprocess.")
215
- || calleeText.endsWith(".Popen")
216
- || calleeText.endsWith(".run")
217
- || calleeText.endsWith(".call")
218
- || calleeText.endsWith(".check_call")
219
- || calleeText.endsWith(".check_output"),
220
- pickArgs: (args) => args[0] ? [args[0]] : [],
221
- },
222
- {
223
- kind: "requests",
224
- matches: (calleeText) => calleeText.startsWith("requests.")
225
- || calleeText.includes(".requests.")
226
- || calleeText.startsWith("httpx.")
227
- || calleeText.includes(".httpx."),
228
- pickArgs: (args) => {
229
- if (args.length === 0)
230
- return [];
231
- const urlKeyword = args.find((arg) => arg.keyword === "url");
232
- if (urlKeyword)
233
- return [urlKeyword];
234
- return args[1] ? [args[1]] : [args[0]];
235
- },
236
- },
237
- {
238
- kind: "httpx",
239
- matches: (calleeText) => calleeText.startsWith("httpx.")
240
- || calleeText.includes(".httpx."),
241
- pickArgs: (args) => {
242
- if (args.length === 0)
243
- return [];
244
- const urlKeyword = args.find((arg) => arg.keyword === "url");
245
- if (urlKeyword)
246
- return [urlKeyword];
247
- return args[1] ? [args[1]] : [args[0]];
248
- },
249
- },
250
- {
251
- kind: "open",
252
- matches: (calleeText) => calleeText === "open" || calleeText.endsWith(".open"),
253
- pickArgs: (args) => args[0] ? [args[0]] : [],
254
- },
255
- ];
256
- }
257
- function getImportModule(node) {
258
- const moduleNode = node.childForFieldName("module_name");
259
- if (!moduleNode)
260
- return { module: "", level: 0 };
261
- if (moduleNode.type === "relative_import") {
262
- let level = 0;
263
- for (let i = 0; i < moduleNode.childCount; i++) {
264
- const child = moduleNode.child(i);
265
- if (!child)
266
- continue;
267
- if (child.type === "import_prefix") {
268
- level += (child.text.match(/\./g) ?? []).length;
269
- }
270
- else if (child.type === ".") {
271
- level += 1;
272
- }
273
- }
274
- const dotted = moduleNode.namedChildren.find((child) => child.type === "dotted_name");
275
- return { module: dotted?.text ?? "", level };
276
- }
277
- return { module: moduleNode.text, level: 0 };
278
- }
279
- async function loadFileContext(state, filePath) {
280
- const cached = state.fileContextCache.get(filePath);
281
- if (cached !== undefined)
282
- return cached;
283
- let source;
284
- try {
285
- source = await readFile(join(state.index.root, filePath), "utf-8");
286
- }
287
- catch {
288
- state.fileContextCache.set(filePath, null);
289
- return null;
290
- }
291
- const tree = state.pythonParser.parse(source);
292
- if (!tree)
293
- return null;
294
- const files = state.index.files.map((entry) => entry.path);
295
- const srcLayout = detectSrcLayout(files);
296
- const imports = new Map();
297
- for (const node of tree.rootNode.namedChildren) {
298
- if (node.type !== "import_from_statement")
299
- continue;
300
- const { module, level } = getImportModule(node);
301
- const resolvedFile = resolvePythonImport({ module, level }, filePath, files, srcLayout);
302
- if (!resolvedFile)
303
- continue;
304
- for (const child of node.namedChildren) {
305
- if (child.type === "aliased_import") {
306
- const importedNode = child.namedChildren[0];
307
- const aliasNode = child.namedChildren[1];
308
- if (importedNode && aliasNode) {
309
- imports.set(aliasNode.text, {
310
- imported_name: importedNode.text,
311
- source_file: resolvedFile,
312
- line: node.startPosition.row + 1,
313
- });
314
- }
315
- continue;
316
- }
317
- if (child.type === "dotted_name") {
318
- const importedName = child.text;
319
- const localName = importedName.split(".").pop() ?? importedName;
320
- imports.set(localName, {
321
- imported_name: importedName,
322
- source_file: resolvedFile,
323
- line: node.startPosition.row + 1,
324
- });
325
- }
326
- }
327
- }
328
- const context = { imports };
329
- state.fileContextCache.set(filePath, context);
330
- return context;
331
- }
332
- function hasPotentialSource(symbol) {
333
- return symbol.source?.includes("request.") ?? false;
334
- }
335
- function hasPotentialSink(symbol) {
336
- const source = symbol.source ?? "";
337
- return source.includes("mark_safe")
338
- || source.includes("redirect(")
339
- || source.includes(".execute(")
340
- || source.includes("subprocess.")
341
- || source.includes("requests.")
342
- || source.includes("httpx.")
343
- || source.includes("open(")
344
- || source.includes("request.session");
345
- }
346
- async function loadCallableContext(symbol, state) {
347
- const cached = state.callableCache.get(symbol.id);
348
- if (cached !== undefined)
349
- return cached;
350
- if (!symbol.source) {
351
- state.callableCache.set(symbol.id, null);
352
- return null;
353
- }
354
- const tree = state.pythonParser.parse(symbol.source);
355
- if (!tree)
356
- return null;
357
- const functionNode = findFunctionNode(tree.rootNode);
358
- if (!functionNode) {
359
- state.callableCache.set(symbol.id, null);
360
- return null;
361
- }
362
- const paramsNode = functionNode.childForFieldName("parameters");
363
- const parameterNames = paramsNode
364
- ? paramsNode.namedChildren
365
- .map(getParameterName)
366
- .filter((name) => Boolean(name))
367
- : [];
368
- const context = {
369
- node: functionNode,
370
- parameter_names: parameterNames,
371
- };
372
- state.callableCache.set(symbol.id, context);
373
- return context;
374
- }
375
- function resolveSelfMethod(currentSymbol, propertyName, state) {
376
- if (!currentSymbol.parent)
377
- return null;
378
- const methods = state.methodsByParent.get(currentSymbol.parent) ?? [];
379
- return methods.find((symbol) => symbol.name === propertyName) ?? null;
380
- }
381
- async function resolveHelperTarget(currentSymbol, calleeNode, state) {
382
- const calleeText = getAttributePath(calleeNode) ?? calleeNode.text;
383
- if (calleeNode.type === "identifier") {
384
- const sameFile = (state.symbolsByName.get(calleeText) ?? [])
385
- .filter((symbol) => symbol.file === currentSymbol.file
386
- && symbol.id !== currentSymbol.id
387
- && (symbol.kind === "function" || symbol.kind === "class" || symbol.kind === "method"));
388
- if (sameFile.length === 1)
389
- return sameFile[0];
390
- const fileContext = await loadFileContext(state, currentSymbol.file);
391
- const imported = fileContext?.imports.get(calleeText);
392
- if (imported) {
393
- const importedMatch = (state.symbolsByName.get(imported.imported_name) ?? [])
394
- .find((symbol) => symbol.file === imported.source_file);
395
- if (importedMatch)
396
- return importedMatch;
397
- }
398
- const unique = (state.symbolsByName.get(calleeText) ?? [])
399
- .filter((symbol) => symbol.file.endsWith(".py") && symbol.id !== currentSymbol.id)
400
- .filter((symbol) => symbol.kind === "function" || symbol.kind === "method" || symbol.kind === "class");
401
- if (unique.length === 1)
402
- return unique[0];
403
- return null;
404
- }
405
- if (calleeNode.type === "attribute") {
406
- const objectNode = calleeNode.childForFieldName("object") ?? calleeNode.namedChild(0);
407
- const propertyNode = calleeNode.childForFieldName("attribute") ?? calleeNode.namedChild(1);
408
- const objectName = getAttributePath(objectNode);
409
- const propertyName = propertyNode?.text;
410
- if ((objectName === "self" || objectName === "cls") && propertyName) {
411
- return resolveSelfMethod(currentSymbol, propertyName, state);
412
- }
413
- const importedModule = objectName ? (await loadFileContext(state, currentSymbol.file))?.imports.get(objectName) : null;
414
- if (importedModule && propertyName) {
415
- const candidates = state.symbolsByName.get(propertyName) ?? [];
416
- const importedMatch = candidates.find((symbol) => symbol.file === importedModule.source_file);
417
- if (importedMatch)
418
- return importedMatch;
419
- }
420
- }
421
- return null;
422
- }
423
- function matchesRequestSource(attributePath) {
424
- if (!attributePath)
425
- return null;
426
- if (attributePath === "request.GET" || attributePath.startsWith("request.GET."))
427
- return "request.GET";
428
- if (attributePath === "request.POST" || attributePath.startsWith("request.POST."))
429
- return "request.POST";
430
- if (attributePath === "request.body")
431
- return "request.body";
432
- if (attributePath === "request.data" || attributePath.startsWith("request.data."))
433
- return "request.data";
434
- if (attributePath === "request.headers" || attributePath.startsWith("request.headers."))
435
- return "request.headers";
436
- if (attributePath === "request.COOKIES" || attributePath.startsWith("request.COOKIES."))
437
- return "request.COOKIES";
438
- if (attributePath === "request.META" || attributePath.startsWith("request.META."))
439
- return "request.META";
440
- return null;
441
- }
442
- function isSessionTarget(node) {
443
- if (node.type === "attribute") {
444
- const path = getAttributePath(node);
445
- return path === "request.session";
446
- }
447
- if (node.type === "subscript") {
448
- const base = node.childForFieldName("value") ?? node.namedChild(0);
449
- return getAttributePath(base) === "request.session";
450
- }
451
- return false;
452
- }
453
- function sinkTraceKey(trace) {
454
- return JSON.stringify({
455
- entry_symbol: trace.entry_symbol,
456
- entry_file: trace.entry_file,
457
- source: trace.source,
458
- sink: trace.sink,
459
- hops: trace.hops,
460
- heuristic: trace.heuristic,
461
- });
462
- }
463
- function addTrace(state, entrySymbol, currentSymbol, sinkKind, sinkNode, paths) {
464
- if (state.truncated)
465
- return;
466
- for (const path of paths) {
467
- if (state.traces.length >= state.maxTraces) {
468
- state.truncated = true;
469
- return;
470
- }
471
- const trace = {
472
- entry_symbol: entrySymbol.name,
473
- entry_file: entrySymbol.file,
474
- source: { ...path.source },
475
- sink: {
476
- kind: sinkKind,
477
- label: sinkNode.text,
478
- file: currentSymbol.file,
479
- line: lineForNode(currentSymbol, sinkNode),
480
- symbol_name: currentSymbol.name,
481
- code: codeForNode(sinkNode),
482
- },
483
- hops: path.hops.map((hop) => ({ ...hop })),
484
- confidence: computeConfidence(path),
485
- heuristic: path.heuristic,
486
- };
487
- const key = sinkTraceKey(trace);
488
- if (state.traceKeys.has(key))
489
- continue;
490
- state.traceKeys.add(key);
491
- state.traces.push(trace);
492
- }
493
- }
494
- async function evaluateExpression(node, symbol, env, state, context) {
495
- switch (node.type) {
496
- case "identifier":
497
- return identifierPaths(env, node.text);
498
- case "attribute": {
499
- const sourceKind = matchesRequestSource(getAttributePath(node));
500
- if (sourceKind)
501
- return [createSourcePath(sourceKind, symbol, node)];
502
- const objectNode = node.childForFieldName("object") ?? node.namedChild(0);
503
- if (!objectNode)
504
- return [];
505
- const basePaths = await evaluateExpression(objectNode, symbol, env, state, context);
506
- if (basePaths.length === 0)
507
- return [];
508
- return appendHop(basePaths, {
509
- kind: "attribute",
510
- file: symbol.file,
511
- line: lineForNode(symbol, node),
512
- symbol_name: symbol.name,
513
- detail: `attribute access ${node.text}`,
514
- });
515
- }
516
- case "subscript": {
517
- const baseNode = node.childForFieldName("value") ?? node.namedChild(0);
518
- const sourceKind = matchesRequestSource(getAttributePath(baseNode));
519
- if (sourceKind)
520
- return [createSourcePath(sourceKind, symbol, node)];
521
- const basePaths = baseNode
522
- ? await evaluateExpression(baseNode, symbol, env, state, context)
523
- : [];
524
- if (basePaths.length === 0)
525
- return [];
526
- return appendHop(basePaths, {
527
- kind: "container",
528
- file: symbol.file,
529
- line: lineForNode(symbol, node),
530
- symbol_name: symbol.name,
531
- detail: `container access ${node.text}`,
532
- });
533
- }
534
- case "string": {
535
- const interpolated = node.namedChildren
536
- .filter((child) => child.type === "interpolation")
537
- .flatMap((child) => child.namedChildren);
538
- if (interpolated.length === 0)
539
- return [];
540
- const paths = [];
541
- for (const child of interpolated) {
542
- paths.push(...await evaluateExpression(child, symbol, env, state, context));
543
- }
544
- if (paths.length === 0)
545
- return [];
546
- return appendHop(paths, {
547
- kind: "container",
548
- file: symbol.file,
549
- line: lineForNode(symbol, node),
550
- symbol_name: symbol.name,
551
- detail: `formatted string ${node.text}`,
552
- });
553
- }
554
- case "list":
555
- case "tuple":
556
- case "dictionary":
557
- case "set": {
558
- const paths = [];
559
- for (const child of node.namedChildren) {
560
- if (child.type === "pair") {
561
- const valueNode = child.namedChildren[1];
562
- if (!valueNode)
563
- continue;
564
- paths.push(...await evaluateExpression(valueNode, symbol, env, state, context));
565
- }
566
- else {
567
- paths.push(...await evaluateExpression(child, symbol, env, state, context));
568
- }
569
- }
570
- if (paths.length === 0)
571
- return [];
572
- return appendHop(paths, {
573
- kind: "container",
574
- file: symbol.file,
575
- line: lineForNode(symbol, node),
576
- symbol_name: symbol.name,
577
- detail: `container literal ${node.text}`,
578
- });
579
- }
580
- case "binary_operator":
581
- case "boolean_operator":
582
- case "comparison_operator": {
583
- const paths = [];
584
- for (const child of node.namedChildren) {
585
- paths.push(...await evaluateExpression(child, symbol, env, state, context));
586
- }
587
- return dedupePaths(paths);
588
- }
589
- case "parenthesized_expression":
590
- return node.namedChildren[0]
591
- ? await evaluateExpression(node.namedChildren[0], symbol, env, state, context)
592
- : [];
593
- case "conditional_expression": {
594
- const paths = [];
595
- for (const child of node.namedChildren) {
596
- paths.push(...await evaluateExpression(child, symbol, env, state, context));
597
- }
598
- return dedupePaths(paths);
599
- }
600
- case "call": {
601
- const calleeNode = node.childForFieldName("function") ?? node.namedChild(0);
602
- const argsNode = node.childForFieldName("arguments") ?? node.namedChild(1);
603
- const callArgs = getCallArguments(argsNode);
604
- const calleeText = getAttributePath(calleeNode) ?? calleeNode?.text ?? "";
605
- const sourceKind = matchesRequestSource(calleeText);
606
- if (sourceKind && calleeText.endsWith(".get")) {
607
- return [createSourcePath(sourceKind, symbol, node)];
608
- }
609
- const evaluatedArgs = await Promise.all(callArgs.map(async (arg) => ({
610
- arg,
611
- paths: await evaluateExpression(arg.node, symbol, env, state, context),
612
- })));
613
- for (const descriptor of state.sinkDescriptors) {
614
- if (!descriptor.matches(calleeText))
615
- continue;
616
- if (!isAllowedPattern(state.defaultSinks, descriptor.kind, calleeText))
617
- continue;
618
- const selectedArgs = descriptor.pickArgs(callArgs);
619
- const taintedArgs = selectedArgs.flatMap((selected) => evaluatedArgs
620
- .filter((entry) => entry.arg.index === selected.index)
621
- .flatMap((entry) => entry.paths));
622
- if (taintedArgs.length > 0) {
623
- addTrace(state, context.entrySymbol, symbol, descriptor.kind, node, dedupePaths(taintedArgs));
624
- }
625
- }
626
- const calleeLeaf = calleeText.split(".").pop() ?? calleeText;
627
- if (KNOWN_SANITIZERS.has(calleeLeaf))
628
- return [];
629
- const taintedInputs = evaluatedArgs
630
- .filter((entry) => entry.paths.length > 0)
631
- .map((entry) => entry);
632
- if (taintedInputs.length === 0)
633
- return [];
634
- const helperTarget = calleeNode
635
- ? await resolveHelperTarget(symbol, calleeNode, state)
636
- : null;
637
- if (helperTarget && context.depth < state.maxDepth && !context.callStack.includes(helperTarget.id)) {
638
- const helperContext = await loadCallableContext(helperTarget, state);
639
- if (helperContext) {
640
- const helperEnv = new Map();
641
- for (const entry of taintedInputs) {
642
- const paramName = helperContext.parameter_names[entry.arg.index];
643
- if (!paramName)
644
- continue;
645
- helperEnv.set(paramName, appendHop(entry.paths, {
646
- kind: "call",
647
- file: symbol.file,
648
- line: lineForNode(symbol, node),
649
- symbol_name: symbol.name,
650
- detail: `call ${calleeText} -> parameter ${paramName}`,
651
- }));
652
- }
653
- const helperResult = await analyzeCallableSymbol(helperTarget, helperEnv, state, {
654
- entrySymbol: context.entrySymbol,
655
- depth: context.depth + 1,
656
- callStack: [...context.callStack, helperTarget.id],
657
- });
658
- if (helperResult.return_paths.length > 0) {
659
- return appendHop(helperResult.return_paths, {
660
- kind: "call",
661
- file: symbol.file,
662
- line: lineForNode(symbol, node),
663
- symbol_name: symbol.name,
664
- detail: `return from ${calleeText}`,
665
- });
666
- }
667
- return [];
668
- }
669
- }
670
- return appendHop(taintedInputs.flatMap((entry) => entry.paths), {
671
- kind: "call",
672
- file: symbol.file,
673
- line: lineForNode(symbol, node),
674
- symbol_name: symbol.name,
675
- detail: `heuristic propagation through ${calleeText}`,
676
- }, { heuristic: true });
677
- }
678
- default:
679
- return [];
680
- }
681
- }
682
- async function analyzeAssignment(assignmentNode, symbol, env, state, context) {
683
- const lhs = assignmentNode.childForFieldName("left") ?? assignmentNode.namedChild(0);
684
- const rhs = assignmentNode.childForFieldName("right") ?? assignmentNode.namedChild(1);
685
- const nextEnv = cloneEnv(env);
686
- if (!lhs || !rhs)
687
- return nextEnv;
688
- const rhsPaths = await evaluateExpression(rhs, symbol, env, state, context);
689
- if (rhsPaths.length === 0)
690
- return nextEnv;
691
- if (lhs.type === "identifier") {
692
- nextEnv.set(lhs.text, appendHop(rhsPaths, {
693
- kind: "assignment",
694
- file: symbol.file,
695
- line: lineForNode(symbol, assignmentNode),
696
- symbol_name: symbol.name,
697
- detail: `${lhs.text} = ${rhs.text}`,
698
- }));
699
- return nextEnv;
700
- }
701
- if (isSessionTarget(lhs) && isAllowedPattern(state.defaultSinks, "session-write", lhs.text)) {
702
- addTrace(state, context.entrySymbol, symbol, "session-write", assignmentNode, rhsPaths);
703
- }
704
- return nextEnv;
705
- }
706
- async function analyzeConditionalLike(node, symbol, env, state, context) {
707
- const conditionNodes = node.namedChildren.filter((child) => child.type !== "block" && child.type !== "else_clause" && child.type !== "elif_clause");
708
- for (const condition of conditionNodes) {
709
- await evaluateExpression(condition, symbol, env, state, context);
710
- }
711
- const branchResults = [];
712
- let hasElseLike = false;
713
- for (const child of node.namedChildren) {
714
- if (child.type === "block") {
715
- branchResults.push(await analyzeBlock(child, symbol, cloneEnv(env), state, context));
716
- continue;
717
- }
718
- if (child.type === "elif_clause") {
719
- hasElseLike = true;
720
- branchResults.push(await analyzeConditionalLike(child, symbol, cloneEnv(env), state, context));
721
- continue;
722
- }
723
- if (child.type === "else_clause") {
724
- hasElseLike = true;
725
- const elseBlock = child.namedChildren.find((grandchild) => grandchild.type === "block");
726
- if (elseBlock)
727
- branchResults.push(await analyzeBlock(elseBlock, symbol, cloneEnv(env), state, context));
728
- }
729
- }
730
- const baseEnvs = hasElseLike ? [] : [env];
731
- return {
732
- env: mergeEnvs(...baseEnvs, ...branchResults.map((entry) => entry.env)),
733
- return_paths: dedupePaths(branchResults.flatMap((entry) => entry.return_paths)),
734
- };
735
- }
736
- async function analyzeLoopLike(node, symbol, env, state, context) {
737
- for (const child of node.namedChildren) {
738
- if (child.type === "block")
739
- continue;
740
- await evaluateExpression(child, symbol, env, state, context);
741
- }
742
- const blockResults = [];
743
- for (const child of node.namedChildren) {
744
- if (child.type !== "block")
745
- continue;
746
- blockResults.push(await analyzeBlock(child, symbol, cloneEnv(env), state, context));
747
- }
748
- return {
749
- env: mergeEnvs(env, ...blockResults.map((entry) => entry.env)),
750
- return_paths: dedupePaths(blockResults.flatMap((entry) => entry.return_paths)),
751
- };
752
- }
753
- async function analyzeStatement(node, symbol, env, state, context) {
754
- switch (node.type) {
755
- case "expression_statement": {
756
- const inner = node.namedChildren[0];
757
- if (!inner)
758
- return { env, return_paths: [] };
759
- if (inner.type === "assignment") {
760
- return {
761
- env: await analyzeAssignment(inner, symbol, env, state, context),
762
- return_paths: [],
763
- };
764
- }
765
- await evaluateExpression(inner, symbol, env, state, context);
766
- return { env, return_paths: [] };
767
- }
768
- case "return_statement": {
769
- const valueNode = node.namedChildren[0];
770
- if (!valueNode)
771
- return { env, return_paths: [] };
772
- const valuePaths = await evaluateExpression(valueNode, symbol, env, state, context);
773
- if (valuePaths.length === 0)
774
- return { env, return_paths: [] };
775
- return {
776
- env,
777
- return_paths: appendHop(valuePaths, {
778
- kind: "return",
779
- file: symbol.file,
780
- line: lineForNode(symbol, node),
781
- symbol_name: symbol.name,
782
- detail: `return ${valueNode.text}`,
783
- }),
784
- };
785
- }
786
- case "if_statement":
787
- case "elif_clause":
788
- return await analyzeConditionalLike(node, symbol, env, state, context);
789
- case "for_statement":
790
- case "while_statement":
791
- case "with_statement":
792
- case "try_statement":
793
- return await analyzeLoopLike(node, symbol, env, state, context);
794
- case "pass_statement":
795
- case "break_statement":
796
- case "continue_statement":
797
- return { env, return_paths: [] };
798
- case "function_definition":
799
- case "async_function_definition":
800
- case "class_definition":
801
- case "decorated_definition":
802
- return { env, return_paths: [] };
803
- default: {
804
- for (const child of node.namedChildren) {
805
- if (child.type === "block") {
806
- await analyzeBlock(child, symbol, cloneEnv(env), state, context);
807
- }
808
- else {
809
- await evaluateExpression(child, symbol, env, state, context);
810
- }
811
- }
812
- return { env, return_paths: [] };
813
- }
814
- }
815
- }
816
- async function analyzeBlock(blockNode, symbol, env, state, context) {
817
- let currentEnv = cloneEnv(env);
818
- let returnPaths = [];
819
- for (const child of blockNode.namedChildren) {
820
- if (state.truncated)
821
- break;
822
- const result = await analyzeStatement(child, symbol, currentEnv, state, context);
823
- currentEnv = result.env;
824
- if (result.return_paths.length > 0) {
825
- returnPaths = dedupePaths([...returnPaths, ...result.return_paths]);
826
- }
827
- }
828
- return {
829
- env: currentEnv,
830
- return_paths: returnPaths,
831
- };
832
- }
833
- async function analyzeCallableSymbol(symbol, initialEnv, state, context) {
834
- const callableContext = await loadCallableContext(symbol, state);
835
- if (!callableContext) {
836
- return { env: initialEnv, return_paths: [] };
837
- }
838
- const bodyNode = callableContext.node.childForFieldName("body");
839
- if (!bodyNode) {
840
- return { env: initialEnv, return_paths: [] };
841
- }
842
- return await analyzeBlock(bodyNode, symbol, initialEnv, state, context);
843
- }
844
- function shouldAnalyzeSymbol(symbol, filePattern) {
845
- if (!symbol.file.endsWith(".py"))
846
- return false;
847
- if (filePattern && !symbol.file.includes(filePattern))
848
- return false;
849
- if (!symbol.source)
850
- return false;
851
- if (symbol.kind !== "function" && symbol.kind !== "method")
852
- return false;
853
- return hasPotentialSource(symbol) || hasPotentialSink(symbol);
854
- }
3
+ import { DEFAULT_MAX_DEPTH, DEFAULT_MAX_TRACES, DEFAULT_SINK_PATTERNS, DEFAULT_SOURCE_PATTERNS, buildSinkDescriptors, isAllowedPattern, } from "./taint/taint-model.js";
4
+ import { analyzeCallableSymbol, shouldAnalyzeSymbol, } from "./taint/taint-analyzer.js";
855
5
  function buildState(index, pythonParser, options) {
856
6
  const symbolsByName = new Map();
857
7
  const methodsByParent = new Map();