toolip 1.0.6 → 2.0.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 (308) hide show
  1. package/README.md +189 -448
  2. package/dist/src/analyzers/ast/ast-security-analyzer.d.ts +6 -0
  3. package/dist/src/analyzers/ast/ast-security-analyzer.js +64 -0
  4. package/dist/src/analyzers/ast/ast-security-analyzer.js.map +1 -0
  5. package/dist/src/analyzers/ast/rules.d.ts +48 -0
  6. package/dist/src/analyzers/ast/rules.js +39 -0
  7. package/dist/src/analyzers/ast/rules.js.map +1 -0
  8. package/dist/src/analyzers/ast/source-analysis.d.ts +2 -0
  9. package/dist/src/analyzers/ast/source-analysis.js +225 -0
  10. package/dist/src/analyzers/ast/source-analysis.js.map +1 -0
  11. package/dist/src/analyzers/dependency-confusion/analyzer.d.ts +9 -0
  12. package/dist/src/analyzers/dependency-confusion/analyzer.js +98 -0
  13. package/dist/src/analyzers/dependency-confusion/analyzer.js.map +1 -0
  14. package/dist/src/analyzers/docker/analyzer.d.ts +6 -0
  15. package/dist/src/analyzers/docker/analyzer.js +103 -0
  16. package/dist/src/analyzers/docker/analyzer.js.map +1 -0
  17. package/dist/src/analyzers/git-history/analyzer.d.ts +8 -0
  18. package/dist/src/analyzers/git-history/analyzer.js +157 -0
  19. package/dist/src/analyzers/git-history/analyzer.js.map +1 -0
  20. package/dist/src/analyzers/git-history/secret-patterns.d.ts +7 -0
  21. package/dist/src/analyzers/git-history/secret-patterns.js +33 -0
  22. package/dist/src/analyzers/git-history/secret-patterns.js.map +1 -0
  23. package/dist/src/analyzers/install-scripts/install-script-analyzer.d.ts +6 -0
  24. package/dist/src/analyzers/install-scripts/install-script-analyzer.js +135 -0
  25. package/dist/src/analyzers/install-scripts/install-script-analyzer.js.map +1 -0
  26. package/dist/src/analyzers/reachability/import-graph.d.ts +9 -0
  27. package/dist/src/analyzers/reachability/import-graph.js +110 -0
  28. package/dist/src/analyzers/reachability/import-graph.js.map +1 -0
  29. package/dist/src/analyzers/reachability/reachability-analyzer.d.ts +16 -0
  30. package/dist/src/analyzers/reachability/reachability-analyzer.js +95 -0
  31. package/dist/src/analyzers/reachability/reachability-analyzer.js.map +1 -0
  32. package/dist/src/analyzers/vulnerability/osv-analyzer.d.ts +9 -0
  33. package/dist/src/analyzers/vulnerability/osv-analyzer.js +94 -0
  34. package/dist/src/analyzers/vulnerability/osv-analyzer.js.map +1 -0
  35. package/dist/src/analyzers/vulnerability/severity.d.ts +3 -0
  36. package/dist/src/analyzers/vulnerability/severity.js +13 -0
  37. package/dist/src/analyzers/vulnerability/severity.js.map +1 -0
  38. package/dist/src/application/analyzer-runner.d.ts +12 -0
  39. package/dist/src/application/analyzer-runner.js +45 -0
  40. package/dist/src/application/analyzer-runner.js.map +1 -0
  41. package/dist/src/commands/alternatives.d.ts +2 -0
  42. package/dist/src/commands/alternatives.js +17 -0
  43. package/dist/src/commands/alternatives.js.map +1 -0
  44. package/dist/src/commands/announce.d.ts +2 -0
  45. package/dist/src/commands/announce.js +27 -0
  46. package/dist/src/commands/announce.js.map +1 -0
  47. package/dist/src/commands/ast-scan.d.ts +2 -0
  48. package/dist/src/commands/ast-scan.js +86 -0
  49. package/dist/src/commands/ast-scan.js.map +1 -0
  50. package/dist/src/commands/audit-repo.d.ts +2 -0
  51. package/dist/src/commands/audit-repo.js +20 -0
  52. package/dist/src/commands/audit-repo.js.map +1 -0
  53. package/dist/src/commands/compare.d.ts +2 -0
  54. package/dist/src/commands/compare.js +19 -0
  55. package/dist/src/commands/compare.js.map +1 -0
  56. package/dist/src/commands/config.d.ts +2 -0
  57. package/dist/src/commands/config.js +69 -0
  58. package/dist/src/commands/config.js.map +1 -0
  59. package/dist/src/commands/dependency-confusion.d.ts +2 -0
  60. package/dist/src/commands/dependency-confusion.js +37 -0
  61. package/dist/src/commands/dependency-confusion.js.map +1 -0
  62. package/dist/src/commands/diff.d.ts +2 -0
  63. package/dist/src/commands/diff.js +24 -0
  64. package/dist/src/commands/diff.js.map +1 -0
  65. package/dist/src/commands/docker-scan.d.ts +2 -0
  66. package/dist/src/commands/docker-scan.js +34 -0
  67. package/dist/src/commands/docker-scan.js.map +1 -0
  68. package/dist/src/commands/doctor.d.ts +2 -0
  69. package/dist/src/commands/doctor.js +42 -0
  70. package/dist/src/commands/doctor.js.map +1 -0
  71. package/dist/src/commands/git-audit.d.ts +2 -0
  72. package/dist/src/commands/git-audit.js +37 -0
  73. package/dist/src/commands/git-audit.js.map +1 -0
  74. package/dist/src/commands/git-history.d.ts +2 -0
  75. package/dist/src/commands/git-history.js +40 -0
  76. package/dist/src/commands/git-history.js.map +1 -0
  77. package/dist/src/commands/history.d.ts +2 -0
  78. package/dist/src/commands/history.js +69 -0
  79. package/dist/src/commands/history.js.map +1 -0
  80. package/dist/src/commands/hook.d.ts +2 -0
  81. package/dist/src/commands/hook.js +16 -0
  82. package/dist/src/commands/hook.js.map +1 -0
  83. package/dist/src/commands/inspect.d.ts +2 -0
  84. package/dist/src/commands/inspect.js +24 -0
  85. package/dist/src/commands/inspect.js.map +1 -0
  86. package/dist/src/commands/install-scripts.d.ts +2 -0
  87. package/dist/src/commands/install-scripts.js +52 -0
  88. package/dist/src/commands/install-scripts.js.map +1 -0
  89. package/dist/src/commands/learn.d.ts +2 -0
  90. package/dist/src/commands/learn.js +42 -0
  91. package/dist/src/commands/learn.js.map +1 -0
  92. package/dist/src/commands/licenses.d.ts +2 -0
  93. package/dist/src/commands/licenses.js +40 -0
  94. package/dist/src/commands/licenses.js.map +1 -0
  95. package/dist/src/commands/mcp.d.ts +2 -0
  96. package/dist/src/commands/mcp.js +10 -0
  97. package/dist/src/commands/mcp.js.map +1 -0
  98. package/dist/src/commands/monorepo.d.ts +2 -0
  99. package/dist/src/commands/monorepo.js +21 -0
  100. package/dist/src/commands/monorepo.js.map +1 -0
  101. package/dist/src/commands/package-health.d.ts +2 -0
  102. package/dist/src/commands/package-health.js +50 -0
  103. package/dist/src/commands/package-health.js.map +1 -0
  104. package/dist/src/commands/pre-commit.d.ts +2 -0
  105. package/dist/src/commands/pre-commit.js +37 -0
  106. package/dist/src/commands/pre-commit.js.map +1 -0
  107. package/dist/src/commands/profile.d.ts +2 -0
  108. package/dist/src/commands/profile.js +18 -0
  109. package/dist/src/commands/profile.js.map +1 -0
  110. package/dist/src/commands/publish.d.ts +2 -0
  111. package/dist/src/commands/publish.js +25 -0
  112. package/dist/src/commands/publish.js.map +1 -0
  113. package/dist/src/commands/reachability.d.ts +2 -0
  114. package/dist/src/commands/reachability.js +47 -0
  115. package/dist/src/commands/reachability.js.map +1 -0
  116. package/dist/src/commands/sbom.d.ts +2 -0
  117. package/dist/src/commands/sbom.js +33 -0
  118. package/dist/src/commands/sbom.js.map +1 -0
  119. package/dist/src/commands/scan.d.ts +2 -0
  120. package/dist/src/commands/scan.js +48 -0
  121. package/dist/src/commands/scan.js.map +1 -0
  122. package/dist/src/commands/score.d.ts +2 -0
  123. package/dist/src/commands/score.js +24 -0
  124. package/dist/src/commands/score.js.map +1 -0
  125. package/dist/src/commands/self-test.d.ts +2 -0
  126. package/dist/src/commands/self-test.js +63 -0
  127. package/dist/src/commands/self-test.js.map +1 -0
  128. package/dist/src/commands/tree.d.ts +2 -0
  129. package/dist/src/commands/tree.js +21 -0
  130. package/dist/src/commands/tree.js.map +1 -0
  131. package/dist/src/commands/upgrade-pr.d.ts +2 -0
  132. package/dist/src/commands/upgrade-pr.js +15 -0
  133. package/dist/src/commands/upgrade-pr.js.map +1 -0
  134. package/dist/src/commands/vault.d.ts +2 -0
  135. package/dist/src/commands/vault.js +86 -0
  136. package/dist/src/commands/vault.js.map +1 -0
  137. package/dist/src/commands/vulnerabilities.d.ts +2 -0
  138. package/dist/src/commands/vulnerabilities.js +42 -0
  139. package/dist/src/commands/vulnerabilities.js.map +1 -0
  140. package/dist/src/commands/watch.d.ts +2 -0
  141. package/dist/src/commands/watch.js +34 -0
  142. package/dist/src/commands/watch.js.map +1 -0
  143. package/dist/src/config/version.d.ts +6 -0
  144. package/dist/src/config/version.js +29 -0
  145. package/dist/src/config/version.js.map +1 -0
  146. package/dist/src/contracts/analyzer.d.ts +23 -0
  147. package/dist/src/contracts/analyzer.js +2 -0
  148. package/dist/src/contracts/analyzer.js.map +1 -0
  149. package/dist/src/contracts/finding.d.ts +35 -0
  150. package/dist/src/contracts/finding.js +13 -0
  151. package/dist/src/contracts/finding.js.map +1 -0
  152. package/dist/src/contracts/report.d.ts +30 -0
  153. package/dist/src/contracts/report.js +2 -0
  154. package/dist/src/contracts/report.js.map +1 -0
  155. package/dist/src/contracts/rule.d.ts +12 -0
  156. package/dist/src/contracts/rule.js +7 -0
  157. package/dist/src/contracts/rule.js.map +1 -0
  158. package/dist/src/core/alternatives.d.ts +8 -0
  159. package/dist/src/core/alternatives.js +35 -0
  160. package/dist/src/core/alternatives.js.map +1 -0
  161. package/dist/src/core/analyze-package.d.ts +2 -0
  162. package/dist/src/core/analyze-package.js +49 -0
  163. package/dist/src/core/analyze-package.js.map +1 -0
  164. package/dist/src/core/announce/generate.d.ts +9 -0
  165. package/dist/src/core/announce/generate.js +19 -0
  166. package/dist/src/core/announce/generate.js.map +1 -0
  167. package/dist/src/core/compare-packages.d.ts +7 -0
  168. package/dist/src/core/compare-packages.js +19 -0
  169. package/dist/src/core/compare-packages.js.map +1 -0
  170. package/dist/src/core/config/load.d.ts +3 -0
  171. package/dist/src/core/config/load.js +21 -0
  172. package/dist/src/core/config/load.js.map +1 -0
  173. package/dist/src/core/config/policy.d.ts +3 -0
  174. package/dist/src/core/config/policy.js +48 -0
  175. package/dist/src/core/config/policy.js.map +1 -0
  176. package/dist/src/core/config/schema.d.ts +172 -0
  177. package/dist/src/core/config/schema.js +84 -0
  178. package/dist/src/core/config/schema.js.map +1 -0
  179. package/dist/src/core/dependencies/inventory.d.ts +9 -0
  180. package/dist/src/core/dependencies/inventory.js +43 -0
  181. package/dist/src/core/dependencies/inventory.js.map +1 -0
  182. package/dist/src/core/dependency-scan.d.ts +17 -0
  183. package/dist/src/core/dependency-scan.js +70 -0
  184. package/dist/src/core/dependency-scan.js.map +1 -0
  185. package/dist/src/core/dependency-tree.d.ts +16 -0
  186. package/dist/src/core/dependency-tree.js +19 -0
  187. package/dist/src/core/dependency-tree.js.map +1 -0
  188. package/dist/src/core/dependency-types.d.ts +17 -0
  189. package/dist/src/core/dependency-types.js +2 -0
  190. package/dist/src/core/dependency-types.js.map +1 -0
  191. package/dist/src/core/diff/security-diff.d.ts +10 -0
  192. package/dist/src/core/diff/security-diff.js +20 -0
  193. package/dist/src/core/diff/security-diff.js.map +1 -0
  194. package/dist/src/core/file-walker.d.ts +6 -0
  195. package/dist/src/core/file-walker.js +27 -0
  196. package/dist/src/core/file-walker.js.map +1 -0
  197. package/dist/src/core/git-audit.d.ts +12 -0
  198. package/dist/src/core/git-audit.js +111 -0
  199. package/dist/src/core/git-audit.js.map +1 -0
  200. package/dist/src/core/github/remote-audit.d.ts +5 -0
  201. package/dist/src/core/github/remote-audit.js +28 -0
  202. package/dist/src/core/github/remote-audit.js.map +1 -0
  203. package/dist/src/core/github/upgrade-pr.d.ts +4 -0
  204. package/dist/src/core/github/upgrade-pr.js +41 -0
  205. package/dist/src/core/github/upgrade-pr.js.map +1 -0
  206. package/dist/src/core/history/git-metadata.d.ts +5 -0
  207. package/dist/src/core/history/git-metadata.js +37 -0
  208. package/dist/src/core/history/git-metadata.js.map +1 -0
  209. package/dist/src/core/history/store.d.ts +5 -0
  210. package/dist/src/core/history/store.js +65 -0
  211. package/dist/src/core/history/store.js.map +1 -0
  212. package/dist/src/core/history/types.d.ts +27 -0
  213. package/dist/src/core/history/types.js +2 -0
  214. package/dist/src/core/history/types.js.map +1 -0
  215. package/dist/src/core/hooks.d.ts +1 -0
  216. package/dist/src/core/hooks.js +14 -0
  217. package/dist/src/core/hooks.js.map +1 -0
  218. package/dist/src/core/learn.d.ts +11 -0
  219. package/dist/src/core/learn.js +163 -0
  220. package/dist/src/core/learn.js.map +1 -0
  221. package/dist/src/core/license-analysis.d.ts +18 -0
  222. package/dist/src/core/license-analysis.js +98 -0
  223. package/dist/src/core/license-analysis.js.map +1 -0
  224. package/dist/src/core/load-toolip-ignore.d.ts +5 -0
  225. package/dist/src/core/load-toolip-ignore.js +35 -0
  226. package/dist/src/core/load-toolip-ignore.js.map +1 -0
  227. package/dist/src/core/monorepo/discover.d.ts +7 -0
  228. package/dist/src/core/monorepo/discover.js +49 -0
  229. package/dist/src/core/monorepo/discover.js.map +1 -0
  230. package/dist/src/core/npm-registry.d.ts +3 -0
  231. package/dist/src/core/npm-registry.js +5 -0
  232. package/dist/src/core/npm-registry.js.map +1 -0
  233. package/dist/src/core/pre-commit.d.ts +11 -0
  234. package/dist/src/core/pre-commit.js +22 -0
  235. package/dist/src/core/pre-commit.js.map +1 -0
  236. package/dist/src/core/profile-project.d.ts +23 -0
  237. package/dist/src/core/profile-project.js +119 -0
  238. package/dist/src/core/profile-project.js.map +1 -0
  239. package/dist/src/core/publish/html.d.ts +6 -0
  240. package/dist/src/core/publish/html.js +44 -0
  241. package/dist/src/core/publish/html.js.map +1 -0
  242. package/dist/src/core/read-dependencies.d.ts +2 -0
  243. package/dist/src/core/read-dependencies.js +24 -0
  244. package/dist/src/core/read-dependencies.js.map +1 -0
  245. package/dist/src/core/report-writer.d.ts +5 -0
  246. package/dist/src/core/report-writer.js +61 -0
  247. package/dist/src/core/report-writer.js.map +1 -0
  248. package/dist/src/core/report.d.ts +34 -0
  249. package/dist/src/core/report.js +26 -0
  250. package/dist/src/core/report.js.map +1 -0
  251. package/dist/src/core/risk-score.d.ts +5 -0
  252. package/dist/src/core/risk-score.js +14 -0
  253. package/dist/src/core/risk-score.js.map +1 -0
  254. package/dist/src/core/sbom/generate.d.ts +2 -0
  255. package/dist/src/core/sbom/generate.js +120 -0
  256. package/dist/src/core/sbom/generate.js.map +1 -0
  257. package/dist/src/core/scanner-context.d.ts +12 -0
  258. package/dist/src/core/scanner-context.js +27 -0
  259. package/dist/src/core/scanner-context.js.map +1 -0
  260. package/dist/src/core/score.d.ts +13 -0
  261. package/dist/src/core/score.js +44 -0
  262. package/dist/src/core/score.js.map +1 -0
  263. package/dist/src/core/security-doctor.d.ts +12 -0
  264. package/dist/src/core/security-doctor.js +158 -0
  265. package/dist/src/core/security-doctor.js.map +1 -0
  266. package/dist/src/core/security-patterns.d.ts +14 -0
  267. package/dist/src/core/security-patterns.js +139 -0
  268. package/dist/src/core/security-patterns.js.map +1 -0
  269. package/dist/src/core/typosquat.d.ts +6 -0
  270. package/dist/src/core/typosquat.js +50 -0
  271. package/dist/src/core/typosquat.js.map +1 -0
  272. package/dist/src/core/vault.d.ts +48 -0
  273. package/dist/src/core/vault.js +127 -0
  274. package/dist/src/core/vault.js.map +1 -0
  275. package/dist/src/core/watch/watch.d.ts +5 -0
  276. package/dist/src/core/watch/watch.js +49 -0
  277. package/dist/src/core/watch/watch.js.map +1 -0
  278. package/dist/src/errors/toolip-error.d.ts +8 -0
  279. package/dist/src/errors/toolip-error.js +11 -0
  280. package/dist/src/errors/toolip-error.js.map +1 -0
  281. package/dist/src/index.d.ts +2 -0
  282. package/dist/src/index.js +89 -0
  283. package/dist/src/index.js.map +1 -0
  284. package/dist/src/mcp/server.d.ts +1 -0
  285. package/dist/src/mcp/server.js +64 -0
  286. package/dist/src/mcp/server.js.map +1 -0
  287. package/dist/src/providers/depsdev/client.d.ts +71 -0
  288. package/dist/src/providers/depsdev/client.js +44 -0
  289. package/dist/src/providers/depsdev/client.js.map +1 -0
  290. package/dist/src/providers/osv/client.d.ts +15 -0
  291. package/dist/src/providers/osv/client.js +51 -0
  292. package/dist/src/providers/osv/client.js.map +1 -0
  293. package/dist/src/providers/osv/types.d.ts +38 -0
  294. package/dist/src/providers/osv/types.js +2 -0
  295. package/dist/src/providers/osv/types.js.map +1 -0
  296. package/dist/src/storage/memory-cache.d.ts +7 -0
  297. package/dist/src/storage/memory-cache.js +25 -0
  298. package/dist/src/storage/memory-cache.js.map +1 -0
  299. package/dist/src/utils/error-handler.d.ts +1 -0
  300. package/dist/src/utils/error-handler.js +24 -0
  301. package/dist/src/utils/error-handler.js.map +1 -0
  302. package/dist/src/utils/output.d.ts +6 -0
  303. package/dist/src/utils/output.js +72 -0
  304. package/dist/src/utils/output.js.map +1 -0
  305. package/dist/src/utils/package-output.d.ts +4 -0
  306. package/dist/src/utils/package-output.js +40 -0
  307. package/dist/src/utils/package-output.js.map +1 -0
  308. package/package.json +13 -8
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../../src/core/score.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,cAAc,CAAC,KAAuD;IACpF,MAAM,gBAAgB,GAAG,KAAK,CAAC,KAAK,EAAE,gBAAgB,IAAI,GAAG,CAAC,CAAC;IAC/D,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,EAAE,aAAa,IAAI,GAAG,CAAC,CAAC;IACzD,MAAM,qBAAqB,GAAG,KAAK,CAAC,KAAK,EAAE,qBAAqB,IAAI,GAAG,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,SAAS,IAAI,GAAG,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,CAAC,gBAAgB,GAAG,aAAa,GAAG,qBAAqB,GAAG,SAAS,CAAC,GAAG,CAAC,CAC3E,CAAC;IAEF,OAAO;QACL,gBAAgB;QAChB,aAAa;QACb,qBAAqB;QACrB,SAAS;QACT,OAAO;QACP,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC;KAC3B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAyB;IACjE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACjD,IAAI,OAAO,CAAC,QAAQ,KAAK,UAAU;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACvD,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACnD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACrD,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK;YAAE,OAAO,KAAK,GAAG,CAAC,CAAC;QACjD,OAAO,KAAK,GAAG,CAAC,CAAC;IACnB,CAAC,EAAE,CAAC,CAAC,CAAC;IAEN,OAAO,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,KAAK,CAAC,KAAa;IAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ToolipFinding } from './report.js';
2
+ export type SecurityDoctorResult = {
3
+ findings: ToolipFinding[];
4
+ summary: {
5
+ filesScanned: number;
6
+ secrets: number;
7
+ dangerousCode: number;
8
+ configuration: number;
9
+ headers: number;
10
+ };
11
+ };
12
+ export declare function runSecurityDoctor(root: string): Promise<SecurityDoctorResult>;
@@ -0,0 +1,158 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { analyzeAstSource } from '../analyzers/ast/source-analysis.js';
3
+ import { createScannerContext } from './scanner-context.js';
4
+ import { configSecurityPatterns, secretPatterns, securityHeaderNames } from './security-patterns.js';
5
+ const secretScanExtensions = new Set([
6
+ 'js',
7
+ 'jsx',
8
+ 'ts',
9
+ 'tsx',
10
+ 'mjs',
11
+ 'cjs',
12
+ 'json',
13
+ 'yml',
14
+ 'yaml',
15
+ 'env',
16
+ 'txt',
17
+ 'pem',
18
+ 'key'
19
+ ]);
20
+ const codeExtensions = new Set([
21
+ 'js',
22
+ 'jsx',
23
+ 'ts',
24
+ 'tsx',
25
+ 'mjs',
26
+ 'cjs'
27
+ ]);
28
+ export async function runSecurityDoctor(root) {
29
+ const context = await createScannerContext(root);
30
+ const findings = [];
31
+ for (const file of context.files) {
32
+ if (!shouldScanSecrets(file.relativePath, file.extension)) {
33
+ continue;
34
+ }
35
+ let content = '';
36
+ try {
37
+ content = await readFile(file.absolutePath, 'utf8');
38
+ }
39
+ catch {
40
+ continue;
41
+ }
42
+ findings.push(...scanContent(file.relativePath, content, secretPatterns));
43
+ if (codeExtensions.has(file.extension)) {
44
+ findings.push(...analyzeAstSource(file.relativePath, content).map((finding) => ({
45
+ id: finding.id,
46
+ title: finding.title,
47
+ severity: finding.severity,
48
+ category: finding.category,
49
+ message: finding.message,
50
+ recommendation: finding.remediation?.summary ??
51
+ 'Review the resolved AST finding.',
52
+ file: finding.location?.file,
53
+ evidence: finding.evidence?.[0]?.summary
54
+ })));
55
+ findings.push(...scanContent(file.relativePath, content, configSecurityPatterns));
56
+ }
57
+ }
58
+ findings.push(...detectMissingSecurityHeaders(context.files.map((file) => file.relativePath)));
59
+ return {
60
+ findings,
61
+ summary: {
62
+ filesScanned: context.files.length,
63
+ secrets: findings.filter((finding) => finding.category === 'secrets').length,
64
+ dangerousCode: findings.filter((finding) => finding.category === 'dangerous-code').length,
65
+ configuration: findings.filter((finding) => finding.category === 'configuration').length,
66
+ headers: findings.filter((finding) => finding.category === 'security-headers').length
67
+ }
68
+ };
69
+ }
70
+ function shouldScanSecrets(relativePath, extension) {
71
+ if (relativePath.endsWith('.d.ts'))
72
+ return false;
73
+ if (relativePath.endsWith('.map'))
74
+ return false;
75
+ if (relativePath.startsWith('dist/'))
76
+ return false;
77
+ if (relativePath.endsWith('.env'))
78
+ return true;
79
+ if (relativePath.includes('.env.'))
80
+ return true;
81
+ return secretScanExtensions.has(extension);
82
+ }
83
+ function scanContent(relativePath, content, patterns) {
84
+ const findings = [];
85
+ for (const pattern of patterns) {
86
+ pattern.regex.lastIndex = 0;
87
+ const match = pattern.regex.exec(content);
88
+ pattern.regex.lastIndex = 0;
89
+ if (!match) {
90
+ continue;
91
+ }
92
+ findings.push({
93
+ id: `${pattern.id}-${relativePath
94
+ .toUpperCase()
95
+ .replaceAll(/[^A-Z0-9]/g, '-')}`,
96
+ title: formatTitle(pattern, relativePath),
97
+ severity: resolveSeverity(pattern, relativePath),
98
+ category: pattern.category,
99
+ message: formatMessage(pattern, relativePath),
100
+ recommendation: pattern.recommendation,
101
+ file: relativePath,
102
+ evidence: redactEvidence(match[0])
103
+ });
104
+ }
105
+ return findings;
106
+ }
107
+ function isTestFile(relativePath) {
108
+ return (relativePath.startsWith('tests/') ||
109
+ relativePath.includes('/tests/') ||
110
+ relativePath.includes('/__tests__/') ||
111
+ /\.(test|spec)\.[cm]?[jt]sx?$/.test(relativePath));
112
+ }
113
+ function resolveSeverity(pattern, relativePath) {
114
+ if (pattern.category === 'secrets' &&
115
+ isTestFile(relativePath)) {
116
+ return 'low';
117
+ }
118
+ return pattern.severity;
119
+ }
120
+ function formatTitle(pattern, relativePath) {
121
+ if (pattern.category === 'secrets' &&
122
+ isTestFile(relativePath)) {
123
+ return `Potential test fixture: ${pattern.title}`;
124
+ }
125
+ return pattern.title;
126
+ }
127
+ function formatMessage(pattern, relativePath) {
128
+ if (pattern.category === 'secrets' &&
129
+ isTestFile(relativePath)) {
130
+ return `${pattern.message} This match is inside a test file, so Toolip reduced its severity. Confirm that it is synthetic fixture data.`;
131
+ }
132
+ return pattern.message;
133
+ }
134
+ function redactEvidence(value) {
135
+ if (value.length <= 16) {
136
+ return value;
137
+ }
138
+ return `${value.slice(0, 8)}...[redacted]...${value.slice(-4)}`;
139
+ }
140
+ function detectMissingSecurityHeaders(relativePaths) {
141
+ const possibleServerFiles = relativePaths.filter((file) => !file.startsWith('dist/') &&
142
+ /server|app|main|index|middleware/i.test(file) &&
143
+ /\.(js|ts|jsx|tsx|mjs|cjs)$/.test(file));
144
+ if (possibleServerFiles.length === 0) {
145
+ return [];
146
+ }
147
+ return securityHeaderNames.map((header) => ({
148
+ id: `TOOLIP-HEADER-VERIFY-${header
149
+ .toUpperCase()
150
+ .replaceAll('-', '_')}`,
151
+ title: `Verify security header: ${header}`,
152
+ severity: 'info',
153
+ category: 'security-headers',
154
+ message: `Toolip found server-like files. Confirm that ${header} is configured in production responses.`,
155
+ recommendation: 'Use Helmet or equivalent framework middleware to set secure HTTP response headers.'
156
+ }));
157
+ }
158
+ //# sourceMappingURL=security-doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-doctor.js","sourceRoot":"","sources":["../../../src/core/security-doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ToolipFinding } from './report.js';
2
+ export type SecurityPattern = {
3
+ id: string;
4
+ title: string;
5
+ category: string;
6
+ severity: ToolipFinding['severity'];
7
+ regex: RegExp;
8
+ message: string;
9
+ recommendation: string;
10
+ };
11
+ export declare const secretPatterns: SecurityPattern[];
12
+ export declare const dangerousCodePatterns: SecurityPattern[];
13
+ export declare const configSecurityPatterns: SecurityPattern[];
14
+ export declare const securityHeaderNames: string[];
@@ -0,0 +1,139 @@
1
+ export const secretPatterns = [
2
+ {
3
+ id: 'TOOLIP-SECRET-GITHUB-TOKEN',
4
+ title: 'GitHub token detected',
5
+ category: 'secrets',
6
+ severity: 'critical',
7
+ regex: /\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g,
8
+ message: 'A GitHub token-like secret was found.',
9
+ recommendation: 'Revoke the token, remove it from Git history, and store its replacement securely.'
10
+ },
11
+ {
12
+ id: 'TOOLIP-SECRET-AWS-ACCESS-KEY',
13
+ title: 'AWS access key detected',
14
+ category: 'secrets',
15
+ severity: 'critical',
16
+ regex: /\bAKIA[0-9A-Z]{16}\b/g,
17
+ message: 'An AWS access key-like value was found.',
18
+ recommendation: 'Rotate the credential immediately and audit its usage.'
19
+ },
20
+ {
21
+ id: 'TOOLIP-SECRET-PRIVATE-KEY',
22
+ title: 'Private key detected',
23
+ category: 'secrets',
24
+ severity: 'critical',
25
+ regex: /-----BEGIN (RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----/g,
26
+ message: 'Private key material was found.',
27
+ recommendation: 'Remove the key from the repository and rotate affected credentials.'
28
+ },
29
+ {
30
+ id: 'TOOLIP-SECRET-NPM-TOKEN',
31
+ title: 'npm token detected',
32
+ category: 'secrets',
33
+ severity: 'critical',
34
+ regex: /\bnpm_[A-Za-z0-9]{20,}\b/g,
35
+ message: 'An npm token-like value was found.',
36
+ recommendation: 'Rotate the token and store its replacement securely.'
37
+ },
38
+ {
39
+ id: 'TOOLIP-SECRET-HARDCODED-PASSWORD',
40
+ title: 'Hardcoded password detected',
41
+ category: 'secrets',
42
+ severity: 'high',
43
+ regex: /\b(password|passwd|pwd)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
44
+ message: 'A hardcoded password-like assignment was found.',
45
+ recommendation: 'Move passwords into environment variables or an encrypted secret manager.'
46
+ },
47
+ {
48
+ id: 'TOOLIP-SECRET-JWT-SECRET',
49
+ title: 'Hardcoded JWT secret detected',
50
+ category: 'secrets',
51
+ severity: 'high',
52
+ regex: /\b(jwtSecret|JWT_SECRET|jwt_secret)\s*[:=]\s*['"][^'"]{8,}['"]/g,
53
+ message: 'A hardcoded JWT secret was found.',
54
+ recommendation: 'Load a strong random secret from a secure runtime source.'
55
+ },
56
+ {
57
+ id: 'TOOLIP-SECRET-GENERIC-API-KEY',
58
+ title: 'Generic API key detected',
59
+ category: 'secrets',
60
+ severity: 'medium',
61
+ regex: /\b(apiKey|API_KEY|api_key)\s*[:=]\s*['"][A-Za-z0-9_-]{16,}['"]/g,
62
+ message: 'A hardcoded API key-like value was found.',
63
+ recommendation: 'Remove API keys from source code and rotate exposed credentials.'
64
+ }
65
+ ];
66
+ export const dangerousCodePatterns = [
67
+ {
68
+ id: 'TOOLIP-DANGEROUS-EVAL',
69
+ title: 'Dangerous eval usage',
70
+ category: 'dangerous-code',
71
+ severity: 'high',
72
+ regex: /\beval\s*\(/g,
73
+ message: 'eval() can execute arbitrary code and introduce injection risk.',
74
+ recommendation: 'Replace eval() with explicit parsing or safe control flow.'
75
+ },
76
+ {
77
+ id: 'TOOLIP-DANGEROUS-NEW-FUNCTION',
78
+ title: 'Dangerous Function constructor usage',
79
+ category: 'dangerous-code',
80
+ severity: 'high',
81
+ regex: /\bnew\s+Function\s*\(/g,
82
+ message: 'The Function constructor executes dynamic code.',
83
+ recommendation: 'Avoid runtime code generation and use explicit functions.'
84
+ },
85
+ {
86
+ id: 'TOOLIP-DANGEROUS-CHILD-PROCESS-EXEC',
87
+ title: 'Unsafe child_process exec usage',
88
+ category: 'dangerous-code',
89
+ severity: 'high',
90
+ regex: /(?:\bchild_process\s*\.\s*exec|(?<![\w.])exec)\s*\(/g,
91
+ message: 'Shell execution may become unsafe when untrusted input reaches the command.',
92
+ recommendation: 'Prefer execFile() or spawn() with argument arrays and strict validation.'
93
+ },
94
+ {
95
+ id: 'TOOLIP-DANGEROUS-EXECSYNC',
96
+ title: 'Unsafe execSync usage',
97
+ category: 'dangerous-code',
98
+ severity: 'high',
99
+ regex: /(?:\bchild_process\s*\.\s*execSync|(?<![\w.])execSync)\s*\(/g,
100
+ message: 'Synchronous shell execution can introduce injection and blocking risks.',
101
+ recommendation: 'Avoid shell execution or use safer process APIs with validated arguments.'
102
+ }
103
+ ];
104
+ export const configSecurityPatterns = [
105
+ {
106
+ id: 'TOOLIP-CONFIG-OPEN-CORS',
107
+ title: 'Open CORS policy detected',
108
+ category: 'configuration',
109
+ severity: 'medium',
110
+ regex: /\borigin\s*:\s*['"]\*['"]/g,
111
+ message: 'CORS origin is configured as "*".',
112
+ recommendation: 'Restrict allowed origins to trusted domains.'
113
+ },
114
+ {
115
+ id: 'TOOLIP-CONFIG-WEAK-JWT-SECRET',
116
+ title: 'Weak JWT secret detected',
117
+ category: 'configuration',
118
+ severity: 'high',
119
+ regex: /\b(jwtSecret|JWT_SECRET|jwt_secret)\s*[:=]\s*['"](secret|changeme|password|123456|devsecret)['"]/gi,
120
+ message: 'A weak JWT secret was detected.',
121
+ recommendation: 'Use a long, random, high-entropy secret.'
122
+ },
123
+ {
124
+ id: 'TOOLIP-CONFIG-LONG-JWT-EXPIRY',
125
+ title: 'Long-lived JWT expiry detected',
126
+ category: 'configuration',
127
+ severity: 'medium',
128
+ regex: /\b(expiresIn|JWT_EXPIRES_IN)\s*[:=]\s*['"](?:365d|999d|1000d|never|10y)['"]/gi,
129
+ message: 'A long-lived JWT expiry was detected.',
130
+ recommendation: 'Use short-lived access tokens and refresh-token rotation.'
131
+ }
132
+ ];
133
+ export const securityHeaderNames = [
134
+ 'content-security-policy',
135
+ 'strict-transport-security',
136
+ 'x-frame-options',
137
+ 'x-content-type-options'
138
+ ];
139
+ //# sourceMappingURL=security-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-patterns.js","sourceRoot":"","sources":["../../../src/core/security-patterns.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,cAAc,GAAsB;IAC/C;QACE,EAAE,EAAE,4BAA4B;QAChC,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,kCAAkC;QACzC,OAAO,EAAE,uCAAuC;QAChD,cAAc,EACZ,mFAAmF;KACtF;IACD;QACE,EAAE,EAAE,8BAA8B;QAClC,KAAK,EAAE,yBAAyB;QAChC,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,uBAAuB;QAC9B,OAAO,EAAE,yCAAyC;QAClD,cAAc,EACZ,wDAAwD;KAC3D;IACD;QACE,EAAE,EAAE,2BAA2B;QAC/B,KAAK,EAAE,sBAAsB;QAC7B,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,uDAAuD;QAC9D,OAAO,EAAE,iCAAiC;QAC1C,cAAc,EACZ,qEAAqE;KACxE;IACD;QACE,EAAE,EAAE,yBAAyB;QAC7B,KAAK,EAAE,oBAAoB;QAC3B,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,2BAA2B;QAClC,OAAO,EAAE,oCAAoC;QAC7C,cAAc,EACZ,sDAAsD;KACzD;IACD;QACE,EAAE,EAAE,kCAAkC;QACtC,KAAK,EAAE,6BAA6B;QACpC,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,sDAAsD;QAC7D,OAAO,EAAE,iDAAiD;QAC1D,cAAc,EACZ,2EAA2E;KAC9E;IACD;QACE,EAAE,EAAE,0BAA0B;QAC9B,KAAK,EAAE,+BAA+B;QACtC,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,iEAAiE;QACxE,OAAO,EAAE,mCAAmC;QAC5C,cAAc,EACZ,2DAA2D;KAC9D;IACD;QACE,EAAE,EAAE,+BAA+B;QACnC,KAAK,EAAE,0BAA0B;QACjC,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,iEAAiE;QACxE,OAAO,EAAE,2CAA2C;QACpD,cAAc,EACZ,kEAAkE;KACrE;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAsB;IACtD;QACE,EAAE,EAAE,uBAAuB;QAC3B,KAAK,EAAE,sBAAsB;QAC7B,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,cAAc;QACrB,OAAO,EACL,iEAAiE;QACnE,cAAc,EACZ,4DAA4D;KAC/D;IACD;QACE,EAAE,EAAE,+BAA+B;QACnC,KAAK,EAAE,sCAAsC;QAC7C,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,wBAAwB;QAC/B,OAAO,EACL,iDAAiD;QACnD,cAAc,EACZ,2DAA2D;KAC9D;IACD;QACE,EAAE,EAAE,qCAAqC;QACzC,KAAK,EAAE,iCAAiC;QACxC,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EACH,sDAAsD;QACxD,OAAO,EACL,6EAA6E;QAC/E,cAAc,EACZ,0EAA0E;KAC7E;IACD;QACE,EAAE,EAAE,2BAA2B;QAC/B,KAAK,EAAE,uBAAuB;QAC9B,QAAQ,EAAE,gBAAgB;QAC1B,QAAQ,EAAE,MAAM;QAChB,KAAK,EACH,8DAA8D;QAChE,OAAO,EACL,yEAAyE;QAC3E,cAAc,EACZ,2EAA2E;KAC9E;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAsB;IACvD;QACE,EAAE,EAAE,yBAAyB;QAC7B,KAAK,EAAE,2BAA2B;QAClC,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,4BAA4B;QACnC,OAAO,EAAE,mCAAmC;QAC5C,cAAc,EACZ,8CAA8C;KACjD;IACD;QACE,EAAE,EAAE,+BAA+B;QACnC,KAAK,EAAE,0BAA0B;QACjC,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,MAAM;QAChB,KAAK,EACH,oGAAoG;QACtG,OAAO,EAAE,iCAAiC;QAC1C,cAAc,EACZ,0CAA0C;KAC7C;IACD;QACE,EAAE,EAAE,+BAA+B;QACnC,KAAK,EAAE,gCAAgC;QACvC,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,QAAQ;QAClB,KAAK,EACH,+EAA+E;QACjF,OAAO,EAAE,uCAAuC;QAChD,cAAc,EACZ,2DAA2D;KAC9D;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,yBAAyB;IACzB,2BAA2B;IAC3B,iBAAiB;IACjB,wBAAwB;CACzB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export type TyposquatResult = {
2
+ input: string;
3
+ suspected: boolean;
4
+ suggestions: string[];
5
+ };
6
+ export declare function detectTyposquat(input: string): TyposquatResult;
@@ -0,0 +1,50 @@
1
+ const popularPackages = [
2
+ 'express',
3
+ 'fastify',
4
+ 'react',
5
+ 'vue',
6
+ 'axios',
7
+ 'got',
8
+ 'lodash',
9
+ 'typescript',
10
+ 'commander',
11
+ 'chalk',
12
+ 'zod',
13
+ 'prisma',
14
+ 'vite',
15
+ 'next',
16
+ 'nestjs'
17
+ ];
18
+ export function detectTyposquat(input) {
19
+ const normalized = input.trim().toLowerCase();
20
+ const suggestions = popularPackages
21
+ .map((candidate) => ({
22
+ candidate,
23
+ distance: levenshtein(normalized, candidate)
24
+ }))
25
+ .filter((item) => item.distance > 0 && item.distance <= 2)
26
+ .sort((a, b) => a.distance - b.distance)
27
+ .map((item) => item.candidate);
28
+ return {
29
+ input,
30
+ suspected: suggestions.length > 0,
31
+ suggestions
32
+ };
33
+ }
34
+ function levenshtein(a, b) {
35
+ const matrix = Array.from({ length: a.length + 1 }, (_, row) => Array.from({ length: b.length + 1 }, (_, col) => {
36
+ if (row === 0)
37
+ return col;
38
+ if (col === 0)
39
+ return row;
40
+ return 0;
41
+ }));
42
+ for (let row = 1; row <= a.length; row += 1) {
43
+ for (let col = 1; col <= b.length; col += 1) {
44
+ const cost = a[row - 1] === b[col - 1] ? 0 : 1;
45
+ matrix[row][col] = Math.min(matrix[row - 1][col] + 1, matrix[row][col - 1] + 1, matrix[row - 1][col - 1] + cost);
46
+ }
47
+ }
48
+ return matrix[a.length][b.length];
49
+ }
50
+ //# sourceMappingURL=typosquat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typosquat.js","sourceRoot":"","sources":["../../../src/core/typosquat.ts"],"names":[],"mappings":"AAMA,MAAM,eAAe,GAAG;IACtB,SAAS;IACT,SAAS;IACT,OAAO;IACP,KAAK;IACL,OAAO;IACP,KAAK;IACL,QAAQ;IACR,YAAY;IACZ,WAAW;IACX,OAAO;IACP,KAAK;IACL,QAAQ;IACR,MAAM;IACN,MAAM;IACN,QAAQ;CACT,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE9C,MAAM,WAAW,GAAG,eAAe;SAChC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACnB,SAAS;QACT,QAAQ,EAAE,WAAW,CAAC,UAAU,EAAE,SAAS,CAAC;KAC7C,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;SACzD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;SACvC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEjC,OAAO;QACL,KAAK;QACL,SAAS,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC;QACjC,WAAW;KACZ,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,CAAS,EAAE,CAAS;IACvC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAC7D,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAC9C,IAAI,GAAG,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC;QAC1B,IAAI,GAAG,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC;QAC1B,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CACH,CAAC;IAEF,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QAC5C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAE/C,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CACzB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EACxB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,EACxB,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAChC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,48 @@
1
+ export type VaultRecord = {
2
+ key: string;
3
+ value: string;
4
+ env: string;
5
+ updatedAt: string;
6
+ };
7
+ export type VaultFile = {
8
+ version: 1;
9
+ salt: string;
10
+ iv: string;
11
+ authTag: string;
12
+ data: string;
13
+ };
14
+ export type VaultData = {
15
+ secrets: VaultRecord[];
16
+ };
17
+ export declare function defaultVaultPath(): string;
18
+ export declare function initVault(masterPassword: string, vaultPath?: string): Promise<void>;
19
+ export declare function setSecret(input: {
20
+ key: string;
21
+ value: string;
22
+ env?: string;
23
+ masterPassword: string;
24
+ vaultPath?: string;
25
+ }): Promise<void>;
26
+ export declare function getSecret(input: {
27
+ key: string;
28
+ env?: string;
29
+ masterPassword: string;
30
+ vaultPath?: string;
31
+ }): Promise<VaultRecord>;
32
+ export declare function listSecrets(input: {
33
+ env?: string;
34
+ masterPassword: string;
35
+ vaultPath?: string;
36
+ }): Promise<VaultRecord[]>;
37
+ export declare function deleteSecret(input: {
38
+ key: string;
39
+ env?: string;
40
+ masterPassword: string;
41
+ vaultPath?: string;
42
+ }): Promise<boolean>;
43
+ export declare function exportEnv(input: {
44
+ env?: string;
45
+ masterPassword: string;
46
+ vaultPath?: string;
47
+ }): Promise<string>;
48
+ export declare function destroyVault(vaultPath?: string): Promise<void>;
@@ -0,0 +1,127 @@
1
+ import { mkdir, readFile, writeFile, rm } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import crypto from 'node:crypto';
4
+ import os from 'node:os';
5
+ import { ToolipError } from '../errors/toolip-error.js';
6
+ const algorithm = 'aes-256-gcm';
7
+ export function defaultVaultPath() {
8
+ return path.join(os.homedir(), '.toolip', 'vault.json');
9
+ }
10
+ export async function initVault(masterPassword, vaultPath = defaultVaultPath()) {
11
+ await writeEncryptedVault({ secrets: [] }, masterPassword, vaultPath);
12
+ }
13
+ export async function setSecret(input) {
14
+ const vaultPath = input.vaultPath ?? defaultVaultPath();
15
+ let data;
16
+ try {
17
+ data = await readEncryptedVault(input.masterPassword, vaultPath);
18
+ }
19
+ catch {
20
+ data = { secrets: [] };
21
+ }
22
+ const env = input.env ?? 'development';
23
+ const existing = data.secrets.find((secret) => secret.key === input.key && secret.env === env);
24
+ if (existing) {
25
+ existing.value = input.value;
26
+ existing.updatedAt = new Date().toISOString();
27
+ }
28
+ else {
29
+ data.secrets.push({
30
+ key: input.key,
31
+ value: input.value,
32
+ env,
33
+ updatedAt: new Date().toISOString()
34
+ });
35
+ }
36
+ await writeEncryptedVault(data, input.masterPassword, vaultPath);
37
+ }
38
+ export async function getSecret(input) {
39
+ const data = await readEncryptedVault(input.masterPassword, input.vaultPath ?? defaultVaultPath());
40
+ const env = input.env ?? 'development';
41
+ const secret = data.secrets.find((item) => item.key === input.key && item.env === env);
42
+ if (!secret) {
43
+ throw new ToolipError(`Secret not found: ${input.key}`, {
44
+ code: 'VAULT_SECRET_NOT_FOUND',
45
+ exitCode: 1
46
+ });
47
+ }
48
+ return secret;
49
+ }
50
+ export async function listSecrets(input) {
51
+ const data = await readEncryptedVault(input.masterPassword, input.vaultPath ?? defaultVaultPath());
52
+ const env = input.env;
53
+ return data.secrets
54
+ .filter((secret) => !env || secret.env === env)
55
+ .sort((a, b) => a.key.localeCompare(b.key));
56
+ }
57
+ export async function deleteSecret(input) {
58
+ const vaultPath = input.vaultPath ?? defaultVaultPath();
59
+ const data = await readEncryptedVault(input.masterPassword, vaultPath);
60
+ const env = input.env ?? 'development';
61
+ const before = data.secrets.length;
62
+ data.secrets = data.secrets.filter((secret) => !(secret.key === input.key && secret.env === env));
63
+ await writeEncryptedVault(data, input.masterPassword, vaultPath);
64
+ return data.secrets.length < before;
65
+ }
66
+ export async function exportEnv(input) {
67
+ const secrets = await listSecrets(input);
68
+ return secrets.map((secret) => `${secret.key}="${escapeEnv(secret.value)}"`).join('\n');
69
+ }
70
+ export async function destroyVault(vaultPath = defaultVaultPath()) {
71
+ await rm(vaultPath, { force: true });
72
+ }
73
+ async function readEncryptedVault(masterPassword, vaultPath) {
74
+ let raw = '';
75
+ try {
76
+ raw = await readFile(vaultPath, 'utf8');
77
+ }
78
+ catch {
79
+ throw new ToolipError('Vault not initialized. Run toolip vault init first.', {
80
+ code: 'VAULT_NOT_INITIALIZED',
81
+ exitCode: 1
82
+ });
83
+ }
84
+ const parsed = JSON.parse(raw);
85
+ try {
86
+ const key = deriveKey(masterPassword, Buffer.from(parsed.salt, 'base64'));
87
+ const decipher = crypto.createDecipheriv(algorithm, key, Buffer.from(parsed.iv, 'base64'));
88
+ decipher.setAuthTag(Buffer.from(parsed.authTag, 'base64'));
89
+ const decrypted = Buffer.concat([
90
+ decipher.update(Buffer.from(parsed.data, 'base64')),
91
+ decipher.final()
92
+ ]);
93
+ return JSON.parse(decrypted.toString('utf8'));
94
+ }
95
+ catch {
96
+ throw new ToolipError('Invalid vault password or corrupted vault.', {
97
+ code: 'VAULT_DECRYPT_FAILED',
98
+ exitCode: 1
99
+ });
100
+ }
101
+ }
102
+ async function writeEncryptedVault(data, masterPassword, vaultPath) {
103
+ await mkdir(path.dirname(vaultPath), { recursive: true });
104
+ const salt = crypto.randomBytes(16);
105
+ const iv = crypto.randomBytes(12);
106
+ const key = deriveKey(masterPassword, salt);
107
+ const cipher = crypto.createCipheriv(algorithm, key, iv);
108
+ const encrypted = Buffer.concat([
109
+ cipher.update(JSON.stringify(data), 'utf8'),
110
+ cipher.final()
111
+ ]);
112
+ const file = {
113
+ version: 1,
114
+ salt: salt.toString('base64'),
115
+ iv: iv.toString('base64'),
116
+ authTag: cipher.getAuthTag().toString('base64'),
117
+ data: encrypted.toString('base64')
118
+ };
119
+ await writeFile(vaultPath, `${JSON.stringify(file, null, 2)}\n`, 'utf8');
120
+ }
121
+ function deriveKey(masterPassword, salt) {
122
+ return crypto.scryptSync(masterPassword, salt, 32);
123
+ }
124
+ function escapeEnv(value) {
125
+ return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
126
+ }
127
+ //# sourceMappingURL=vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.js","sourceRoot":"","sources":["../../../src/core/vault.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export type WatchOptions = {
2
+ debounceMs?: number;
3
+ ignored?: RegExp[];
4
+ };
5
+ export declare function watchProject(root: string, onChange: () => Promise<void>, options?: WatchOptions): () => void;
@@ -0,0 +1,49 @@
1
+ import { watch } from 'node:fs';
2
+ import path from 'node:path';
3
+ export function watchProject(root, onChange, options = {}) {
4
+ const debounceMs = options.debounceMs ?? 500;
5
+ const ignored = options.ignored ?? [
6
+ /(^|\/)node_modules(\/|$)/,
7
+ /(^|\/)\.git(\/|$)/,
8
+ /(^|\/)dist(\/|$)/,
9
+ /(^|\/)\.toolip-report(\/|$)/
10
+ ];
11
+ let timer;
12
+ let running = false;
13
+ let queued = false;
14
+ const run = async () => {
15
+ if (running) {
16
+ queued = true;
17
+ return;
18
+ }
19
+ running = true;
20
+ try {
21
+ await onChange();
22
+ }
23
+ finally {
24
+ running = false;
25
+ if (queued) {
26
+ queued = false;
27
+ await run();
28
+ }
29
+ }
30
+ };
31
+ const watcher = watch(root, { recursive: true }, (_event, filename) => {
32
+ if (!filename)
33
+ return;
34
+ const normalized = filename.toString().replaceAll(path.sep, '/');
35
+ if (ignored.some((pattern) => pattern.test(normalized)))
36
+ return;
37
+ if (timer)
38
+ clearTimeout(timer);
39
+ timer = setTimeout(() => {
40
+ void run();
41
+ }, debounceMs);
42
+ });
43
+ return () => {
44
+ if (timer)
45
+ clearTimeout(timer);
46
+ watcher.close();
47
+ };
48
+ }
49
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../../src/core/watch/watch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,IAAI,MAAM,WAAW,CAAC;AAO7B,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,QAA6B,EAC7B,UAAwB,EAAE;IAE1B,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,CAAC;IAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI;QACjC,0BAA0B;QAC1B,mBAAmB;QACnB,kBAAkB;QAClB,6BAA6B;KAC9B,CAAC;IAEF,IAAI,KAAiC,CAAC;IACtC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,GAAG,GAAG,KAAK,IAAmB,EAAE;QACpC,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,GAAG,IAAI,CAAC;YACd,OAAO;QACT,CAAC;QAED,OAAO,GAAG,IAAI,CAAC;QAEf,IAAI,CAAC;YACH,MAAM,QAAQ,EAAE,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,OAAO,GAAG,KAAK,CAAC;YAEhB,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,GAAG,KAAK,CAAC;gBACf,MAAM,GAAG,EAAE,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE;QACpE,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACjE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAAE,OAAO;QAEhE,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YACtB,KAAK,GAAG,EAAE,CAAC;QACb,CAAC,EAAE,UAAU,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,EAAE;QACV,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC,CAAC;AACJ,CAAC"}