@cdxgen/cdxgen 13.2.0 → 13.4.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 (311) hide show
  1. package/README.md +33 -14
  2. package/bin/cdxgen.js +310 -138
  3. package/bin/evinse.js +22 -0
  4. package/bin/repl.js +86 -0
  5. package/bin/sign.js +119 -15
  6. package/bin/tracebom.js +69 -5
  7. package/bin/validate.js +107 -19
  8. package/bin/verify.js +172 -63
  9. package/data/helpers/init.gradle +46 -21
  10. package/data/remediations.json +85 -0
  11. package/data/rules/dependency-sources.yaml +67 -0
  12. package/data/rules/scala-evidence.yaml +115 -0
  13. package/lib/audit/index.js +38 -6
  14. package/lib/cli/bomAssembly.js +105 -15
  15. package/lib/cli/cliOptions.js +93 -1
  16. package/lib/cli/index.js +156 -58
  17. package/lib/cli/jsBom.js +99 -53
  18. package/lib/cli/jvmBom.js +708 -147
  19. package/lib/cli/managedBom.js +415 -224
  20. package/lib/cli/nativeBom.js +264 -44
  21. package/lib/core/activity.js +12 -0
  22. package/lib/core/env.js +22 -15
  23. package/lib/core/fs.js +176 -7
  24. package/lib/core/httpClient.js +159 -24
  25. package/lib/core/metadataProperties.js +97 -0
  26. package/lib/core/pluginRun.js +184 -0
  27. package/lib/core/processTree.js +100 -0
  28. package/lib/core/projectConfig.js +31 -4
  29. package/lib/core/runState.js +39 -0
  30. package/lib/core/toml.js +72 -0
  31. package/lib/ecosystems/asarutils.js +4 -2
  32. package/lib/ecosystems/bunutils.js +274 -108
  33. package/lib/ecosystems/cargoCache.js +231 -8
  34. package/lib/ecosystems/caxa.js +434 -2
  35. package/lib/ecosystems/cmakeResolver.js +76 -21
  36. package/lib/ecosystems/cppBuildContext.js +631 -0
  37. package/lib/ecosystems/cppEvidence.js +399 -51
  38. package/lib/ecosystems/cppIncludeResolver.js +294 -0
  39. package/lib/ecosystems/denoutils.js +93 -66
  40. package/lib/ecosystems/ecosystems.js +1983 -793
  41. package/lib/ecosystems/golem.js +28 -12
  42. package/lib/ecosystems/gradleutils.js +356 -37
  43. package/lib/ecosystems/jsEvidence.js +104 -44
  44. package/lib/ecosystems/kosi.js +31 -7
  45. package/lib/ecosystems/npmutils.js +174 -9
  46. package/lib/ecosystems/parsers-dotnet.js +616 -159
  47. package/lib/ecosystems/parsers-elm.js +46 -28
  48. package/lib/ecosystems/parsers-gleam.js +3 -4
  49. package/lib/ecosystems/parsers-go.js +371 -70
  50. package/lib/ecosystems/parsers-js.js +263 -76
  51. package/lib/ecosystems/parsers-julia.js +2 -3
  52. package/lib/ecosystems/parsers-jvm.js +204 -12
  53. package/lib/ecosystems/parsers-misc.js +929 -216
  54. package/lib/ecosystems/parsers-python.js +167 -24
  55. package/lib/ecosystems/parsers-rust.js +28 -22
  56. package/lib/ecosystems/parsers-terraform.js +1573 -19
  57. package/lib/ecosystems/pythonutils.js +102 -6
  58. package/lib/ecosystems/remote/huggingface.js +3 -0
  59. package/lib/ecosystems/rubyutils.js +1492 -182
  60. package/lib/ecosystems/rusi.js +54 -10
  61. package/lib/ecosystems/sbtutils.js +243 -187
  62. package/lib/ecosystems/scalacliutils.js +342 -0
  63. package/lib/ecosystems/scalasem.js +2618 -0
  64. package/lib/ecosystems/terraformRegistry.js +288 -0
  65. package/lib/ecosystems/utils.js +2 -0
  66. package/lib/ecosystems/vendoredCode.js +156 -0
  67. package/lib/evinser/evinser.js +1008 -191
  68. package/lib/evinser/swiftsem.js +1914 -302
  69. package/lib/helpers/agenticToolutils.js +2 -2
  70. package/lib/helpers/bomSigner.js +1101 -222
  71. package/lib/inventory/aiCollector.js +4 -1
  72. package/lib/inventory/analyzer.js +110 -127
  73. package/lib/inventory/atomUtils.js +703 -43
  74. package/lib/inventory/auditCategories.js +7 -0
  75. package/lib/inventory/buildToolRateLimit.js +144 -0
  76. package/lib/inventory/cacheCommands.js +2 -1
  77. package/lib/inventory/cdxrs.js +103 -12
  78. package/lib/inventory/cmakeBuildDirs.js +254 -0
  79. package/lib/inventory/deps.js +501 -124
  80. package/lib/inventory/depsUtils.js +183 -11
  81. package/lib/inventory/display.js +4 -5
  82. package/lib/inventory/dosai.js +798 -57
  83. package/lib/inventory/dosaiParsers.js +310 -15
  84. package/lib/inventory/dynamic.js +90 -6
  85. package/lib/inventory/evidenceUtils.js +166 -113
  86. package/lib/inventory/fetchBatch.js +690 -55
  87. package/lib/inventory/fetchDiskCache.js +597 -0
  88. package/lib/inventory/forgeEnricher.js +14 -5
  89. package/lib/inventory/jvmLocalRepos.js +917 -0
  90. package/lib/inventory/mcpConfigParser.js +2 -3
  91. package/lib/inventory/parentSelection.js +146 -0
  92. package/lib/inventory/protobom.js +8 -1
  93. package/lib/inventory/purl.js +152 -3
  94. package/lib/inventory/rustFormulationParser.js +3 -4
  95. package/lib/inventory/sbomDocument.js +2 -70
  96. package/lib/inventory/scalaCoords.js +153 -0
  97. package/lib/inventory/source.js +45 -27
  98. package/lib/inventory/spdx.js +101 -0
  99. package/lib/inventory/traceRunner.js +295 -25
  100. package/lib/inventory/tracedCrypto.js +294 -0
  101. package/lib/managers/binary.js +115 -24
  102. package/lib/managers/docker.js +467 -46
  103. package/lib/managers/oci.js +63 -3
  104. package/lib/parsers/cmakeCache.js +69 -0
  105. package/lib/parsers/cmakeLists.js +466 -0
  106. package/lib/parsers/cmakePresets.js +400 -0
  107. package/lib/parsers/compileCommands.js +557 -0
  108. package/lib/parsers/largeJson.js +454 -0
  109. package/lib/parsers/npmrc.js +19 -1
  110. package/lib/parsers/strictJson.js +322 -0
  111. package/lib/parsers/terraformConfig.js +1073 -0
  112. package/lib/parsers/terraformSource.js +652 -0
  113. package/lib/server/server.js +23 -0
  114. package/lib/stages/postgen/introspection/markers.js +1 -1
  115. package/lib/stages/postgen/postgen.js +83 -16
  116. package/lib/stages/postgen/specVersionCompat.js +32 -0
  117. package/lib/validator/bomValidator.js +6 -16
  118. package/lib/validator/index.js +64 -11
  119. package/lib/validator/reporters/console.js +3 -0
  120. package/lib/validator/reporters/json.js +2 -0
  121. package/lib/validator/reporters/sarif.js +7 -0
  122. package/package.json +23 -23
  123. package/types/lib/audit/index.d.ts.map +1 -1
  124. package/types/lib/cli/bomAssembly.d.ts +2 -1
  125. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  126. package/types/lib/cli/cliOptions.d.ts +33 -1
  127. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  128. package/types/lib/cli/index.d.ts.map +1 -1
  129. package/types/lib/cli/jsBom.d.ts.map +1 -1
  130. package/types/lib/cli/jvmBom.d.ts +24 -1
  131. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  132. package/types/lib/cli/managedBom.d.ts +7 -4
  133. package/types/lib/cli/managedBom.d.ts.map +1 -1
  134. package/types/lib/cli/nativeBom.d.ts +3 -1
  135. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  136. package/types/lib/core/activity.d.ts.map +1 -1
  137. package/types/lib/core/env.d.ts +9 -0
  138. package/types/lib/core/env.d.ts.map +1 -1
  139. package/types/lib/core/fs.d.ts +55 -0
  140. package/types/lib/core/fs.d.ts.map +1 -1
  141. package/types/lib/core/httpClient.d.ts +13 -8
  142. package/types/lib/core/httpClient.d.ts.map +1 -1
  143. package/types/lib/core/metadataProperties.d.ts +39 -0
  144. package/types/lib/core/metadataProperties.d.ts.map +1 -0
  145. package/types/lib/core/pluginRun.d.ts +97 -0
  146. package/types/lib/core/pluginRun.d.ts.map +1 -0
  147. package/types/lib/core/processTree.d.ts +36 -0
  148. package/types/lib/core/processTree.d.ts.map +1 -0
  149. package/types/lib/core/projectConfig.d.ts +6 -2
  150. package/types/lib/core/projectConfig.d.ts.map +1 -1
  151. package/types/lib/core/runState.d.ts +29 -0
  152. package/types/lib/core/runState.d.ts.map +1 -0
  153. package/types/lib/core/toml.d.ts +20 -0
  154. package/types/lib/core/toml.d.ts.map +1 -0
  155. package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
  156. package/types/lib/ecosystems/bunutils.d.ts +12 -5
  157. package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
  158. package/types/lib/ecosystems/cargoCache.d.ts +12 -0
  159. package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
  160. package/types/lib/ecosystems/caxa.d.ts +14 -0
  161. package/types/lib/ecosystems/caxa.d.ts.map +1 -1
  162. package/types/lib/ecosystems/cmakeResolver.d.ts +28 -3
  163. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
  164. package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
  165. package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
  166. package/types/lib/ecosystems/cppEvidence.d.ts +17 -1
  167. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  168. package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
  169. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
  170. package/types/lib/ecosystems/denoutils.d.ts +9 -3
  171. package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
  172. package/types/lib/ecosystems/ecosystems.d.ts +62 -13
  173. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  174. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  175. package/types/lib/ecosystems/gradleutils.d.ts +70 -4
  176. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  177. package/types/lib/ecosystems/jsEvidence.d.ts +5 -2
  178. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  179. package/types/lib/ecosystems/kosi.d.ts +13 -0
  180. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  181. package/types/lib/ecosystems/npmutils.d.ts +57 -0
  182. package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
  183. package/types/lib/ecosystems/parsers-dotnet.d.ts +118 -4
  184. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  185. package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
  186. package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
  187. package/types/lib/ecosystems/parsers-go.d.ts +54 -2
  188. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  189. package/types/lib/ecosystems/parsers-js.d.ts +16 -5
  190. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  191. package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
  192. package/types/lib/ecosystems/parsers-jvm.d.ts +46 -1
  193. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  194. package/types/lib/ecosystems/parsers-misc.d.ts +70 -4
  195. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  196. package/types/lib/ecosystems/parsers-python.d.ts +53 -3
  197. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  198. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  199. package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
  200. package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
  201. package/types/lib/ecosystems/pythonutils.d.ts +27 -2
  202. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  203. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  204. package/types/lib/ecosystems/rubyutils.d.ts +164 -3
  205. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  206. package/types/lib/ecosystems/rusi.d.ts +13 -0
  207. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  208. package/types/lib/ecosystems/sbtutils.d.ts +88 -2
  209. package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
  210. package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
  211. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
  212. package/types/lib/ecosystems/scalasem.d.ts +311 -0
  213. package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
  214. package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
  215. package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
  216. package/types/lib/ecosystems/utils.d.ts +2 -2
  217. package/types/lib/ecosystems/utils.d.ts.map +1 -1
  218. package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
  219. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
  220. package/types/lib/evinser/evinser.d.ts +132 -15
  221. package/types/lib/evinser/evinser.d.ts.map +1 -1
  222. package/types/lib/evinser/swiftsem.d.ts +280 -15
  223. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  224. package/types/lib/helpers/bomSigner.d.ts +182 -13
  225. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  226. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  227. package/types/lib/inventory/analyzer.d.ts.map +1 -1
  228. package/types/lib/inventory/atomUtils.d.ts +219 -5
  229. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  230. package/types/lib/inventory/auditCategories.d.ts +3 -0
  231. package/types/lib/inventory/auditCategories.d.ts.map +1 -1
  232. package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
  233. package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
  234. package/types/lib/inventory/cacheCommands.d.ts +2 -1
  235. package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
  236. package/types/lib/inventory/cdxrs.d.ts +8 -3
  237. package/types/lib/inventory/cdxrs.d.ts.map +1 -1
  238. package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
  239. package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
  240. package/types/lib/inventory/deps.d.ts +59 -1
  241. package/types/lib/inventory/deps.d.ts.map +1 -1
  242. package/types/lib/inventory/depsUtils.d.ts +15 -0
  243. package/types/lib/inventory/depsUtils.d.ts.map +1 -1
  244. package/types/lib/inventory/display.d.ts.map +1 -1
  245. package/types/lib/inventory/dosai.d.ts +121 -9
  246. package/types/lib/inventory/dosai.d.ts.map +1 -1
  247. package/types/lib/inventory/dosaiParsers.d.ts +53 -7
  248. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  249. package/types/lib/inventory/dynamic.d.ts +10 -0
  250. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  251. package/types/lib/inventory/evidenceUtils.d.ts +19 -4
  252. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  253. package/types/lib/inventory/fetchBatch.d.ts +83 -14
  254. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  255. package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
  256. package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
  257. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
  258. package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
  259. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
  260. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  261. package/types/lib/inventory/parentSelection.d.ts +34 -0
  262. package/types/lib/inventory/parentSelection.d.ts.map +1 -0
  263. package/types/lib/inventory/plugins.d.ts.map +1 -1
  264. package/types/lib/inventory/protobom.d.ts.map +1 -1
  265. package/types/lib/inventory/purl.d.ts +71 -2
  266. package/types/lib/inventory/purl.d.ts.map +1 -1
  267. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  268. package/types/lib/inventory/sbomDocument.d.ts.map +1 -1
  269. package/types/lib/inventory/scalaCoords.d.ts +80 -0
  270. package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
  271. package/types/lib/inventory/source.d.ts.map +1 -1
  272. package/types/lib/inventory/spdx.d.ts +9 -0
  273. package/types/lib/inventory/spdx.d.ts.map +1 -1
  274. package/types/lib/inventory/traceRunner.d.ts +59 -1
  275. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  276. package/types/lib/inventory/tracedCrypto.d.ts +42 -0
  277. package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
  278. package/types/lib/managers/binary.d.ts +30 -1
  279. package/types/lib/managers/binary.d.ts.map +1 -1
  280. package/types/lib/managers/docker.d.ts +29 -0
  281. package/types/lib/managers/docker.d.ts.map +1 -1
  282. package/types/lib/managers/oci.d.ts +17 -1
  283. package/types/lib/managers/oci.d.ts.map +1 -1
  284. package/types/lib/parsers/cmakeCache.d.ts +16 -0
  285. package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
  286. package/types/lib/parsers/cmakeLists.d.ts +77 -0
  287. package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
  288. package/types/lib/parsers/cmakePresets.d.ts +78 -0
  289. package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
  290. package/types/lib/parsers/compileCommands.d.ts +115 -0
  291. package/types/lib/parsers/compileCommands.d.ts.map +1 -0
  292. package/types/lib/parsers/largeJson.d.ts +52 -0
  293. package/types/lib/parsers/largeJson.d.ts.map +1 -0
  294. package/types/lib/parsers/npmrc.d.ts +5 -0
  295. package/types/lib/parsers/npmrc.d.ts.map +1 -1
  296. package/types/lib/parsers/strictJson.d.ts +46 -0
  297. package/types/lib/parsers/strictJson.d.ts.map +1 -0
  298. package/types/lib/parsers/terraformConfig.d.ts +70 -0
  299. package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
  300. package/types/lib/parsers/terraformSource.d.ts +66 -0
  301. package/types/lib/parsers/terraformSource.d.ts.map +1 -0
  302. package/types/lib/server/server.d.ts.map +1 -1
  303. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  304. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  305. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  306. package/types/lib/validator/index.d.ts +18 -1
  307. package/types/lib/validator/index.d.ts.map +1 -1
  308. package/types/lib/validator/reporters/console.d.ts.map +1 -1
  309. package/types/lib/validator/reporters/json.d.ts.map +1 -1
  310. package/types/lib/validator/reporters/sarif.d.ts.map +1 -1
  311. package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
package/lib/cli/index.js CHANGED
@@ -44,6 +44,7 @@ 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,
@@ -65,6 +66,7 @@ import {
65
66
  hasHbomProjectType,
66
67
  } from "../inventory/hbom.js";
67
68
  import { mergeHostInventoryBoms } from "../inventory/hostTopology.js";
69
+ import { orderParentCandidates } from "../inventory/parentSelection.js";
68
70
  // Imported directly rather than through the utils.js barrel: purl validity is
69
71
  // checked in a hot path and the barrel is already the root of several import
70
72
  // cycles.
@@ -84,6 +86,7 @@ import {
84
86
  exportArchive,
85
87
  exportImage,
86
88
  getPkgPathList,
89
+ isImageReference,
87
90
  parseImageName,
88
91
  } from "../managers/docker.js";
89
92
  import {
@@ -876,6 +879,19 @@ export async function createMultiXBom(pathList, options) {
876
879
  let components = [];
877
880
  let dependencies = [];
878
881
  let parentSubComponents = [];
882
+ // Each builder detects the project of its own ecosystem. A builder that sets
883
+ // options.parentComponent to force its project into its own BOM must not
884
+ // make that project the next builder's too, or the next ecosystem's project
885
+ // is lost: every builder starts from the parent the caller gave.
886
+ const callerParent = options.parentComponent;
887
+ const withOwnParent = async (build) => {
888
+ options.parentComponent = callerParent;
889
+ try {
890
+ return await build();
891
+ } finally {
892
+ options.parentComponent = callerParent;
893
+ }
894
+ };
879
895
  setActivityContext({
880
896
  projectType: Array.isArray(options.projectType)
881
897
  ? options.projectType.join(",")
@@ -922,7 +938,7 @@ export async function createMultiXBom(pathList, options) {
922
938
  }
923
939
  }
924
940
  setProjectTypeActivityContext(exactAiInventoryType || "js", path);
925
- bomData = await createNodejsBom(path, options);
941
+ bomData = await withOwnParent(() => createNodejsBom(path, options));
926
942
  if (bomData?.bomJson?.components?.length) {
927
943
  if (exactAiInventoryType) {
928
944
  thoughtLog(
@@ -972,7 +988,7 @@ export async function createMultiXBom(pathList, options) {
972
988
  );
973
989
  }
974
990
  setProjectTypeActivityContext("java", path);
975
- bomData = await createJavaBom(path, options);
991
+ bomData = await withOwnParent(() => createJavaBom(path, options));
976
992
  if (bomData?.bomJson?.components?.length) {
977
993
  thoughtLog(
978
994
  `I found ${bomData.bomJson.components.length} java packages.`,
@@ -1037,7 +1053,7 @@ export async function createMultiXBom(pathList, options) {
1037
1053
  );
1038
1054
  }
1039
1055
  setProjectTypeActivityContext("py", path);
1040
- bomData = await createPythonBom(path, options);
1056
+ bomData = await withOwnParent(() => createPythonBom(path, options));
1041
1057
  if (bomData?.bomJson?.components?.length) {
1042
1058
  thoughtLog(
1043
1059
  `I found ${bomData.bomJson.components.length} python packages.`,
@@ -1058,6 +1074,17 @@ export async function createMultiXBom(pathList, options) {
1058
1074
  ) {
1059
1075
  parentSubComponents.push(bomData.parentComponent);
1060
1076
  }
1077
+ // Retain metadata.component.components. uv workspace members are
1078
+ // nested under the python project, so hoisting them keeps them
1079
+ // siblings of the other sub-components instead of riding one level
1080
+ // deeper (or being dropped by the same-name collapse) when another
1081
+ // ecosystem's project becomes the parent.
1082
+ if (bomData.parentComponent?.components?.length) {
1083
+ parentSubComponents = parentSubComponents.concat(
1084
+ bomData.parentComponent.components,
1085
+ );
1086
+ delete bomData.parentComponent.components;
1087
+ }
1061
1088
  }
1062
1089
  if (bomData?.formulationList?.length) {
1063
1090
  formulationList = formulationList.concat(bomData.formulationList);
@@ -1070,7 +1097,7 @@ export async function createMultiXBom(pathList, options) {
1070
1097
  );
1071
1098
  }
1072
1099
  setProjectTypeActivityContext("go", path);
1073
- bomData = await createGoBom(path, options);
1100
+ bomData = await withOwnParent(() => createGoBom(path, options));
1074
1101
  if (bomData?.bomJson?.components?.length) {
1075
1102
  thoughtLog(`I found ${bomData.bomJson.components.length} go packages.`);
1076
1103
  if (DEBUG_MODE) {
@@ -1098,7 +1125,7 @@ export async function createMultiXBom(pathList, options) {
1098
1125
  );
1099
1126
  }
1100
1127
  setProjectTypeActivityContext("rust", path);
1101
- bomData = await createRustBom(path, options);
1128
+ bomData = await withOwnParent(() => createRustBom(path, options));
1102
1129
  if (bomData?.bomJson?.components?.length) {
1103
1130
  thoughtLog(
1104
1131
  `I found ${bomData.bomJson.components.length} rust packages.`,
@@ -1135,7 +1162,7 @@ export async function createMultiXBom(pathList, options) {
1135
1162
  );
1136
1163
  }
1137
1164
  setProjectTypeActivityContext("php", path);
1138
- bomData = createPHPBom(path, options);
1165
+ bomData = await withOwnParent(() => createPHPBom(path, options));
1139
1166
  if (bomData?.bomJson?.components?.length) {
1140
1167
  thoughtLog(
1141
1168
  `I found ${bomData.bomJson.components.length} php packages.`,
@@ -1172,7 +1199,7 @@ export async function createMultiXBom(pathList, options) {
1172
1199
  );
1173
1200
  }
1174
1201
  setProjectTypeActivityContext("ruby", path);
1175
- bomData = await createRubyBom(path, options);
1202
+ bomData = await withOwnParent(() => createRubyBom(path, options));
1176
1203
  if (bomData?.bomJson?.components?.length) {
1177
1204
  thoughtLog(
1178
1205
  `We got ${bomData.bomJson.components.length} ruby packages.`,
@@ -1208,7 +1235,7 @@ export async function createMultiXBom(pathList, options) {
1208
1235
  thoughtLog("**CSHARP**: What about csharp and fsharp projects?");
1209
1236
  }
1210
1237
  setProjectTypeActivityContext("csharp", path);
1211
- bomData = await createCsharpBom(path, options);
1238
+ bomData = await withOwnParent(() => createCsharpBom(path, options));
1212
1239
  if (bomData?.bomJson?.components?.length) {
1213
1240
  thoughtLog(
1214
1241
  `There are ${bomData.bomJson.components.length} csharp packages.`,
@@ -1245,7 +1272,7 @@ export async function createMultiXBom(pathList, options) {
1245
1272
  );
1246
1273
  }
1247
1274
  setProjectTypeActivityContext("dart", path);
1248
- bomData = await createDartBom(path, options);
1275
+ bomData = await withOwnParent(() => createDartBom(path, options));
1249
1276
  if (bomData?.bomJson?.components?.length) {
1250
1277
  thoughtLog(
1251
1278
  `I found ${bomData.bomJson.components.length} pub packages.`,
@@ -1275,7 +1302,7 @@ export async function createMultiXBom(pathList, options) {
1275
1302
  );
1276
1303
  }
1277
1304
  setProjectTypeActivityContext("haskell", path);
1278
- bomData = createHaskellBom(path, options);
1305
+ bomData = await withOwnParent(() => createHaskellBom(path, options));
1279
1306
  if (bomData?.bomJson?.components?.length) {
1280
1307
  thoughtLog(
1281
1308
  `I found ${bomData.bomJson.components.length} hackage packages.`,
@@ -1305,7 +1332,7 @@ export async function createMultiXBom(pathList, options) {
1305
1332
  );
1306
1333
  }
1307
1334
  setProjectTypeActivityContext("elixir", path);
1308
- bomData = createElixirBom(path, options);
1335
+ bomData = await withOwnParent(() => createElixirBom(path, options));
1309
1336
  if (bomData?.bomJson?.components?.length) {
1310
1337
  thoughtLog(
1311
1338
  `I found ${bomData.bomJson.components.length} mix packages.`,
@@ -1335,7 +1362,7 @@ export async function createMultiXBom(pathList, options) {
1335
1362
  );
1336
1363
  }
1337
1364
  setProjectTypeActivityContext("c", path);
1338
- bomData = createCppBom(path, options);
1365
+ bomData = await withOwnParent(() => createCppBom(path, options));
1339
1366
  if (bomData?.bomJson?.components?.length) {
1340
1367
  thoughtLog(
1341
1368
  `I found ${bomData.bomJson.components.length} cpp packages.`,
@@ -1357,6 +1384,10 @@ export async function createMultiXBom(pathList, options) {
1357
1384
  parentSubComponents.push(bomData.parentComponent);
1358
1385
  }
1359
1386
  }
1387
+ // presets and compilers describe the build, whatever it depends on
1388
+ if (bomData?.formulationList?.length) {
1389
+ formulationList = formulationList.concat(bomData.formulationList);
1390
+ }
1360
1391
  }
1361
1392
  if (hasAnyProjectType(["oci", "clojure"], options)) {
1362
1393
  if (!hasAnyProjectType(["oci"], options, false)) {
@@ -1365,7 +1396,7 @@ export async function createMultiXBom(pathList, options) {
1365
1396
  );
1366
1397
  }
1367
1398
  setProjectTypeActivityContext("clojure", path);
1368
- bomData = createClojureBom(path, options);
1399
+ bomData = await withOwnParent(() => createClojureBom(path, options));
1369
1400
  if (bomData?.bomJson?.components?.length) {
1370
1401
  thoughtLog(
1371
1402
  `I found ${bomData.bomJson.components.length} clojure packages.`,
@@ -1395,7 +1426,7 @@ export async function createMultiXBom(pathList, options) {
1395
1426
  );
1396
1427
  }
1397
1428
  setProjectTypeActivityContext("github", path);
1398
- bomData = createGitHubBom(path, options);
1429
+ bomData = await withOwnParent(() => createGitHubBom(path, options));
1399
1430
  if (bomData?.bomJson?.components?.length) {
1400
1431
  thoughtLog(
1401
1432
  `I found ${bomData.bomJson.components.length} github action packages as well. Should I convert these to formulation instead 🤔`,
@@ -1425,7 +1456,7 @@ export async function createMultiXBom(pathList, options) {
1425
1456
  );
1426
1457
  }
1427
1458
  setProjectTypeActivityContext("cloudbuild", path);
1428
- bomData = createCloudBuildBom(path, options);
1459
+ bomData = await withOwnParent(() => createCloudBuildBom(path, options));
1429
1460
  if (bomData?.bomJson?.components?.length) {
1430
1461
  thoughtLog(
1431
1462
  `I found ${bomData.bomJson.components.length} cloudbuild packages.`,
@@ -1455,7 +1486,7 @@ export async function createMultiXBom(pathList, options) {
1455
1486
  );
1456
1487
  }
1457
1488
  setProjectTypeActivityContext("swift", path);
1458
- bomData = await createSwiftBom(path, options);
1489
+ bomData = await withOwnParent(() => createSwiftBom(path, options));
1459
1490
  if (bomData?.bomJson?.components?.length) {
1460
1491
  thoughtLog(
1461
1492
  `I found ${bomData.bomJson.components.length} swift packages here.`,
@@ -1493,7 +1524,7 @@ export async function createMultiXBom(pathList, options) {
1493
1524
  detail:
1494
1525
  "Components are being inferred by scanning jar/war/ear files from disk.",
1495
1526
  });
1496
- bomData = await createJarBom(path, options);
1527
+ bomData = await withOwnParent(() => createJarBom(path, options));
1497
1528
  if (bomData?.bomJson?.components?.length) {
1498
1529
  thoughtLog(
1499
1530
  `I found ${bomData.bomJson.components.length} jar packages as well.`,
@@ -1518,7 +1549,7 @@ export async function createMultiXBom(pathList, options) {
1518
1549
  }
1519
1550
  if (hasAnyProjectType(["oci", "cocoa"], options)) {
1520
1551
  setProjectTypeActivityContext("cocoa", path);
1521
- bomData = await createCocoaBom(path, options);
1552
+ bomData = await withOwnParent(() => createCocoaBom(path, options));
1522
1553
  if (bomData?.bomJson?.components?.length) {
1523
1554
  if (DEBUG_MODE) {
1524
1555
  console.log(
@@ -1537,7 +1568,7 @@ export async function createMultiXBom(pathList, options) {
1537
1568
  }
1538
1569
  if (hasAnyProjectType(["oci", "nix"], options)) {
1539
1570
  setProjectTypeActivityContext("nix", path);
1540
- bomData = await createNixBom(path, options);
1571
+ bomData = await withOwnParent(() => createNixBom(path, options));
1541
1572
  if (bomData?.bomJson?.components?.length) {
1542
1573
  if (DEBUG_MODE) {
1543
1574
  console.log(
@@ -1559,7 +1590,7 @@ export async function createMultiXBom(pathList, options) {
1559
1590
  }
1560
1591
  if (hasAnyProjectType(["caxa"], options, false)) {
1561
1592
  setProjectTypeActivityContext("caxa", path);
1562
- bomData = await createCaxaBom(path, options);
1593
+ bomData = await withOwnParent(() => createCaxaBom(path, options));
1563
1594
  if (bomData?.bomJson?.components?.length) {
1564
1595
  if (DEBUG_MODE) {
1565
1596
  console.log(
@@ -1581,7 +1612,7 @@ export async function createMultiXBom(pathList, options) {
1581
1612
  }
1582
1613
  if (hasAnyProjectType(["asar"], options, false)) {
1583
1614
  setProjectTypeActivityContext("asar", path);
1584
- bomData = await createAsarBom(path, options);
1615
+ bomData = await withOwnParent(() => createAsarBom(path, options));
1585
1616
  if (bomData?.bomJson?.components?.length) {
1586
1617
  if (DEBUG_MODE) {
1587
1618
  console.log(
@@ -1603,7 +1634,9 @@ export async function createMultiXBom(pathList, options) {
1603
1634
  }
1604
1635
  if (hasAnyProjectType(["vscode-extension"], options, false)) {
1605
1636
  setProjectTypeActivityContext("vscode-extension", path);
1606
- bomData = await createVscodeExtensionBom(path, options);
1637
+ bomData = await withOwnParent(() =>
1638
+ createVscodeExtensionBom(path, options),
1639
+ );
1607
1640
  if (bomData?.bomJson?.components?.length) {
1608
1641
  if (DEBUG_MODE) {
1609
1642
  console.log(
@@ -1646,7 +1679,9 @@ export async function createMultiXBom(pathList, options) {
1646
1679
  sharedOptions.__didScanChromeExtensions = true;
1647
1680
  }
1648
1681
  setProjectTypeActivityContext("chrome-extension", path);
1649
- bomData = await createChromeExtensionBom(path, options);
1682
+ bomData = await withOwnParent(() =>
1683
+ createChromeExtensionBom(path, options),
1684
+ );
1650
1685
  if (bomData?.bomJson?.components?.length) {
1651
1686
  if (DEBUG_MODE) {
1652
1687
  console.log(
@@ -1667,6 +1702,34 @@ export async function createMultiXBom(pathList, options) {
1667
1702
  }
1668
1703
  }
1669
1704
  }
1705
+ if (hasAnyProjectType(["terraform"], options)) {
1706
+ thoughtLog(
1707
+ "**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.",
1708
+ );
1709
+ setProjectTypeActivityContext("terraform", path);
1710
+ bomData = await withOwnParent(() => createTerraformBom(path, options));
1711
+ if (bomData?.bomJson?.components?.length) {
1712
+ thoughtLog(
1713
+ `I found ${bomData.bomJson.components.length} terraform components. Should I also resolve their licenses from the registry when FETCH_LICENSE is enabled?`,
1714
+ );
1715
+ if (DEBUG_MODE) {
1716
+ console.log(
1717
+ `Found ${bomData.bomJson.components.length} terraform components at ${path}`,
1718
+ );
1719
+ }
1720
+ components = components.concat(bomData.bomJson.components);
1721
+ dependencies = mergeDependencies(
1722
+ dependencies,
1723
+ bomData.bomJson.dependencies,
1724
+ );
1725
+ if (
1726
+ bomData.parentComponent &&
1727
+ Object.keys(bomData.parentComponent).length
1728
+ ) {
1729
+ parentSubComponents.push(bomData.parentComponent);
1730
+ }
1731
+ }
1732
+ }
1670
1733
  // Collect any crypto keys
1671
1734
  if (
1672
1735
  options.specVersion >= 1.6 &&
@@ -1679,7 +1742,7 @@ export async function createMultiXBom(pathList, options) {
1679
1742
  );
1680
1743
  }
1681
1744
  setProjectTypeActivityContext("cbom", path);
1682
- bomData = await createCryptoCertsBom(path, options);
1745
+ bomData = await withOwnParent(() => createCryptoCertsBom(path, options));
1683
1746
  if (bomData?.bomJson?.components?.length) {
1684
1747
  thoughtLog(
1685
1748
  `I found ${bomData.bomJson.components.length} crypto assets.`,
@@ -1770,7 +1833,7 @@ export async function createMultiXBom(pathList, options) {
1770
1833
  !options.lastWorkingDir.includes("/home/")
1771
1834
  ) {
1772
1835
  setProjectTypeActivityContext("jar", options.lastWorkingDir);
1773
- bomData = createJarBom(options.lastWorkingDir, options);
1836
+ bomData = await createJarBom(options.lastWorkingDir, options);
1774
1837
  if (bomData?.bomJson?.components?.length) {
1775
1838
  if (DEBUG_MODE) {
1776
1839
  console.log(
@@ -1796,14 +1859,24 @@ export async function createMultiXBom(pathList, options) {
1796
1859
  thoughtLog("**METADATA**: Tweaking the parent component hierarchy.");
1797
1860
  }
1798
1861
  if (!parentComponent || !Object.keys(parentComponent).length) {
1799
- parentComponent = parentSubComponents[0];
1862
+ // the project whose manifest sits at the scan root describes the
1863
+ // repository; ties keep the order the ecosystems were scanned in
1864
+ parentComponent = orderParentCandidates(
1865
+ parentSubComponents,
1866
+ pathList,
1867
+ options,
1868
+ )[0];
1800
1869
  }
1801
1870
  // Our naive approach to appending to sub-components could result in same parent being included as a child
1802
1871
  // This is filtered out here
1803
1872
  parentSubComponents = parentSubComponents.filter(
1804
1873
  (c) => c["bom-ref"] !== parentComponent["bom-ref"],
1805
1874
  );
1806
- parentComponent.components = trimComponents(parentSubComponents);
1875
+ // keep the parent's own sub-components (a CMake project's sub-projects)
1876
+ parentComponent.components = trimComponents([
1877
+ ...(parentComponent.components || []),
1878
+ ...parentSubComponents,
1879
+ ]);
1807
1880
  if (
1808
1881
  parentComponent.components.length === 1 &&
1809
1882
  parentComponent.components[0].name === parentComponent.name &&
@@ -1813,24 +1886,15 @@ export async function createMultiXBom(pathList, options) {
1813
1886
  delete parentComponent.components;
1814
1887
  }
1815
1888
  // Add references between the multiple sub-boms
1816
- let parentDependencies = dependencies.find(
1817
- (d) => d["ref"] === parentComponent["bom-ref"],
1818
- );
1819
- if (!parentDependencies) {
1820
- parentDependencies = {
1821
- ref: parentComponent["bom-ref"],
1822
- };
1823
- dependencies = mergeDependencies(dependencies, parentDependencies);
1824
- }
1825
- if (!parentDependencies["dependsOn"]) {
1826
- parentDependencies["dependsOn"] = [];
1827
- }
1828
- for (const parentSub of parentSubComponents) {
1829
- // Issue: 1622. We might have already captured this parent component dependency
1830
- if (!parentDependencies["dependsOn"].includes(parentSub["bom-ref"])) {
1831
- parentDependencies["dependsOn"].push(parentSub["bom-ref"]);
1832
- }
1833
- }
1889
+ // mergeDependencies returns fresh objects and unions dependsOn per ref,
1890
+ // so the parent edges are folded in through a single merge
1891
+ const parentRef = parentComponent["bom-ref"];
1892
+ const parentSubRefs = parentSubComponents
1893
+ .map((c) => c["bom-ref"])
1894
+ .filter((ref) => ref && ref !== parentRef);
1895
+ dependencies = mergeDependencies(dependencies, [
1896
+ { ref: parentRef, dependsOn: parentSubRefs },
1897
+ ]);
1834
1898
  }
1835
1899
  // some cleanup, but not complete
1836
1900
  for (const path of pathList) {
@@ -1900,17 +1964,49 @@ export async function createDynamicBom(path, options) {
1900
1964
  blockExec: options.traceBlockExec,
1901
1965
  traceCrypto: options.traceCrypto,
1902
1966
  cbom: options.cbom,
1967
+ proxyEgress: options.traceProxyEgress,
1968
+ allowLoopback: options.traceAllowLoopback,
1969
+ dryRun: options.traceDryRun,
1970
+ policy: options.tracePolicy,
1971
+ policyFile: options.tracePolicyFile,
1972
+ blockInterpreters: options.traceBlockInterpreters,
1973
+ denyPersistenceWrites: options.traceDenyPersistenceWrites,
1974
+ privateTmp: options.tracePrivateTmp,
1975
+ protectHome: options.traceProtectHome,
1903
1976
  };
1904
1977
 
1905
- const { components: pkgList, services: traceServices } =
1906
- await buildDynamicComponents(commandStr, workingDir, traceOptions);
1978
+ const {
1979
+ components: pkgList,
1980
+ services: traceServices,
1981
+ dryRunSummary,
1982
+ } = await buildDynamicComponents(commandStr, workingDir, traceOptions);
1907
1983
 
1908
- return buildBomNSData(options, pkgList, "generic", {
1984
+ const bomNSData = buildBomNSData(options, pkgList, "generic", {
1909
1985
  src: workingDir,
1910
1986
  projectType: "dynamic",
1911
1987
  filename: commandStr,
1912
1988
  services: traceServices,
1913
1989
  });
1990
+ // A dry run denies every side effect, so the attempted-operation counts are
1991
+ // the result. Only counts are recorded, never the paths or targets.
1992
+ if (dryRunSummary && bomNSData?.bomJson?.metadata) {
1993
+ const metadata = bomNSData.bomJson.metadata;
1994
+ metadata.properties = metadata.properties || [];
1995
+ metadata.properties.push({ name: "cdx:dynamic:dryRun", value: "true" });
1996
+ metadata.properties.push({
1997
+ name: "cdx:dynamic:dryRun:captured",
1998
+ value: dryRunSummary.captured === false ? "false" : "true",
1999
+ });
2000
+ for (const [key, value] of Object.entries(dryRunSummary)) {
2001
+ if (Number.isInteger(value)) {
2002
+ metadata.properties.push({
2003
+ name: `cdx:dynamic:dryRun:${key}`,
2004
+ value: String(value),
2005
+ });
2006
+ }
2007
+ }
2008
+ }
2009
+ return bomNSData;
1914
2010
  }
1915
2011
 
1916
2012
  /**
@@ -2431,14 +2527,10 @@ export async function createXBom(path, options) {
2431
2527
  return createPerlBom(path, options);
2432
2528
  }
2433
2529
 
2434
- // Terraform and OpenTofu providers
2435
- const tfLockFiles = getAllFiles(
2436
- path,
2437
- `${options.multiProject ? "**/" : ""}.terraform.lock.hcl`,
2438
- options,
2439
- );
2440
- if (tfLockFiles.length) {
2441
- return createTerraformBom(path, options);
2530
+ // Terraform and OpenTofu providers and modules, discovered with the same
2531
+ // patterns and exclusions the workspace assembly uses.
2532
+ if (hasTerraformConfiguration(path, options)) {
2533
+ return await createTerraformBom(path, options);
2442
2534
  }
2443
2535
  }
2444
2536
 
@@ -2561,7 +2653,13 @@ async function createBomForPath(path, options) {
2561
2653
  } else if (
2562
2654
  (options.projectType &&
2563
2655
  !options.projectType?.includes("universal") &&
2564
- hasAnyProjectType(["oci"], options, false)) ||
2656
+ hasAnyProjectType(["oci"], options, false) &&
2657
+ // Explicit container types accept every documented image reference
2658
+ // style (postgres:15-alpine, shiftleft/scan-slim, registry:5000/ns/img),
2659
+ // but only for inputs that cannot be a local path: existing files and
2660
+ // directories keep flowing to the tar, oci-dir and source scanners.
2661
+ !safeExistsSync(path) &&
2662
+ isImageReference(path)) ||
2565
2663
  path.startsWith("docker.io") ||
2566
2664
  path.startsWith("quay.io") ||
2567
2665
  path.startsWith("ghcr.io") ||
@@ -2822,7 +2920,7 @@ async function createBomForPath(path, options) {
2822
2920
  return createPerlBom(path, options);
2823
2921
  }
2824
2922
  if (PROJECT_TYPE_ALIASES["terraform"].includes(projectType[0])) {
2825
- return createTerraformBom(path, options);
2923
+ return await createTerraformBom(path, options);
2826
2924
  }
2827
2925
  if (PROJECT_TYPE_ALIASES["caxa"].includes(projectType[0])) {
2828
2926
  return await createCaxaBom(path, options);