@cdxgen/cdxgen 13.3.0 → 13.5.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 (372) hide show
  1. package/README.md +12 -9
  2. package/bin/cdxgen-secure.js +15 -0
  3. package/bin/cdxgen.js +115 -31
  4. package/bin/evinse.js +23 -1
  5. package/bin/hbom.js +15 -7
  6. package/bin/repl.js +115 -0
  7. package/bin/sign.js +45 -15
  8. package/bin/tracebom.js +5 -1
  9. package/bin/validate.js +84 -18
  10. package/bin/verify.js +155 -86
  11. package/data/cbomosdb-queries.json +13 -1
  12. package/data/component-tags.json +8 -0
  13. package/data/helpers/init.gradle +46 -21
  14. package/data/queries-darwin.json +25 -1
  15. package/data/queries-win.json +19 -1
  16. package/data/queries.json +41 -0
  17. package/data/remediations.json +344 -1
  18. package/data/rules/cbom-security.yaml +235 -4
  19. package/data/rules/dependency-sources.yaml +67 -0
  20. package/data/rules/go-binaries.yaml +46 -0
  21. package/data/rules/golem-go.yaml +80 -0
  22. package/data/rules/hbom-compliance.yaml +40 -22
  23. package/data/rules/hbom-performance.yaml +7 -1
  24. package/data/rules/host-topology.yaml +1 -1
  25. package/data/rules/obom-runtime.yaml +31 -2
  26. package/data/rules/php-runtime.yaml +143 -0
  27. package/data/rules/scala-evidence.yaml +115 -0
  28. package/lib/audit/index.js +52 -6
  29. package/lib/cli/bomAssembly.js +28 -3
  30. package/lib/cli/cliOptions.js +110 -3
  31. package/lib/cli/index.js +186 -58
  32. package/lib/cli/jsBom.js +50 -29
  33. package/lib/cli/jvmBom.js +779 -146
  34. package/lib/cli/managedBom.js +1021 -261
  35. package/lib/cli/nativeBom.js +364 -58
  36. package/lib/core/activity.js +12 -0
  37. package/lib/core/env.js +47 -17
  38. package/lib/core/fs.js +31 -21
  39. package/lib/core/httpClient.js +233 -69
  40. package/lib/core/pluginRun.js +184 -0
  41. package/lib/core/processTree.js +100 -0
  42. package/lib/core/projectConfig.js +1 -0
  43. package/lib/core/projectTooling.js +97 -0
  44. package/lib/core/propertySanitizer.js +72 -0
  45. package/lib/core/runState.js +39 -0
  46. package/lib/core/toml.js +72 -0
  47. package/lib/ecosystems/asarutils.js +4 -2
  48. package/lib/ecosystems/bunutils.js +5 -7
  49. package/lib/ecosystems/cargoCache.js +231 -8
  50. package/lib/ecosystems/cmakeResolver.js +10 -21
  51. package/lib/ecosystems/cppBuildContext.js +631 -0
  52. package/lib/ecosystems/cppEvidence.js +337 -22
  53. package/lib/ecosystems/cppIncludeResolver.js +294 -0
  54. package/lib/ecosystems/denoutils.js +93 -66
  55. package/lib/ecosystems/ecosystems.js +1967 -788
  56. package/lib/ecosystems/golem.js +578 -18
  57. package/lib/ecosystems/gradleutils.js +340 -46
  58. package/lib/ecosystems/jsEvidence.js +85 -24
  59. package/lib/ecosystems/kosi.js +21 -4
  60. package/lib/ecosystems/npmutils.js +64 -0
  61. package/lib/ecosystems/parsers-dotnet.js +668 -153
  62. package/lib/ecosystems/parsers-elm.js +46 -28
  63. package/lib/ecosystems/parsers-gleam.js +3 -4
  64. package/lib/ecosystems/parsers-go.js +1283 -297
  65. package/lib/ecosystems/parsers-js.js +92 -26
  66. package/lib/ecosystems/parsers-julia.js +2 -3
  67. package/lib/ecosystems/parsers-jvm.js +463 -29
  68. package/lib/ecosystems/parsers-misc.js +405 -93
  69. package/lib/ecosystems/parsers-python.js +152 -20
  70. package/lib/ecosystems/parsers-rust.js +4 -4
  71. package/lib/ecosystems/parsers-terraform.js +1573 -19
  72. package/lib/ecosystems/pythonutils.js +102 -6
  73. package/lib/ecosystems/remote/huggingface.js +3 -0
  74. package/lib/ecosystems/rubyutils.js +73 -20
  75. package/lib/ecosystems/rusi.js +32 -9
  76. package/lib/ecosystems/sbtutils.js +243 -187
  77. package/lib/ecosystems/scalacliutils.js +343 -0
  78. package/lib/ecosystems/scalasem.js +2620 -0
  79. package/lib/ecosystems/terraformRegistry.js +288 -0
  80. package/lib/ecosystems/utils.js +2 -0
  81. package/lib/ecosystems/vendoredCode.js +156 -0
  82. package/lib/evinser/evinser.js +695 -78
  83. package/lib/evinser/swiftsem.js +68 -5
  84. package/lib/helpers/agenticToolutils.js +2 -2
  85. package/lib/helpers/bomSigner.js +576 -128
  86. package/lib/inventory/agentSkillSpec.js +17 -0
  87. package/lib/inventory/aiCollector.js +4 -1
  88. package/lib/inventory/analyzer.js +110 -127
  89. package/lib/inventory/apkInstalledDb.js +243 -0
  90. package/lib/inventory/atomUtils.js +204 -48
  91. package/lib/inventory/auditCategories.js +10 -3
  92. package/lib/inventory/buildToolRateLimit.js +144 -0
  93. package/lib/inventory/cacheCommands.js +2 -1
  94. package/lib/inventory/cacheDir.js +52 -9
  95. package/lib/inventory/certificates.js +2371 -0
  96. package/lib/inventory/cmakeBuildDirs.js +254 -0
  97. package/lib/inventory/communityAiConfigParser.js +4 -9
  98. package/lib/inventory/deps.js +507 -128
  99. package/lib/inventory/display.js +200 -3
  100. package/lib/inventory/dosai.js +747 -101
  101. package/lib/inventory/dosaiParsers.js +310 -15
  102. package/lib/inventory/dynamic.js +96 -8
  103. package/lib/inventory/envcontext.js +168 -5
  104. package/lib/inventory/evidenceUtils.js +590 -132
  105. package/lib/inventory/fetchBatch.js +574 -38
  106. package/lib/inventory/fetchDiskCache.js +597 -0
  107. package/lib/inventory/forgeEnricher.js +14 -5
  108. package/lib/inventory/formulationParsers.js +3 -2
  109. package/lib/inventory/goBuildInfo.js +140 -0
  110. package/lib/inventory/hbom.js +67 -7
  111. package/lib/inventory/hbomAnalysis.js +16 -0
  112. package/lib/inventory/hostTopology.js +21 -0
  113. package/lib/inventory/jvmLocalRepos.js +917 -0
  114. package/lib/inventory/mcpConfigParser.js +2 -3
  115. package/lib/inventory/osPackagePurl.js +244 -0
  116. package/lib/inventory/osPackageResolver.js +89 -87
  117. package/lib/inventory/osinfo.js +79 -31
  118. package/lib/inventory/osqueryTransform.js +114 -5
  119. package/lib/inventory/parentSelection.js +146 -0
  120. package/lib/inventory/phpBuildInfo.js +487 -0
  121. package/lib/inventory/phpHostProbe.js +641 -0
  122. package/lib/inventory/rootfsCerts.js +426 -0
  123. package/lib/inventory/rustFormulationParser.js +3 -4
  124. package/lib/inventory/scalaCoords.js +153 -0
  125. package/lib/inventory/source.js +215 -11
  126. package/lib/inventory/spdx.js +245 -0
  127. package/lib/inventory/traceRunner.js +93 -8
  128. package/lib/inventory/tracedCrypto.js +423 -0
  129. package/lib/managers/binary.js +529 -183
  130. package/lib/managers/docker.js +199 -44
  131. package/lib/managers/oci.js +24 -2
  132. package/lib/parsers/cmakeCache.js +69 -0
  133. package/lib/parsers/cmakeLists.js +16 -2
  134. package/lib/parsers/cmakePresets.js +400 -0
  135. package/lib/parsers/compileCommands.js +557 -0
  136. package/lib/parsers/email.js +277 -0
  137. package/lib/parsers/largeJson.js +34 -2
  138. package/lib/parsers/strictJson.js +322 -0
  139. package/lib/parsers/terraformConfig.js +1073 -0
  140. package/lib/parsers/terraformSource.js +652 -0
  141. package/lib/server/server.js +209 -1
  142. package/lib/stages/postgen/annotator.js +17 -1
  143. package/lib/stages/postgen/introspection/markers.js +1 -1
  144. package/lib/stages/postgen/introspection/reflect.js +4 -1
  145. package/lib/stages/postgen/postgen.js +20 -6
  146. package/lib/stages/postgen/ruleEngine.js +58 -1
  147. package/lib/stages/postgen/specVersionCompat.js +62 -0
  148. package/lib/stages/pregen/pregen.js +117 -5
  149. package/lib/validator/bomValidator.js +26 -5
  150. package/lib/validator/generated/runtime.mjs +13 -0
  151. package/lib/validator/generated/validate-1.6.mjs +26 -7
  152. package/lib/validator/generated/validate-1.7.mjs +31 -12
  153. package/lib/validator/generated/validate-2.0.mjs +30 -11
  154. package/lib/validator/index.js +25 -10
  155. package/lib/validator/reporters/json.js +1 -0
  156. package/package.json +23 -23
  157. package/types/bin/cdxgen-secure.d.ts +3 -0
  158. package/types/bin/cdxgen-secure.d.ts.map +1 -0
  159. package/types/bin/repl.d.ts.map +1 -1
  160. package/types/lib/audit/index.d.ts.map +1 -1
  161. package/types/lib/cli/bomAssembly.d.ts +9 -2
  162. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  163. package/types/lib/cli/cliOptions.d.ts +43 -0
  164. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  165. package/types/lib/cli/index.d.ts.map +1 -1
  166. package/types/lib/cli/jsBom.d.ts.map +1 -1
  167. package/types/lib/cli/jvmBom.d.ts +44 -1
  168. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  169. package/types/lib/cli/managedBom.d.ts +7 -4
  170. package/types/lib/cli/managedBom.d.ts.map +1 -1
  171. package/types/lib/cli/nativeBom.d.ts +3 -1
  172. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  173. package/types/lib/core/activity.d.ts.map +1 -1
  174. package/types/lib/core/env.d.ts +27 -2
  175. package/types/lib/core/env.d.ts.map +1 -1
  176. package/types/lib/core/fs.d.ts.map +1 -1
  177. package/types/lib/core/httpClient.d.ts +13 -8
  178. package/types/lib/core/httpClient.d.ts.map +1 -1
  179. package/types/lib/core/pluginRun.d.ts +97 -0
  180. package/types/lib/core/pluginRun.d.ts.map +1 -0
  181. package/types/lib/core/processTree.d.ts +36 -0
  182. package/types/lib/core/processTree.d.ts.map +1 -0
  183. package/types/lib/core/projectConfig.d.ts.map +1 -1
  184. package/types/lib/core/projectTooling.d.ts +41 -0
  185. package/types/lib/core/projectTooling.d.ts.map +1 -0
  186. package/types/lib/core/propertySanitizer.d.ts +26 -0
  187. package/types/lib/core/propertySanitizer.d.ts.map +1 -1
  188. package/types/lib/core/runState.d.ts +29 -0
  189. package/types/lib/core/runState.d.ts.map +1 -0
  190. package/types/lib/core/toml.d.ts +20 -0
  191. package/types/lib/core/toml.d.ts.map +1 -0
  192. package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
  193. package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
  194. package/types/lib/ecosystems/cargoCache.d.ts +12 -0
  195. package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
  196. package/types/lib/ecosystems/cmakeResolver.d.ts +5 -3
  197. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
  198. package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
  199. package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
  200. package/types/lib/ecosystems/cppEvidence.d.ts +19 -3
  201. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  202. package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
  203. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
  204. package/types/lib/ecosystems/denoutils.d.ts +9 -3
  205. package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
  206. package/types/lib/ecosystems/ecosystems.d.ts +62 -13
  207. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  208. package/types/lib/ecosystems/golem.d.ts +81 -1
  209. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  210. package/types/lib/ecosystems/gradleutils.d.ts +59 -7
  211. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  212. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  213. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  214. package/types/lib/ecosystems/npmutils.d.ts +15 -0
  215. package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
  216. package/types/lib/ecosystems/parsers-dotnet.d.ts +155 -5
  217. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  218. package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
  219. package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
  220. package/types/lib/ecosystems/parsers-go.d.ts +119 -5
  221. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  222. package/types/lib/ecosystems/parsers-js.d.ts +6 -1
  223. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  224. package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
  225. package/types/lib/ecosystems/parsers-jvm.d.ts +74 -3
  226. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  227. package/types/lib/ecosystems/parsers-misc.d.ts +21 -59
  228. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  229. package/types/lib/ecosystems/parsers-python.d.ts +57 -6
  230. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  231. package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
  232. package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
  233. package/types/lib/ecosystems/pythonutils.d.ts +26 -1
  234. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  235. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  236. package/types/lib/ecosystems/rubyutils.d.ts +21 -1
  237. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  238. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  239. package/types/lib/ecosystems/sbtutils.d.ts +88 -2
  240. package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
  241. package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
  242. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
  243. package/types/lib/ecosystems/scalasem.d.ts +311 -0
  244. package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
  245. package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
  246. package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
  247. package/types/lib/ecosystems/utils.d.ts +2 -2
  248. package/types/lib/ecosystems/utils.d.ts.map +1 -1
  249. package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
  250. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
  251. package/types/lib/evinser/evinser.d.ts +100 -8
  252. package/types/lib/evinser/evinser.d.ts.map +1 -1
  253. package/types/lib/evinser/swiftsem.d.ts +10 -0
  254. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  255. package/types/lib/helpers/bomSigner.d.ts +80 -4
  256. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  257. package/types/lib/inventory/agentSkillSpec.d.ts +13 -0
  258. package/types/lib/inventory/agentSkillSpec.d.ts.map +1 -0
  259. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  260. package/types/lib/inventory/analyzer.d.ts.map +1 -1
  261. package/types/lib/inventory/apkInstalledDb.d.ts +42 -0
  262. package/types/lib/inventory/apkInstalledDb.d.ts.map +1 -0
  263. package/types/lib/inventory/atomUtils.d.ts +96 -10
  264. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  265. package/types/lib/inventory/auditCategories.d.ts +3 -0
  266. package/types/lib/inventory/auditCategories.d.ts.map +1 -1
  267. package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
  268. package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
  269. package/types/lib/inventory/cacheCommands.d.ts +2 -1
  270. package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
  271. package/types/lib/inventory/cacheDir.d.ts +12 -4
  272. package/types/lib/inventory/cacheDir.d.ts.map +1 -1
  273. package/types/lib/inventory/certificates.d.ts +205 -0
  274. package/types/lib/inventory/certificates.d.ts.map +1 -0
  275. package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
  276. package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
  277. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  278. package/types/lib/inventory/deps.d.ts +61 -2
  279. package/types/lib/inventory/deps.d.ts.map +1 -1
  280. package/types/lib/inventory/display.d.ts +18 -0
  281. package/types/lib/inventory/display.d.ts.map +1 -1
  282. package/types/lib/inventory/dosai.d.ts +202 -14
  283. package/types/lib/inventory/dosai.d.ts.map +1 -1
  284. package/types/lib/inventory/dosaiParsers.d.ts +53 -7
  285. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  286. package/types/lib/inventory/dynamic.d.ts +16 -1
  287. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  288. package/types/lib/inventory/envcontext.d.ts +40 -2
  289. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  290. package/types/lib/inventory/evidenceUtils.d.ts +48 -14
  291. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  292. package/types/lib/inventory/fetchBatch.d.ts +83 -14
  293. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  294. package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
  295. package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
  296. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
  297. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  298. package/types/lib/inventory/goBuildInfo.d.ts +10 -0
  299. package/types/lib/inventory/goBuildInfo.d.ts.map +1 -0
  300. package/types/lib/inventory/hbom.d.ts.map +1 -1
  301. package/types/lib/inventory/hbomAnalysis.d.ts +10 -0
  302. package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -1
  303. package/types/lib/inventory/hostTopology.d.ts.map +1 -1
  304. package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
  305. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
  306. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  307. package/types/lib/inventory/osPackagePurl.d.ts +99 -0
  308. package/types/lib/inventory/osPackagePurl.d.ts.map +1 -0
  309. package/types/lib/inventory/osPackageResolver.d.ts +6 -2
  310. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
  311. package/types/lib/inventory/osinfo.d.ts +31 -6
  312. package/types/lib/inventory/osinfo.d.ts.map +1 -1
  313. package/types/lib/inventory/osqueryTransform.d.ts +51 -0
  314. package/types/lib/inventory/osqueryTransform.d.ts.map +1 -1
  315. package/types/lib/inventory/parentSelection.d.ts +34 -0
  316. package/types/lib/inventory/parentSelection.d.ts.map +1 -0
  317. package/types/lib/inventory/phpBuildInfo.d.ts +142 -0
  318. package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -0
  319. package/types/lib/inventory/phpHostProbe.d.ts +35 -0
  320. package/types/lib/inventory/phpHostProbe.d.ts.map +1 -0
  321. package/types/lib/inventory/rootfsCerts.d.ts +27 -0
  322. package/types/lib/inventory/rootfsCerts.d.ts.map +1 -0
  323. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  324. package/types/lib/inventory/scalaCoords.d.ts +80 -0
  325. package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
  326. package/types/lib/inventory/source.d.ts +28 -0
  327. package/types/lib/inventory/source.d.ts.map +1 -1
  328. package/types/lib/inventory/spdx.d.ts +24 -0
  329. package/types/lib/inventory/spdx.d.ts.map +1 -1
  330. package/types/lib/inventory/traceRunner.d.ts +16 -1
  331. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  332. package/types/lib/inventory/tracedCrypto.d.ts +64 -0
  333. package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
  334. package/types/lib/managers/binary.d.ts +10 -0
  335. package/types/lib/managers/binary.d.ts.map +1 -1
  336. package/types/lib/managers/docker.d.ts +12 -0
  337. package/types/lib/managers/docker.d.ts.map +1 -1
  338. package/types/lib/managers/oci.d.ts +3 -1
  339. package/types/lib/managers/oci.d.ts.map +1 -1
  340. package/types/lib/parsers/cmakeCache.d.ts +16 -0
  341. package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
  342. package/types/lib/parsers/cmakeLists.d.ts +2 -1
  343. package/types/lib/parsers/cmakeLists.d.ts.map +1 -1
  344. package/types/lib/parsers/cmakePresets.d.ts +78 -0
  345. package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
  346. package/types/lib/parsers/compileCommands.d.ts +115 -0
  347. package/types/lib/parsers/compileCommands.d.ts.map +1 -0
  348. package/types/lib/parsers/email.d.ts +19 -0
  349. package/types/lib/parsers/email.d.ts.map +1 -0
  350. package/types/lib/parsers/largeJson.d.ts +13 -0
  351. package/types/lib/parsers/largeJson.d.ts.map +1 -1
  352. package/types/lib/parsers/strictJson.d.ts +46 -0
  353. package/types/lib/parsers/strictJson.d.ts.map +1 -0
  354. package/types/lib/parsers/terraformConfig.d.ts +70 -0
  355. package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
  356. package/types/lib/parsers/terraformSource.d.ts +66 -0
  357. package/types/lib/parsers/terraformSource.d.ts.map +1 -0
  358. package/types/lib/server/server.d.ts +8 -0
  359. package/types/lib/server/server.d.ts.map +1 -1
  360. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  361. package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -1
  362. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  363. package/types/lib/stages/postgen/ruleEngine.d.ts +7 -4
  364. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  365. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  366. package/types/lib/stages/pregen/pregen.d.ts +14 -1
  367. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  368. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  369. package/types/lib/validator/index.d.ts +8 -0
  370. package/types/lib/validator/index.d.ts.map +1 -1
  371. package/types/lib/validator/reporters/json.d.ts.map +1 -1
  372. package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Shared plumbing for plugin (rusi/golem/kosi) invocations: resolving the
3
+ * directory to analyze, and reporting a failed run.
4
+ */
5
+
6
+ import { isAbsolute, join, normalize, resolve, sep } from "node:path";
7
+ import process from "node:process";
8
+
9
+ import { DEBUG_MODE } from "./activity.js";
10
+ import { deferFailOnError } from "./deferredExit.js";
11
+ import { safeExistsSync } from "./fs.js";
12
+
13
+ /**
14
+ * The working directory, when a relative source argument names it.
15
+ *
16
+ * cdxgen is frequently launched with its working directory already set to the
17
+ * project (depscan does exactly that) while the path argument stays relative
18
+ * to some repository root, e.g. cwd `/work/repo/test/data/app` with argument
19
+ * `test/data/app`. A plain `path.resolve` then produces the doubled
20
+ * `/work/repo/test/data/app/test/data/app`. This recognises that shape and
21
+ * nothing looser: the argument's path segments must be the trailing segments
22
+ * of the working directory, so a mistyped argument run from some other
23
+ * project is never silently redirected to that project.
24
+ *
25
+ * @param {string} src The source path as the caller typed it.
26
+ * @param {string} [cwd] Working directory; defaults to `process.cwd()`.
27
+ * @returns {string|undefined} The absolute working directory when the
28
+ * argument names it, otherwise undefined.
29
+ */
30
+ export function cwdNamedByRelativeSource(src, cwd = process.cwd()) {
31
+ if (typeof src !== "string" || !src || isAbsolute(src)) {
32
+ return undefined;
33
+ }
34
+ // normalize() converts separators to the platform's, so one split on sep
35
+ // handles both "a/b" and "a\\b" on Windows; on POSIX a backslash is an
36
+ // ordinary file-name character and must not split.
37
+ const relParts = normalize(src)
38
+ .split(sep)
39
+ .filter((part) => part && part !== ".");
40
+ if (!relParts.length || relParts.includes("..")) {
41
+ return undefined;
42
+ }
43
+ const absCwd = resolve(cwd);
44
+ const cwdParts = absCwd.split(sep).filter(Boolean);
45
+ if (relParts.length > cwdParts.length) {
46
+ return undefined;
47
+ }
48
+ const tail = cwdParts.slice(cwdParts.length - relParts.length);
49
+ const caseInsensitive = process.platform === "win32";
50
+ const same = (a, b) =>
51
+ caseInsensitive ? a.toLowerCase() === b.toLowerCase() : a === b;
52
+ return relParts.every((part, i) => same(part, tail[i])) ? absCwd : undefined;
53
+ }
54
+
55
+ /**
56
+ * Resolve the source path argument once, at cdxgen's entry point.
57
+ *
58
+ * Everything downstream — the BOM generators, evinse, and the rusi/golem/kosi
59
+ * launchers — resolves the argument against the working directory, so the
60
+ * doubled-directory shape has to be corrected before any of them run;
61
+ * correcting it only in the plugin launchers leaves the main BOM built from a
62
+ * directory that does not exist.
63
+ *
64
+ * @param {string} src The source path as the caller typed it.
65
+ * @param {string} [cwd] Working directory; defaults to `process.cwd()`.
66
+ * @returns {{path: string, rewritten: boolean, missing: boolean}} `path` is
67
+ * the argument to use: unchanged when it resolves to an existing path, the
68
+ * working directory when the argument names it (`rewritten`), and otherwise
69
+ * unchanged with `missing` set.
70
+ */
71
+ export function resolveSourcePathArgument(src, cwd = process.cwd()) {
72
+ if (typeof src !== "string" || !src) {
73
+ return { path: src, rewritten: false, missing: false };
74
+ }
75
+ if (safeExistsSync(resolve(cwd, src))) {
76
+ return { path: src, rewritten: false, missing: false };
77
+ }
78
+ const named = cwdNamedByRelativeSource(src, cwd);
79
+ if (named) {
80
+ return { path: named, rewritten: true, missing: false };
81
+ }
82
+ return { path: src, rewritten: false, missing: true };
83
+ }
84
+
85
+ /**
86
+ * Resolve the directory a plugin should analyze.
87
+ *
88
+ * The entry point already corrects the doubled-directory shape (see
89
+ * resolveSourcePathArgument); this is the same rule for callers that reach a
90
+ * plugin launcher directly (evinse, the library API). An existing directory
91
+ * wins and an absolute path is never rewritten. Otherwise the working
92
+ * directory is used only when the argument names it AND it carries the
93
+ * project marker the plugin needs (a `Cargo.toml` for rusi, a `go.mod` for
94
+ * golem). Anything else keeps the resolved path so the plugin's own error
95
+ * names the directory that was actually attempted.
96
+ *
97
+ * @param {string} src The source path as the caller typed it.
98
+ * @param {string[]} markerFiles File names that, present in the working
99
+ * directory, identify it as the project the plugin should analyze.
100
+ * @returns {string} The directory to pass to the plugin.
101
+ */
102
+ export function resolvePluginSourceDir(src, markerFiles = []) {
103
+ const resolved = resolve(src);
104
+ if (safeExistsSync(resolved) || isAbsolute(src)) {
105
+ return resolved;
106
+ }
107
+ const cwd = cwdNamedByRelativeSource(src);
108
+ if (!cwd) {
109
+ return resolved;
110
+ }
111
+ for (const marker of markerFiles) {
112
+ if (marker && safeExistsSync(join(cwd, marker))) {
113
+ console.error(
114
+ `Resolved source directory ${resolved} does not exist; the working directory ${cwd} is the project the argument names (found ${marker}), using it instead.`,
115
+ );
116
+ return cwd;
117
+ }
118
+ }
119
+ return resolved;
120
+ }
121
+
122
+ /**
123
+ * Report a failed plugin run, keeping the two failure classes apart.
124
+ *
125
+ * A spawn error means the plugin binary itself could not run — not installed,
126
+ * not executable, blocked by the command policy — which is an installation
127
+ * problem. A non-zero exit status or a missing report means the plugin ran
128
+ * and the analysis failed, which must not be dressed up as an installation
129
+ * problem: the message names the directory and says the reachability
130
+ * evidence will be missing, because a silent degradation is what let a
131
+ * doubled `--dir` go unnoticed in the first place.
132
+ *
133
+ * Under `--fail-on-error` the failure additionally claims the process exit
134
+ * status through the deferred-exit contract.
135
+ *
136
+ * @param {Object} run What ran and how it failed.
137
+ * @param {string} run.tool Plugin name, e.g. "rusi".
138
+ * @param {string} run.ecosystem Ecosystem the plugin serves, e.g. "rust".
139
+ * @param {string} run.executable The binary that was invoked.
140
+ * @param {string[]} run.args The arguments it was invoked with.
141
+ * @param {string} run.dir The directory that was analyzed.
142
+ * @param {Object} run.result The spawn result.
143
+ * @param {string} run.outputFile The report file the plugin should have written.
144
+ * @param {Object} [run.options] CLI options, for the `--fail-on-error` contract.
145
+ * @returns {void}
146
+ */
147
+ export function reportPluginRunFailure({
148
+ tool,
149
+ ecosystem,
150
+ executable,
151
+ args,
152
+ dir,
153
+ result,
154
+ outputFile,
155
+ options,
156
+ }) {
157
+ const command = `${executable} ${(args || []).join(" ")}`.trim();
158
+ if (result?.error) {
159
+ console.error(
160
+ `${tool} plugin could not be executed for ${dir}: ${result.error.message}. Check if the ${tool} plugin was installed successfully.`,
161
+ );
162
+ } else {
163
+ const status =
164
+ typeof result?.status === "number" ? result.status : "unknown";
165
+ const reason = safeExistsSync(outputFile)
166
+ ? "exited unsuccessfully"
167
+ : "wrote no report";
168
+ console.error(
169
+ `${tool} analysis ${reason} for directory ${dir} (exit status ${status}); ${ecosystem} reachability evidence will be missing from the BOM.`,
170
+ );
171
+ }
172
+ if (DEBUG_MODE && (result?.stdout || result?.stderr)) {
173
+ console.error(result.stdout, result.stderr);
174
+ }
175
+ deferFailOnError(options, {
176
+ ecosystem,
177
+ tool,
178
+ detail: result?.error
179
+ ? `${tool} plugin could not be executed: ${result.error.message}`
180
+ : `${tool} analysis failed for directory ${dir}`,
181
+ exitCode: typeof result?.status === "number" ? result.status : undefined,
182
+ command,
183
+ });
184
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Helpers for external commands stopped by cdxgen's spawn timeout.
3
+ *
4
+ * Layer 0: this module imports nothing outside `lib/core`, so both the atom
5
+ * and the dosai runners (layer 2) can share it.
6
+ */
7
+
8
+ import { DEBUG_MODE } from "./activity.js";
9
+ import { safeSpawnSync } from "./fs.js";
10
+ import { isWin } from "./paths.js";
11
+
12
+ /**
13
+ * A duration for a message: seconds to one decimal below a minute, minutes to
14
+ * one decimal from there.
15
+ *
16
+ * @param {number} ms Duration in milliseconds
17
+ * @returns {string} Human-readable duration
18
+ */
19
+ export function formatDuration(ms) {
20
+ if (ms >= 60_000) {
21
+ const minutes = Math.round(ms / 6_000) / 10;
22
+ return `${minutes} minute${minutes === 1 ? "" : "s"}`;
23
+ }
24
+ return `${Math.round(ms / 100) / 10} seconds`;
25
+ }
26
+
27
+ /**
28
+ * Stop the descendants a timed-out run left behind on Windows.
29
+ *
30
+ * The spawn timeout terminates only the process cdxgen spawned, and Windows
31
+ * neither kills nor re-parents its children: a shell's command, a runtime's
32
+ * workers, or the build hosts a .NET analyzer starts keep running while still
33
+ * pointing at the dead process's pid. `taskkill /T` on that pid finds nothing,
34
+ * because the root is already gone. The live descendants are therefore found
35
+ * by parent pid in a process snapshot and stopped, limited to processes
36
+ * created after the run started. The root's own children must also predate
37
+ * its end: once the root is gone its pid can be handed to an unrelated
38
+ * process, whose children would otherwise look like the run's. Elsewhere this
39
+ * does nothing: an orphan is re-parented and can no longer be told apart.
40
+ *
41
+ * @param {number|undefined} rootPid pid of the process cdxgen spawned
42
+ * @param {number} startedAt Epoch milliseconds at which the run started
43
+ * @param {number} [endedAt] Epoch milliseconds at which the spawned process ended
44
+ * @param {string} [toolName] Name of the tool, for the debug message
45
+ * @returns {number[]} The pids that were stopped
46
+ */
47
+ export function reapProcessTree(
48
+ rootPid,
49
+ startedAt,
50
+ endedAt = Date.now(),
51
+ toolName = "external",
52
+ ) {
53
+ if (!isWin || !Number.isInteger(rootPid) || rootPid <= 0) {
54
+ return [];
55
+ }
56
+ // All three values are integers, so interpolating them cannot inject anything.
57
+ const since = Math.max(0, Math.floor(startedAt) - 1000);
58
+ const until = Math.max(since, Math.floor(endedAt) + 1000);
59
+ const script = [
60
+ `$root = ${rootPid}`,
61
+ `$since = [DateTimeOffset]::FromUnixTimeMilliseconds(${since}).UtcDateTime`,
62
+ `$until = [DateTimeOffset]::FromUnixTimeMilliseconds(${until}).UtcDateTime`,
63
+ "$children = @{}",
64
+ "foreach ($p in Get-CimInstance Win32_Process -Property ProcessId,ParentProcessId,CreationDate) {",
65
+ " if (-not $p.CreationDate) { continue }",
66
+ " $created = $p.CreationDate.ToUniversalTime()",
67
+ " if ($created -lt $since) { continue }",
68
+ " if ([int]$p.ParentProcessId -eq $root -and $created -gt $until) { continue }",
69
+ " $children[[int]$p.ParentProcessId] += @([int]$p.ProcessId)",
70
+ "}",
71
+ "$found = [System.Collections.Generic.List[int]]::new()",
72
+ "$queue = [System.Collections.Generic.Queue[int]]::new()",
73
+ "$queue.Enqueue($root)",
74
+ "while ($queue.Count) {",
75
+ " foreach ($child in @($children[$queue.Dequeue()])) {",
76
+ " if ($child -and -not $found.Contains($child)) { $found.Add($child); $queue.Enqueue($child) }",
77
+ " }",
78
+ "}",
79
+ "foreach ($child in $found) { Stop-Process -Id $child -Force -ErrorAction SilentlyContinue }",
80
+ "$found -join ','",
81
+ ].join("\n");
82
+ const result = safeSpawnSync(
83
+ "powershell",
84
+ ["-NoProfile", "-NonInteractive", "-Command", script],
85
+ { timeout: 60000 },
86
+ );
87
+ const reaped = `${result?.stdout || ""}`
88
+ .trim()
89
+ .split(",")
90
+ .map((pid) => Number.parseInt(pid, 10))
91
+ .filter((pid) => pid > 0);
92
+ if (DEBUG_MODE) {
93
+ console.log(
94
+ reaped.length
95
+ ? `Stopped ${reaped.length} process(es) the timed-out ${toolName} run left behind: ${reaped.join(", ")}.`
96
+ : `The timed-out ${toolName} run left no processes behind.`,
97
+ );
98
+ }
99
+ return reaped;
100
+ }
@@ -45,6 +45,7 @@ const ANNOUNCED_OPTIONS = new Set([
45
45
  "api-key",
46
46
  "include-formulation",
47
47
  "install-deps",
48
+ "introspect",
48
49
  "deep",
49
50
  "tea-publish",
50
51
  "tea-fetch",
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Policy for running the scanned project's own build tooling.
3
+ *
4
+ * Build tools such as Maven, Gradle, Poetry, MSBuild, SwiftPM, Leiningen and
5
+ * CocoaPods read configuration or run code that ships with the project
6
+ * (`.mvn/jvm.config`, `.poetry/plugins`, `Directory.Build.rsp`, `Package.swift`,
7
+ * `project.clj`, podspecs). Running them on an untrusted project runs that
8
+ * project's code, so they belong to the same surface as dependency
9
+ * installation and are skipped whenever installation is disabled.
10
+ */
11
+ import { isSecureMode, readEnvironmentVariable } from "./activity.js";
12
+ import { recordDegradation } from "./buildLedger.js";
13
+
14
+ /**
15
+ * Whether secure mode is on right now. `isSecureMode` is read once when the
16
+ * modules load, but the `cdxgen-secure` command turns secure mode on later,
17
+ * by setting CDXGEN_SECURE_MODE before the scan starts.
18
+ *
19
+ * @returns {boolean} true when secure mode is on
20
+ */
21
+ export function isSecureModeActive() {
22
+ return (
23
+ isSecureMode ||
24
+ ["true", "1"].includes(readEnvironmentVariable("CDXGEN_SECURE_MODE"))
25
+ );
26
+ }
27
+
28
+ /**
29
+ * Whether the scan may run the scanned project's own build tooling, such as
30
+ * wrapper scripts or build definitions that Maven, Gradle, sbt, Mill, Poetry,
31
+ * PDM, MSBuild, SwiftPM, Leiningen and CocoaPods evaluate.
32
+ *
33
+ * Tooling follows `options.installDeps`, which defaults to off in secure mode
34
+ * when a caller does not set it. Introspection mode exists to observe the
35
+ * project's own toolchain, so it keeps that tooling on even when dependency
36
+ * installation is disabled, as long as the operator asked for it rather than
37
+ * a config file in the scanned project. Secure mode still wins:
38
+ * CDXGEN_INTROSPECT alone must not make a secure-mode scan run the scanned
39
+ * project's code.
40
+ *
41
+ * @param {Object} [options] CLI options
42
+ * @returns {boolean} true when project tooling may run
43
+ */
44
+ export function isProjectToolingAllowed(options) {
45
+ const secureMode = isSecureModeActive();
46
+ const installDeps = options?.installDeps ?? !secureMode;
47
+ if (installDeps !== false) {
48
+ return true;
49
+ }
50
+ return (
51
+ options?.introspect === true &&
52
+ options?.introspectFromConfigFile !== true &&
53
+ !secureMode
54
+ );
55
+ }
56
+
57
+ // The skips already reported for each scan, keyed by the scan's options.
58
+ // Callers without options share one key.
59
+ const reportedSkips = new WeakMap();
60
+ const noOptionsKey = {};
61
+
62
+ /**
63
+ * Tell the user that a tool was skipped because project tooling is not
64
+ * allowed, and record the matching degradation for the fidelity report.
65
+ * Each skip is reported once per scan, however many manifests it applies to.
66
+ * A skip that only costs evidence, not BOM content, passes no remediation id
67
+ * and is only shown.
68
+ *
69
+ * @param {Object} options CLI options of the scan
70
+ * @param {string|null} remediationId Remediation id from
71
+ * data/remediations.json, or null for a message only
72
+ * @param {string} message Console message shown to the user
73
+ * @param {Object} [fields] Degradation fields (ecosystem, tool, impact, detail)
74
+ * @returns {void}
75
+ */
76
+ export function reportProjectToolingSkipped(
77
+ options,
78
+ remediationId,
79
+ message,
80
+ fields,
81
+ ) {
82
+ const key = options && typeof options === "object" ? options : noOptionsKey;
83
+ let reported = reportedSkips.get(key);
84
+ if (!reported) {
85
+ reported = new Set();
86
+ reportedSkips.set(key, reported);
87
+ }
88
+ const skipKey = remediationId || message;
89
+ if (reported.has(skipKey)) {
90
+ return;
91
+ }
92
+ reported.add(skipKey);
93
+ console.log(message);
94
+ if (remediationId) {
95
+ recordDegradation(remediationId, fields);
96
+ }
97
+ }
@@ -26,6 +26,15 @@ const JSON_PROPERTY_NAMES = new Set([
26
26
  ]);
27
27
  const URL_PATTERN = /https?:\/\/[^\s<>"'),\]}]+/giu;
28
28
  const MAX_STRUCTURE_DEPTH = 6;
29
+ // What an RFC 3986 path may hold as it is: unreserved characters, sub-delims,
30
+ // ":", "@", "/" and well-formed percent-escapes. A query or fragment may also
31
+ // hold "?". Everything else is percent-encoded.
32
+ const URI_PATH_UNSAFE =
33
+ /%(?![0-9A-Fa-f]{2})|[^A-Za-z0-9\-._~!$&'()*+,;=:@/%]/gu;
34
+ const URI_QUERY_UNSAFE =
35
+ /%(?![0-9A-Fa-f]{2})|[^A-Za-z0-9\-._~!$&'()*+,;=:@/?%]/gu;
36
+ const URI_SCHEME_AUTHORITY = /^[A-Za-z][A-Za-z0-9+.-]*:\/\/[^/?#]*/u;
37
+ const UTF8_ENCODER = new TextEncoder();
29
38
 
30
39
  function sanitizeUrlForBom(value) {
31
40
  const input = String(value || "").trim();
@@ -146,6 +155,69 @@ export function sanitizeBomUrl(value) {
146
155
  return sanitizeUrlForBom(value);
147
156
  }
148
157
 
158
+ function percentEncodeUnsafe(text, unsafe) {
159
+ return text.replace(unsafe, (character) =>
160
+ Array.from(
161
+ UTF8_ENCODER.encode(character),
162
+ (byte) => `%${byte.toString(16).toUpperCase().padStart(2, "0")}`,
163
+ ).join(""),
164
+ );
165
+ }
166
+
167
+ /**
168
+ * Percent-encode what an RFC 3986 URI reference cannot hold as it is, so a
169
+ * route template or URL can be emitted where CycloneDX expects an
170
+ * iri-reference, such as `services[].endpoints[]`. The braces of a route
171
+ * template, spaces, `<>`, `[]` outside an IPv6 host, `|`, `^`, non-ASCII
172
+ * characters and a `%` that starts no escape are encoded:
173
+ * `/users/{id}` becomes `/users/%7Bid%7D`. The scheme and authority of an
174
+ * absolute URL are kept as written, the query and fragment stay a query and
175
+ * fragment, and existing escapes are kept, so encoding twice changes
176
+ * nothing. Nothing is removed; strip credentials with {@link sanitizeBomUrl}
177
+ * first.
178
+ *
179
+ * @param {unknown} value Route template, path or URL
180
+ * @returns {string} The encoded reference
181
+ */
182
+ export function encodeUriReference(value) {
183
+ const text = String(value ?? "");
184
+ const authority = URI_SCHEME_AUTHORITY.exec(text)?.[0] ?? "";
185
+ const rest = text.slice(authority.length);
186
+ const queryStart = rest.indexOf("?");
187
+ const fragmentStart = rest.indexOf("#");
188
+ const pathEnd = Math.min(
189
+ queryStart < 0 ? rest.length : queryStart,
190
+ fragmentStart < 0 ? rest.length : fragmentStart,
191
+ );
192
+ let encoded =
193
+ authority + percentEncodeUnsafe(rest.slice(0, pathEnd), URI_PATH_UNSAFE);
194
+ if (pathEnd === queryStart) {
195
+ const queryEnd = fragmentStart > queryStart ? fragmentStart : rest.length;
196
+ encoded += `?${percentEncodeUnsafe(rest.slice(queryStart + 1, queryEnd), URI_QUERY_UNSAFE)}`;
197
+ }
198
+ if (fragmentStart >= 0) {
199
+ encoded += `#${percentEncodeUnsafe(rest.slice(fragmentStart + 1), URI_QUERY_UNSAFE)}`;
200
+ }
201
+ return encoded;
202
+ }
203
+
204
+ /**
205
+ * Whether a value carries a token shape the BOM sanitizer redacts: cloud
206
+ * access keys, bearer tokens, GitHub, Slack and npm tokens, JWTs and the
207
+ * like. Callers that cannot splice a `[redacted]` marker into the value, such
208
+ * as a URL path segment, use it to drop the value instead.
209
+ *
210
+ * @param {unknown} value Value to check
211
+ * @returns {boolean} true when the value holds an inline credential
212
+ */
213
+ export function hasInlineCredential(value) {
214
+ const text = String(value ?? "");
215
+ return INLINE_CREDENTIAL_PATTERNS.some((pattern) => {
216
+ pattern.lastIndex = 0;
217
+ return pattern.test(text);
218
+ });
219
+ }
220
+
149
221
  /**
150
222
  * Sanitize a property value before serializing it into BOM properties.
151
223
  *
@@ -0,0 +1,39 @@
1
+ /**
2
+ * State that lasts for one run.
3
+ *
4
+ * Registry answers, prefetched documents, recorded misses and local cache
5
+ * lookups are kept in module state, so that a package several lockfiles name
6
+ * costs one lookup. A run is one BOM generation. The CLI exits when it ends, but
7
+ * a long-lived process such as the server performs many, and nothing a run
8
+ * remembered should outlive it: the registries publish new releases, builds
9
+ * download new artifacts, and the memory belongs to the next scan.
10
+ *
11
+ * Every module that keeps such state registers a reset when it loads. The
12
+ * server calls {@link resetRunState} between scans. A module that has not
13
+ * loaded yet holds nothing to reset.
14
+ */
15
+
16
+ /** @type {Map<string, () => void>} */
17
+ const runResets = new Map();
18
+
19
+ /**
20
+ * Register the function that empties a module's per-run state.
21
+ *
22
+ * @param {string} name Unique name, normally the module and what it holds
23
+ * @param {() => void} reset Empties that state
24
+ * @returns {void}
25
+ */
26
+ export function registerRunReset(name, reset) {
27
+ runResets.set(name, reset);
28
+ }
29
+
30
+ /**
31
+ * Empty the per-run state of every module that registered one.
32
+ *
33
+ * @returns {void}
34
+ */
35
+ export function resetRunState() {
36
+ for (const reset of runResets.values()) {
37
+ reset();
38
+ }
39
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * TOML parsing with stable, ordinary objects.
3
+ *
4
+ * smol-toml 1.9 began returning tables and inline tables with a `null`
5
+ * prototype so that a hostile `__proto__` key in a manifest cannot pollute
6
+ * `Object.prototype`. The SBOM data itself is unaffected, but cdxgen hands
7
+ * parsed manifests straight to callers (and `assert.deepStrictEqual` in the
8
+ * test suite), which compare by prototype and would see every table as a
9
+ * different kind of value. Re-wrapping the parse result with the standard
10
+ * prototype keeps the pre-1.9 contract: plain objects all the way down,
11
+ * `__proto__` keys included as ordinary own properties.
12
+ */
13
+
14
+ import { parse as smolParse } from "smol-toml";
15
+
16
+ /**
17
+ * Recursively rebuild a parsed value with `Object.prototype` roots.
18
+ *
19
+ * Class instances other than plain tables (smol-toml dates, strings, numbers)
20
+ * are passed through untouched, and arrays are copied only when an element
21
+ * actually changes, so unmodified branches keep their original identity.
22
+ *
23
+ * @param {unknown} value value produced by smol-toml's parse
24
+ * @returns {unknown} the same data with plain-prototype objects
25
+ */
26
+ function toPlainPrototype(value) {
27
+ if (!value || typeof value !== "object") {
28
+ return value;
29
+ }
30
+ if (Array.isArray(value)) {
31
+ let changed = false;
32
+ const out = new Array(value.length);
33
+ for (let i = 0; i < value.length; i++) {
34
+ out[i] = toPlainPrototype(value[i]);
35
+ if (out[i] !== value[i]) {
36
+ changed = true;
37
+ }
38
+ }
39
+ return changed ? out : value;
40
+ }
41
+ const proto = Object.getPrototypeOf(value);
42
+ if (proto !== null && proto !== Object.prototype) {
43
+ return value;
44
+ }
45
+ const out = {};
46
+ for (const [key, entry] of Object.entries(value)) {
47
+ if (key === "__proto__") {
48
+ // Plain assignment would re-point the new object's prototype instead
49
+ // of recording the key, reintroducing the pollution smol-toml guards
50
+ // against.
51
+ Object.defineProperty(out, key, {
52
+ value: toPlainPrototype(entry),
53
+ enumerable: true,
54
+ writable: true,
55
+ configurable: true,
56
+ });
57
+ } else {
58
+ out[key] = toPlainPrototype(entry);
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+
64
+ /**
65
+ * Parse a TOML document into plain objects.
66
+ *
67
+ * @param {string} text TOML source
68
+ * @returns {Object} parsed document whose tables use `Object.prototype`
69
+ */
70
+ export function parseToml(text) {
71
+ return toPlainPrototype(smolParse(text));
72
+ }
@@ -30,6 +30,7 @@ import {
30
30
  } from "../inventory/analyzer.js";
31
31
  import { tryBuildPurl } from "../inventory/purl.js";
32
32
  import { xml2js } from "../parsers/xml.js";
33
+ import { resolveNpmLicense } from "./npmutils.js";
33
34
 
34
35
  const ASAR_JS_ANALYSIS_EXTENSIONS = new Set([
35
36
  ".cjs",
@@ -1040,8 +1041,9 @@ function createArchiveParentComponent(
1040
1041
  ? primaryPackageJson.author
1041
1042
  : primaryPackageJson.author?.name || "";
1042
1043
  }
1043
- if (primaryPackageJson?.license) {
1044
- component.license = primaryPackageJson.license;
1044
+ const license = resolveNpmLicense(primaryPackageJson);
1045
+ if (license) {
1046
+ component.license = license;
1045
1047
  }
1046
1048
  if (primaryPackageJson?.repository) {
1047
1049
  const repositoryUrl =
@@ -3,8 +3,8 @@ import { dirname } from "node:path";
3
3
 
4
4
  import { build } from "@cdxgen/cdx-purl";
5
5
 
6
- import { DEBUG_MODE, readEnvironmentVariable } from "../core/activity.js";
7
- import { shouldFetchLicense, shouldFetchVCS } from "../core/env.js";
6
+ import { DEBUG_MODE } from "../core/activity.js";
7
+ import { shouldFetchPackageMetadata } from "../core/env.js";
8
8
  import { safeExistsSync } from "../core/fs.js";
9
9
  import { getNpmMetadata } from "./ecosystems.js";
10
10
  import {
@@ -554,11 +554,9 @@ export async function parseBunLock(bunLockFile, options = {}) {
554
554
  });
555
555
  }
556
556
 
557
- if (
558
- shouldFetchLicense() ||
559
- shouldFetchVCS() ||
560
- readEnvironmentVariable("FETCH_LICENSE") === "true"
561
- ) {
557
+ // The shared metadata gate: FETCH_LICENSE and the provenance fetch that
558
+ // --bom-audit turns on both reach the registry from here.
559
+ if (shouldFetchPackageMetadata()) {
562
560
  if (DEBUG_MODE) {
563
561
  console.log(
564
562
  `About to fetch npm registry metadata for ${pkgList.length} packages in parseBunLock`,