@cdxgen/cdxgen 13.5.0 → 13.7.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 (380) hide show
  1. package/README.md +17 -10
  2. package/bin/audit.js +7 -4
  3. package/bin/cdxgen.js +260 -37
  4. package/bin/convert.js +146 -22
  5. package/bin/evinse.js +28 -3
  6. package/bin/repl.js +47 -3
  7. package/bin/sign.js +211 -34
  8. package/bin/tracebom.js +18 -6
  9. package/bin/validate.js +24 -3
  10. package/bin/verify.js +113 -5
  11. package/data/behavior-taxonomy.schema.json +1491 -0
  12. package/data/cyclonedx-2.0-bundled.schema.json +18606 -5528
  13. package/data/cyclonedx-2.0-cryptography-defs.schema.json +857 -0
  14. package/data/license-aliases.json +24 -2
  15. package/data/pqc-migration.json +239 -0
  16. package/data/remediations.json +176 -0
  17. package/data/rules/ai-bom.yaml +1 -1
  18. package/data/rules/brotli-decoder.yaml +107 -0
  19. package/data/rules/cbom-security.yaml +4 -3
  20. package/data/rules/package-integrity.yaml +28 -0
  21. package/data/rules/vscode-extensions.yaml +75 -0
  22. package/data/spdx-license-list.json +121 -7
  23. package/data/spdx-licenses.json +69 -0
  24. package/data/spdx.schema.json +845 -2
  25. package/lib/audit/index.js +25 -3
  26. package/lib/cli/bomAssembly.js +172 -4
  27. package/lib/cli/cliOptions.js +121 -17
  28. package/lib/cli/index.js +720 -902
  29. package/lib/cli/jsBom.js +156 -64
  30. package/lib/cli/jvmBom.js +602 -86
  31. package/lib/cli/managedBom.js +161 -19
  32. package/lib/cli/nativeBom.js +52 -5
  33. package/lib/core/boundedFile.js +344 -0
  34. package/lib/core/brotliProbe.js +182 -0
  35. package/lib/core/env.js +34 -0
  36. package/lib/core/fs.js +138 -3
  37. package/lib/core/globPatterns.js +218 -0
  38. package/lib/core/httpClient.js +98 -1
  39. package/lib/core/lockPaths.js +38 -0
  40. package/lib/core/paths.js +24 -1
  41. package/lib/core/processTree.js +100 -8
  42. package/lib/core/projectConfig.js +332 -25
  43. package/lib/core/toolRegistry.js +184 -0
  44. package/lib/ecosystems/cppEvidence.js +263 -106
  45. package/lib/ecosystems/cppIncludeResolver.js +16 -5
  46. package/lib/ecosystems/denoutils.js +2 -2
  47. package/lib/ecosystems/ecosystems.js +25 -10
  48. package/lib/ecosystems/gemHostProbe.js +301 -0
  49. package/lib/ecosystems/golem.js +3 -8
  50. package/lib/ecosystems/gradleutils.js +1909 -229
  51. package/lib/ecosystems/jsEvidence.js +90 -38
  52. package/lib/ecosystems/kosi.js +3 -5
  53. package/lib/ecosystems/npmVersionResolution.js +376 -0
  54. package/lib/ecosystems/parsers-bazel.js +107 -6
  55. package/lib/ecosystems/parsers-js.js +505 -22
  56. package/lib/ecosystems/parsers-misc.js +209 -20
  57. package/lib/ecosystems/parsers-python.js +178 -30
  58. package/lib/ecosystems/parsers-rust.js +117 -15
  59. package/lib/ecosystems/pythonutils.js +128 -2
  60. package/lib/ecosystems/remote/huggingface.js +22 -0
  61. package/lib/ecosystems/rubyutils.js +538 -31
  62. package/lib/ecosystems/rusi.js +2 -4
  63. package/lib/ecosystems/scalacliutils.js +2 -0
  64. package/lib/ecosystems/scalasem.js +798 -152
  65. package/lib/ecosystems/vendoredCode.js +237 -3
  66. package/lib/ecosystems/venvProbe.js +360 -0
  67. package/lib/evinser/evinser.js +536 -71
  68. package/lib/evinser/scalasem.js +5 -1
  69. package/lib/helpers/agenticToolutils.js +525 -94
  70. package/lib/helpers/bomSigner.js +43 -9
  71. package/lib/helpers/jssSigner.js +1276 -0
  72. package/lib/helpers/vsixutils.js +1574 -315
  73. package/lib/inventory/agentBlueprint.js +193 -0
  74. package/lib/inventory/agentToolNames.js +145 -0
  75. package/lib/inventory/aiCollector.js +153 -7
  76. package/lib/inventory/aiInventory.js +44 -8
  77. package/lib/inventory/aiProviders.js +324 -0
  78. package/lib/inventory/atomUtils.js +77 -0
  79. package/lib/inventory/bomUtils.js +8 -1
  80. package/lib/inventory/brotliDecoder.js +142 -0
  81. package/lib/inventory/buildToolRateLimit.js +1 -1
  82. package/lib/inventory/cbomutils.js +56 -7
  83. package/lib/inventory/ciParsers/githubActionsLock.js +821 -0
  84. package/lib/inventory/citations.js +31 -2
  85. package/lib/inventory/communityAiConfigParser.js +978 -80
  86. package/lib/inventory/cyclonedx20.js +152 -0
  87. package/lib/inventory/cyclonedx20Common.js +286 -0
  88. package/lib/inventory/cyclonedx20Derived.js +159 -0
  89. package/lib/inventory/cyclonedx20Parties.js +552 -0
  90. package/lib/inventory/cyclonedx20Read.js +768 -0
  91. package/lib/inventory/cyclonedx20ReadCommon.js +374 -0
  92. package/lib/inventory/cyclonedx20ReadComponents.js +692 -0
  93. package/lib/inventory/cyclonedx20ReadContext.js +380 -0
  94. package/lib/inventory/cyclonedx20ReadEvidence.js +466 -0
  95. package/lib/inventory/cyclonedx20ReadSections.js +599 -0
  96. package/lib/inventory/cyclonedx20Render.js +766 -0
  97. package/lib/inventory/cyclonedx20RenderComponents.js +716 -0
  98. package/lib/inventory/cyclonedx20RenderDefinitions.js +405 -0
  99. package/lib/inventory/cyclonedx20RenderEvidence.js +726 -0
  100. package/lib/inventory/cyclonedx20RenderHardware.js +203 -0
  101. package/lib/inventory/cyclonedx20RenderPatents.js +174 -0
  102. package/lib/inventory/cyclonedx20RenderRefIds.js +314 -0
  103. package/lib/inventory/cyclonedx20RenderSections.js +499 -0
  104. package/lib/inventory/cyclonedx20Tables.js +594 -0
  105. package/lib/inventory/deps.js +141 -13
  106. package/lib/inventory/dosai.js +375 -6
  107. package/lib/inventory/dosaiParsers.js +3 -6
  108. package/lib/inventory/dotnetRuntime.js +367 -0
  109. package/lib/inventory/ecosystemFormulationParsers.js +979 -0
  110. package/lib/inventory/envcontext.js +436 -48
  111. package/lib/inventory/evidenceUtils.js +13 -1
  112. package/lib/inventory/fetchBatch.js +1 -1
  113. package/lib/inventory/formulationParsers.js +124 -14
  114. package/lib/inventory/gtfobins.js +13 -0
  115. package/lib/inventory/hbom.js +45 -6
  116. package/lib/inventory/hbomLoader.js +166 -0
  117. package/lib/inventory/hostRuntimeProbe.js +686 -0
  118. package/lib/inventory/jvmLocalRepos.js +9 -2
  119. package/lib/inventory/jvmToolEnv.js +29 -0
  120. package/lib/inventory/licenseEnhancer.js +12 -0
  121. package/lib/inventory/mavenCentralMirror.js +534 -0
  122. package/lib/inventory/mcpConfigParser.js +5 -0
  123. package/lib/inventory/nodeBuildInfo.js +218 -0
  124. package/lib/inventory/nodeHostProbe.js +202 -0
  125. package/lib/inventory/occurrenceKey.js +90 -0
  126. package/lib/inventory/osPackageResolver.js +182 -0
  127. package/lib/inventory/phpBuildInfo.js +10 -59
  128. package/lib/inventory/phpHostProbe.js +32 -488
  129. package/lib/inventory/pqcMigration.js +426 -0
  130. package/lib/inventory/rubyBuildInfo.js +972 -0
  131. package/lib/inventory/rubyHostProbe.js +218 -0
  132. package/lib/inventory/rustFormulationParser.js +21 -10
  133. package/lib/inventory/scalaCoords.js +4 -3
  134. package/lib/inventory/scalaDedupe.js +440 -0
  135. package/lib/inventory/source.js +114 -8
  136. package/lib/managers/binary.js +337 -3
  137. package/lib/managers/docker.js +79 -0
  138. package/lib/parsers/huggingfaceManifest.js +9 -1
  139. package/lib/parsers/huggingfaceUtils.js +18 -0
  140. package/lib/parsers/kiroPermissions.js +166 -0
  141. package/lib/parsers/largeJson.js +28 -11
  142. package/lib/parsers/vscodeExtensionId.js +183 -0
  143. package/lib/server/server.js +48 -35
  144. package/lib/stages/postgen/postgen.js +41 -1
  145. package/lib/stages/postgen/ruleEngine.js +13 -5
  146. package/lib/stages/postgen/specVersionCompat.js +76 -0
  147. package/lib/stages/pregen/envAudit.js +1 -0
  148. package/lib/stages/pregen/pregen.js +114 -57
  149. package/lib/validator/bomValidator.js +14 -2
  150. package/lib/validator/complianceEngine.js +30 -3
  151. package/lib/validator/complianceRules.js +1416 -4
  152. package/lib/validator/generated/validate-1.6.mjs +1 -1
  153. package/lib/validator/generated/validate-1.7.mjs +1 -1
  154. package/lib/validator/generated/validate-2.0.mjs +57554 -13851
  155. package/lib/validator/index.js +49 -8
  156. package/lib/validator/reporters/json.js +6 -0
  157. package/package.json +11 -10
  158. package/types/bin/repl.d.ts.map +1 -1
  159. package/types/lib/audit/index.d.ts +6 -2
  160. package/types/lib/audit/index.d.ts.map +1 -1
  161. package/types/lib/cli/bomAssembly.d.ts +29 -1
  162. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  163. package/types/lib/cli/cliOptions.d.ts +6 -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 +3 -18
  167. package/types/lib/cli/jsBom.d.ts.map +1 -1
  168. package/types/lib/cli/jvmBom.d.ts +15 -0
  169. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  170. package/types/lib/cli/managedBom.d.ts.map +1 -1
  171. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  172. package/types/lib/core/boundedFile.d.ts +100 -0
  173. package/types/lib/core/boundedFile.d.ts.map +1 -0
  174. package/types/lib/core/brotliProbe.d.ts +37 -0
  175. package/types/lib/core/brotliProbe.d.ts.map +1 -0
  176. package/types/lib/core/env.d.ts +14 -0
  177. package/types/lib/core/env.d.ts.map +1 -1
  178. package/types/lib/core/fs.d.ts +4 -0
  179. package/types/lib/core/fs.d.ts.map +1 -1
  180. package/types/lib/core/globPatterns.d.ts +70 -0
  181. package/types/lib/core/globPatterns.d.ts.map +1 -0
  182. package/types/lib/core/httpClient.d.ts +24 -0
  183. package/types/lib/core/httpClient.d.ts.map +1 -1
  184. package/types/lib/core/lockPaths.d.ts +19 -0
  185. package/types/lib/core/lockPaths.d.ts.map +1 -0
  186. package/types/lib/core/paths.d.ts +9 -0
  187. package/types/lib/core/paths.d.ts.map +1 -1
  188. package/types/lib/core/processTree.d.ts +17 -4
  189. package/types/lib/core/processTree.d.ts.map +1 -1
  190. package/types/lib/core/projectConfig.d.ts +47 -8
  191. package/types/lib/core/projectConfig.d.ts.map +1 -1
  192. package/types/lib/core/toolRegistry.d.ts +36 -0
  193. package/types/lib/core/toolRegistry.d.ts.map +1 -0
  194. package/types/lib/ecosystems/cppEvidence.d.ts +40 -13
  195. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  196. package/types/lib/ecosystems/cppIncludeResolver.d.ts +2 -1
  197. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -1
  198. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  199. package/types/lib/ecosystems/gemHostProbe.d.ts +28 -0
  200. package/types/lib/ecosystems/gemHostProbe.d.ts.map +1 -0
  201. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  202. package/types/lib/ecosystems/gradleutils.d.ts +294 -20
  203. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  204. package/types/lib/ecosystems/jsEvidence.d.ts +14 -1
  205. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  206. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  207. package/types/lib/ecosystems/npmVersionResolution.d.ts +119 -0
  208. package/types/lib/ecosystems/npmVersionResolution.d.ts.map +1 -0
  209. package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -1
  210. package/types/lib/ecosystems/parsers-js.d.ts +17 -20
  211. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  212. package/types/lib/ecosystems/parsers-misc.d.ts +19 -0
  213. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  214. package/types/lib/ecosystems/parsers-python.d.ts +10 -0
  215. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  216. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  217. package/types/lib/ecosystems/pythonutils.d.ts +19 -1
  218. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  219. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  220. package/types/lib/ecosystems/rubyutils.d.ts +144 -12
  221. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  222. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  223. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -1
  224. package/types/lib/ecosystems/scalasem.d.ts +58 -16
  225. package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
  226. package/types/lib/ecosystems/vendoredCode.d.ts +26 -0
  227. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -1
  228. package/types/lib/ecosystems/venvProbe.d.ts +40 -0
  229. package/types/lib/ecosystems/venvProbe.d.ts.map +1 -0
  230. package/types/lib/evinser/evinser.d.ts +120 -13
  231. package/types/lib/evinser/evinser.d.ts.map +1 -1
  232. package/types/lib/evinser/scalasem.d.ts.map +1 -1
  233. package/types/lib/helpers/agenticToolutils.d.ts +53 -19
  234. package/types/lib/helpers/agenticToolutils.d.ts.map +1 -1
  235. package/types/lib/helpers/bomSigner.d.ts +20 -3
  236. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  237. package/types/lib/helpers/jssSigner.d.ts +288 -0
  238. package/types/lib/helpers/jssSigner.d.ts.map +1 -0
  239. package/types/lib/helpers/vsixutils.d.ts +303 -19
  240. package/types/lib/helpers/vsixutils.d.ts.map +1 -1
  241. package/types/lib/inventory/agentBlueprint.d.ts +70 -0
  242. package/types/lib/inventory/agentBlueprint.d.ts.map +1 -0
  243. package/types/lib/inventory/agentToolNames.d.ts +51 -0
  244. package/types/lib/inventory/agentToolNames.d.ts.map +1 -0
  245. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  246. package/types/lib/inventory/aiInventory.d.ts.map +1 -1
  247. package/types/lib/inventory/aiProviders.d.ts +85 -0
  248. package/types/lib/inventory/aiProviders.d.ts.map +1 -0
  249. package/types/lib/inventory/atomUtils.d.ts +19 -0
  250. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  251. package/types/lib/inventory/bomUtils.d.ts.map +1 -1
  252. package/types/lib/inventory/brotliDecoder.d.ts +58 -0
  253. package/types/lib/inventory/brotliDecoder.d.ts.map +1 -0
  254. package/types/lib/inventory/cbomutils.d.ts +17 -0
  255. package/types/lib/inventory/cbomutils.d.ts.map +1 -1
  256. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts +101 -0
  257. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts.map +1 -0
  258. package/types/lib/inventory/citations.d.ts +5 -0
  259. package/types/lib/inventory/citations.d.ts.map +1 -1
  260. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  261. package/types/lib/inventory/cyclonedx20.d.ts +99 -0
  262. package/types/lib/inventory/cyclonedx20.d.ts.map +1 -0
  263. package/types/lib/inventory/cyclonedx20Common.d.ts +102 -0
  264. package/types/lib/inventory/cyclonedx20Common.d.ts.map +1 -0
  265. package/types/lib/inventory/cyclonedx20Derived.d.ts +74 -0
  266. package/types/lib/inventory/cyclonedx20Derived.d.ts.map +1 -0
  267. package/types/lib/inventory/cyclonedx20Parties.d.ts +91 -0
  268. package/types/lib/inventory/cyclonedx20Parties.d.ts.map +1 -0
  269. package/types/lib/inventory/cyclonedx20Read.d.ts +51 -0
  270. package/types/lib/inventory/cyclonedx20Read.d.ts.map +1 -0
  271. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts +69 -0
  272. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts.map +1 -0
  273. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts +77 -0
  274. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts.map +1 -0
  275. package/types/lib/inventory/cyclonedx20ReadContext.d.ts +118 -0
  276. package/types/lib/inventory/cyclonedx20ReadContext.d.ts.map +1 -0
  277. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts +40 -0
  278. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts.map +1 -0
  279. package/types/lib/inventory/cyclonedx20ReadSections.d.ts +45 -0
  280. package/types/lib/inventory/cyclonedx20ReadSections.d.ts.map +1 -0
  281. package/types/lib/inventory/cyclonedx20Render.d.ts +53 -0
  282. package/types/lib/inventory/cyclonedx20Render.d.ts.map +1 -0
  283. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts +73 -0
  284. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts.map +1 -0
  285. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts +29 -0
  286. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts.map +1 -0
  287. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts +110 -0
  288. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts.map +1 -0
  289. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts +42 -0
  290. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts.map +1 -0
  291. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts +26 -0
  292. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts.map +1 -0
  293. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts +55 -0
  294. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts.map +1 -0
  295. package/types/lib/inventory/cyclonedx20RenderSections.d.ts +45 -0
  296. package/types/lib/inventory/cyclonedx20RenderSections.d.ts.map +1 -0
  297. package/types/lib/inventory/cyclonedx20Tables.d.ts +134 -0
  298. package/types/lib/inventory/cyclonedx20Tables.d.ts.map +1 -0
  299. package/types/lib/inventory/deps.d.ts +35 -2
  300. package/types/lib/inventory/deps.d.ts.map +1 -1
  301. package/types/lib/inventory/dosai.d.ts +36 -1
  302. package/types/lib/inventory/dosai.d.ts.map +1 -1
  303. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  304. package/types/lib/inventory/dotnetRuntime.d.ts +91 -0
  305. package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -0
  306. package/types/lib/inventory/ecosystemFormulationParsers.d.ts +73 -0
  307. package/types/lib/inventory/ecosystemFormulationParsers.d.ts.map +1 -0
  308. package/types/lib/inventory/envcontext.d.ts +74 -12
  309. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  310. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  311. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  312. package/types/lib/inventory/gtfobins.d.ts.map +1 -1
  313. package/types/lib/inventory/hbom.d.ts +11 -0
  314. package/types/lib/inventory/hbom.d.ts.map +1 -1
  315. package/types/lib/inventory/hbomLoader.d.ts +54 -0
  316. package/types/lib/inventory/hbomLoader.d.ts.map +1 -1
  317. package/types/lib/inventory/hostRuntimeProbe.d.ts +44 -0
  318. package/types/lib/inventory/hostRuntimeProbe.d.ts.map +1 -0
  319. package/types/lib/inventory/jvmLocalRepos.d.ts +5 -1
  320. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -1
  321. package/types/lib/inventory/jvmToolEnv.d.ts +12 -0
  322. package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
  323. package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -1
  324. package/types/lib/inventory/mavenCentralMirror.d.ts +170 -0
  325. package/types/lib/inventory/mavenCentralMirror.d.ts.map +1 -0
  326. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  327. package/types/lib/inventory/nodeBuildInfo.d.ts +95 -0
  328. package/types/lib/inventory/nodeBuildInfo.d.ts.map +1 -0
  329. package/types/lib/inventory/nodeHostProbe.d.ts +15 -0
  330. package/types/lib/inventory/nodeHostProbe.d.ts.map +1 -0
  331. package/types/lib/inventory/occurrenceKey.d.ts +52 -0
  332. package/types/lib/inventory/occurrenceKey.d.ts.map +1 -0
  333. package/types/lib/inventory/osPackageResolver.d.ts +38 -0
  334. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
  335. package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -1
  336. package/types/lib/inventory/phpHostProbe.d.ts.map +1 -1
  337. package/types/lib/inventory/pqcMigration.d.ts +84 -0
  338. package/types/lib/inventory/pqcMigration.d.ts.map +1 -0
  339. package/types/lib/inventory/rubyBuildInfo.d.ts +271 -0
  340. package/types/lib/inventory/rubyBuildInfo.d.ts.map +1 -0
  341. package/types/lib/inventory/rubyHostProbe.d.ts +47 -0
  342. package/types/lib/inventory/rubyHostProbe.d.ts.map +1 -0
  343. package/types/lib/inventory/rustFormulationParser.d.ts +7 -2
  344. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  345. package/types/lib/inventory/scalaCoords.d.ts.map +1 -1
  346. package/types/lib/inventory/scalaDedupe.d.ts +43 -0
  347. package/types/lib/inventory/scalaDedupe.d.ts.map +1 -0
  348. package/types/lib/inventory/source.d.ts +25 -0
  349. package/types/lib/inventory/source.d.ts.map +1 -1
  350. package/types/lib/managers/binary.d.ts.map +1 -1
  351. package/types/lib/managers/docker.d.ts +12 -0
  352. package/types/lib/managers/docker.d.ts.map +1 -1
  353. package/types/lib/parsers/huggingfaceManifest.d.ts +10 -1
  354. package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -1
  355. package/types/lib/parsers/huggingfaceUtils.d.ts +12 -0
  356. package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
  357. package/types/lib/parsers/kiroPermissions.d.ts +62 -0
  358. package/types/lib/parsers/kiroPermissions.d.ts.map +1 -0
  359. package/types/lib/parsers/largeJson.d.ts +4 -3
  360. package/types/lib/parsers/largeJson.d.ts.map +1 -1
  361. package/types/lib/parsers/vscodeExtensionId.d.ts +48 -0
  362. package/types/lib/parsers/vscodeExtensionId.d.ts.map +1 -0
  363. package/types/lib/server/server.d.ts.map +1 -1
  364. package/types/lib/stages/postgen/postgen.d.ts +7 -0
  365. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  366. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  367. package/types/lib/stages/postgen/specVersionCompat.d.ts +25 -0
  368. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  369. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  370. package/types/lib/stages/pregen/pregen.d.ts +12 -8
  371. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  372. package/types/lib/validator/bomValidator.d.ts +5 -1
  373. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  374. package/types/lib/validator/complianceEngine.d.ts +4 -4
  375. package/types/lib/validator/complianceEngine.d.ts.map +1 -1
  376. package/types/lib/validator/complianceRules.d.ts +14 -2
  377. package/types/lib/validator/complianceRules.d.ts.map +1 -1
  378. package/types/lib/validator/index.d.ts +10 -0
  379. package/types/lib/validator/index.d.ts.map +1 -1
  380. package/types/lib/validator/reporters/json.d.ts.map +1 -1
@@ -0,0 +1,766 @@
1
+ /**
2
+ * Render the 1.x-shaped internal model as a CycloneDX 2.0 document: the
3
+ * document sections, reference integrity and the render report. The public
4
+ * entry points are re-exported from cyclonedx20.js.
5
+ */
6
+
7
+ import { thoughtLog } from "../core/logger.js";
8
+ import {
9
+ clone,
10
+ collectDeclaredRefIds,
11
+ countDrop,
12
+ countRewrite,
13
+ countSignatureDrop,
14
+ countUnmapped,
15
+ createRenderStats,
16
+ isBomLink,
17
+ isNonEmptyString,
18
+ isObjectRecord,
19
+ referencesParty,
20
+ setDefined,
21
+ takeShadow,
22
+ } from "./cyclonedx20Common.js";
23
+ import { appendDerivedSections } from "./cyclonedx20Derived.js";
24
+ import { toCommonContact, toCommonEntity } from "./cyclonedx20Parties.js";
25
+ import {
26
+ convertComponent,
27
+ convertLicenses,
28
+ convertService,
29
+ convertTools,
30
+ } from "./cyclonedx20RenderComponents.js";
31
+ import {
32
+ convertStandards,
33
+ renderDeclarations,
34
+ } from "./cyclonedx20RenderDefinitions.js";
35
+ import {
36
+ derivedPartyDeclarations,
37
+ identityClaimContext,
38
+ } from "./cyclonedx20RenderEvidence.js";
39
+ import { convertPatents } from "./cyclonedx20RenderPatents.js";
40
+ import {
41
+ dedupeRefIds,
42
+ resolveAffectsRefs,
43
+ resolveDependencyRefs,
44
+ } from "./cyclonedx20RenderRefIds.js";
45
+ import {
46
+ convertFormulation,
47
+ renderAnnotations,
48
+ renderCitations,
49
+ renderCompositions,
50
+ renderVulnerabilities,
51
+ } from "./cyclonedx20RenderSections.js";
52
+ import {
53
+ CDX20_INTERNAL_SECTIONS_KEY,
54
+ FORMULA_COMPONENT_REFS_PROPERTY,
55
+ } from "./cyclonedx20Tables.js";
56
+
57
+ /**
58
+ * Render metadata (#/$defs/cyclonedx-metadata-2.0/$defs/metadata). Every 1.x
59
+ * field except `component` (the inventory subject) and the deprecated
60
+ * `manufacture` has a 2.0 home; organizations and contacts rename `bom-ref`
61
+ * to `refId`. Key order follows the input.
62
+ */
63
+ function renderMetadata(metadata, stats) {
64
+ if (!isObjectRecord(metadata)) {
65
+ return undefined;
66
+ }
67
+ const { component: _component, tools, ...rest } = metadata;
68
+ const shadow = takeShadow(stats, "metadata", rest);
69
+ if (shadow) {
70
+ const restoredTools = convertTools(tools, stats);
71
+ if (restoredTools) {
72
+ shadow.tools = restoredTools;
73
+ }
74
+ return Object.keys(shadow).length ? shadow : undefined;
75
+ }
76
+ const converted = {};
77
+ for (const [key, value] of Object.entries(metadata)) {
78
+ // 1.x builders sometimes leave explicit `undefined` members (addMetadata's
79
+ // `supplier: undefined`); JSON drops them, so the render does too.
80
+ if (value === undefined || key === "component") {
81
+ continue;
82
+ }
83
+ if (key === "tools") {
84
+ const tools = convertTools(value, stats);
85
+ if (tools) {
86
+ converted.tools = tools;
87
+ }
88
+ } else if (key === "supplier" || key === "manufacturer") {
89
+ const entity = toCommonEntity(value, stats);
90
+ if (entity) {
91
+ converted[key] = entity;
92
+ }
93
+ } else if (key === "authors" && Array.isArray(value)) {
94
+ const authors = value
95
+ .map((contact) => toCommonContact(contact, stats))
96
+ .filter(Boolean);
97
+ if (authors.length) {
98
+ converted.authors = authors;
99
+ }
100
+ } else if (key === "licenses") {
101
+ converted.licenses = convertLicenses(value, stats) ?? clone(value);
102
+ } else if (
103
+ [
104
+ "timestamp",
105
+ "lifecycles",
106
+ "distributionConstraints",
107
+ "properties",
108
+ ].includes(key)
109
+ ) {
110
+ converted[key] = clone(value);
111
+ } else {
112
+ countDrop(stats, `metadata.${key}`);
113
+ }
114
+ }
115
+ return Object.keys(converted).length ? converted : undefined;
116
+ }
117
+
118
+ /**
119
+ * Render the inventory
120
+ * (#/$defs/cyclonedx-component-2.0/$defs/inventory, required
121
+ * `[subject, components]`). Root components and services become the
122
+ * inventory's components; without a subject component (cbom/aibom style) the
123
+ * entries are returned for the definitions registry instead.
124
+ */
125
+ function renderInventory(source, stats) {
126
+ const subject = isObjectRecord(source.metadata?.component)
127
+ ? source.metadata.component
128
+ : undefined;
129
+ const subjectRef = isNonEmptyString(subject?.["bom-ref"])
130
+ ? subject["bom-ref"]
131
+ : undefined;
132
+ const context = {
133
+ hasSubject: Boolean(subject),
134
+ subjectRef,
135
+ inventoryRefId: subjectRef ? `inventory-${subjectRef}` : undefined,
136
+ subjectlessEntries: [],
137
+ };
138
+ const entries = [
139
+ ...(Array.isArray(source.components)
140
+ ? source.components.map((c) => convertComponent(c, stats))
141
+ : []),
142
+ ...(Array.isArray(source.services)
143
+ ? source.services.map((s) => convertService(s, stats))
144
+ : []),
145
+ ];
146
+ if (!subject) {
147
+ context.subjectlessEntries = entries;
148
+ return context;
149
+ }
150
+ // A document read from 2.0 keeps its inventory's own members (refId,
151
+ // properties, signatures); the renderer otherwise derives the refId.
152
+ const own = takeShadow(stats, "inventory", subject);
153
+ if (own) {
154
+ context.inventoryRefId = isNonEmptyString(own.refId)
155
+ ? own.refId
156
+ : undefined;
157
+ }
158
+ const inventory = {
159
+ subject: convertComponent(subject, stats),
160
+ components: entries,
161
+ };
162
+ if (context.inventoryRefId) {
163
+ inventory.refId = context.inventoryRefId;
164
+ }
165
+ if (own) {
166
+ const { refId: _refId, ...members } = own;
167
+ Object.assign(inventory, members);
168
+ }
169
+ context.inventories = [inventory];
170
+ return context;
171
+ }
172
+
173
+ /**
174
+ * Render dependencies (#/$defs/cyclonedx-dependency-2.0/$defs/dependency,
175
+ * required `[ref]`); refs are refIds now, values unchanged. An empty
176
+ * `dependsOn` says the component has no dependencies (a missing one says
177
+ * nothing), so it is kept. References that resolve to nothing are dropped
178
+ * once every refId is known (resolveDependencyRefs).
179
+ */
180
+ function renderDependencies(dependencies, stats) {
181
+ if (!Array.isArray(dependencies) || !dependencies.length) {
182
+ return undefined;
183
+ }
184
+ return dependencies
185
+ .filter((dep) => {
186
+ const valid = isObjectRecord(dep) && typeof dep.ref === "string";
187
+ if (!valid) {
188
+ countDrop(stats, "dependency (no ref)");
189
+ }
190
+ return valid;
191
+ })
192
+ .map((dep) => {
193
+ const converted = { ref: dep.ref };
194
+ if (Array.isArray(dep.dependsOn)) {
195
+ converted.dependsOn = [...dep.dependsOn];
196
+ }
197
+ if (Array.isArray(dep.provides)) {
198
+ converted.provides = [...dep.provides];
199
+ }
200
+ return converted;
201
+ });
202
+ }
203
+
204
+ // 1.x definitions members (and the components and services the internal
205
+ // model may hold there) that renderOwnDefinitions converts itself.
206
+ const DEFINITION_MEMBERS = new Set([
207
+ "components",
208
+ "services",
209
+ "parties",
210
+ "standards",
211
+ "patents",
212
+ ]);
213
+
214
+ /**
215
+ * Convert the 1.x definitions members: standards and patents take their 2.0
216
+ * form, components, services and parties are left to renderOwnDefinitions,
217
+ * and any other member is counted.
218
+ */
219
+ function convertDefinitionMembers(sourceDefinitions, stats) {
220
+ if (!isObjectRecord(sourceDefinitions)) {
221
+ return {};
222
+ }
223
+ const { components, services, parties } = sourceDefinitions;
224
+ const definitions = clone({ components, services, parties });
225
+ for (const key of Object.keys(definitions)) {
226
+ if (definitions[key] === undefined) {
227
+ delete definitions[key];
228
+ }
229
+ }
230
+ setDefined(
231
+ definitions,
232
+ "standards",
233
+ convertStandards(sourceDefinitions.standards, stats),
234
+ );
235
+ setDefined(
236
+ definitions,
237
+ "patents",
238
+ convertPatents(sourceDefinitions.patents, stats),
239
+ );
240
+ countUnmapped(stats, "definitions", sourceDefinitions, DEFINITION_MEMBERS);
241
+ return definitions;
242
+ }
243
+
244
+ /**
245
+ * Assemble the renderer's own definitions
246
+ * (#/$defs/cyclonedx-definition-2.0/$defs/definitions): converted 1.x
247
+ * definitions, the entries of a subject-less document (the way upstream's
248
+ * valid-component-evidence-assertion-2.0.json declares its components) and
249
+ * the formula components the 2.0 formula has no field for, after the
250
+ * components a 2.0 read kept for 2.0 output. A subject-less document's
251
+ * formula components are counted and dropped instead: they would share
252
+ * definitions with the SBOM components, and 2.0 records no formula
253
+ * membership. 2.0 definitions have no `services`, so 1.x definition
254
+ * services become service components.
255
+ */
256
+ function renderOwnDefinitions(
257
+ sourceDefinitions,
258
+ { subjectlessEntries, hasSubject },
259
+ carriedComponents,
260
+ stats,
261
+ ) {
262
+ const definitions = convertDefinitionMembers(sourceDefinitions, stats);
263
+ // Definitions components a 2.0 read kept for 2.0 output come first, the
264
+ // order the reader expects (see cyclonedx20Read.js).
265
+ const components = [
266
+ ...(Array.isArray(carriedComponents) ? clone(carriedComponents) : []),
267
+ ...(Array.isArray(definitions.components)
268
+ ? definitions.components.map((c) => convertComponent(c, stats))
269
+ : []),
270
+ ];
271
+ if (Array.isArray(definitions.services)) {
272
+ components.push(
273
+ ...definitions.services.map((s) => convertService(s, stats)),
274
+ );
275
+ }
276
+ delete definitions.services;
277
+ components.push(...subjectlessEntries);
278
+ if (hasSubject) {
279
+ components.push(...stats.formulaComponents);
280
+ } else {
281
+ components.push(...subjectlessFormulaComponents(subjectlessEntries, stats));
282
+ }
283
+ // An empty list read from 2.0 stays, so the round trip keeps it.
284
+ if (components.length || Array.isArray(carriedComponents)) {
285
+ definitions.components = components;
286
+ } else {
287
+ delete definitions.components;
288
+ }
289
+ return definitions;
290
+ }
291
+
292
+ /**
293
+ * The formula components of a subject-less document. Its SBOM entries live in
294
+ * definitions.components too, so each formula records which entries are its
295
+ * own in the FORMULA_COMPONENT_REFS_PROPERTY property (see
296
+ * addFormulaMembership); the reader puts them back. A formula component
297
+ * without a refId cannot be named there, and one whose refId is also an SBOM
298
+ * entry stays only in the SBOM; both are counted.
299
+ */
300
+ function subjectlessFormulaComponents(subjectlessEntries, stats) {
301
+ const sbomRefIds = new Set(
302
+ subjectlessEntries
303
+ .map((entry) => entry?.refId)
304
+ .filter((refId) => isNonEmptyString(refId)),
305
+ );
306
+ const kept = new Set();
307
+ const components = [];
308
+ stats.formulaMembership = stats.formulaMembership.map((members = []) =>
309
+ members.filter((component) => {
310
+ if (!isNonEmptyString(component?.refId)) {
311
+ countDrop(
312
+ stats,
313
+ "formula component without a refId (subject-less document)",
314
+ );
315
+ return false;
316
+ }
317
+ if (sbomRefIds.has(component.refId)) {
318
+ countDrop(
319
+ stats,
320
+ "formula component that is also an SBOM component (subject-less document)",
321
+ );
322
+ return false;
323
+ }
324
+ if (!kept.has(component.refId)) {
325
+ kept.add(component.refId);
326
+ components.push(component);
327
+ }
328
+ return true;
329
+ }),
330
+ );
331
+ return components;
332
+ }
333
+
334
+ /**
335
+ * Record the components of each formula of a subject-less document in the
336
+ * formula's FORMULA_COMPONENT_REFS_PROPERTY property (a JSON array of
337
+ * refIds), since 2.0 has no formula member for them.
338
+ */
339
+ function addFormulaMembership(formulation, stats) {
340
+ if (!Array.isArray(formulation)) {
341
+ return;
342
+ }
343
+ formulation.forEach((formula, index) => {
344
+ const refIds = (stats.formulaMembership[index] || []).map(
345
+ (component) => component.refId,
346
+ );
347
+ if (!isObjectRecord(formula) || !refIds.length) {
348
+ return;
349
+ }
350
+ const properties = (
351
+ Array.isArray(formula.properties) ? formula.properties : []
352
+ ).filter((property) => property?.name !== FORMULA_COMPONENT_REFS_PROPERTY);
353
+ properties.push({
354
+ name: FORMULA_COMPONENT_REFS_PROPERTY,
355
+ value: JSON.stringify(refIds),
356
+ });
357
+ formula.properties = properties;
358
+ });
359
+ }
360
+
361
+ /**
362
+ * Annotation subjects are elementLinks
363
+ * (#/$defs/cyclonedx-common-2.0/$defs/elementLink): a refId declared in this
364
+ * document or a BOM-Link into another one. A 1.x subject naming the document
365
+ * serial number (cdxgen's own summary annotation) is retargeted to the
366
+ * inventory; any other subject that resolves to nothing is dropped. An
367
+ * annotation may end with no subjects, which the schema allows.
368
+ */
369
+ function resolveAnnotationSubjects(annotations, context, declared, stats) {
370
+ for (const annotation of annotations || []) {
371
+ const subjects = [];
372
+ for (const subject of annotation.subjects) {
373
+ if (declared.has(subject) || isBomLink(subject)) {
374
+ subjects.push(subject);
375
+ } else if (
376
+ subject === context.serialNumber &&
377
+ context.inventoryRefId &&
378
+ declared.has(context.inventoryRefId)
379
+ ) {
380
+ countRewrite(stats, "annotation subject (serial number → inventory)");
381
+ subjects.push(context.inventoryRefId);
382
+ } else {
383
+ countDrop(stats, "annotation subject (undeclared)");
384
+ }
385
+ }
386
+ annotation.subjects = [...new Set(subjects)];
387
+ }
388
+ }
389
+
390
+ /** Drop composition targets that resolve to nothing, then empty entries. */
391
+ function resolveCompositionTargets(compositions, declared, stats) {
392
+ if (!compositions) {
393
+ return undefined;
394
+ }
395
+ const kept = [];
396
+ for (const composition of compositions) {
397
+ composition.targets = composition.targets.filter((target) => {
398
+ const resolves = declared.has(target) || isBomLink(target);
399
+ if (!resolves) {
400
+ countDrop(stats, "composition target (undeclared)");
401
+ }
402
+ return resolves;
403
+ });
404
+ if (composition.targets.length) {
405
+ kept.push(composition);
406
+ } else {
407
+ countDrop(stats, "composition (no declared target)");
408
+ }
409
+ }
410
+ return kept.length ? kept : undefined;
411
+ }
412
+
413
+ /**
414
+ * Declared parties: the document's own and carried parties, then each
415
+ * derived party (see derivedPartyDeclarations: the cdxgen party, and the
416
+ * party of the tool asserting the identifiers of another tool's BOM) that is
417
+ * not declared yet and that something in the finished document references
418
+ * (identifiers it asserts, identity evidence it is the asserter of). Each is
419
+ * declared at most once.
420
+ */
421
+ function renderParties(ownParties, carriedParties, document, declared, stats) {
422
+ const parties = [
423
+ ...(Array.isArray(ownParties) ? ownParties : []),
424
+ ...carriedParties,
425
+ ];
426
+ for (const party of derivedPartyDeclarations(stats.claims, declared)) {
427
+ if (
428
+ referencesParty(document, party.refId) &&
429
+ !parties.some((candidate) => candidate?.refId === party.refId)
430
+ ) {
431
+ parties.push(party);
432
+ }
433
+ }
434
+ return parties.length ? parties : undefined;
435
+ }
436
+
437
+ /** Root required members (#/$defs properties specFormat, specVersion). */
438
+ function renderDocumentHeader(source) {
439
+ const out = {};
440
+ // A document read from 2.0 carries its own `$schema`, `$comment` and
441
+ // `ext:` extension members.
442
+ const root = source[CDX20_INTERNAL_SECTIONS_KEY]?.root;
443
+ if (isObjectRecord(root) && root.$schema !== undefined) {
444
+ out.$schema = root.$schema;
445
+ } else if (source.$schema !== undefined) {
446
+ out.$schema = source.$schema;
447
+ }
448
+ for (const [key, value] of Object.entries(isObjectRecord(root) ? root : {})) {
449
+ if (key !== "$schema") {
450
+ out[key] = clone(value);
451
+ }
452
+ }
453
+ out.specFormat = "CycloneDX";
454
+ out.specVersion = "2.0";
455
+ if (source.serialNumber !== undefined) {
456
+ out.serialNumber = source.serialNumber;
457
+ }
458
+ if (source.version !== undefined) {
459
+ out.version = source.version;
460
+ }
461
+ return out;
462
+ }
463
+
464
+ // Keys of the internal sections object that are not document sections.
465
+ const NON_SECTION_KEYS = Object.freeze(
466
+ new Set([
467
+ "definitions",
468
+ "definitionsParties",
469
+ "root",
470
+ "shadows",
471
+ "compositions",
472
+ ]),
473
+ );
474
+
475
+ /** Copy the carried 2.0-only sections, except the definitions parts. */
476
+ function renderCarriedSections(out, carried) {
477
+ for (const [section, value] of Object.entries(carried)) {
478
+ if (!NON_SECTION_KEYS.has(section)) {
479
+ out[section] = clone(value);
480
+ }
481
+ }
482
+ }
483
+
484
+ /**
485
+ * Render the 1.x-shaped internal model as a CycloneDX 2.0 document and report
486
+ * what could not be carried. Pure: the input is never mutated and the output
487
+ * shares no objects with it. Deterministic: the same input renders to the
488
+ * same JSON.
489
+ *
490
+ * @param {object} internalBom BOM in the 1.x shape
491
+ * @param {{hardwareMapper?: Function, hardwareOptions?: {includeSensitiveIdentifiers?: boolean, identifierPolicy?: string}}} [context]
492
+ * What the render may use besides the model: `hardwareMapper` is the
493
+ * optional toCdx20HardwareComponent of @cdxgen/cdx-hbom and
494
+ * `hardwareOptions` its identifier options (see hbomLoader.js:
495
+ * hardwareRenderContext and cyclonedx20RenderHardware.js). The output
496
+ * depends only on the model and this context.
497
+ * @returns {{bomJson: object, report: {drops: Object<string, number>, rewrites: Object<string, number>, customSchemes: string[], droppedMethods: Array<{reason: string, technique: string}>}}}
498
+ * The 2.0 document, the counts of values the render could not carry
499
+ * (`drops`) and of values it rewrote without losing data (`rewrites`), by
500
+ * label
501
+ */
502
+ export function renderCycloneDx20WithReport(internalBom, context = {}) {
503
+ const source = isObjectRecord(internalBom) ? internalBom : {};
504
+ const stats = createRenderStats(
505
+ source[CDX20_INTERNAL_SECTIONS_KEY]?.shadows,
506
+ identityClaimContext(source),
507
+ );
508
+ if (typeof context?.hardwareMapper === "function") {
509
+ stats.hardwareMapper = context.hardwareMapper;
510
+ stats.hardwareOptions = isObjectRecord(context.hardwareOptions)
511
+ ? { ...context.hardwareOptions }
512
+ : {};
513
+ }
514
+ const { out, inventory, definitions } = renderOwnSections(source, stats);
515
+ // Inventories first: the subject of a self-scan keeps its members when it
516
+ // repeats the refId of the cdxgen tool in metadata.
517
+ dedupeRefIds(
518
+ [
519
+ { section: "inventories", value: out.inventories },
520
+ { section: "metadata", value: out.metadata },
521
+ { section: "annotations", value: out.annotations },
522
+ { section: "formulation", value: out.formulation },
523
+ { section: "declarations", value: out.declarations },
524
+ { section: "citations", value: out.citations },
525
+ { section: "vulnerabilities", value: out.vulnerabilities },
526
+ { section: "definitions", value: definitions },
527
+ ],
528
+ stats,
529
+ );
530
+ // dedupeRefIds removes the definitions components an inventory declares
531
+ // too; a list left empty goes, unless a 2.0 read carried it.
532
+ if (
533
+ definitions.components?.length === 0 &&
534
+ !Array.isArray(source[CDX20_INTERNAL_SECTIONS_KEY]?.definitions?.components)
535
+ ) {
536
+ delete definitions.components;
537
+ }
538
+ finalizeDocument(out, source, inventory, definitions, stats);
539
+ logRenderStats(stats);
540
+ return { bomJson: out, report: buildRenderReport(stats) };
541
+ }
542
+
543
+ // Root members of the 1.x model the render handles; any other is counted.
544
+ const ROOT_MEMBERS = Object.freeze(
545
+ new Set([
546
+ "$schema",
547
+ "bomFormat",
548
+ "specFormat",
549
+ "specVersion",
550
+ "serialNumber",
551
+ "version",
552
+ "metadata",
553
+ "components",
554
+ "services",
555
+ "externalReferences",
556
+ "dependencies",
557
+ "compositions",
558
+ "vulnerabilities",
559
+ "annotations",
560
+ "formulation",
561
+ "declarations",
562
+ "definitions",
563
+ "citations",
564
+ "properties",
565
+ "signature",
566
+ CDX20_INTERNAL_SECTIONS_KEY,
567
+ ]),
568
+ );
569
+
570
+ /**
571
+ * Render every section the 1.x model has, in document order. Definitions
572
+ * are returned separately: they are merged with the carried 2.0 sections
573
+ * last.
574
+ */
575
+ function renderOwnSections(source, stats) {
576
+ const out = renderDocumentHeader(source);
577
+ setDefined(out, "metadata", renderMetadata(source.metadata, stats));
578
+ const inventory = renderInventory(source, stats);
579
+ setDefined(out, "inventories", inventory.inventories);
580
+ setDefined(
581
+ out,
582
+ "dependencies",
583
+ renderDependencies(source.dependencies, stats),
584
+ );
585
+ setDefined(
586
+ out,
587
+ "compositions",
588
+ renderCompositions(
589
+ source.compositions,
590
+ inventory,
591
+ source[CDX20_INTERNAL_SECTIONS_KEY]?.compositions,
592
+ stats,
593
+ ),
594
+ );
595
+ setDefined(out, "annotations", renderAnnotations(source.annotations, stats));
596
+ if (source.formulation !== undefined) {
597
+ out.formulation = convertFormulation(source.formulation, stats);
598
+ }
599
+ setDefined(
600
+ out,
601
+ "declarations",
602
+ renderDeclarations(source.declarations, stats),
603
+ );
604
+ // After the formulation, which collects the formula components.
605
+ const definitions = renderOwnDefinitions(
606
+ source.definitions,
607
+ inventory,
608
+ source[CDX20_INTERNAL_SECTIONS_KEY]?.definitions?.components,
609
+ stats,
610
+ );
611
+ if (!inventory.hasSubject) {
612
+ addFormulaMembership(out.formulation, stats);
613
+ }
614
+ setDefined(
615
+ out,
616
+ "citations",
617
+ renderCitations(source.citations, inventory.hasSubject, stats),
618
+ );
619
+ setDefined(
620
+ out,
621
+ "vulnerabilities",
622
+ renderVulnerabilities(source.vulnerabilities, stats),
623
+ );
624
+ setDefined(out, "properties", clone(source.properties));
625
+ setDefined(out, "externalReferences", clone(source.externalReferences));
626
+ if (source.signature !== undefined) {
627
+ countSignatureDrop(stats, "signature");
628
+ }
629
+ countUnmapped(stats, "document", source, ROOT_MEMBERS);
630
+ return { out, inventory, definitions };
631
+ }
632
+
633
+ /**
634
+ * Add the carried 2.0-only sections and the derived ones (post-quantum risks,
635
+ * agent parties and blueprint, see cyclonedx20Derived.js), resolve
636
+ * annotation subjects and composition targets against every declared refId,
637
+ * and declare the parties. A carried `definitions` object merges with the
638
+ * freshly assembled one so a round trip keeps both; carried parties append
639
+ * to the declared parties.
640
+ */
641
+ function finalizeDocument(out, source, inventory, definitions, stats) {
642
+ const carried = isObjectRecord(source[CDX20_INTERNAL_SECTIONS_KEY])
643
+ ? source[CDX20_INTERNAL_SECTIONS_KEY]
644
+ : {};
645
+ renderCarriedSections(out, carried);
646
+ const ownParties = definitions.parties;
647
+ delete definitions.parties;
648
+ // The carried definitions components were merged in renderOwnSections, so
649
+ // dedupeRefIds saw them.
650
+ const { components: _carriedComponents, ...carriedDefinitions } =
651
+ isObjectRecord(carried.definitions) ? carried.definitions : {};
652
+ const mergedDefinitions = {
653
+ ...clone(carriedDefinitions),
654
+ ...definitions,
655
+ };
656
+ const carriedParties = appendDerivedSections(
657
+ out,
658
+ Array.isArray(carried.definitionsParties)
659
+ ? clone(carried.definitionsParties)
660
+ : [],
661
+ source,
662
+ );
663
+ const declared = collectDeclaredRefIds([
664
+ out,
665
+ mergedDefinitions,
666
+ ownParties,
667
+ carriedParties,
668
+ ]);
669
+ resolveAnnotationSubjects(
670
+ out.annotations,
671
+ { ...inventory, serialNumber: source.serialNumber },
672
+ declared,
673
+ stats,
674
+ );
675
+ const dependencies = resolveDependencyRefs(out.dependencies, declared, stats);
676
+ if (dependencies) {
677
+ out.dependencies = dependencies;
678
+ } else {
679
+ delete out.dependencies;
680
+ }
681
+ resolveAffectsRefs(out.vulnerabilities, declared, stats);
682
+ const compositions = resolveCompositionTargets(
683
+ out.compositions,
684
+ declared,
685
+ stats,
686
+ );
687
+ if (compositions) {
688
+ out.compositions = compositions;
689
+ } else {
690
+ delete out.compositions;
691
+ }
692
+ setDefined(
693
+ mergedDefinitions,
694
+ "parties",
695
+ renderParties(
696
+ ownParties,
697
+ carriedParties,
698
+ [out, mergedDefinitions],
699
+ declared,
700
+ stats,
701
+ ),
702
+ );
703
+ if (Object.keys(mergedDefinitions).length) {
704
+ out.definitions = mergedDefinitions;
705
+ }
706
+ delete out[CDX20_INTERNAL_SECTIONS_KEY];
707
+ }
708
+
709
+ /**
710
+ * Render the 1.x-shaped internal model as a CycloneDX 2.0 document. Pure: the
711
+ * input is never mutated and the output shares no objects with it. What the
712
+ * render could not carry is logged through thoughtLog; use
713
+ * renderCycloneDx20WithReport for the counts.
714
+ *
715
+ * @param {object} internalBom BOM in the 1.x shape
716
+ * @param {object} [context] See renderCycloneDx20WithReport
717
+ * @returns {object} BOM in the 2.0 shape
718
+ */
719
+ export function renderCycloneDx20(internalBom, context = {}) {
720
+ return renderCycloneDx20WithReport(internalBom, context).bomJson;
721
+ }
722
+
723
+ /** The render counters as a plain, sorted, serializable report. */
724
+ function buildRenderReport(stats) {
725
+ const drops = {};
726
+ for (const label of Object.keys(stats.drops).sort()) {
727
+ drops[label] = stats.drops[label];
728
+ }
729
+ const rewrites = {};
730
+ for (const label of Object.keys(stats.rewrites).sort()) {
731
+ rewrites[label] = stats.rewrites[label];
732
+ }
733
+ return {
734
+ drops,
735
+ rewrites,
736
+ customSchemes: [...stats.customSchemes].sort(),
737
+ droppedMethods: stats.droppedMethods.map((method) => ({ ...method })),
738
+ };
739
+ }
740
+
741
+ function logRenderStats(stats) {
742
+ if (stats.droppedMethods.length) {
743
+ thoughtLog(
744
+ `CycloneDX 2.0 render dropped ${stats.droppedMethods.length} identity method(s): ` +
745
+ JSON.stringify(stats.droppedMethods.slice(0, 10)),
746
+ );
747
+ }
748
+ if (stats.customSchemes.size) {
749
+ thoughtLog(
750
+ `CycloneDX 2.0 render used custom identity schemes: ${[...stats.customSchemes].join(", ")}`,
751
+ );
752
+ }
753
+ for (const [kind, counts] of [
754
+ ["could not carry", stats.drops],
755
+ ["rewrote", stats.rewrites],
756
+ ]) {
757
+ const labels = Object.keys(counts).sort();
758
+ if (labels.length) {
759
+ thoughtLog(
760
+ `CycloneDX 2.0 render ${kind}: ${labels
761
+ .map((label) => `${label} ×${counts[label]}`)
762
+ .join(", ")}`,
763
+ );
764
+ }
765
+ }
766
+ }