@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,768 @@
1
+ /**
2
+ * Read a CycloneDX 2.0 document into the 1.x-shaped internal model. The
3
+ * public entry point is re-exported from cyclonedx20.js.
4
+ *
5
+ * Where definitions.components entries go (2.0 records no membership, so the
6
+ * rule is fixed and deterministic, applied in document order):
7
+ *
8
+ * 0. An entry whose refId a formula lists in its
9
+ * `cdx:formulation:componentRefs` property (a JSON array of refIds, which
10
+ * renderCycloneDx20 writes for a subject-less document) is a component of
11
+ * every formula that lists it.
12
+ * 1. An entry whose refId a formula references (a `ref` member, such as a
13
+ * resource reference, anywhere in its tree) is a component of the first
14
+ * such formula. Other strings that happen to equal the refId, such as a
15
+ * task type, do not count.
16
+ * 2. In a document with inventories, an entry a componentReference the
17
+ * reader resolves points to (from an inventory, a tool, an annotator, a
18
+ * vulnerability or another definitions component) stays in definitions
19
+ * (kept for 2.0 output); its content reaches 1.x through the referencing
20
+ * entries.
21
+ * 3. In a document with inventories, any other entry is a formula component
22
+ * when the document has a formulation (the renderer moves 1.x
23
+ * formula.components there), and otherwise stays in definitions with a
24
+ * loss: 1.x has no home for it.
25
+ * 4. In a document without inventories (the renderer puts a subject-less
26
+ * document's components there), any other entry is a root component.
27
+ * Entries without a refId follow the same rules and are never dropped.
28
+ * 5. Before all of these, an entry whose type 1.x does not have (`material`)
29
+ * stays in definitions with a loss.
30
+ */
31
+
32
+ import { isDeepStrictEqual } from "node:util";
33
+
34
+ import {
35
+ clone,
36
+ collectDeclaredRefIds,
37
+ isNonEmptyString,
38
+ isObjectRecord,
39
+ referencesParty,
40
+ } from "./cyclonedx20Common.js";
41
+ import {
42
+ deriveCycloneDx20Sections,
43
+ isCdxgenListedTool,
44
+ isDerivedAgentParty,
45
+ isDerivedBlueprint,
46
+ isDerivedRisk,
47
+ splitDerivedEntries,
48
+ } from "./cyclonedx20Derived.js";
49
+ import {
50
+ EXTERNAL_REFERENCES_RULE,
51
+ PROPERTIES_RULE,
52
+ } from "./cyclonedx20ReadCommon.js";
53
+ import {
54
+ flushComponentShadows,
55
+ keepComponentShadow,
56
+ readComponentEntry,
57
+ } from "./cyclonedx20ReadComponents.js";
58
+ import {
59
+ addLoss,
60
+ cloneWithDepthLimit,
61
+ createReadContext,
62
+ jsonPointer,
63
+ MAX_READ_DEPTH,
64
+ markInternalModel,
65
+ registerShadow,
66
+ reportUnmapped,
67
+ reverseFields,
68
+ } from "./cyclonedx20ReadContext.js";
69
+ import { flushIdentityShadows } from "./cyclonedx20ReadEvidence.js";
70
+ import {
71
+ readAnnotations,
72
+ readCitations,
73
+ readCompositions,
74
+ readFormulation,
75
+ readMetadata,
76
+ readVulnerabilities,
77
+ } from "./cyclonedx20ReadSections.js";
78
+ import {
79
+ derivedPartyDeclarations,
80
+ identityClaimContext,
81
+ } from "./cyclonedx20RenderEvidence.js";
82
+ import {
83
+ CDX20_INTERNAL_SECTIONS_KEY,
84
+ COMPONENT_TYPES_1X,
85
+ FORMULA_COMPONENT_REFS_PROPERTY,
86
+ } from "./cyclonedx20Tables.js";
87
+
88
+ // 2.0-only root sections, carried verbatim for 2.0 output.
89
+ const CARRIED_SECTIONS = Object.freeze([
90
+ "risks",
91
+ "blueprints",
92
+ "threats",
93
+ "controls",
94
+ "perspectives",
95
+ "profiles",
96
+ "declarations",
97
+ "signatures",
98
+ ]);
99
+ const ROOT_KEYS = Object.freeze(
100
+ new Set([
101
+ "$schema",
102
+ "$comment",
103
+ "specFormat",
104
+ "specVersion",
105
+ "serialNumber",
106
+ "version",
107
+ "metadata",
108
+ "inventories",
109
+ "dependencies",
110
+ "compositions",
111
+ "vulnerabilities",
112
+ "annotations",
113
+ "formulation",
114
+ "definitions",
115
+ "citations",
116
+ "properties",
117
+ "externalReferences",
118
+ ...CARRIED_SECTIONS,
119
+ ]),
120
+ );
121
+ const INVENTORY_KEYS = Object.freeze(
122
+ new Set(["refId", "subject", "components"]),
123
+ );
124
+ const CARRIED_REASON =
125
+ "2.0-only section with no 1.x field: dropped from 1.x and SPDX output (a 2.0 render of the read model keeps it)";
126
+ const DERIVED_REASON =
127
+ "differs from what cdxgen derives from the 1.x model: a 2.0 render replaces it with the derived entry";
128
+
129
+ /**
130
+ * Read a 2.0 document into the internal 1.x-shaped model. Never throws on a
131
+ * schema-valid 2.0 document. Objects nested deeper than MAX_READ_DEPTH are
132
+ * left out, each with a loss. The returned model carries the internal model
133
+ * mark (markInternalModel), which loadBomForAnalysis checks. Every member the reader sees but cannot carry
134
+ * into 1.x is reported in `losses` as `{pointer, reason}`, where `pointer` is
135
+ * an RFC 6901 JSON pointer into the input. Objects whose 1.x form would not
136
+ * render back to the same 2.0 object are kept under the internal sections
137
+ * key, so renderCycloneDx20 restores them while they are unchanged.
138
+ *
139
+ * @param {object} bom20 BOM in the 2.0 shape
140
+ * @returns {{internalBom: object, losses: Array<{pointer: string, reason: string}>}}
141
+ */
142
+ export function readCycloneDx20(bom20) {
143
+ const { value: doc, truncated } = isObjectRecord(bom20)
144
+ ? cloneWithDepthLimit(bom20)
145
+ : { value: {}, truncated: [] };
146
+ const ctx = createReadContext(doc);
147
+ for (const pointer of truncated) {
148
+ addLoss(
149
+ ctx,
150
+ pointer,
151
+ `nested deeper than ${MAX_READ_DEPTH} objects: not read`,
152
+ );
153
+ }
154
+ ctx.componentIndex = indexComponents(doc);
155
+ reportUnmapped(ctx, "document", doc, "", ROOT_KEYS);
156
+ const internal = readHeader(doc);
157
+ const metadata = readMetadata(ctx, doc.metadata);
158
+ ctx.claims = identityClaimContext({ metadata });
159
+ const inventory = readInventories(ctx, doc, metadata);
160
+ const placement = classifyDefinitions(ctx, doc);
161
+ readRootDefinitions(ctx, doc, placement, inventory);
162
+ setList(internal, "components", inventory.components);
163
+ setList(internal, "services", inventory.services);
164
+ readDependencies(ctx, doc, internal);
165
+ setList(
166
+ internal,
167
+ "compositions",
168
+ doc.compositions !== undefined
169
+ ? readCompositions(ctx, doc.compositions, inventory.subjects)
170
+ : undefined,
171
+ );
172
+ readOptionalSections(ctx, doc, internal, placement);
173
+ if (Object.keys(metadata).length) {
174
+ internal.metadata = metadata;
175
+ }
176
+ flushComponentShadows(ctx);
177
+ flushIdentityShadows(ctx);
178
+ const sections = collectCarriedSections(ctx, doc, placement, internal);
179
+ if (Object.keys(sections).length) {
180
+ internal[CDX20_INTERNAL_SECTIONS_KEY] = sections;
181
+ }
182
+ return { internalBom: markInternalModel(internal), losses: ctx.losses };
183
+ }
184
+
185
+ /** Root header: 1.x has no `$schema` for 2.0 (it is carried for 2.0). */
186
+ function readHeader(doc) {
187
+ const internal = { bomFormat: "CycloneDX", specVersion: "2.0" };
188
+ for (const field of ["serialNumber", "version"]) {
189
+ if (doc[field] !== undefined) {
190
+ internal[field] = doc[field];
191
+ }
192
+ }
193
+ return internal;
194
+ }
195
+
196
+ /** Assign a non-empty list. */
197
+ function setList(target, key, value) {
198
+ if (Array.isArray(value) && value.length) {
199
+ target[key] = value;
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Map refId → the first concrete declaration (document order: tools,
205
+ * inventories, definitions), so componentReferences resolve.
206
+ */
207
+ function indexComponents(doc) {
208
+ const index = new Map();
209
+ const visit = (entry, pointer) => {
210
+ if (!isObjectRecord(entry)) {
211
+ return;
212
+ }
213
+ const isReference =
214
+ typeof entry.ref === "string" && entry.name === undefined;
215
+ if (
216
+ !isReference &&
217
+ isNonEmptyString(entry.refId) &&
218
+ !index.has(entry.refId)
219
+ ) {
220
+ index.set(entry.refId, { entry, pointer });
221
+ }
222
+ (Array.isArray(entry.components) ? entry.components : []).forEach(
223
+ (child, childIndex) => {
224
+ visit(child, jsonPointer(pointer, "components", childIndex));
225
+ },
226
+ );
227
+ };
228
+ (doc.metadata?.tools?.components || []).forEach((entry, i) => {
229
+ visit(entry, jsonPointer("/metadata/tools/components", i));
230
+ });
231
+ (Array.isArray(doc.inventories) ? doc.inventories : []).forEach(
232
+ (inventory, i) => {
233
+ visit(inventory?.subject, jsonPointer("/inventories", i, "subject"));
234
+ (inventory?.components || []).forEach((entry, j) => {
235
+ visit(entry, jsonPointer("/inventories", i, "components", j));
236
+ });
237
+ },
238
+ );
239
+ (doc.definitions?.components || []).forEach((entry, i) => {
240
+ visit(entry, jsonPointer("/definitions/components", i));
241
+ });
242
+ return index;
243
+ }
244
+
245
+ /** Push a read entry once per refId; a repeat is a loss. */
246
+ function addInventoryEntry(ctx, inventory, read, pointer) {
247
+ if (!read) {
248
+ return;
249
+ }
250
+ if (read.refId !== undefined) {
251
+ if (inventory.seen.has(read.refId)) {
252
+ addLoss(
253
+ ctx,
254
+ pointer,
255
+ "the component is already listed; 1.x lists it once",
256
+ );
257
+ return;
258
+ }
259
+ inventory.seen.add(read.refId);
260
+ }
261
+ keepComponentShadow(ctx, read);
262
+ inventory[read.isService ? "services" : "components"].push(read.internal);
263
+ }
264
+
265
+ /**
266
+ * Read the inventories: the first subject becomes metadata.component, the
267
+ * components of every inventory become root components and services.
268
+ */
269
+ function readInventories(ctx, doc, metadata) {
270
+ const inventory = {
271
+ components: [],
272
+ services: [],
273
+ seen: new Set(),
274
+ subjects: new Map(),
275
+ };
276
+ if (doc.inventories !== undefined && !Array.isArray(doc.inventories)) {
277
+ addLoss(ctx, "/inventories", "expected an array");
278
+ return inventory;
279
+ }
280
+ (doc.inventories || []).forEach((entry, index) => {
281
+ const pointer = jsonPointer("/inventories", index);
282
+ if (!isObjectRecord(entry)) {
283
+ addLoss(ctx, pointer, "inventory is not an object");
284
+ return;
285
+ }
286
+ reportUnmapped(ctx, "inventory", entry, pointer, INVENTORY_KEYS);
287
+ readInventorySubject(ctx, entry, pointer, metadata, inventory);
288
+ (Array.isArray(entry.components) ? entry.components : []).forEach(
289
+ (component, componentIndex) => {
290
+ const entryPointer = jsonPointer(pointer, "components", componentIndex);
291
+ addInventoryEntry(
292
+ ctx,
293
+ inventory,
294
+ readComponentEntry(ctx, component, entryPointer),
295
+ entryPointer,
296
+ );
297
+ },
298
+ );
299
+ });
300
+ return inventory;
301
+ }
302
+
303
+ /** One inventory subject: the first is metadata.component. */
304
+ function readInventorySubject(ctx, entry, pointer, metadata, inventory) {
305
+ const subjectPointer = jsonPointer(pointer, "subject");
306
+ const read = isObjectRecord(entry.subject)
307
+ ? readComponentEntry(ctx, entry.subject, subjectPointer)
308
+ : undefined;
309
+ if (entry.refId !== undefined) {
310
+ inventory.subjects.set(entry.refId, read?.refId);
311
+ }
312
+ if (!read) {
313
+ return;
314
+ }
315
+ if (metadata.component === undefined && !read.isService) {
316
+ keepComponentShadow(ctx, read);
317
+ metadata.component = read.internal;
318
+ if (read.refId !== undefined) {
319
+ inventory.seen.add(read.refId);
320
+ }
321
+ // The renderer derives the inventory refId from the subject; keep the
322
+ // inventory's own members for the 2.0 round trip.
323
+ const { subject: _subject, components: _components, ...own } = entry;
324
+ registerShadow(ctx, "inventory", read.internal, own);
325
+ return;
326
+ }
327
+ addLoss(
328
+ ctx,
329
+ subjectPointer,
330
+ "1.x has one metadata.component; this inventory subject is read as a root component",
331
+ );
332
+ addInventoryEntry(ctx, inventory, read, subjectPointer);
333
+ }
334
+
335
+ /** `ref` values of componentReference-shaped objects under `node`. */
336
+ function collectReferences(node, into = new Set()) {
337
+ if (Array.isArray(node)) {
338
+ for (const value of node) {
339
+ collectReferences(value, into);
340
+ }
341
+ } else if (isObjectRecord(node)) {
342
+ if (typeof node.ref === "string" && node.name === undefined) {
343
+ into.add(node.ref);
344
+ }
345
+ for (const value of Object.values(node)) {
346
+ collectReferences(value, into);
347
+ }
348
+ }
349
+ return into;
350
+ }
351
+
352
+ /**
353
+ * The refIds the componentReferences the reader resolves into 1.x name:
354
+ * those under the inventories, metadata (tools), annotations,
355
+ * vulnerabilities and the definitions components themselves. References from
356
+ * 2.0-only sections do not count, since 1.x drops those sections.
357
+ */
358
+ function resolvedReferences(doc) {
359
+ const refs = new Set();
360
+ for (const section of [
361
+ doc.inventories,
362
+ doc.metadata,
363
+ doc.annotations,
364
+ doc.vulnerabilities,
365
+ doc.definitions?.components,
366
+ ]) {
367
+ collectReferences(section, refs);
368
+ }
369
+ return refs;
370
+ }
371
+
372
+ /** Where one definitions entry goes, per the rule in the module comment. */
373
+ function placeDefinition(entry, facts) {
374
+ if (
375
+ isObjectRecord(entry) &&
376
+ typeof entry.type === "string" &&
377
+ entry.type !== "service" &&
378
+ entry.type !== "component-choice" &&
379
+ !COMPONENT_TYPES_1X.has(entry.type)
380
+ ) {
381
+ return { place: "carried", reason: "type" };
382
+ }
383
+ const refId = isNonEmptyString(entry?.refId) ? entry.refId : undefined;
384
+ if (refId !== undefined) {
385
+ const listed = facts.formulaMembers
386
+ .map((refs, index) => (refs.has(refId) ? index : -1))
387
+ .filter((index) => index >= 0);
388
+ if (listed.length) {
389
+ return { place: "formula", formula: listed[0], alsoIn: listed.slice(1) };
390
+ }
391
+ const formula = facts.formulaRefs.findIndex((refs) => refs.has(refId));
392
+ if (formula >= 0) {
393
+ return { place: "formula", formula };
394
+ }
395
+ }
396
+ if (facts.hasInventories) {
397
+ if (refId !== undefined && facts.referenced.has(refId)) {
398
+ return { place: "carried" };
399
+ }
400
+ return facts.hasFormulation
401
+ ? { place: "formula", formula: 0, unreferenced: true }
402
+ : { place: "carried", reason: "unreferenced" };
403
+ }
404
+ return { place: "root" };
405
+ }
406
+
407
+ const PLACE_ORDER = Object.freeze({ carried: 0, root: 1, formula: 2 });
408
+
409
+ /**
410
+ * The refIds a formula lists in its FORMULA_COMPONENT_REFS_PROPERTY property;
411
+ * a value that is not a JSON array of strings lists none.
412
+ */
413
+ function formulaMembers(formula) {
414
+ const members = new Set();
415
+ const properties = Array.isArray(formula?.properties)
416
+ ? formula.properties
417
+ : [];
418
+ for (const property of properties) {
419
+ if (
420
+ property?.name !== FORMULA_COMPONENT_REFS_PROPERTY ||
421
+ typeof property.value !== "string"
422
+ ) {
423
+ continue;
424
+ }
425
+ let refIds;
426
+ try {
427
+ refIds = JSON.parse(property.value);
428
+ } catch {
429
+ continue;
430
+ }
431
+ if (Array.isArray(refIds)) {
432
+ for (const refId of refIds) {
433
+ if (isNonEmptyString(refId)) {
434
+ members.add(refId);
435
+ }
436
+ }
437
+ }
438
+ }
439
+ return members;
440
+ }
441
+
442
+ /** Classify every definitions.components entry. */
443
+ function classifyDefinitions(ctx, doc) {
444
+ const entries = Array.isArray(doc.definitions?.components)
445
+ ? doc.definitions.components
446
+ : [];
447
+ const formulation = Array.isArray(doc.formulation) ? doc.formulation : [];
448
+ const facts = {
449
+ formulaRefs: formulation.map((formula) => collectReferences(formula)),
450
+ formulaMembers: formulation.map(formulaMembers),
451
+ referenced: resolvedReferences(doc),
452
+ hasInventories:
453
+ Array.isArray(doc.inventories) && doc.inventories.length > 0,
454
+ hasFormulation: formulation.length > 0,
455
+ };
456
+ const placement = entries.map((entry) => placeDefinition(entry, facts));
457
+ let rank = 0;
458
+ placement.forEach((placed, index) => {
459
+ const pointer = jsonPointer("/definitions/components", index);
460
+ if (placed.reason === "type") {
461
+ addLoss(
462
+ ctx,
463
+ jsonPointer(pointer, "type"),
464
+ `component type '${doc.definitions.components[index].type}' has no 1.x equivalent: dropped from 1.x and SPDX output (a 2.0 render of the read model keeps it)`,
465
+ );
466
+ } else if (placed.reason === "unreferenced") {
467
+ addLoss(
468
+ ctx,
469
+ pointer,
470
+ "a definitions component nothing references has no 1.x home",
471
+ );
472
+ } else if (placed.unreferenced && formulation.length > 1) {
473
+ addLoss(
474
+ ctx,
475
+ pointer,
476
+ "formula membership is not recorded; read into the first formula",
477
+ );
478
+ }
479
+ if (PLACE_ORDER[placed.place] < rank) {
480
+ addLoss(ctx, pointer, "definitions.components order changes on render");
481
+ }
482
+ rank = Math.max(rank, PLACE_ORDER[placed.place]);
483
+ });
484
+ return placement;
485
+ }
486
+
487
+ /** Root-placed definitions entries become root components and services. */
488
+ function readRootDefinitions(ctx, doc, placement, inventory) {
489
+ placement.forEach((placed, index) => {
490
+ if (placed.place !== "root") {
491
+ return;
492
+ }
493
+ const pointer = jsonPointer("/definitions/components", index);
494
+ addInventoryEntry(
495
+ ctx,
496
+ inventory,
497
+ readComponentEntry(ctx, doc.definitions.components[index], pointer),
498
+ pointer,
499
+ );
500
+ });
501
+ }
502
+
503
+ /** dependencies: ref, dependsOn and provides keep their names. */
504
+ function readDependencies(ctx, doc, internal) {
505
+ if (doc.dependencies === undefined) {
506
+ return;
507
+ }
508
+ if (!Array.isArray(doc.dependencies)) {
509
+ addLoss(ctx, "/dependencies", "expected an array");
510
+ return;
511
+ }
512
+ internal.dependencies = doc.dependencies
513
+ .map((dependency, index) =>
514
+ isObjectRecord(dependency)
515
+ ? reverseFields(
516
+ ctx,
517
+ "dependency",
518
+ dependency,
519
+ jsonPointer("/dependencies", index),
520
+ {
521
+ ref: true,
522
+ dependsOn: true,
523
+ provides: true,
524
+ },
525
+ )
526
+ : undefined,
527
+ )
528
+ .filter((dependency) => typeof dependency?.ref === "string");
529
+ }
530
+
531
+ /** Formula components go back into their formula. */
532
+ function attachFormulaComponents(ctx, doc, formulation, placement) {
533
+ placement.forEach((placed, index) => {
534
+ if (placed.place !== "formula" || !formulation[placed.formula]) {
535
+ return;
536
+ }
537
+ const read = readComponentEntry(
538
+ ctx,
539
+ doc.definitions.components[index],
540
+ jsonPointer("/definitions/components", index),
541
+ );
542
+ if (read) {
543
+ keepComponentShadow(ctx, read);
544
+ const member = read.isService ? "services" : "components";
545
+ (formulation[placed.formula][member] ||= []).push(read.internal);
546
+ for (const other of placed.alsoIn || []) {
547
+ if (formulation[other]) {
548
+ (formulation[other][member] ||= []).push(clone(read.internal));
549
+ }
550
+ }
551
+ }
552
+ });
553
+ }
554
+
555
+ /** annotations, formulation, citations, vulnerabilities and root lists. */
556
+ function readOptionalSections(ctx, doc, internal, placement) {
557
+ if (doc.annotations !== undefined) {
558
+ setList(internal, "annotations", readAnnotations(ctx, doc.annotations));
559
+ }
560
+ if (doc.formulation !== undefined) {
561
+ const formulation = readFormulation(ctx, doc.formulation) || [];
562
+ attachFormulaComponents(ctx, doc, formulation, placement);
563
+ setList(internal, "formulation", formulation);
564
+ }
565
+ if (doc.citations !== undefined) {
566
+ setList(internal, "citations", readCitations(ctx, doc.citations));
567
+ }
568
+ if (doc.vulnerabilities !== undefined) {
569
+ setList(
570
+ internal,
571
+ "vulnerabilities",
572
+ readVulnerabilities(ctx, doc.vulnerabilities),
573
+ );
574
+ }
575
+ for (const [key, rule] of [
576
+ ["properties", PROPERTIES_RULE],
577
+ ["externalReferences", EXTERNAL_REFERENCES_RULE],
578
+ ]) {
579
+ if (doc[key] !== undefined) {
580
+ setList(internal, key, rule.convert(ctx, doc[key], jsonPointer("", key)));
581
+ }
582
+ }
583
+ }
584
+
585
+ /**
586
+ * How many trailing definitions.parties entries are parties renderCycloneDx20
587
+ * derives again from the read 1.x model (derivedPartyDeclarations): the
588
+ * renderer appends, in its order, each derived party the finished document
589
+ * references and does not declare yet. The longest such tail that renders
590
+ * back identically is dropped by the reader, so a derived party neither
591
+ * reaches the internal model nor goes stale when the 1.x tools change. With
592
+ * no matching tail the count is 0 and every party is carried.
593
+ */
594
+ function countDerivedParties(ctx, doc) {
595
+ const parties = doc.definitions.parties;
596
+ if (!Array.isArray(parties) || !parties.length) {
597
+ return 0;
598
+ }
599
+ const { parties: _parties, ...definitions } = doc.definitions;
600
+ const rest = { ...doc, definitions };
601
+ const candidates = derivedPartyDeclarations(
602
+ ctx.claims,
603
+ collectDeclaredRefIds([rest, parties]),
604
+ ).filter((party) => referencesParty(rest, party.refId));
605
+ for (let count = candidates.length; count > 0; count--) {
606
+ if (count > parties.length) {
607
+ continue;
608
+ }
609
+ const remaining = parties.slice(0, parties.length - count);
610
+ const remainingRefIds = new Set(remaining.map((party) => party?.refId));
611
+ const expected = derivedPartyDeclarations(
612
+ ctx.claims,
613
+ collectDeclaredRefIds([rest, remaining]),
614
+ ).filter(
615
+ (party) =>
616
+ referencesParty(rest, party.refId) && !remainingRefIds.has(party.refId),
617
+ );
618
+ if (isDeepStrictEqual(expected, parties.slice(remaining.length))) {
619
+ return count;
620
+ }
621
+ }
622
+ return 0;
623
+ }
624
+
625
+ /**
626
+ * The 2.0 value of a carried root section without the entries the renderer
627
+ * derives (cyclonedx20Derived.js): those that match the derivation from the
628
+ * read model are dropped silently, those that differ with a loss. Returns
629
+ * undefined when nothing else is left.
630
+ */
631
+ function carriedSectionValue(ctx, doc, section, derived) {
632
+ const value = doc[section];
633
+ if (!derived.cdxgenListed) {
634
+ // cdxgen derives nothing for another tool's document, so entries that
635
+ // look derived (risk-pqc-*, party-agent-*, the agent blueprint) are that
636
+ // tool's own and are carried like any other.
637
+ return value;
638
+ }
639
+ if (section === "blueprints" && Array.isArray(value)) {
640
+ const { kept, differing } = splitDerivedEntries(
641
+ value,
642
+ derived.blueprints,
643
+ isDerivedBlueprint,
644
+ );
645
+ differing.forEach((index) => {
646
+ addLoss(ctx, jsonPointer("/blueprints", index), DERIVED_REASON);
647
+ });
648
+ return kept.length || !value.length ? kept : undefined;
649
+ }
650
+ if (section === "risks" && Array.isArray(value?.risks)) {
651
+ const { kept, differing } = splitDerivedEntries(
652
+ value.risks,
653
+ derived.risks,
654
+ isDerivedRisk,
655
+ );
656
+ differing.forEach((index) => {
657
+ addLoss(ctx, jsonPointer("/risks/risks", index), DERIVED_REASON);
658
+ });
659
+ const { risks: _risks, ...members } = value;
660
+ const rest =
661
+ kept.length || !value.risks.length
662
+ ? { ...clone(members), risks: kept }
663
+ : clone(members);
664
+ return Object.keys(rest).length ? rest : undefined;
665
+ }
666
+ return value;
667
+ }
668
+
669
+ /**
670
+ * Carry the definitions parties the renderer does not derive again: the
671
+ * trailing claim parties (countDerivedParties) and the agent parties that
672
+ * match the derivation are dropped silently, a differing agent party with a
673
+ * loss; every other party is carried with a loss, since 1.x has no home for
674
+ * it.
675
+ */
676
+ function carryDefinitionsParties(ctx, doc, sections, derived) {
677
+ const parties = doc.definitions.parties;
678
+ if (!Array.isArray(parties)) {
679
+ sections.definitionsParties = parties;
680
+ return;
681
+ }
682
+ const derivedAgents = new Map(
683
+ derived.agentParties.map((party) => [party.refId, party]),
684
+ );
685
+ const kept = [];
686
+ parties
687
+ .slice(0, parties.length - countDerivedParties(ctx, doc))
688
+ .forEach((party, index) => {
689
+ const pointer = jsonPointer("/definitions/parties", index);
690
+ if (!derived.cdxgenListed || !isDerivedAgentParty(party)) {
691
+ kept.push(party);
692
+ addLoss(ctx, pointer, CARRIED_REASON);
693
+ } else if (!isDeepStrictEqual(derivedAgents.get(party.refId), party)) {
694
+ addLoss(ctx, pointer, DERIVED_REASON);
695
+ }
696
+ });
697
+ if (kept.length || !parties.length) {
698
+ sections.definitionsParties = kept;
699
+ }
700
+ }
701
+
702
+ /**
703
+ * The 2.0-only parts kept under the internal sections key: root sections,
704
+ * definitions other than the components read into 1.x, `$schema` and
705
+ * `$comment`, and the shadows. Entries the renderer derives from the model
706
+ * (post-quantum risks, agent parties and blueprint) are not carried.
707
+ */
708
+ function collectCarriedSections(ctx, doc, placement, internal) {
709
+ const sections = {};
710
+ const derived = {
711
+ ...deriveCycloneDx20Sections(internal),
712
+ cdxgenListed: isCdxgenListedTool(internal),
713
+ };
714
+ for (const section of CARRIED_SECTIONS) {
715
+ if (doc[section] === undefined) {
716
+ continue;
717
+ }
718
+ const value = carriedSectionValue(ctx, doc, section, derived);
719
+ if (value !== undefined) {
720
+ sections[section] = value;
721
+ addLoss(ctx, jsonPointer("", section), CARRIED_REASON);
722
+ }
723
+ }
724
+ if (isObjectRecord(doc.definitions)) {
725
+ const { components, parties, ...rest } = doc.definitions;
726
+ if (parties !== undefined) {
727
+ carryDefinitionsParties(ctx, doc, sections, derived);
728
+ }
729
+ const carriedComponents = (
730
+ Array.isArray(components) ? components : []
731
+ ).filter((_entry, index) => placement[index]?.place === "carried");
732
+ if (
733
+ carriedComponents.length ||
734
+ (Array.isArray(components) && !components.length)
735
+ ) {
736
+ rest.components = carriedComponents;
737
+ }
738
+ for (const key of Object.keys(rest)) {
739
+ if (key !== "components") {
740
+ addLoss(ctx, jsonPointer("/definitions", key), CARRIED_REASON);
741
+ }
742
+ }
743
+ if (Object.keys(rest).length) {
744
+ sections.definitions = rest;
745
+ }
746
+ }
747
+ // `$schema`, `$comment` and `ext:` extension members (reported as losses
748
+ // by the root allowlist, except `$schema`) ride along for 2.0 output.
749
+ const root = {};
750
+ for (const [key, value] of Object.entries(doc)) {
751
+ if (key === "$schema" || key === "$comment" || key.startsWith("ext:")) {
752
+ root[key] = value;
753
+ }
754
+ }
755
+ if (doc.$comment !== undefined) {
756
+ addLoss(ctx, "/$comment", "$comment has no 1.x field");
757
+ }
758
+ if (Object.keys(root).length) {
759
+ sections.root = root;
760
+ }
761
+ if (ctx.carriedCompositions?.length) {
762
+ sections.compositions = ctx.carriedCompositions;
763
+ }
764
+ if (Object.keys(ctx.shadows).length) {
765
+ sections.shadows = ctx.shadows;
766
+ }
767
+ return sections;
768
+ }