kirograph 0.16.1 → 0.19.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 (365) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +103 -1605
  3. package/dist/architecture/layers/dart.js +112 -0
  4. package/dist/architecture/layers/dart.js.map +7 -0
  5. package/dist/architecture/layers/index.js +3 -1
  6. package/dist/architecture/layers/index.js.map +2 -2
  7. package/dist/bin/banner.js +74 -6
  8. package/dist/bin/banner.js.map +2 -2
  9. package/dist/bin/commands/affected.js +40 -5
  10. package/dist/bin/commands/affected.js.map +2 -2
  11. package/dist/bin/commands/attack-surface.js +157 -0
  12. package/dist/bin/commands/attack-surface.js.map +7 -0
  13. package/dist/bin/commands/benchmark.js +206 -0
  14. package/dist/bin/commands/benchmark.js.map +7 -0
  15. package/dist/bin/commands/budget.js +70 -0
  16. package/dist/bin/commands/budget.js.map +7 -0
  17. package/dist/bin/commands/communities.js +77 -0
  18. package/dist/bin/commands/communities.js.map +7 -0
  19. package/dist/bin/commands/data.js +665 -0
  20. package/dist/bin/commands/data.js.map +7 -0
  21. package/dist/bin/commands/dep-confusion.js +119 -0
  22. package/dist/bin/commands/dep-confusion.js.map +7 -0
  23. package/dist/bin/commands/export.js +304 -10
  24. package/dist/bin/commands/export.js.map +2 -2
  25. package/dist/bin/commands/flows.js +97 -0
  26. package/dist/bin/commands/flows.js.map +7 -0
  27. package/dist/bin/commands/help.js +386 -100
  28. package/dist/bin/commands/help.js.map +2 -2
  29. package/dist/bin/commands/install.js +90 -8
  30. package/dist/bin/commands/install.js.map +2 -2
  31. package/dist/bin/commands/licenses.js +201 -0
  32. package/dist/bin/commands/licenses.js.map +7 -0
  33. package/dist/bin/commands/reachability.js +160 -0
  34. package/dist/bin/commands/reachability.js.map +7 -0
  35. package/dist/bin/commands/read.js +100 -0
  36. package/dist/bin/commands/read.js.map +7 -0
  37. package/dist/bin/commands/refactor.js +116 -0
  38. package/dist/bin/commands/refactor.js.map +7 -0
  39. package/dist/bin/commands/remediation.js +133 -0
  40. package/dist/bin/commands/remediation.js.map +7 -0
  41. package/dist/bin/commands/sbom.js +76 -0
  42. package/dist/bin/commands/sbom.js.map +7 -0
  43. package/dist/bin/commands/security-ci-report.js +267 -0
  44. package/dist/bin/commands/security-ci-report.js.map +7 -0
  45. package/dist/bin/commands/security-export.js +1349 -0
  46. package/dist/bin/commands/security-export.js.map +7 -0
  47. package/dist/bin/commands/security-flows.js +126 -0
  48. package/dist/bin/commands/security-flows.js.map +7 -0
  49. package/dist/bin/commands/security-secrets.js +170 -0
  50. package/dist/bin/commands/security-secrets.js.map +7 -0
  51. package/dist/bin/commands/security.js +193 -0
  52. package/dist/bin/commands/security.js.map +7 -0
  53. package/dist/bin/commands/staleness.js +144 -0
  54. package/dist/bin/commands/staleness.js.map +7 -0
  55. package/dist/bin/commands/status.js +102 -2
  56. package/dist/bin/commands/status.js.map +2 -2
  57. package/dist/bin/commands/supply-chain.js +138 -0
  58. package/dist/bin/commands/supply-chain.js.map +7 -0
  59. package/dist/bin/commands/uninit.js +109 -60
  60. package/dist/bin/commands/uninit.js.map +2 -2
  61. package/dist/bin/commands/vex.js +76 -0
  62. package/dist/bin/commands/vex.js.map +7 -0
  63. package/dist/bin/commands/vuln-suppress.js +95 -0
  64. package/dist/bin/commands/vuln-suppress.js.map +7 -0
  65. package/dist/bin/commands/vulns.js +382 -0
  66. package/dist/bin/commands/vulns.js.map +7 -0
  67. package/dist/bin/installer/auto-detect.js +125 -0
  68. package/dist/bin/installer/auto-detect.js.map +7 -0
  69. package/dist/bin/installer/cli-agent.js +28 -5
  70. package/dist/bin/installer/cli-agent.js.map +2 -2
  71. package/dist/bin/installer/common.js +47 -0
  72. package/dist/bin/installer/common.js.map +2 -2
  73. package/dist/bin/installer/config-prompt.js +39 -1
  74. package/dist/bin/installer/config-prompt.js.map +2 -2
  75. package/dist/bin/installer/detect.js +309 -0
  76. package/dist/bin/installer/detect.js.map +7 -0
  77. package/dist/bin/installer/index.js +36 -1
  78. package/dist/bin/installer/index.js.map +2 -2
  79. package/dist/bin/installer/instructions.js +195 -3
  80. package/dist/bin/installer/instructions.js.map +2 -2
  81. package/dist/bin/installer/steering.js +440 -0
  82. package/dist/bin/installer/steering.js.map +2 -2
  83. package/dist/bin/installer/targets/aider.js +3 -3
  84. package/dist/bin/installer/targets/aider.js.map +2 -2
  85. package/dist/bin/installer/targets/amp.js +3 -3
  86. package/dist/bin/installer/targets/amp.js.map +2 -2
  87. package/dist/bin/installer/targets/antigravity.js +35 -6
  88. package/dist/bin/installer/targets/antigravity.js.map +2 -2
  89. package/dist/bin/installer/targets/augment.js +3 -3
  90. package/dist/bin/installer/targets/augment.js.map +2 -2
  91. package/dist/bin/installer/targets/claude.js +49 -5
  92. package/dist/bin/installer/targets/claude.js.map +2 -2
  93. package/dist/bin/installer/targets/cline.js +32 -6
  94. package/dist/bin/installer/targets/cline.js.map +2 -2
  95. package/dist/bin/installer/targets/codex.js +64 -12
  96. package/dist/bin/installer/targets/codex.js.map +2 -2
  97. package/dist/bin/installer/targets/continue.js +2 -2
  98. package/dist/bin/installer/targets/continue.js.map +2 -2
  99. package/dist/bin/installer/targets/copilot-cli.js +101 -0
  100. package/dist/bin/installer/targets/copilot-cli.js.map +7 -0
  101. package/dist/bin/installer/targets/copilot.js +31 -5
  102. package/dist/bin/installer/targets/copilot.js.map +2 -2
  103. package/dist/bin/installer/targets/cursor.js +4 -4
  104. package/dist/bin/installer/targets/cursor.js.map +2 -2
  105. package/dist/bin/installer/targets/devin.js +2 -2
  106. package/dist/bin/installer/targets/devin.js.map +2 -2
  107. package/dist/bin/installer/targets/gemini-cli.js +2 -2
  108. package/dist/bin/installer/targets/gemini-cli.js.map +2 -2
  109. package/dist/bin/installer/targets/generic.js +2 -14
  110. package/dist/bin/installer/targets/generic.js.map +2 -2
  111. package/dist/bin/installer/targets/goose.js +3 -3
  112. package/dist/bin/installer/targets/goose.js.map +2 -2
  113. package/dist/bin/installer/targets/index.js +250 -0
  114. package/dist/bin/installer/targets/index.js.map +2 -2
  115. package/dist/bin/installer/targets/junie.js +2 -2
  116. package/dist/bin/installer/targets/junie.js.map +2 -2
  117. package/dist/bin/installer/targets/kilo.js +2 -2
  118. package/dist/bin/installer/targets/kilo.js.map +2 -2
  119. package/dist/bin/installer/targets/kiro.js +3 -3
  120. package/dist/bin/installer/targets/kiro.js.map +2 -2
  121. package/dist/bin/installer/targets/opencode.js +2 -2
  122. package/dist/bin/installer/targets/opencode.js.map +2 -2
  123. package/dist/bin/installer/targets/openhands.js +3 -3
  124. package/dist/bin/installer/targets/openhands.js.map +2 -2
  125. package/dist/bin/installer/targets/qoder.js +91 -0
  126. package/dist/bin/installer/targets/qoder.js.map +7 -0
  127. package/dist/bin/installer/targets/qwen.js +96 -0
  128. package/dist/bin/installer/targets/qwen.js.map +7 -0
  129. package/dist/bin/installer/targets/replit.js +3 -3
  130. package/dist/bin/installer/targets/replit.js.map +2 -2
  131. package/dist/bin/installer/targets/roo.js +2 -2
  132. package/dist/bin/installer/targets/roo.js.map +2 -2
  133. package/dist/bin/installer/targets/tabnine.js +3 -3
  134. package/dist/bin/installer/targets/tabnine.js.map +2 -2
  135. package/dist/bin/installer/targets/trae.js +5 -5
  136. package/dist/bin/installer/targets/trae.js.map +2 -2
  137. package/dist/bin/installer/targets/warp.js +2 -2
  138. package/dist/bin/installer/targets/warp.js.map +2 -2
  139. package/dist/bin/installer/targets/windsurf.js +35 -6
  140. package/dist/bin/installer/targets/windsurf.js.map +2 -2
  141. package/dist/bin/kirograph.js +74 -6
  142. package/dist/bin/kirograph.js.map +3 -3
  143. package/dist/bin/progress.js +30 -0
  144. package/dist/bin/progress.js.map +2 -2
  145. package/dist/compression/naive-cost.js +25 -0
  146. package/dist/compression/naive-cost.js.map +2 -2
  147. package/dist/compression/tracker.js +91 -2
  148. package/dist/compression/tracker.js.map +2 -2
  149. package/dist/compression/types.js.map +1 -1
  150. package/dist/config.js +126 -3
  151. package/dist/config.js.map +2 -2
  152. package/dist/core/pipeline.js +92 -4
  153. package/dist/core/pipeline.js.map +2 -2
  154. package/dist/data/filters.js +105 -0
  155. package/dist/data/filters.js.map +7 -0
  156. package/dist/data/indexer.js +225 -0
  157. package/dist/data/indexer.js.map +7 -0
  158. package/dist/data/linker.js +150 -0
  159. package/dist/data/linker.js.map +7 -0
  160. package/dist/data/lint.js +109 -0
  161. package/dist/data/lint.js.map +7 -0
  162. package/dist/data/parsers/csv.js +132 -0
  163. package/dist/data/parsers/csv.js.map +7 -0
  164. package/dist/data/parsers/excel.js +88 -0
  165. package/dist/data/parsers/excel.js.map +7 -0
  166. package/dist/data/parsers/index.js +79 -0
  167. package/dist/data/parsers/index.js.map +7 -0
  168. package/dist/data/parsers/json-array.js +89 -0
  169. package/dist/data/parsers/json-array.js.map +7 -0
  170. package/dist/data/parsers/jsonl.js +84 -0
  171. package/dist/data/parsers/jsonl.js.map +7 -0
  172. package/dist/data/parsers/parquet.js +95 -0
  173. package/dist/data/parsers/parquet.js.map +7 -0
  174. package/dist/data/profiler.js +182 -0
  175. package/dist/data/profiler.js.map +7 -0
  176. package/dist/data/queries.js +512 -0
  177. package/dist/data/queries.js.map +7 -0
  178. package/dist/data/types.js +17 -0
  179. package/dist/data/types.js.map +7 -0
  180. package/dist/db/data-schema.sql +61 -0
  181. package/dist/db/database.js +67 -5
  182. package/dist/db/database.js.map +2 -2
  183. package/dist/db/memory-schema.sql +5 -1
  184. package/dist/db/schema.sql +3 -1
  185. package/dist/db/security-schema.sql +72 -0
  186. package/dist/extraction/extractor.js +81 -0
  187. package/dist/extraction/extractor.js.map +2 -2
  188. package/dist/extraction/grammars.js +32 -8
  189. package/dist/extraction/grammars.js.map +2 -2
  190. package/dist/extraction/languages.js +43 -1
  191. package/dist/extraction/languages.js.map +2 -2
  192. package/dist/extraction/notebook.js +300 -0
  193. package/dist/extraction/notebook.js.map +7 -0
  194. package/dist/extraction/wasm/tree-sitter-astro.wasm +0 -0
  195. package/dist/extraction/wasm/tree-sitter-gdscript.wasm +0 -0
  196. package/dist/extraction/wasm/tree-sitter-julia.wasm +0 -0
  197. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  198. package/dist/extraction/wasm/tree-sitter-perl.wasm +0 -0
  199. package/dist/extraction/wasm/tree-sitter-powershell.wasm +0 -0
  200. package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
  201. package/dist/extraction/wasm/tree-sitter-sql.wasm +0 -0
  202. package/dist/extraction/wasm/tree-sitter-verilog.wasm +0 -0
  203. package/dist/frameworks/flutter.js +130 -0
  204. package/dist/frameworks/flutter.js.map +7 -0
  205. package/dist/frameworks/index.js +7 -1
  206. package/dist/frameworks/index.js.map +3 -3
  207. package/dist/graph/communities.js +317 -0
  208. package/dist/graph/communities.js.map +7 -0
  209. package/dist/graph/flows.js +138 -0
  210. package/dist/graph/flows.js.map +7 -0
  211. package/dist/graph/refactor.js +155 -0
  212. package/dist/graph/refactor.js.map +7 -0
  213. package/dist/index.js +1 -1
  214. package/dist/index.js.map +2 -2
  215. package/dist/mcp/cache.js +172 -0
  216. package/dist/mcp/cache.js.map +7 -0
  217. package/dist/mcp/read-modes.js +295 -0
  218. package/dist/mcp/read-modes.js.map +7 -0
  219. package/dist/mcp/server.js +2 -1
  220. package/dist/mcp/server.js.map +2 -2
  221. package/dist/mcp/tool-names.js +29 -1
  222. package/dist/mcp/tool-names.js.map +2 -2
  223. package/dist/mcp/tools.js +1588 -6
  224. package/dist/mcp/tools.js.map +3 -3
  225. package/dist/memory/database.js +32 -2
  226. package/dist/memory/database.js.map +2 -2
  227. package/dist/memory/types.js.map +1 -1
  228. package/dist/resolution/bridges/android-rn.js +298 -0
  229. package/dist/resolution/bridges/android-rn.js.map +7 -0
  230. package/dist/resolution/bridges/expo-modules.js +155 -0
  231. package/dist/resolution/bridges/expo-modules.js.map +7 -0
  232. package/dist/resolution/bridges/flutter-channel.js +385 -0
  233. package/dist/resolution/bridges/flutter-channel.js.map +7 -0
  234. package/dist/resolution/bridges/index.js +80 -0
  235. package/dist/resolution/bridges/index.js.map +7 -0
  236. package/dist/resolution/bridges/native-events.js +188 -0
  237. package/dist/resolution/bridges/native-events.js.map +7 -0
  238. package/dist/resolution/bridges/native-views.js +244 -0
  239. package/dist/resolution/bridges/native-views.js.map +7 -0
  240. package/dist/resolution/bridges/react-native.js +161 -0
  241. package/dist/resolution/bridges/react-native.js.map +7 -0
  242. package/dist/resolution/bridges/swift-objc.js +227 -0
  243. package/dist/resolution/bridges/swift-objc.js.map +7 -0
  244. package/dist/resolution/bridges/turbomodules.js +216 -0
  245. package/dist/resolution/bridges/turbomodules.js.map +7 -0
  246. package/dist/resolution/index.js +61 -2
  247. package/dist/resolution/index.js.map +2 -2
  248. package/dist/security/attack-surface.js +164 -0
  249. package/dist/security/attack-surface.js.map +7 -0
  250. package/dist/security/context-warnings.js +123 -0
  251. package/dist/security/context-warnings.js.map +7 -0
  252. package/dist/security/context-warnings.test.js +300 -0
  253. package/dist/security/context-warnings.test.js.map +7 -0
  254. package/dist/security/data-flows.js +228 -0
  255. package/dist/security/data-flows.js.map +7 -0
  256. package/dist/security/dep-confusion.js +255 -0
  257. package/dist/security/dep-confusion.js.map +7 -0
  258. package/dist/security/errors.js +51 -0
  259. package/dist/security/errors.js.map +7 -0
  260. package/dist/security/export/fix-suggestions.js +58 -0
  261. package/dist/security/export/fix-suggestions.js.map +7 -0
  262. package/dist/security/export/fix-suggestions.test.js +74 -0
  263. package/dist/security/export/fix-suggestions.test.js.map +7 -0
  264. package/dist/security/export/sbom.js +230 -0
  265. package/dist/security/export/sbom.js.map +7 -0
  266. package/dist/security/export/sbom.test.js +288 -0
  267. package/dist/security/export/sbom.test.js.map +7 -0
  268. package/dist/security/export/serialization.js +142 -0
  269. package/dist/security/export/serialization.js.map +7 -0
  270. package/dist/security/export/serialization.test.js +310 -0
  271. package/dist/security/export/serialization.test.js.map +7 -0
  272. package/dist/security/export/vex.js +220 -0
  273. package/dist/security/export/vex.js.map +7 -0
  274. package/dist/security/export/vex.test.js +278 -0
  275. package/dist/security/export/vex.test.js.map +7 -0
  276. package/dist/security/index.js +67 -0
  277. package/dist/security/index.js.map +7 -0
  278. package/dist/security/integrator-transitives.test.js +359 -0
  279. package/dist/security/integrator-transitives.test.js.map +7 -0
  280. package/dist/security/integrator.js +491 -0
  281. package/dist/security/integrator.js.map +7 -0
  282. package/dist/security/integrator.test.js +237 -0
  283. package/dist/security/integrator.test.js.map +7 -0
  284. package/dist/security/license.js +70 -0
  285. package/dist/security/license.js.map +7 -0
  286. package/dist/security/manifest/adapter.js +243 -0
  287. package/dist/security/manifest/adapter.js.map +7 -0
  288. package/dist/security/manifest/adapter.test.js +272 -0
  289. package/dist/security/manifest/adapter.test.js.map +7 -0
  290. package/dist/security/manifest/parser.js +376 -0
  291. package/dist/security/manifest/parser.js.map +7 -0
  292. package/dist/security/manifest/parser.test.js +110 -0
  293. package/dist/security/manifest/parser.test.js.map +7 -0
  294. package/dist/security/manifest/plugins/cargo.js +233 -0
  295. package/dist/security/manifest/plugins/cargo.js.map +7 -0
  296. package/dist/security/manifest/plugins/cargo.test.js +304 -0
  297. package/dist/security/manifest/plugins/cargo.test.js.map +7 -0
  298. package/dist/security/manifest/plugins/composer.js +152 -0
  299. package/dist/security/manifest/plugins/composer.js.map +7 -0
  300. package/dist/security/manifest/plugins/go.js +146 -0
  301. package/dist/security/manifest/plugins/go.js.map +7 -0
  302. package/dist/security/manifest/plugins/go.test.js +341 -0
  303. package/dist/security/manifest/plugins/go.test.js.map +7 -0
  304. package/dist/security/manifest/plugins/gradle.js +159 -0
  305. package/dist/security/manifest/plugins/gradle.js.map +7 -0
  306. package/dist/security/manifest/plugins/hex.js +159 -0
  307. package/dist/security/manifest/plugins/hex.js.map +7 -0
  308. package/dist/security/manifest/plugins/maven.js +128 -0
  309. package/dist/security/manifest/plugins/maven.js.map +7 -0
  310. package/dist/security/manifest/plugins/maven.test.js +389 -0
  311. package/dist/security/manifest/plugins/maven.test.js.map +7 -0
  312. package/dist/security/manifest/plugins/npm.js +284 -0
  313. package/dist/security/manifest/plugins/npm.js.map +7 -0
  314. package/dist/security/manifest/plugins/npm.test.js +298 -0
  315. package/dist/security/manifest/plugins/npm.test.js.map +7 -0
  316. package/dist/security/manifest/plugins/nuget.js +186 -0
  317. package/dist/security/manifest/plugins/nuget.js.map +7 -0
  318. package/dist/security/manifest/plugins/pip.js +123 -0
  319. package/dist/security/manifest/plugins/pip.js.map +7 -0
  320. package/dist/security/manifest/plugins/pip.test.js +208 -0
  321. package/dist/security/manifest/plugins/pip.test.js.map +7 -0
  322. package/dist/security/manifest/plugins/pubspec.js +212 -0
  323. package/dist/security/manifest/plugins/pubspec.js.map +7 -0
  324. package/dist/security/manifest/plugins/pyproject.js +261 -0
  325. package/dist/security/manifest/plugins/pyproject.js.map +7 -0
  326. package/dist/security/manifest/plugins/rubygems.js +185 -0
  327. package/dist/security/manifest/plugins/rubygems.js.map +7 -0
  328. package/dist/security/manifest/plugins/swift.js +200 -0
  329. package/dist/security/manifest/plugins/swift.js.map +7 -0
  330. package/dist/security/owasp.js +104 -0
  331. package/dist/security/owasp.js.map +7 -0
  332. package/dist/security/pipeline.js +125 -0
  333. package/dist/security/pipeline.js.map +7 -0
  334. package/dist/security/reachability.js +276 -0
  335. package/dist/security/reachability.js.map +7 -0
  336. package/dist/security/reachability.test.js +394 -0
  337. package/dist/security/reachability.test.js.map +7 -0
  338. package/dist/security/remediation.js +126 -0
  339. package/dist/security/remediation.js.map +7 -0
  340. package/dist/security/secrets.js +176 -0
  341. package/dist/security/secrets.js.map +7 -0
  342. package/dist/security/staleness.js +231 -0
  343. package/dist/security/staleness.js.map +7 -0
  344. package/dist/security/supply-chain.js +301 -0
  345. package/dist/security/supply-chain.js.map +7 -0
  346. package/dist/security/suppressions.js +106 -0
  347. package/dist/security/suppressions.js.map +7 -0
  348. package/dist/security/types.js +17 -0
  349. package/dist/security/types.js.map +7 -0
  350. package/dist/security/vuln/client.js +355 -0
  351. package/dist/security/vuln/client.js.map +7 -0
  352. package/dist/security/vuln/client.test.js +288 -0
  353. package/dist/security/vuln/client.test.js.map +7 -0
  354. package/dist/security/vuln/epss-client.js +95 -0
  355. package/dist/security/vuln/epss-client.js.map +7 -0
  356. package/dist/security/vuln/index.js +29 -0
  357. package/dist/security/vuln/index.js.map +7 -0
  358. package/dist/security/vuln/osv-adapter.js +321 -0
  359. package/dist/security/vuln/osv-adapter.js.map +7 -0
  360. package/dist/security/vuln/osv-adapter.test.js +391 -0
  361. package/dist/security/vuln/osv-adapter.test.js.map +7 -0
  362. package/dist/security/vuln/types.js +17 -0
  363. package/dist/security/vuln/types.js.map +7 -0
  364. package/dist/types.js.map +2 -2
  365. package/package.json +5 -2
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var secrets_exports = {};
30
+ __export(secrets_exports, {
31
+ SecretsScanner: () => SecretsScanner
32
+ });
33
+ module.exports = __toCommonJS(secrets_exports);
34
+ var fs = __toESM(require("fs"));
35
+ var path = __toESM(require("path"));
36
+ const SECRET_PATTERNS = [
37
+ { name: "AWS Access Key ID", severity: "critical", pattern: /AKIA[0-9A-Z]{16}/ },
38
+ { name: "AWS Secret Access Key", severity: "critical", pattern: /aws[_\-]secret[_\-]?(access[_\-]?)?key\s*[=:]\s*["']?([A-Za-z0-9\/+=]{40})["']?/i },
39
+ { name: "GitHub Token", severity: "critical", pattern: /gh[pousr]_[A-Za-z0-9]{36,}/ },
40
+ { name: "Stripe Secret Key", severity: "critical", pattern: /sk_(live|test)_[A-Za-z0-9]{24,}/ },
41
+ { name: "Stripe Publishable Key", severity: "high", pattern: /pk_(live|test)_[A-Za-z0-9]{24,}/ },
42
+ { name: "SendGrid API Key", severity: "critical", pattern: /SG\.[A-Za-z0-9_\-]{22}\.[A-Za-z0-9_\-]{43}/ },
43
+ { name: "Twilio Account SID", severity: "high", pattern: /AC[a-z0-9]{32}/ },
44
+ { name: "Slack Token", severity: "high", pattern: /xox[baprs]-[A-Za-z0-9-]{10,}/ },
45
+ { name: "Private Key (PEM)", severity: "critical", pattern: /-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/ },
46
+ { name: "JWT Token (hardcoded)", severity: "high", pattern: /eyJ[A-Za-z0-9+\/]{20,}\.[A-Za-z0-9+\/]{20,}\.[A-Za-z0-9+\/\-_]{20,}/ },
47
+ { name: "Generic API Key", severity: "medium", pattern: /api[_\-]?key\s*[=:]\s*["']([A-Za-z0-9_\-]{20,})["']/i },
48
+ { name: "Generic Secret", severity: "medium", pattern: /(?:secret|password|passwd|pwd)\s*[=:]\s*["']([^"'\s]{8,})["']/i },
49
+ { name: "Bearer Token", severity: "medium", pattern: /bearer\s+[A-Za-z0-9+\/=]{20,}/i },
50
+ { name: "Database URL", severity: "high", pattern: /(postgres|mysql|mongodb|redis):\/\/[^:]+:[^@]+@[^\/\s]+/ }
51
+ ];
52
+ const SKIP_DIRS = ["node_modules", ".kirograph", "dist", "build"];
53
+ const TEST_PATTERNS = [
54
+ /\.test\.[tj]sx?$/,
55
+ /\.spec\.[tj]sx?$/,
56
+ /\/__tests__\//,
57
+ /\/test\//,
58
+ /\/tests\//
59
+ ];
60
+ function isTestFile(filePath) {
61
+ return TEST_PATTERNS.some((p) => p.test(filePath));
62
+ }
63
+ function shouldSkipPath(filePath) {
64
+ const parts = filePath.split(path.sep);
65
+ return parts.some((p) => SKIP_DIRS.includes(p));
66
+ }
67
+ function redact(value) {
68
+ if (value.length <= 4) return value + "****";
69
+ return value.slice(0, 4) + "****";
70
+ }
71
+ class SecretsScanner {
72
+ constructor(db, projectRoot) {
73
+ this.db = db;
74
+ this.projectRoot = projectRoot;
75
+ }
76
+ async scan(options) {
77
+ const rawDb = this.db.getRawDb();
78
+ const includeTests = options?.includeTests ?? false;
79
+ const fileRows = rawDb.all(`SELECT path FROM files`);
80
+ const findings = [];
81
+ let filesScanned = 0;
82
+ for (const { path: relOrAbsPath } of fileRows) {
83
+ const absPath = path.isAbsolute(relOrAbsPath) ? relOrAbsPath : path.join(this.projectRoot, relOrAbsPath);
84
+ if (shouldSkipPath(absPath)) continue;
85
+ if (!includeTests && isTestFile(absPath)) continue;
86
+ let content;
87
+ try {
88
+ content = fs.readFileSync(absPath, "utf8");
89
+ } catch {
90
+ continue;
91
+ }
92
+ filesScanned++;
93
+ const lines = content.split("\n");
94
+ for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
95
+ const lineText = lines[lineIdx];
96
+ const lineNumber = lineIdx + 1;
97
+ for (const { name, severity, pattern } of SECRET_PATTERNS) {
98
+ const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g");
99
+ let match;
100
+ while ((match = re.exec(lineText)) !== null) {
101
+ const matchedValue = match[0];
102
+ const column = match.index + 1;
103
+ const { nodeId, nodeName } = this.findContainingNode(rawDb, absPath, lineNumber);
104
+ const entryPoints = nodeId ? this.findEntryPoints(rawDb, nodeId) : [];
105
+ findings.push({
106
+ filePath: absPath,
107
+ line: lineNumber,
108
+ column,
109
+ type: name,
110
+ severity,
111
+ snippet: redact(matchedValue),
112
+ nodeId,
113
+ nodeName,
114
+ reachableFromEntryPoints: entryPoints,
115
+ entryPointCount: entryPoints.length
116
+ });
117
+ if (match[0].length === 0) re.lastIndex++;
118
+ }
119
+ }
120
+ }
121
+ }
122
+ const criticalCount = findings.filter((f) => f.severity === "critical").length;
123
+ const highCount = findings.filter((f) => f.severity === "high").length;
124
+ findings.sort((a, b) => {
125
+ const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
126
+ const diff = severityOrder[a.severity] - severityOrder[b.severity];
127
+ if (diff !== 0) return diff;
128
+ if (a.filePath !== b.filePath) return a.filePath.localeCompare(b.filePath);
129
+ return a.line - b.line;
130
+ });
131
+ return {
132
+ findings,
133
+ filesScanned,
134
+ totalFindings: findings.length,
135
+ criticalCount,
136
+ highCount
137
+ };
138
+ }
139
+ // ── Private helpers ──────────────────────────────────────────────────────────
140
+ findContainingNode(rawDb, filePath, line) {
141
+ const row = rawDb.get(
142
+ `SELECT id, name FROM nodes
143
+ WHERE file_path = ? AND start_line <= ? AND end_line >= ?
144
+ AND kind IN ('function', 'method')
145
+ ORDER BY (end_line - start_line) ASC
146
+ LIMIT 1`,
147
+ [filePath, line, line]
148
+ );
149
+ if (!row) return {};
150
+ return { nodeId: row.id, nodeName: row.name };
151
+ }
152
+ findEntryPoints(rawDb, nodeId) {
153
+ const rows = rawDb.all(
154
+ `WITH RECURSIVE callers(node_id, depth) AS (
155
+ SELECT source, 1 FROM edges WHERE target = ? AND kind = 'calls'
156
+ UNION
157
+ SELECT e.source, c.depth + 1
158
+ FROM edges e
159
+ JOIN callers c ON e.target = c.node_id
160
+ WHERE c.depth < 5 AND e.kind = 'calls'
161
+ )
162
+ SELECT DISTINCT n.id, n.name
163
+ FROM callers c
164
+ JOIN nodes n ON n.id = c.node_id
165
+ WHERE n.kind IN ('route', 'function')
166
+ AND (n.name LIKE '%route%' OR n.name LIKE '%handler%' OR n.name LIKE '%controller%')`,
167
+ [nodeId]
168
+ );
169
+ return rows.map((r) => r.id);
170
+ }
171
+ }
172
+ // Annotate the CommonJS export names for ESM import in node:
173
+ 0 && (module.exports = {
174
+ SecretsScanner
175
+ });
176
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/security/secrets.ts"],
4
+ "sourcesContent": ["/**\n * KiroGraph-Sec Secrets Scanner\n *\n * Regex-based secret detection that scans source files and enriches findings\n * with call graph context (containing function + reachability from entry points).\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { GraphDatabase } from '../db/database';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface SecretFinding {\n filePath: string;\n line: number;\n column: number;\n type: string;\n severity: 'critical' | 'high' | 'medium' | 'low';\n /** Redacted: first 4 chars of the matched value + \"****\" */\n snippet: string;\n nodeId?: string;\n nodeName?: string;\n reachableFromEntryPoints: string[];\n entryPointCount: number;\n}\n\nexport interface SecretsResult {\n findings: SecretFinding[];\n filesScanned: number;\n totalFindings: number;\n criticalCount: number;\n highCount: number;\n}\n\n// \u2500\u2500 Secret patterns \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface SecretPattern {\n name: string;\n severity: 'critical' | 'high' | 'medium' | 'low';\n pattern: RegExp;\n}\n\nconst SECRET_PATTERNS: SecretPattern[] = [\n { name: 'AWS Access Key ID', severity: 'critical', pattern: /AKIA[0-9A-Z]{16}/ },\n { name: 'AWS Secret Access Key', severity: 'critical', pattern: /aws[_\\-]secret[_\\-]?(access[_\\-]?)?key\\s*[=:]\\s*[\"']?([A-Za-z0-9\\/+=]{40})[\"']?/i },\n { name: 'GitHub Token', severity: 'critical', pattern: /gh[pousr]_[A-Za-z0-9]{36,}/ },\n { name: 'Stripe Secret Key', severity: 'critical', pattern: /sk_(live|test)_[A-Za-z0-9]{24,}/ },\n { name: 'Stripe Publishable Key', severity: 'high', pattern: /pk_(live|test)_[A-Za-z0-9]{24,}/ },\n { name: 'SendGrid API Key', severity: 'critical', pattern: /SG\\.[A-Za-z0-9_\\-]{22}\\.[A-Za-z0-9_\\-]{43}/ },\n { name: 'Twilio Account SID', severity: 'high', pattern: /AC[a-z0-9]{32}/ },\n { name: 'Slack Token', severity: 'high', pattern: /xox[baprs]-[A-Za-z0-9-]{10,}/ },\n { name: 'Private Key (PEM)', severity: 'critical', pattern: /-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/ },\n { name: 'JWT Token (hardcoded)', severity: 'high', pattern: /eyJ[A-Za-z0-9+\\/]{20,}\\.[A-Za-z0-9+\\/]{20,}\\.[A-Za-z0-9+\\/\\-_]{20,}/ },\n { name: 'Generic API Key', severity: 'medium', pattern: /api[_\\-]?key\\s*[=:]\\s*[\"']([A-Za-z0-9_\\-]{20,})[\"']/i },\n { name: 'Generic Secret', severity: 'medium', pattern: /(?:secret|password|passwd|pwd)\\s*[=:]\\s*[\"']([^\"'\\s]{8,})[\"']/i },\n { name: 'Bearer Token', severity: 'medium', pattern: /bearer\\s+[A-Za-z0-9+\\/=]{20,}/i },\n { name: 'Database URL', severity: 'high', pattern: /(postgres|mysql|mongodb|redis):\\/\\/[^:]+:[^@]+@[^\\/\\s]+/ },\n];\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst SKIP_DIRS = ['node_modules', '.kirograph', 'dist', 'build'];\nconst TEST_PATTERNS = [\n /\\.test\\.[tj]sx?$/,\n /\\.spec\\.[tj]sx?$/,\n /\\/__tests__\\//,\n /\\/test\\//,\n /\\/tests\\//,\n];\n\nfunction isTestFile(filePath: string): boolean {\n return TEST_PATTERNS.some(p => p.test(filePath));\n}\n\nfunction shouldSkipPath(filePath: string): boolean {\n const parts = filePath.split(path.sep);\n return parts.some(p => SKIP_DIRS.includes(p));\n}\n\n/**\n * Redact a matched string: show only the first 4 characters followed by \"****\".\n * If the match is shorter than 4 chars, show all of it + \"****\".\n */\nfunction redact(value: string): string {\n if (value.length <= 4) return value + '****';\n return value.slice(0, 4) + '****';\n}\n\n// \u2500\u2500 SecretsScanner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class SecretsScanner {\n constructor(\n private readonly db: GraphDatabase,\n private readonly projectRoot: string,\n ) {}\n\n async scan(options?: { includeTests?: boolean }): Promise<SecretsResult> {\n const rawDb = this.db.getRawDb();\n const includeTests = options?.includeTests ?? false;\n\n // 1. Collect all indexed files\n const fileRows: Array<{ path: string }> = rawDb.all(`SELECT path FROM files`);\n\n const findings: SecretFinding[] = [];\n let filesScanned = 0;\n\n for (const { path: relOrAbsPath } of fileRows) {\n // Resolve to absolute path\n const absPath = path.isAbsolute(relOrAbsPath)\n ? relOrAbsPath\n : path.join(this.projectRoot, relOrAbsPath);\n\n // Skip paths in blacklisted dirs\n if (shouldSkipPath(absPath)) continue;\n\n // Skip test files unless opted-in\n if (!includeTests && isTestFile(absPath)) continue;\n\n // Read file content\n let content: string;\n try {\n content = fs.readFileSync(absPath, 'utf8');\n } catch {\n // File might have been deleted since indexing \u2014 skip silently\n continue;\n }\n\n filesScanned++;\n const lines = content.split('\\n');\n\n for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {\n const lineText = lines[lineIdx];\n const lineNumber = lineIdx + 1;\n\n for (const { name, severity, pattern } of SECRET_PATTERNS) {\n // Clone regex to reset lastIndex between calls\n const re = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : pattern.flags + 'g');\n let match: RegExpExecArray | null;\n\n while ((match = re.exec(lineText)) !== null) {\n const matchedValue = match[0];\n const column = match.index + 1;\n\n // Enrich with graph context\n const { nodeId, nodeName } = this.findContainingNode(rawDb, absPath, lineNumber);\n const entryPoints = nodeId\n ? this.findEntryPoints(rawDb, nodeId)\n : [];\n\n findings.push({\n filePath: absPath,\n line: lineNumber,\n column,\n type: name,\n severity,\n snippet: redact(matchedValue),\n nodeId,\n nodeName,\n reachableFromEntryPoints: entryPoints,\n entryPointCount: entryPoints.length,\n });\n\n // Avoid infinite loops on zero-width matches\n if (match[0].length === 0) re.lastIndex++;\n }\n }\n }\n }\n\n const criticalCount = findings.filter(f => f.severity === 'critical').length;\n const highCount = findings.filter(f => f.severity === 'high').length;\n\n // Sort: critical first, then high, then by file path + line\n findings.sort((a, b) => {\n const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };\n const diff = severityOrder[a.severity] - severityOrder[b.severity];\n if (diff !== 0) return diff;\n if (a.filePath !== b.filePath) return a.filePath.localeCompare(b.filePath);\n return a.line - b.line;\n });\n\n return {\n findings,\n filesScanned,\n totalFindings: findings.length,\n criticalCount,\n highCount,\n };\n }\n\n // \u2500\u2500 Private helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private findContainingNode(\n rawDb: any,\n filePath: string,\n line: number,\n ): { nodeId?: string; nodeName?: string } {\n const row: { id: string; name: string } | undefined = rawDb.get(\n `SELECT id, name FROM nodes\n WHERE file_path = ? AND start_line <= ? AND end_line >= ?\n AND kind IN ('function', 'method')\n ORDER BY (end_line - start_line) ASC\n LIMIT 1`,\n [filePath, line, line],\n );\n\n if (!row) return {};\n return { nodeId: row.id, nodeName: row.name };\n }\n\n private findEntryPoints(rawDb: any, nodeId: string): string[] {\n const rows: Array<{ id: string; name: string }> = rawDb.all(\n `WITH RECURSIVE callers(node_id, depth) AS (\n SELECT source, 1 FROM edges WHERE target = ? AND kind = 'calls'\n UNION\n SELECT e.source, c.depth + 1\n FROM edges e\n JOIN callers c ON e.target = c.node_id\n WHERE c.depth < 5 AND e.kind = 'calls'\n )\n SELECT DISTINCT n.id, n.name\n FROM callers c\n JOIN nodes n ON n.id = c.node_id\n WHERE n.kind IN ('route', 'function')\n AND (n.name LIKE '%route%' OR n.name LIKE '%handler%' OR n.name LIKE '%controller%')`,\n [nodeId],\n );\n\n return rows.map(r => r.id);\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var staleness_exports = {};
20
+ __export(staleness_exports, {
21
+ StalenessChecker: () => StalenessChecker
22
+ });
23
+ module.exports = __toCommonJS(staleness_exports);
24
+ var import_parser = require("./manifest/parser");
25
+ var import_errors = require("../errors");
26
+ const TIMEOUT_MS = 1e4;
27
+ async function fetchJson(url, headers) {
28
+ const controller = new AbortController();
29
+ const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
30
+ try {
31
+ const resp = await fetch(url, {
32
+ signal: controller.signal,
33
+ headers: {
34
+ "Accept": "application/json",
35
+ ...headers
36
+ }
37
+ });
38
+ if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
39
+ return await resp.json();
40
+ } finally {
41
+ clearTimeout(timer);
42
+ }
43
+ }
44
+ async function fetchNpm(name) {
45
+ const encoded = encodeURIComponent(name);
46
+ const data = await fetchJson(`https://registry.npmjs.org/${encoded}/latest`);
47
+ const version = data["version"];
48
+ const full = await fetchJson(`https://registry.npmjs.org/${encoded}`);
49
+ const time = full["time"] ?? {};
50
+ const publishedStr = time[version] ?? full["time"]?.["modified"] ?? "";
51
+ const latestPublished = publishedStr ? new Date(publishedStr).getTime() : Date.now();
52
+ return { latestVersion: version, latestPublished };
53
+ }
54
+ async function fetchPypi(name) {
55
+ const data = await fetchJson(`https://pypi.org/pypi/${encodeURIComponent(name)}/json`);
56
+ const info = data["info"];
57
+ const version = info["version"];
58
+ const releases = data["releases"] ?? {};
59
+ const files = releases[version] ?? [];
60
+ const uploadTime = files[0]?.["upload_time_iso_8601"] ?? "";
61
+ const latestPublished = uploadTime ? new Date(uploadTime).getTime() : Date.now();
62
+ return { latestVersion: version, latestPublished };
63
+ }
64
+ async function fetchCrates(name) {
65
+ const data = await fetchJson(
66
+ `https://crates.io/api/v1/crates/${encodeURIComponent(name)}`,
67
+ { "User-Agent": "KiroGraph/1.0" }
68
+ );
69
+ const crate = data["crate"];
70
+ const version = crate["newest_version"];
71
+ const updatedAt = crate["updated_at"] ?? "";
72
+ const latestPublished = updatedAt ? new Date(updatedAt).getTime() : Date.now();
73
+ return { latestVersion: version, latestPublished };
74
+ }
75
+ async function fetchRubygems(name) {
76
+ const data = await fetchJson(`https://rubygems.org/api/v1/gems/${encodeURIComponent(name)}.json`);
77
+ const version = data["version"];
78
+ const createdAt = data["version_created_at"] ?? "";
79
+ const latestPublished = createdAt ? new Date(createdAt).getTime() : Date.now();
80
+ return { latestVersion: version, latestPublished };
81
+ }
82
+ async function fetchPackagist(name) {
83
+ const parts = name.split("/");
84
+ if (parts.length !== 2) throw new Error(`Invalid Composer package name: ${name}`);
85
+ const [vendor, pkg] = parts;
86
+ const data = await fetchJson(`https://repo.packagist.org/p2/${encodeURIComponent(vendor)}/${encodeURIComponent(pkg)}.json`);
87
+ const packages = data["packages"] ?? {};
88
+ const versions = packages[name] ?? [];
89
+ if (versions.length === 0) throw new Error(`No versions found for ${name}`);
90
+ let latestVersion = "";
91
+ let latestPublished = 0;
92
+ for (const v of versions) {
93
+ const versionStr = v["version"] ?? "";
94
+ if (versionStr.startsWith("dev-") || versionStr === "dev-master") continue;
95
+ if (!latestVersion || (0, import_parser.compareVersions)(versionStr, latestVersion) > 0) {
96
+ latestVersion = versionStr;
97
+ const timeStr = v["time"] ?? "";
98
+ latestPublished = timeStr ? new Date(timeStr).getTime() : 0;
99
+ }
100
+ }
101
+ if (!latestVersion) throw new Error(`No stable versions found for ${name}`);
102
+ return { latestVersion, latestPublished: latestPublished || Date.now() };
103
+ }
104
+ async function fetchLatest(ecosystem, packageName) {
105
+ const eco = ecosystem.toLowerCase();
106
+ try {
107
+ switch (eco) {
108
+ case "npm":
109
+ return await fetchNpm(packageName);
110
+ case "pypi":
111
+ return await fetchPypi(packageName);
112
+ case "pip":
113
+ return await fetchPypi(packageName);
114
+ // alias
115
+ case "cargo":
116
+ return await fetchCrates(packageName);
117
+ case "rubygems":
118
+ return await fetchRubygems(packageName);
119
+ case "composer":
120
+ return await fetchPackagist(packageName);
121
+ default:
122
+ return null;
123
+ }
124
+ } catch (err) {
125
+ throw err;
126
+ }
127
+ }
128
+ function getMajorVersion(version) {
129
+ const clean = version.startsWith("v") ? version.slice(1) : version;
130
+ const stripped = clean.replace(/^[~^>=<]+/, "");
131
+ const major = parseInt(stripped.split(".")[0] ?? "0", 10);
132
+ return isNaN(major) ? 0 : major;
133
+ }
134
+ function computeStaleness(resolvedVersion, latestVersion, latestPublished) {
135
+ const resolvedMajor = getMajorVersion(resolvedVersion);
136
+ const latestMajor = getMajorVersion(latestVersion);
137
+ const majorVersionsBehind = Math.max(0, latestMajor - resolvedMajor);
138
+ const monthsSinceLatest = Math.max(0, (Date.now() - latestPublished) / (1e3 * 60 * 60 * 24 * 30));
139
+ const versionScore = Math.min(majorVersionsBehind * 0.2, 0.6);
140
+ const timeScore = Math.min(monthsSinceLatest / 36, 0.4);
141
+ const score = Math.min(versionScore + timeScore, 1);
142
+ return { score, majorVersionsBehind, monthsSinceLatest: Math.round(monthsSinceLatest) };
143
+ }
144
+ class StalenessChecker {
145
+ constructor(db) {
146
+ this.db = db;
147
+ }
148
+ /**
149
+ * Check all dependencies in sec_dependencies that have a supported ecosystem.
150
+ * Returns a summary of checked/stale counts and any errors encountered.
151
+ */
152
+ async checkAll() {
153
+ const rawDb = this.db.getRawDb();
154
+ const rows = rawDb.all(
155
+ `SELECT node_id, package_name, ecosystem, resolved_version, declared_constraint
156
+ FROM sec_dependencies`
157
+ );
158
+ let checked = 0;
159
+ let stale = 0;
160
+ const errors = [];
161
+ for (const row of rows) {
162
+ const result = await this._checkRow(row);
163
+ if (result === null) continue;
164
+ if (result instanceof Error) {
165
+ errors.push(`${row.package_name} (${row.ecosystem}): ${result.message}`);
166
+ continue;
167
+ }
168
+ checked++;
169
+ if (result.stalenessScore >= 0.3) stale++;
170
+ }
171
+ return { checked, stale, errors };
172
+ }
173
+ /**
174
+ * Check a single dependency by node_id. Returns null if the ecosystem is
175
+ * not supported or the dependency is not found.
176
+ */
177
+ async checkOne(nodeId) {
178
+ const rawDb = this.db.getRawDb();
179
+ const row = rawDb.get(
180
+ `SELECT node_id, package_name, ecosystem, resolved_version, declared_constraint
181
+ FROM sec_dependencies WHERE node_id = ?`,
182
+ [nodeId]
183
+ );
184
+ if (!row) return null;
185
+ const result = await this._checkRow(row);
186
+ if (result === null || result instanceof Error) return null;
187
+ return result;
188
+ }
189
+ async _checkRow(row) {
190
+ const resolvedVersion = row.resolved_version ?? row.declared_constraint;
191
+ let registryResult;
192
+ try {
193
+ registryResult = await fetchLatest(row.ecosystem, row.package_name);
194
+ } catch (err) {
195
+ const msg = err instanceof Error ? err.message : String(err);
196
+ (0, import_errors.logWarn)(`[staleness] Failed to fetch ${row.package_name} (${row.ecosystem}): ${msg}`);
197
+ return new Error(msg);
198
+ }
199
+ if (registryResult === null) {
200
+ return null;
201
+ }
202
+ const { latestVersion, latestPublished } = registryResult;
203
+ const { score, majorVersionsBehind, monthsSinceLatest } = computeStaleness(
204
+ resolvedVersion,
205
+ latestVersion,
206
+ latestPublished
207
+ );
208
+ const rawDb = this.db.getRawDb();
209
+ rawDb.run(
210
+ `UPDATE sec_dependencies
211
+ SET latest_version = ?, latest_published = ?, staleness_score = ?
212
+ WHERE node_id = ?`,
213
+ [latestVersion, latestPublished, score, row.node_id]
214
+ );
215
+ return {
216
+ packageName: row.package_name,
217
+ ecosystem: row.ecosystem,
218
+ resolvedVersion,
219
+ latestVersion,
220
+ latestPublished,
221
+ stalenessScore: score,
222
+ majorVersionsBehind,
223
+ monthsSinceLatest
224
+ };
225
+ }
226
+ }
227
+ // Annotate the CommonJS export names for ESM import in node:
228
+ 0 && (module.exports = {
229
+ StalenessChecker
230
+ });
231
+ //# sourceMappingURL=staleness.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/security/staleness.ts"],
4
+ "sourcesContent": ["/**\n * Dependency Staleness Checker\n *\n * Queries public package registries (npm, PyPI, crates.io, RubyGems, Packagist)\n * to determine the latest published version and compute a staleness score for\n * each dependency tracked in sec_dependencies.\n *\n * Score formula:\n * score = min(majorVersionsBehind * 0.2, 0.6) // up to 0.6 for version lag\n * + min(monthsSinceLatest / 36, 0.4) // up to 0.4 for time lag\n * score = min(score, 1.0)\n */\n\nimport { compareVersions } from './manifest/parser';\nimport { logWarn, logError } from '../errors';\nimport type { GraphDatabase } from '../db/database';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface StalenessResult {\n packageName: string;\n ecosystem: string;\n resolvedVersion: string;\n latestVersion: string;\n latestPublished: number; // epoch ms\n stalenessScore: number; // 0.0\u20131.0\n majorVersionsBehind: number;\n monthsSinceLatest: number;\n}\n\n// \u2500\u2500 Registry fetch helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst TIMEOUT_MS = 10_000;\n\nasync function fetchJson(url: string, headers?: Record<string, string>): Promise<unknown> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);\n try {\n const resp = await fetch(url, {\n signal: controller.signal,\n headers: {\n 'Accept': 'application/json',\n ...headers,\n },\n });\n if (!resp.ok) throw new Error(`HTTP ${resp.status}`);\n return await resp.json();\n } finally {\n clearTimeout(timer);\n }\n}\n\ninterface RegistryResult {\n latestVersion: string;\n latestPublished: number; // epoch ms\n}\n\nasync function fetchNpm(name: string): Promise<RegistryResult> {\n // Scoped packages: @scope/name \u2014 must be URL-encoded as %40scope%2Fname\n const encoded = encodeURIComponent(name);\n const data = await fetchJson(`https://registry.npmjs.org/${encoded}/latest`) as Record<string, unknown>;\n const version = data['version'] as string;\n // Fetch full metadata for publish time\n const full = await fetchJson(`https://registry.npmjs.org/${encoded}`) as Record<string, unknown>;\n const time = (full['time'] as Record<string, string>) ?? {};\n const publishedStr = time[version] ?? (full['time'] as Record<string, string>)?.['modified'] ?? '';\n const latestPublished = publishedStr ? new Date(publishedStr).getTime() : Date.now();\n return { latestVersion: version, latestPublished };\n}\n\nasync function fetchPypi(name: string): Promise<RegistryResult> {\n const data = await fetchJson(`https://pypi.org/pypi/${encodeURIComponent(name)}/json`) as Record<string, unknown>;\n const info = data['info'] as Record<string, unknown>;\n const version = info['version'] as string;\n const releases = (data['releases'] as Record<string, Array<Record<string, string>>>) ?? {};\n const files = releases[version] ?? [];\n const uploadTime = files[0]?.['upload_time_iso_8601'] ?? '';\n const latestPublished = uploadTime ? new Date(uploadTime).getTime() : Date.now();\n return { latestVersion: version, latestPublished };\n}\n\nasync function fetchCrates(name: string): Promise<RegistryResult> {\n const data = await fetchJson(\n `https://crates.io/api/v1/crates/${encodeURIComponent(name)}`,\n { 'User-Agent': 'KiroGraph/1.0' },\n ) as Record<string, unknown>;\n const crate = data['crate'] as Record<string, unknown>;\n const version = crate['newest_version'] as string;\n const updatedAt = (crate['updated_at'] as string) ?? '';\n const latestPublished = updatedAt ? new Date(updatedAt).getTime() : Date.now();\n return { latestVersion: version, latestPublished };\n}\n\nasync function fetchRubygems(name: string): Promise<RegistryResult> {\n const data = await fetchJson(`https://rubygems.org/api/v1/gems/${encodeURIComponent(name)}.json`) as Record<string, unknown>;\n const version = data['version'] as string;\n const createdAt = (data['version_created_at'] as string) ?? '';\n const latestPublished = createdAt ? new Date(createdAt).getTime() : Date.now();\n return { latestVersion: version, latestPublished };\n}\n\nasync function fetchPackagist(name: string): Promise<RegistryResult> {\n // name is expected to be \"vendor/package\"\n const parts = name.split('/');\n if (parts.length !== 2) throw new Error(`Invalid Composer package name: ${name}`);\n const [vendor, pkg] = parts;\n const data = await fetchJson(`https://repo.packagist.org/p2/${encodeURIComponent(vendor!)}/${encodeURIComponent(pkg!)}.json`) as Record<string, unknown>;\n const packages = (data['packages'] as Record<string, unknown[]>) ?? {};\n const versions = (packages[name] ?? []) as Array<Record<string, unknown>>;\n if (versions.length === 0) throw new Error(`No versions found for ${name}`);\n\n // Find highest non-dev version\n let latestVersion = '';\n let latestPublished = 0;\n for (const v of versions) {\n const versionStr = (v['version'] as string) ?? '';\n if (versionStr.startsWith('dev-') || versionStr === 'dev-master') continue;\n if (!latestVersion || compareVersions(versionStr, latestVersion) > 0) {\n latestVersion = versionStr;\n const timeStr = (v['time'] as string) ?? '';\n latestPublished = timeStr ? new Date(timeStr).getTime() : 0;\n }\n }\n if (!latestVersion) throw new Error(`No stable versions found for ${name}`);\n return { latestVersion, latestPublished: latestPublished || Date.now() };\n}\n\n// \u2500\u2500 Ecosystem dispatch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function fetchLatest(ecosystem: string, packageName: string): Promise<RegistryResult | null> {\n const eco = ecosystem.toLowerCase();\n try {\n switch (eco) {\n case 'npm': return await fetchNpm(packageName);\n case 'pypi': return await fetchPypi(packageName);\n case 'pip': return await fetchPypi(packageName); // alias\n case 'cargo': return await fetchCrates(packageName);\n case 'rubygems': return await fetchRubygems(packageName);\n case 'composer': return await fetchPackagist(packageName);\n default:\n // Maven, Go, NuGet, Swift, Pub, Hex, Gradle \u2014 skip\n return null;\n }\n } catch (err) {\n throw err; // let caller handle\n }\n}\n\n// \u2500\u2500 Score calculation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction getMajorVersion(version: string): number {\n const clean = version.startsWith('v') ? version.slice(1) : version;\n const stripped = clean.replace(/^[~^>=<]+/, '');\n const major = parseInt(stripped.split('.')[0] ?? '0', 10);\n return isNaN(major) ? 0 : major;\n}\n\nfunction computeStaleness(\n resolvedVersion: string,\n latestVersion: string,\n latestPublished: number,\n): { score: number; majorVersionsBehind: number; monthsSinceLatest: number } {\n const resolvedMajor = getMajorVersion(resolvedVersion);\n const latestMajor = getMajorVersion(latestVersion);\n const majorVersionsBehind = Math.max(0, latestMajor - resolvedMajor);\n\n const monthsSinceLatest = Math.max(0, (Date.now() - latestPublished) / (1000 * 60 * 60 * 24 * 30));\n\n const versionScore = Math.min(majorVersionsBehind * 0.2, 0.6);\n const timeScore = Math.min(monthsSinceLatest / 36, 0.4);\n const score = Math.min(versionScore + timeScore, 1.0);\n\n return { score, majorVersionsBehind, monthsSinceLatest: Math.round(monthsSinceLatest) };\n}\n\n// \u2500\u2500 StalenessChecker \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class StalenessChecker {\n constructor(private readonly db: GraphDatabase) {}\n\n /**\n * Check all dependencies in sec_dependencies that have a supported ecosystem.\n * Returns a summary of checked/stale counts and any errors encountered.\n */\n async checkAll(): Promise<{ checked: number; stale: number; errors: string[] }> {\n const rawDb = this.db.getRawDb();\n const rows: Array<{\n node_id: string;\n package_name: string;\n ecosystem: string;\n resolved_version: string | null;\n declared_constraint: string;\n }> = rawDb.all(\n `SELECT node_id, package_name, ecosystem, resolved_version, declared_constraint\n FROM sec_dependencies`,\n );\n\n let checked = 0;\n let stale = 0;\n const errors: string[] = [];\n\n for (const row of rows) {\n const result = await this._checkRow(row);\n if (result === null) continue; // unsupported ecosystem \u2014 skip\n if (result instanceof Error) {\n errors.push(`${row.package_name} (${row.ecosystem}): ${result.message}`);\n continue;\n }\n checked++;\n if (result.stalenessScore >= 0.3) stale++;\n }\n\n return { checked, stale, errors };\n }\n\n /**\n * Check a single dependency by node_id. Returns null if the ecosystem is\n * not supported or the dependency is not found.\n */\n async checkOne(nodeId: string): Promise<StalenessResult | null> {\n const rawDb = this.db.getRawDb();\n const row: {\n node_id: string;\n package_name: string;\n ecosystem: string;\n resolved_version: string | null;\n declared_constraint: string;\n } | undefined = rawDb.get(\n `SELECT node_id, package_name, ecosystem, resolved_version, declared_constraint\n FROM sec_dependencies WHERE node_id = ?`,\n [nodeId],\n );\n\n if (!row) return null;\n\n const result = await this._checkRow(row);\n if (result === null || result instanceof Error) return null;\n return result;\n }\n\n private async _checkRow(row: {\n node_id: string;\n package_name: string;\n ecosystem: string;\n resolved_version: string | null;\n declared_constraint: string;\n }): Promise<StalenessResult | Error | null> {\n const resolvedVersion = row.resolved_version ?? row.declared_constraint;\n\n let registryResult: RegistryResult | null;\n try {\n registryResult = await fetchLatest(row.ecosystem, row.package_name);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logWarn(`[staleness] Failed to fetch ${row.package_name} (${row.ecosystem}): ${msg}`);\n return new Error(msg);\n }\n\n if (registryResult === null) {\n // Unsupported ecosystem \u2014 skip silently\n return null;\n }\n\n const { latestVersion, latestPublished } = registryResult;\n const { score, majorVersionsBehind, monthsSinceLatest } = computeStaleness(\n resolvedVersion,\n latestVersion,\n latestPublished,\n );\n\n // Persist to sec_dependencies\n const rawDb = this.db.getRawDb();\n rawDb.run(\n `UPDATE sec_dependencies\n SET latest_version = ?, latest_published = ?, staleness_score = ?\n WHERE node_id = ?`,\n [latestVersion, latestPublished, score, row.node_id],\n );\n\n return {\n packageName: row.package_name,\n ecosystem: row.ecosystem,\n resolvedVersion,\n latestVersion,\n latestPublished,\n stalenessScore: score,\n majorVersionsBehind,\n monthsSinceLatest,\n };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }