@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
package/lib/cli/index.js CHANGED
@@ -44,12 +44,14 @@ import {
44
44
  parseOpenapiSpecData,
45
45
  parsePrivadoFile,
46
46
  } from "../ecosystems/parsers-misc.js";
47
+ import { hasTerraformConfiguration } from "../ecosystems/parsers-terraform.js";
47
48
  import { isPyLockFile } from "../ecosystems/pylockutils.js";
48
49
  import {
49
50
  buildDependencyTrackBomRequest,
50
51
  getDependencyTrackBomApiUrl,
51
52
  } from "../helpers/remote/dependency-track.js";
52
53
  import { optionIncludesAiInventoryProjectType } from "../inventory/aiInventory.js";
54
+ import { readApkInstalledDb } from "../inventory/apkInstalledDb.js";
53
55
  import { isCycloneDxComponentTypeEnabled } from "../inventory/bomUtils.js";
54
56
  import {
55
57
  mergeDependencies,
@@ -57,7 +59,10 @@ import {
57
59
  trimComponents,
58
60
  } from "../inventory/depsUtils.js";
59
61
  import { buildDynamicComponents } from "../inventory/dynamic.js";
60
- import { convertOSQueryResults } from "../inventory/evidenceUtils.js";
62
+ import {
63
+ convertApkPackages,
64
+ convertOSQueryResults,
65
+ } from "../inventory/evidenceUtils.js";
61
66
  import {
62
67
  createHbomDocument,
63
68
  ensureHbomRuntimeSupport,
@@ -65,6 +70,8 @@ import {
65
70
  hasHbomProjectType,
66
71
  } from "../inventory/hbom.js";
67
72
  import { mergeHostInventoryBoms } from "../inventory/hostTopology.js";
73
+ import { orderParentCandidates } from "../inventory/parentSelection.js";
74
+ import { probeHostPhp } from "../inventory/phpHostProbe.js";
68
75
  // Imported directly rather than through the utils.js barrel: purl validity is
69
76
  // checked in a hot path and the barrel is already the root of several import
70
77
  // cycles.
@@ -84,6 +91,7 @@ import {
84
91
  exportArchive,
85
92
  exportImage,
86
93
  getPkgPathList,
94
+ isFollowableManifestImage,
87
95
  isImageReference,
88
96
  parseImageName,
89
97
  } from "../managers/docker.js";
@@ -270,6 +278,37 @@ export function createOSBom(_path, options) {
270
278
  );
271
279
  }
272
280
  } // for
281
+ // osquery has no apk table, so the packages of an Alpine, Wolfi or Chainguard
282
+ // host come from the apk installed database, after the osquery categories and
283
+ // as a category of their own. They are all components: the OS itself is the
284
+ // first row of the first osquery category, as before.
285
+ if (_platform() === "linux") {
286
+ const apkInventory = readApkInstalledDb();
287
+ if (apkInventory.state === "unreadable") {
288
+ recordDegradation("os.apk-installed-db.unreadable", {
289
+ ecosystem: "generic",
290
+ tool: "apk",
291
+ impact: "components",
292
+ path: apkInventory.path,
293
+ detail:
294
+ "The apk installed database exists but could not be read in full, so the packages it lists are missing from the OBOM.",
295
+ });
296
+ }
297
+ if (apkInventory.packages.length) {
298
+ pkgList = pkgList.concat(
299
+ convertApkPackages(apkInventory.packages).sort((a, b) =>
300
+ a.name.localeCompare(b.name),
301
+ ),
302
+ );
303
+ }
304
+ }
305
+ // The package tables cannot see a PHP that no package manager installed. Its
306
+ // edges stay out: an OBOM has no dependency graph, and a partial one makes
307
+ // post-processing infer the OS root's dependencies from these files alone.
308
+ const hostPhp = probeHostPhp({ executeOsQuery, packageComponents: pkgList });
309
+ if (hostPhp.components.length) {
310
+ pkgList = pkgList.concat(hostPhp.components);
311
+ }
273
312
  const hostTrustInventory = enrichOSComponentsWithTrustData(pkgList);
274
313
  if (hostTrustInventory?.components?.length) {
275
314
  pkgList = hostTrustInventory.components;
@@ -513,11 +552,14 @@ export async function createContainerSpecLikeBom(path, options) {
513
552
  if (imageBomData?.bomJson?.components) {
514
553
  components = components.concat(imageBomData.bomJson.components);
515
554
  }
555
+ doneimages.push(img.image);
556
+ if (!isFollowableManifestImage(img.image, imageObj)) {
557
+ continue;
558
+ }
516
559
  const bomData = await createBom(img.image, {
517
560
  specVersion: options.specVersion,
518
561
  projectType: ["oci"],
519
562
  });
520
- doneimages.push(img.image);
521
563
  if (bomData) {
522
564
  if (bomData.components?.length) {
523
565
  // Inject properties
@@ -732,6 +774,7 @@ export async function createMultiXBom(pathList, options) {
732
774
  let dependencies = [];
733
775
  let bomData;
734
776
  let formulationList = [];
777
+ let metadataProperties = [];
735
778
  let parentComponent = determineParentComponent(options) || {};
736
779
  let parentSubComponents = [];
737
780
  const setProjectTypeActivityContext = (projectType, sourcePath) => {
@@ -865,6 +908,7 @@ export async function createMultiXBom(pathList, options) {
865
908
  dependencies: [],
866
909
  options: { ...sharedOptions },
867
910
  parentSubComponents: [],
911
+ metadataProperties: [],
868
912
  };
869
913
  }
870
914
  };
@@ -877,6 +921,20 @@ export async function createMultiXBom(pathList, options) {
877
921
  let components = [];
878
922
  let dependencies = [];
879
923
  let parentSubComponents = [];
924
+ let metadataProperties = [];
925
+ // Each builder detects the project of its own ecosystem. A builder that sets
926
+ // options.parentComponent to force its project into its own BOM must not
927
+ // make that project the next builder's too, or the next ecosystem's project
928
+ // is lost: every builder starts from the parent the caller gave.
929
+ const callerParent = options.parentComponent;
930
+ const withOwnParent = async (build) => {
931
+ options.parentComponent = callerParent;
932
+ try {
933
+ return await build();
934
+ } finally {
935
+ options.parentComponent = callerParent;
936
+ }
937
+ };
880
938
  setActivityContext({
881
939
  projectType: Array.isArray(options.projectType)
882
940
  ? options.projectType.join(",")
@@ -923,7 +981,7 @@ export async function createMultiXBom(pathList, options) {
923
981
  }
924
982
  }
925
983
  setProjectTypeActivityContext(exactAiInventoryType || "js", path);
926
- bomData = await createNodejsBom(path, options);
984
+ bomData = await withOwnParent(() => createNodejsBom(path, options));
927
985
  if (bomData?.bomJson?.components?.length) {
928
986
  if (exactAiInventoryType) {
929
987
  thoughtLog(
@@ -973,7 +1031,7 @@ export async function createMultiXBom(pathList, options) {
973
1031
  );
974
1032
  }
975
1033
  setProjectTypeActivityContext("java", path);
976
- bomData = await createJavaBom(path, options);
1034
+ bomData = await withOwnParent(() => createJavaBom(path, options));
977
1035
  if (bomData?.bomJson?.components?.length) {
978
1036
  thoughtLog(
979
1037
  `I found ${bomData.bomJson.components.length} java packages.`,
@@ -1038,7 +1096,7 @@ export async function createMultiXBom(pathList, options) {
1038
1096
  );
1039
1097
  }
1040
1098
  setProjectTypeActivityContext("py", path);
1041
- bomData = await createPythonBom(path, options);
1099
+ bomData = await withOwnParent(() => createPythonBom(path, options));
1042
1100
  if (bomData?.bomJson?.components?.length) {
1043
1101
  thoughtLog(
1044
1102
  `I found ${bomData.bomJson.components.length} python packages.`,
@@ -1059,6 +1117,17 @@ export async function createMultiXBom(pathList, options) {
1059
1117
  ) {
1060
1118
  parentSubComponents.push(bomData.parentComponent);
1061
1119
  }
1120
+ // Retain metadata.component.components. uv workspace members are
1121
+ // nested under the python project, so hoisting them keeps them
1122
+ // siblings of the other sub-components instead of riding one level
1123
+ // deeper (or being dropped by the same-name collapse) when another
1124
+ // ecosystem's project becomes the parent.
1125
+ if (bomData.parentComponent?.components?.length) {
1126
+ parentSubComponents = parentSubComponents.concat(
1127
+ bomData.parentComponent.components,
1128
+ );
1129
+ delete bomData.parentComponent.components;
1130
+ }
1062
1131
  }
1063
1132
  if (bomData?.formulationList?.length) {
1064
1133
  formulationList = formulationList.concat(bomData.formulationList);
@@ -1071,7 +1140,7 @@ export async function createMultiXBom(pathList, options) {
1071
1140
  );
1072
1141
  }
1073
1142
  setProjectTypeActivityContext("go", path);
1074
- bomData = await createGoBom(path, options);
1143
+ bomData = await withOwnParent(() => createGoBom(path, options));
1075
1144
  if (bomData?.bomJson?.components?.length) {
1076
1145
  thoughtLog(`I found ${bomData.bomJson.components.length} go packages.`);
1077
1146
  if (DEBUG_MODE) {
@@ -1099,7 +1168,7 @@ export async function createMultiXBom(pathList, options) {
1099
1168
  );
1100
1169
  }
1101
1170
  setProjectTypeActivityContext("rust", path);
1102
- bomData = await createRustBom(path, options);
1171
+ bomData = await withOwnParent(() => createRustBom(path, options));
1103
1172
  if (bomData?.bomJson?.components?.length) {
1104
1173
  thoughtLog(
1105
1174
  `I found ${bomData.bomJson.components.length} rust packages.`,
@@ -1136,7 +1205,13 @@ export async function createMultiXBom(pathList, options) {
1136
1205
  );
1137
1206
  }
1138
1207
  setProjectTypeActivityContext("php", path);
1139
- bomData = createPHPBom(path, options);
1208
+ bomData = await withOwnParent(() => createPHPBom(path, options));
1209
+ // A lock with no packages can still hold the project's platform data.
1210
+ if (bomData?.metadataProperties?.length) {
1211
+ metadataProperties = metadataProperties.concat(
1212
+ bomData.metadataProperties,
1213
+ );
1214
+ }
1140
1215
  if (bomData?.bomJson?.components?.length) {
1141
1216
  thoughtLog(
1142
1217
  `I found ${bomData.bomJson.components.length} php packages.`,
@@ -1173,7 +1248,7 @@ export async function createMultiXBom(pathList, options) {
1173
1248
  );
1174
1249
  }
1175
1250
  setProjectTypeActivityContext("ruby", path);
1176
- bomData = await createRubyBom(path, options);
1251
+ bomData = await withOwnParent(() => createRubyBom(path, options));
1177
1252
  if (bomData?.bomJson?.components?.length) {
1178
1253
  thoughtLog(
1179
1254
  `We got ${bomData.bomJson.components.length} ruby packages.`,
@@ -1209,8 +1284,13 @@ export async function createMultiXBom(pathList, options) {
1209
1284
  thoughtLog("**CSHARP**: What about csharp and fsharp projects?");
1210
1285
  }
1211
1286
  setProjectTypeActivityContext("csharp", path);
1212
- bomData = await createCsharpBom(path, options);
1213
- if (bomData?.bomJson?.components?.length) {
1287
+ bomData = await withOwnParent(() => createCsharpBom(path, options));
1288
+ // Every project the scan read has a dependency entry of its own, so a
1289
+ // project that uses no packages is kept along with its parent.
1290
+ if (
1291
+ bomData?.bomJson?.components?.length ||
1292
+ bomData?.bomJson?.dependencies?.length
1293
+ ) {
1214
1294
  thoughtLog(
1215
1295
  `There are ${bomData.bomJson.components.length} csharp packages.`,
1216
1296
  );
@@ -1246,7 +1326,7 @@ export async function createMultiXBom(pathList, options) {
1246
1326
  );
1247
1327
  }
1248
1328
  setProjectTypeActivityContext("dart", path);
1249
- bomData = await createDartBom(path, options);
1329
+ bomData = await withOwnParent(() => createDartBom(path, options));
1250
1330
  if (bomData?.bomJson?.components?.length) {
1251
1331
  thoughtLog(
1252
1332
  `I found ${bomData.bomJson.components.length} pub packages.`,
@@ -1276,7 +1356,7 @@ export async function createMultiXBom(pathList, options) {
1276
1356
  );
1277
1357
  }
1278
1358
  setProjectTypeActivityContext("haskell", path);
1279
- bomData = createHaskellBom(path, options);
1359
+ bomData = await withOwnParent(() => createHaskellBom(path, options));
1280
1360
  if (bomData?.bomJson?.components?.length) {
1281
1361
  thoughtLog(
1282
1362
  `I found ${bomData.bomJson.components.length} hackage packages.`,
@@ -1306,7 +1386,7 @@ export async function createMultiXBom(pathList, options) {
1306
1386
  );
1307
1387
  }
1308
1388
  setProjectTypeActivityContext("elixir", path);
1309
- bomData = createElixirBom(path, options);
1389
+ bomData = await withOwnParent(() => createElixirBom(path, options));
1310
1390
  if (bomData?.bomJson?.components?.length) {
1311
1391
  thoughtLog(
1312
1392
  `I found ${bomData.bomJson.components.length} mix packages.`,
@@ -1336,7 +1416,7 @@ export async function createMultiXBom(pathList, options) {
1336
1416
  );
1337
1417
  }
1338
1418
  setProjectTypeActivityContext("c", path);
1339
- bomData = createCppBom(path, options);
1419
+ bomData = await withOwnParent(() => createCppBom(path, options));
1340
1420
  if (bomData?.bomJson?.components?.length) {
1341
1421
  thoughtLog(
1342
1422
  `I found ${bomData.bomJson.components.length} cpp packages.`,
@@ -1358,6 +1438,10 @@ export async function createMultiXBom(pathList, options) {
1358
1438
  parentSubComponents.push(bomData.parentComponent);
1359
1439
  }
1360
1440
  }
1441
+ // presets and compilers describe the build, whatever it depends on
1442
+ if (bomData?.formulationList?.length) {
1443
+ formulationList = formulationList.concat(bomData.formulationList);
1444
+ }
1361
1445
  }
1362
1446
  if (hasAnyProjectType(["oci", "clojure"], options)) {
1363
1447
  if (!hasAnyProjectType(["oci"], options, false)) {
@@ -1366,7 +1450,7 @@ export async function createMultiXBom(pathList, options) {
1366
1450
  );
1367
1451
  }
1368
1452
  setProjectTypeActivityContext("clojure", path);
1369
- bomData = createClojureBom(path, options);
1453
+ bomData = await withOwnParent(() => createClojureBom(path, options));
1370
1454
  if (bomData?.bomJson?.components?.length) {
1371
1455
  thoughtLog(
1372
1456
  `I found ${bomData.bomJson.components.length} clojure packages.`,
@@ -1396,7 +1480,7 @@ export async function createMultiXBom(pathList, options) {
1396
1480
  );
1397
1481
  }
1398
1482
  setProjectTypeActivityContext("github", path);
1399
- bomData = createGitHubBom(path, options);
1483
+ bomData = await withOwnParent(() => createGitHubBom(path, options));
1400
1484
  if (bomData?.bomJson?.components?.length) {
1401
1485
  thoughtLog(
1402
1486
  `I found ${bomData.bomJson.components.length} github action packages as well. Should I convert these to formulation instead 🤔`,
@@ -1426,7 +1510,7 @@ export async function createMultiXBom(pathList, options) {
1426
1510
  );
1427
1511
  }
1428
1512
  setProjectTypeActivityContext("cloudbuild", path);
1429
- bomData = createCloudBuildBom(path, options);
1513
+ bomData = await withOwnParent(() => createCloudBuildBom(path, options));
1430
1514
  if (bomData?.bomJson?.components?.length) {
1431
1515
  thoughtLog(
1432
1516
  `I found ${bomData.bomJson.components.length} cloudbuild packages.`,
@@ -1456,7 +1540,7 @@ export async function createMultiXBom(pathList, options) {
1456
1540
  );
1457
1541
  }
1458
1542
  setProjectTypeActivityContext("swift", path);
1459
- bomData = await createSwiftBom(path, options);
1543
+ bomData = await withOwnParent(() => createSwiftBom(path, options));
1460
1544
  if (bomData?.bomJson?.components?.length) {
1461
1545
  thoughtLog(
1462
1546
  `I found ${bomData.bomJson.components.length} swift packages here.`,
@@ -1494,7 +1578,7 @@ export async function createMultiXBom(pathList, options) {
1494
1578
  detail:
1495
1579
  "Components are being inferred by scanning jar/war/ear files from disk.",
1496
1580
  });
1497
- bomData = await createJarBom(path, options);
1581
+ bomData = await withOwnParent(() => createJarBom(path, options));
1498
1582
  if (bomData?.bomJson?.components?.length) {
1499
1583
  thoughtLog(
1500
1584
  `I found ${bomData.bomJson.components.length} jar packages as well.`,
@@ -1519,7 +1603,7 @@ export async function createMultiXBom(pathList, options) {
1519
1603
  }
1520
1604
  if (hasAnyProjectType(["oci", "cocoa"], options)) {
1521
1605
  setProjectTypeActivityContext("cocoa", path);
1522
- bomData = await createCocoaBom(path, options);
1606
+ bomData = await withOwnParent(() => createCocoaBom(path, options));
1523
1607
  if (bomData?.bomJson?.components?.length) {
1524
1608
  if (DEBUG_MODE) {
1525
1609
  console.log(
@@ -1538,7 +1622,7 @@ export async function createMultiXBom(pathList, options) {
1538
1622
  }
1539
1623
  if (hasAnyProjectType(["oci", "nix"], options)) {
1540
1624
  setProjectTypeActivityContext("nix", path);
1541
- bomData = await createNixBom(path, options);
1625
+ bomData = await withOwnParent(() => createNixBom(path, options));
1542
1626
  if (bomData?.bomJson?.components?.length) {
1543
1627
  if (DEBUG_MODE) {
1544
1628
  console.log(
@@ -1560,7 +1644,7 @@ export async function createMultiXBom(pathList, options) {
1560
1644
  }
1561
1645
  if (hasAnyProjectType(["caxa"], options, false)) {
1562
1646
  setProjectTypeActivityContext("caxa", path);
1563
- bomData = await createCaxaBom(path, options);
1647
+ bomData = await withOwnParent(() => createCaxaBom(path, options));
1564
1648
  if (bomData?.bomJson?.components?.length) {
1565
1649
  if (DEBUG_MODE) {
1566
1650
  console.log(
@@ -1582,7 +1666,7 @@ export async function createMultiXBom(pathList, options) {
1582
1666
  }
1583
1667
  if (hasAnyProjectType(["asar"], options, false)) {
1584
1668
  setProjectTypeActivityContext("asar", path);
1585
- bomData = await createAsarBom(path, options);
1669
+ bomData = await withOwnParent(() => createAsarBom(path, options));
1586
1670
  if (bomData?.bomJson?.components?.length) {
1587
1671
  if (DEBUG_MODE) {
1588
1672
  console.log(
@@ -1604,7 +1688,9 @@ export async function createMultiXBom(pathList, options) {
1604
1688
  }
1605
1689
  if (hasAnyProjectType(["vscode-extension"], options, false)) {
1606
1690
  setProjectTypeActivityContext("vscode-extension", path);
1607
- bomData = await createVscodeExtensionBom(path, options);
1691
+ bomData = await withOwnParent(() =>
1692
+ createVscodeExtensionBom(path, options),
1693
+ );
1608
1694
  if (bomData?.bomJson?.components?.length) {
1609
1695
  if (DEBUG_MODE) {
1610
1696
  console.log(
@@ -1647,7 +1733,9 @@ export async function createMultiXBom(pathList, options) {
1647
1733
  sharedOptions.__didScanChromeExtensions = true;
1648
1734
  }
1649
1735
  setProjectTypeActivityContext("chrome-extension", path);
1650
- bomData = await createChromeExtensionBom(path, options);
1736
+ bomData = await withOwnParent(() =>
1737
+ createChromeExtensionBom(path, options),
1738
+ );
1651
1739
  if (bomData?.bomJson?.components?.length) {
1652
1740
  if (DEBUG_MODE) {
1653
1741
  console.log(
@@ -1668,6 +1756,34 @@ export async function createMultiXBom(pathList, options) {
1668
1756
  }
1669
1757
  }
1670
1758
  }
1759
+ if (hasAnyProjectType(["terraform"], options)) {
1760
+ thoughtLog(
1761
+ "**TERRAFORM**: Looking for Terraform and OpenTofu modules and providers. The registry metadata fetch is opt-in, so I will rely on the lock file, the module manifest and the configuration files.",
1762
+ );
1763
+ setProjectTypeActivityContext("terraform", path);
1764
+ bomData = await withOwnParent(() => createTerraformBom(path, options));
1765
+ if (bomData?.bomJson?.components?.length) {
1766
+ thoughtLog(
1767
+ `I found ${bomData.bomJson.components.length} terraform components. Should I also resolve their licenses from the registry when FETCH_LICENSE is enabled?`,
1768
+ );
1769
+ if (DEBUG_MODE) {
1770
+ console.log(
1771
+ `Found ${bomData.bomJson.components.length} terraform components at ${path}`,
1772
+ );
1773
+ }
1774
+ components = components.concat(bomData.bomJson.components);
1775
+ dependencies = mergeDependencies(
1776
+ dependencies,
1777
+ bomData.bomJson.dependencies,
1778
+ );
1779
+ if (
1780
+ bomData.parentComponent &&
1781
+ Object.keys(bomData.parentComponent).length
1782
+ ) {
1783
+ parentSubComponents.push(bomData.parentComponent);
1784
+ }
1785
+ }
1786
+ }
1671
1787
  // Collect any crypto keys
1672
1788
  if (
1673
1789
  options.specVersion >= 1.6 &&
@@ -1680,7 +1796,7 @@ export async function createMultiXBom(pathList, options) {
1680
1796
  );
1681
1797
  }
1682
1798
  setProjectTypeActivityContext("cbom", path);
1683
- bomData = await createCryptoCertsBom(path, options);
1799
+ bomData = await withOwnParent(() => createCryptoCertsBom(path, options));
1684
1800
  if (bomData?.bomJson?.components?.length) {
1685
1801
  thoughtLog(
1686
1802
  `I found ${bomData.bomJson.components.length} crypto assets.`,
@@ -1691,9 +1807,18 @@ export async function createMultiXBom(pathList, options) {
1691
1807
  );
1692
1808
  }
1693
1809
  components = components.concat(bomData.bomJson.components);
1810
+ if (bomData.dependencies?.length) {
1811
+ dependencies = mergeDependencies(dependencies, bomData.dependencies);
1812
+ }
1694
1813
  }
1695
1814
  }
1696
- return { components, dependencies, options, parentSubComponents };
1815
+ return {
1816
+ components,
1817
+ dependencies,
1818
+ options,
1819
+ parentSubComponents,
1820
+ metadataProperties,
1821
+ };
1697
1822
  };
1698
1823
  const pathResults = [];
1699
1824
  // A container scan walks hundreds of paths, so the phase carries a bar and
@@ -1756,6 +1881,9 @@ export async function createMultiXBom(pathList, options) {
1756
1881
  parentSubComponents = parentSubComponents.concat(
1757
1882
  pathResult.parentSubComponents,
1758
1883
  );
1884
+ metadataProperties = metadataProperties.concat(
1885
+ pathResult.metadataProperties,
1886
+ );
1759
1887
  if (pathResult.options.services?.length) {
1760
1888
  sharedOptions.services = mergeServices(
1761
1889
  sharedOptions.services || [],
@@ -1771,7 +1899,7 @@ export async function createMultiXBom(pathList, options) {
1771
1899
  !options.lastWorkingDir.includes("/home/")
1772
1900
  ) {
1773
1901
  setProjectTypeActivityContext("jar", options.lastWorkingDir);
1774
- bomData = createJarBom(options.lastWorkingDir, options);
1902
+ bomData = await createJarBom(options.lastWorkingDir, options);
1775
1903
  if (bomData?.bomJson?.components?.length) {
1776
1904
  if (DEBUG_MODE) {
1777
1905
  console.log(
@@ -1797,14 +1925,24 @@ export async function createMultiXBom(pathList, options) {
1797
1925
  thoughtLog("**METADATA**: Tweaking the parent component hierarchy.");
1798
1926
  }
1799
1927
  if (!parentComponent || !Object.keys(parentComponent).length) {
1800
- parentComponent = parentSubComponents[0];
1928
+ // the project whose manifest sits at the scan root describes the
1929
+ // repository; ties keep the order the ecosystems were scanned in
1930
+ parentComponent = orderParentCandidates(
1931
+ parentSubComponents,
1932
+ pathList,
1933
+ options,
1934
+ )[0];
1801
1935
  }
1802
1936
  // Our naive approach to appending to sub-components could result in same parent being included as a child
1803
1937
  // This is filtered out here
1804
1938
  parentSubComponents = parentSubComponents.filter(
1805
1939
  (c) => c["bom-ref"] !== parentComponent["bom-ref"],
1806
1940
  );
1807
- parentComponent.components = trimComponents(parentSubComponents);
1941
+ // keep the parent's own sub-components (a CMake project's sub-projects)
1942
+ parentComponent.components = trimComponents([
1943
+ ...(parentComponent.components || []),
1944
+ ...parentSubComponents,
1945
+ ]);
1808
1946
  if (
1809
1947
  parentComponent.components.length === 1 &&
1810
1948
  parentComponent.components[0].name === parentComponent.name &&
@@ -1814,24 +1952,15 @@ export async function createMultiXBom(pathList, options) {
1814
1952
  delete parentComponent.components;
1815
1953
  }
1816
1954
  // Add references between the multiple sub-boms
1817
- let parentDependencies = dependencies.find(
1818
- (d) => d["ref"] === parentComponent["bom-ref"],
1819
- );
1820
- if (!parentDependencies) {
1821
- parentDependencies = {
1822
- ref: parentComponent["bom-ref"],
1823
- };
1824
- dependencies = mergeDependencies(dependencies, parentDependencies);
1825
- }
1826
- if (!parentDependencies["dependsOn"]) {
1827
- parentDependencies["dependsOn"] = [];
1828
- }
1829
- for (const parentSub of parentSubComponents) {
1830
- // Issue: 1622. We might have already captured this parent component dependency
1831
- if (!parentDependencies["dependsOn"].includes(parentSub["bom-ref"])) {
1832
- parentDependencies["dependsOn"].push(parentSub["bom-ref"]);
1833
- }
1834
- }
1955
+ // mergeDependencies returns fresh objects and unions dependsOn per ref,
1956
+ // so the parent edges are folded in through a single merge
1957
+ const parentRef = parentComponent["bom-ref"];
1958
+ const parentSubRefs = parentSubComponents
1959
+ .map((c) => c["bom-ref"])
1960
+ .filter((ref) => ref && ref !== parentRef);
1961
+ dependencies = mergeDependencies(dependencies, [
1962
+ { ref: parentRef, dependsOn: parentSubRefs },
1963
+ ]);
1835
1964
  }
1836
1965
  // some cleanup, but not complete
1837
1966
  for (const path of pathList) {
@@ -1844,6 +1973,7 @@ export async function createMultiXBom(pathList, options) {
1844
1973
  components,
1845
1974
  parentComponent,
1846
1975
  dependencies,
1976
+ metadataProperties,
1847
1977
  );
1848
1978
  if (formulationList.length) {
1849
1979
  multiResult.formulationList = formulationList;
@@ -1915,6 +2045,7 @@ export async function createDynamicBom(path, options) {
1915
2045
  const {
1916
2046
  components: pkgList,
1917
2047
  services: traceServices,
2048
+ dependencies: traceDependencies,
1918
2049
  dryRunSummary,
1919
2050
  } = await buildDynamicComponents(commandStr, workingDir, traceOptions);
1920
2051
 
@@ -1923,6 +2054,7 @@ export async function createDynamicBom(path, options) {
1923
2054
  projectType: "dynamic",
1924
2055
  filename: commandStr,
1925
2056
  services: traceServices,
2057
+ dependencies: traceDependencies || [],
1926
2058
  });
1927
2059
  // A dry run denies every side effect, so the attempted-operation counts are
1928
2060
  // the result. Only counts are recorded, never the paths or targets.
@@ -2464,14 +2596,10 @@ export async function createXBom(path, options) {
2464
2596
  return createPerlBom(path, options);
2465
2597
  }
2466
2598
 
2467
- // Terraform and OpenTofu providers
2468
- const tfLockFiles = getAllFiles(
2469
- path,
2470
- `${options.multiProject ? "**/" : ""}.terraform.lock.hcl`,
2471
- options,
2472
- );
2473
- if (tfLockFiles.length) {
2474
- return createTerraformBom(path, options);
2599
+ // Terraform and OpenTofu providers and modules, discovered with the same
2600
+ // patterns and exclusions the workspace assembly uses.
2601
+ if (hasTerraformConfiguration(path, options)) {
2602
+ return await createTerraformBom(path, options);
2475
2603
  }
2476
2604
  }
2477
2605
 
@@ -2861,7 +2989,7 @@ async function createBomForPath(path, options) {
2861
2989
  return createPerlBom(path, options);
2862
2990
  }
2863
2991
  if (PROJECT_TYPE_ALIASES["terraform"].includes(projectType[0])) {
2864
- return createTerraformBom(path, options);
2992
+ return await createTerraformBom(path, options);
2865
2993
  }
2866
2994
  if (PROJECT_TYPE_ALIASES["caxa"].includes(projectType[0])) {
2867
2995
  return await createCaxaBom(path, options);