@cdxgen/cdxgen 13.3.0 → 13.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (372) hide show
  1. package/README.md +12 -9
  2. package/bin/cdxgen-secure.js +15 -0
  3. package/bin/cdxgen.js +115 -31
  4. package/bin/evinse.js +23 -1
  5. package/bin/hbom.js +15 -7
  6. package/bin/repl.js +115 -0
  7. package/bin/sign.js +45 -15
  8. package/bin/tracebom.js +5 -1
  9. package/bin/validate.js +84 -18
  10. package/bin/verify.js +155 -86
  11. package/data/cbomosdb-queries.json +13 -1
  12. package/data/component-tags.json +8 -0
  13. package/data/helpers/init.gradle +46 -21
  14. package/data/queries-darwin.json +25 -1
  15. package/data/queries-win.json +19 -1
  16. package/data/queries.json +41 -0
  17. package/data/remediations.json +344 -1
  18. package/data/rules/cbom-security.yaml +235 -4
  19. package/data/rules/dependency-sources.yaml +67 -0
  20. package/data/rules/go-binaries.yaml +46 -0
  21. package/data/rules/golem-go.yaml +80 -0
  22. package/data/rules/hbom-compliance.yaml +40 -22
  23. package/data/rules/hbom-performance.yaml +7 -1
  24. package/data/rules/host-topology.yaml +1 -1
  25. package/data/rules/obom-runtime.yaml +31 -2
  26. package/data/rules/php-runtime.yaml +143 -0
  27. package/data/rules/scala-evidence.yaml +115 -0
  28. package/lib/audit/index.js +52 -6
  29. package/lib/cli/bomAssembly.js +28 -3
  30. package/lib/cli/cliOptions.js +110 -3
  31. package/lib/cli/index.js +186 -58
  32. package/lib/cli/jsBom.js +50 -29
  33. package/lib/cli/jvmBom.js +779 -146
  34. package/lib/cli/managedBom.js +1021 -261
  35. package/lib/cli/nativeBom.js +364 -58
  36. package/lib/core/activity.js +12 -0
  37. package/lib/core/env.js +47 -17
  38. package/lib/core/fs.js +31 -21
  39. package/lib/core/httpClient.js +233 -69
  40. package/lib/core/pluginRun.js +184 -0
  41. package/lib/core/processTree.js +100 -0
  42. package/lib/core/projectConfig.js +1 -0
  43. package/lib/core/projectTooling.js +97 -0
  44. package/lib/core/propertySanitizer.js +72 -0
  45. package/lib/core/runState.js +39 -0
  46. package/lib/core/toml.js +72 -0
  47. package/lib/ecosystems/asarutils.js +4 -2
  48. package/lib/ecosystems/bunutils.js +5 -7
  49. package/lib/ecosystems/cargoCache.js +231 -8
  50. package/lib/ecosystems/cmakeResolver.js +10 -21
  51. package/lib/ecosystems/cppBuildContext.js +631 -0
  52. package/lib/ecosystems/cppEvidence.js +337 -22
  53. package/lib/ecosystems/cppIncludeResolver.js +294 -0
  54. package/lib/ecosystems/denoutils.js +93 -66
  55. package/lib/ecosystems/ecosystems.js +1967 -788
  56. package/lib/ecosystems/golem.js +578 -18
  57. package/lib/ecosystems/gradleutils.js +340 -46
  58. package/lib/ecosystems/jsEvidence.js +85 -24
  59. package/lib/ecosystems/kosi.js +21 -4
  60. package/lib/ecosystems/npmutils.js +64 -0
  61. package/lib/ecosystems/parsers-dotnet.js +668 -153
  62. package/lib/ecosystems/parsers-elm.js +46 -28
  63. package/lib/ecosystems/parsers-gleam.js +3 -4
  64. package/lib/ecosystems/parsers-go.js +1283 -297
  65. package/lib/ecosystems/parsers-js.js +92 -26
  66. package/lib/ecosystems/parsers-julia.js +2 -3
  67. package/lib/ecosystems/parsers-jvm.js +463 -29
  68. package/lib/ecosystems/parsers-misc.js +405 -93
  69. package/lib/ecosystems/parsers-python.js +152 -20
  70. package/lib/ecosystems/parsers-rust.js +4 -4
  71. package/lib/ecosystems/parsers-terraform.js +1573 -19
  72. package/lib/ecosystems/pythonutils.js +102 -6
  73. package/lib/ecosystems/remote/huggingface.js +3 -0
  74. package/lib/ecosystems/rubyutils.js +73 -20
  75. package/lib/ecosystems/rusi.js +32 -9
  76. package/lib/ecosystems/sbtutils.js +243 -187
  77. package/lib/ecosystems/scalacliutils.js +343 -0
  78. package/lib/ecosystems/scalasem.js +2620 -0
  79. package/lib/ecosystems/terraformRegistry.js +288 -0
  80. package/lib/ecosystems/utils.js +2 -0
  81. package/lib/ecosystems/vendoredCode.js +156 -0
  82. package/lib/evinser/evinser.js +695 -78
  83. package/lib/evinser/swiftsem.js +68 -5
  84. package/lib/helpers/agenticToolutils.js +2 -2
  85. package/lib/helpers/bomSigner.js +576 -128
  86. package/lib/inventory/agentSkillSpec.js +17 -0
  87. package/lib/inventory/aiCollector.js +4 -1
  88. package/lib/inventory/analyzer.js +110 -127
  89. package/lib/inventory/apkInstalledDb.js +243 -0
  90. package/lib/inventory/atomUtils.js +204 -48
  91. package/lib/inventory/auditCategories.js +10 -3
  92. package/lib/inventory/buildToolRateLimit.js +144 -0
  93. package/lib/inventory/cacheCommands.js +2 -1
  94. package/lib/inventory/cacheDir.js +52 -9
  95. package/lib/inventory/certificates.js +2371 -0
  96. package/lib/inventory/cmakeBuildDirs.js +254 -0
  97. package/lib/inventory/communityAiConfigParser.js +4 -9
  98. package/lib/inventory/deps.js +507 -128
  99. package/lib/inventory/display.js +200 -3
  100. package/lib/inventory/dosai.js +747 -101
  101. package/lib/inventory/dosaiParsers.js +310 -15
  102. package/lib/inventory/dynamic.js +96 -8
  103. package/lib/inventory/envcontext.js +168 -5
  104. package/lib/inventory/evidenceUtils.js +590 -132
  105. package/lib/inventory/fetchBatch.js +574 -38
  106. package/lib/inventory/fetchDiskCache.js +597 -0
  107. package/lib/inventory/forgeEnricher.js +14 -5
  108. package/lib/inventory/formulationParsers.js +3 -2
  109. package/lib/inventory/goBuildInfo.js +140 -0
  110. package/lib/inventory/hbom.js +67 -7
  111. package/lib/inventory/hbomAnalysis.js +16 -0
  112. package/lib/inventory/hostTopology.js +21 -0
  113. package/lib/inventory/jvmLocalRepos.js +917 -0
  114. package/lib/inventory/mcpConfigParser.js +2 -3
  115. package/lib/inventory/osPackagePurl.js +244 -0
  116. package/lib/inventory/osPackageResolver.js +89 -87
  117. package/lib/inventory/osinfo.js +79 -31
  118. package/lib/inventory/osqueryTransform.js +114 -5
  119. package/lib/inventory/parentSelection.js +146 -0
  120. package/lib/inventory/phpBuildInfo.js +487 -0
  121. package/lib/inventory/phpHostProbe.js +641 -0
  122. package/lib/inventory/rootfsCerts.js +426 -0
  123. package/lib/inventory/rustFormulationParser.js +3 -4
  124. package/lib/inventory/scalaCoords.js +153 -0
  125. package/lib/inventory/source.js +215 -11
  126. package/lib/inventory/spdx.js +245 -0
  127. package/lib/inventory/traceRunner.js +93 -8
  128. package/lib/inventory/tracedCrypto.js +423 -0
  129. package/lib/managers/binary.js +529 -183
  130. package/lib/managers/docker.js +199 -44
  131. package/lib/managers/oci.js +24 -2
  132. package/lib/parsers/cmakeCache.js +69 -0
  133. package/lib/parsers/cmakeLists.js +16 -2
  134. package/lib/parsers/cmakePresets.js +400 -0
  135. package/lib/parsers/compileCommands.js +557 -0
  136. package/lib/parsers/email.js +277 -0
  137. package/lib/parsers/largeJson.js +34 -2
  138. package/lib/parsers/strictJson.js +322 -0
  139. package/lib/parsers/terraformConfig.js +1073 -0
  140. package/lib/parsers/terraformSource.js +652 -0
  141. package/lib/server/server.js +209 -1
  142. package/lib/stages/postgen/annotator.js +17 -1
  143. package/lib/stages/postgen/introspection/markers.js +1 -1
  144. package/lib/stages/postgen/introspection/reflect.js +4 -1
  145. package/lib/stages/postgen/postgen.js +20 -6
  146. package/lib/stages/postgen/ruleEngine.js +58 -1
  147. package/lib/stages/postgen/specVersionCompat.js +62 -0
  148. package/lib/stages/pregen/pregen.js +117 -5
  149. package/lib/validator/bomValidator.js +26 -5
  150. package/lib/validator/generated/runtime.mjs +13 -0
  151. package/lib/validator/generated/validate-1.6.mjs +26 -7
  152. package/lib/validator/generated/validate-1.7.mjs +31 -12
  153. package/lib/validator/generated/validate-2.0.mjs +30 -11
  154. package/lib/validator/index.js +25 -10
  155. package/lib/validator/reporters/json.js +1 -0
  156. package/package.json +23 -23
  157. package/types/bin/cdxgen-secure.d.ts +3 -0
  158. package/types/bin/cdxgen-secure.d.ts.map +1 -0
  159. package/types/bin/repl.d.ts.map +1 -1
  160. package/types/lib/audit/index.d.ts.map +1 -1
  161. package/types/lib/cli/bomAssembly.d.ts +9 -2
  162. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  163. package/types/lib/cli/cliOptions.d.ts +43 -0
  164. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  165. package/types/lib/cli/index.d.ts.map +1 -1
  166. package/types/lib/cli/jsBom.d.ts.map +1 -1
  167. package/types/lib/cli/jvmBom.d.ts +44 -1
  168. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  169. package/types/lib/cli/managedBom.d.ts +7 -4
  170. package/types/lib/cli/managedBom.d.ts.map +1 -1
  171. package/types/lib/cli/nativeBom.d.ts +3 -1
  172. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  173. package/types/lib/core/activity.d.ts.map +1 -1
  174. package/types/lib/core/env.d.ts +27 -2
  175. package/types/lib/core/env.d.ts.map +1 -1
  176. package/types/lib/core/fs.d.ts.map +1 -1
  177. package/types/lib/core/httpClient.d.ts +13 -8
  178. package/types/lib/core/httpClient.d.ts.map +1 -1
  179. package/types/lib/core/pluginRun.d.ts +97 -0
  180. package/types/lib/core/pluginRun.d.ts.map +1 -0
  181. package/types/lib/core/processTree.d.ts +36 -0
  182. package/types/lib/core/processTree.d.ts.map +1 -0
  183. package/types/lib/core/projectConfig.d.ts.map +1 -1
  184. package/types/lib/core/projectTooling.d.ts +41 -0
  185. package/types/lib/core/projectTooling.d.ts.map +1 -0
  186. package/types/lib/core/propertySanitizer.d.ts +26 -0
  187. package/types/lib/core/propertySanitizer.d.ts.map +1 -1
  188. package/types/lib/core/runState.d.ts +29 -0
  189. package/types/lib/core/runState.d.ts.map +1 -0
  190. package/types/lib/core/toml.d.ts +20 -0
  191. package/types/lib/core/toml.d.ts.map +1 -0
  192. package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
  193. package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
  194. package/types/lib/ecosystems/cargoCache.d.ts +12 -0
  195. package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
  196. package/types/lib/ecosystems/cmakeResolver.d.ts +5 -3
  197. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
  198. package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
  199. package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
  200. package/types/lib/ecosystems/cppEvidence.d.ts +19 -3
  201. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  202. package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
  203. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
  204. package/types/lib/ecosystems/denoutils.d.ts +9 -3
  205. package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
  206. package/types/lib/ecosystems/ecosystems.d.ts +62 -13
  207. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  208. package/types/lib/ecosystems/golem.d.ts +81 -1
  209. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  210. package/types/lib/ecosystems/gradleutils.d.ts +59 -7
  211. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  212. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  213. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  214. package/types/lib/ecosystems/npmutils.d.ts +15 -0
  215. package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
  216. package/types/lib/ecosystems/parsers-dotnet.d.ts +155 -5
  217. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  218. package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
  219. package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
  220. package/types/lib/ecosystems/parsers-go.d.ts +119 -5
  221. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  222. package/types/lib/ecosystems/parsers-js.d.ts +6 -1
  223. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  224. package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
  225. package/types/lib/ecosystems/parsers-jvm.d.ts +74 -3
  226. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  227. package/types/lib/ecosystems/parsers-misc.d.ts +21 -59
  228. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  229. package/types/lib/ecosystems/parsers-python.d.ts +57 -6
  230. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  231. package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
  232. package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
  233. package/types/lib/ecosystems/pythonutils.d.ts +26 -1
  234. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  235. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  236. package/types/lib/ecosystems/rubyutils.d.ts +21 -1
  237. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  238. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  239. package/types/lib/ecosystems/sbtutils.d.ts +88 -2
  240. package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
  241. package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
  242. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
  243. package/types/lib/ecosystems/scalasem.d.ts +311 -0
  244. package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
  245. package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
  246. package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
  247. package/types/lib/ecosystems/utils.d.ts +2 -2
  248. package/types/lib/ecosystems/utils.d.ts.map +1 -1
  249. package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
  250. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
  251. package/types/lib/evinser/evinser.d.ts +100 -8
  252. package/types/lib/evinser/evinser.d.ts.map +1 -1
  253. package/types/lib/evinser/swiftsem.d.ts +10 -0
  254. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  255. package/types/lib/helpers/bomSigner.d.ts +80 -4
  256. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  257. package/types/lib/inventory/agentSkillSpec.d.ts +13 -0
  258. package/types/lib/inventory/agentSkillSpec.d.ts.map +1 -0
  259. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  260. package/types/lib/inventory/analyzer.d.ts.map +1 -1
  261. package/types/lib/inventory/apkInstalledDb.d.ts +42 -0
  262. package/types/lib/inventory/apkInstalledDb.d.ts.map +1 -0
  263. package/types/lib/inventory/atomUtils.d.ts +96 -10
  264. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  265. package/types/lib/inventory/auditCategories.d.ts +3 -0
  266. package/types/lib/inventory/auditCategories.d.ts.map +1 -1
  267. package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
  268. package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
  269. package/types/lib/inventory/cacheCommands.d.ts +2 -1
  270. package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
  271. package/types/lib/inventory/cacheDir.d.ts +12 -4
  272. package/types/lib/inventory/cacheDir.d.ts.map +1 -1
  273. package/types/lib/inventory/certificates.d.ts +205 -0
  274. package/types/lib/inventory/certificates.d.ts.map +1 -0
  275. package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
  276. package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
  277. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  278. package/types/lib/inventory/deps.d.ts +61 -2
  279. package/types/lib/inventory/deps.d.ts.map +1 -1
  280. package/types/lib/inventory/display.d.ts +18 -0
  281. package/types/lib/inventory/display.d.ts.map +1 -1
  282. package/types/lib/inventory/dosai.d.ts +202 -14
  283. package/types/lib/inventory/dosai.d.ts.map +1 -1
  284. package/types/lib/inventory/dosaiParsers.d.ts +53 -7
  285. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  286. package/types/lib/inventory/dynamic.d.ts +16 -1
  287. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  288. package/types/lib/inventory/envcontext.d.ts +40 -2
  289. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  290. package/types/lib/inventory/evidenceUtils.d.ts +48 -14
  291. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  292. package/types/lib/inventory/fetchBatch.d.ts +83 -14
  293. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  294. package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
  295. package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
  296. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
  297. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  298. package/types/lib/inventory/goBuildInfo.d.ts +10 -0
  299. package/types/lib/inventory/goBuildInfo.d.ts.map +1 -0
  300. package/types/lib/inventory/hbom.d.ts.map +1 -1
  301. package/types/lib/inventory/hbomAnalysis.d.ts +10 -0
  302. package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -1
  303. package/types/lib/inventory/hostTopology.d.ts.map +1 -1
  304. package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
  305. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
  306. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  307. package/types/lib/inventory/osPackagePurl.d.ts +99 -0
  308. package/types/lib/inventory/osPackagePurl.d.ts.map +1 -0
  309. package/types/lib/inventory/osPackageResolver.d.ts +6 -2
  310. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
  311. package/types/lib/inventory/osinfo.d.ts +31 -6
  312. package/types/lib/inventory/osinfo.d.ts.map +1 -1
  313. package/types/lib/inventory/osqueryTransform.d.ts +51 -0
  314. package/types/lib/inventory/osqueryTransform.d.ts.map +1 -1
  315. package/types/lib/inventory/parentSelection.d.ts +34 -0
  316. package/types/lib/inventory/parentSelection.d.ts.map +1 -0
  317. package/types/lib/inventory/phpBuildInfo.d.ts +142 -0
  318. package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -0
  319. package/types/lib/inventory/phpHostProbe.d.ts +35 -0
  320. package/types/lib/inventory/phpHostProbe.d.ts.map +1 -0
  321. package/types/lib/inventory/rootfsCerts.d.ts +27 -0
  322. package/types/lib/inventory/rootfsCerts.d.ts.map +1 -0
  323. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  324. package/types/lib/inventory/scalaCoords.d.ts +80 -0
  325. package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
  326. package/types/lib/inventory/source.d.ts +28 -0
  327. package/types/lib/inventory/source.d.ts.map +1 -1
  328. package/types/lib/inventory/spdx.d.ts +24 -0
  329. package/types/lib/inventory/spdx.d.ts.map +1 -1
  330. package/types/lib/inventory/traceRunner.d.ts +16 -1
  331. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  332. package/types/lib/inventory/tracedCrypto.d.ts +64 -0
  333. package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
  334. package/types/lib/managers/binary.d.ts +10 -0
  335. package/types/lib/managers/binary.d.ts.map +1 -1
  336. package/types/lib/managers/docker.d.ts +12 -0
  337. package/types/lib/managers/docker.d.ts.map +1 -1
  338. package/types/lib/managers/oci.d.ts +3 -1
  339. package/types/lib/managers/oci.d.ts.map +1 -1
  340. package/types/lib/parsers/cmakeCache.d.ts +16 -0
  341. package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
  342. package/types/lib/parsers/cmakeLists.d.ts +2 -1
  343. package/types/lib/parsers/cmakeLists.d.ts.map +1 -1
  344. package/types/lib/parsers/cmakePresets.d.ts +78 -0
  345. package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
  346. package/types/lib/parsers/compileCommands.d.ts +115 -0
  347. package/types/lib/parsers/compileCommands.d.ts.map +1 -0
  348. package/types/lib/parsers/email.d.ts +19 -0
  349. package/types/lib/parsers/email.d.ts.map +1 -0
  350. package/types/lib/parsers/largeJson.d.ts +13 -0
  351. package/types/lib/parsers/largeJson.d.ts.map +1 -1
  352. package/types/lib/parsers/strictJson.d.ts +46 -0
  353. package/types/lib/parsers/strictJson.d.ts.map +1 -0
  354. package/types/lib/parsers/terraformConfig.d.ts +70 -0
  355. package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
  356. package/types/lib/parsers/terraformSource.d.ts +66 -0
  357. package/types/lib/parsers/terraformSource.d.ts.map +1 -0
  358. package/types/lib/server/server.d.ts +8 -0
  359. package/types/lib/server/server.d.ts.map +1 -1
  360. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  361. package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -1
  362. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  363. package/types/lib/stages/postgen/ruleEngine.d.ts +7 -4
  364. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  365. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  366. package/types/lib/stages/pregen/pregen.d.ts +14 -1
  367. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  368. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  369. package/types/lib/validator/index.d.ts +8 -0
  370. package/types/lib/validator/index.d.ts.map +1 -1
  371. package/types/lib/validator/reporters/json.d.ts.map +1 -1
  372. package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
@@ -14,7 +14,10 @@ import {
14
14
  isSecureMode,
15
15
  readEnvironmentVariable,
16
16
  } from "../core/activity.js";
17
+ import { PROJECT_TYPE_ALIASES } from "../core/env.js";
17
18
  import { isWin } from "../core/paths.js";
19
+ import { isSecureModeActive } from "../core/projectTooling.js";
20
+ import { resetRunState } from "../core/runState.js";
18
21
  import { CDXGEN_VERSION } from "../core/state.js";
19
22
  import { installConsoleShim, ui } from "../core/ui.js";
20
23
  import { fetchPomXmlAsJson } from "../ecosystems/ecosystems.js";
@@ -26,6 +29,7 @@ import {
26
29
  getGitAllowProtocol,
27
30
  gitClone,
28
31
  isAllowedPath,
32
+ isAllowedRealPath,
29
33
  isAllowedWinPath,
30
34
  maybePurlSource,
31
35
  maybeRemotePath,
@@ -81,6 +85,11 @@ const ALLOWED_PARAMS = [
81
85
  "tlpClassification",
82
86
  ];
83
87
 
88
+ // Options that install packages or run the scanned project's own build tools
89
+ // (for example `cargo check`, which runs build.rs), and so execute code from
90
+ // the scanned repository.
91
+ const CODE_EXECUTION_PARAMS = ["installDeps", "deep"];
92
+
84
93
  const app = connect();
85
94
 
86
95
  export { isAllowedHttpHost };
@@ -155,6 +164,7 @@ export function parseValue(raw) {
155
164
  * @returns {Object} Populated options object
156
165
  */
157
166
  export function parseQueryString(q, body = {}, options = {}) {
167
+ const operatorOptions = { ...options };
158
168
  // Priority is query params followed by body
159
169
  for (const param of ALLOWED_PARAMS) {
160
170
  const raw = q[param] ?? body[param];
@@ -162,7 +172,7 @@ export function parseQueryString(q, body = {}, options = {}) {
162
172
  options[param] = parseValue(raw);
163
173
  }
164
174
  }
165
- options.projectType = options.type?.split(",");
175
+ options.projectType = toProjectTypeList(options.type);
166
176
  delete options.type;
167
177
  if (options.lifecycle === "pre-build") {
168
178
  options.installDeps = false;
@@ -170,9 +180,170 @@ export function parseQueryString(q, body = {}, options = {}) {
170
180
  if (options.profile) {
171
181
  applyProfileOptions(options);
172
182
  }
183
+ // failOnError ends the process, so one failing request would stop the server
184
+ // for every client.
185
+ options.failOnError = false;
186
+ restrictRequestOptions(options, operatorOptions);
173
187
  return options;
174
188
  }
175
189
 
190
+ /**
191
+ * Normalise a `type` value from the request or the start-up options, which may
192
+ * be a comma separated string or an array, into a list of project types.
193
+ *
194
+ * @param {string|string[]|undefined} type Project type value
195
+ * @returns {string[]|undefined} Project types, or undefined when none are given
196
+ */
197
+ function toProjectTypeList(type) {
198
+ if (type === undefined || type === null || type === "") {
199
+ return undefined;
200
+ }
201
+ const types = (Array.isArray(type) ? type : [type])
202
+ .flatMap((t) => String(t).split(","))
203
+ .map((t) => t.trim())
204
+ .filter(Boolean);
205
+ return types.length ? types : undefined;
206
+ }
207
+
208
+ /**
209
+ * Stop a request from turning on options that execute code from the scanned
210
+ * repository when the operator has not. In secure mode, or when the server was
211
+ * started with --no-install-deps, a request may turn these options off but
212
+ * never on.
213
+ *
214
+ * @param {Object} options Options parsed from the request
215
+ * @param {Object} operatorOptions Options the server was started with
216
+ * @returns {void}
217
+ */
218
+ function restrictRequestOptions(options, operatorOptions) {
219
+ if (!isSecureModeActive() && operatorOptions.installDeps !== false) {
220
+ return;
221
+ }
222
+ for (const param of CODE_EXECUTION_PARAMS) {
223
+ // Only an explicit false from the request changes the operator's choice.
224
+ // Values such as "" or 0 would otherwise pass gates that test `!== false`.
225
+ options[param] =
226
+ operatorOptions[param] === true && options[param] !== false;
227
+ }
228
+ }
229
+
230
+ // Project types that inventory the host the server runs on, such as installed
231
+ // packages, users, shell history, IDE and browser extensions, or the Maven,
232
+ // Gradle, sbt, Cargo and Helm caches in the server user's home directory.
233
+ // They ignore the scan path, so the path allowlist does not limit them.
234
+ const HOST_SCOPE_PROJECT_TYPES = new Set(
235
+ [
236
+ "os",
237
+ "hbom",
238
+ "cargo-cache",
239
+ "helm-index",
240
+ "gradle-index",
241
+ "sbt-index",
242
+ "maven-index",
243
+ "vscode-extension",
244
+ "chrome-extension",
245
+ "agentic",
246
+ ]
247
+ .flatMap((key) => PROJECT_TYPE_ALIASES[key] || [key])
248
+ .concat(["maven-repo"]),
249
+ );
250
+
251
+ /**
252
+ * Check request options that the server must refuse outright.
253
+ *
254
+ * @param {Object} reqOptions Options parsed from the request
255
+ * @param {Object} operatorOptions Options the server was started with
256
+ * @returns {Object|null} Error object with status, error and details, or null
257
+ */
258
+ export function validateRequestOptions(reqOptions, operatorOptions = {}) {
259
+ const operatorTypes = new Set(
260
+ toProjectTypeList(operatorOptions.type ?? operatorOptions.projectType) ||
261
+ [],
262
+ );
263
+ const hostScopeType = (reqOptions.projectType || []).find(
264
+ (t) => HOST_SCOPE_PROJECT_TYPES.has(t) && !operatorTypes.has(t),
265
+ );
266
+ if (hostScopeType) {
267
+ return {
268
+ status: 403,
269
+ error: "Project Type Not Allowed",
270
+ details: `The '${hostScopeType}' project type scans the server host. Start the server with this type to allow it.`,
271
+ };
272
+ }
273
+ const excludes = Array.isArray(reqOptions.exclude)
274
+ ? reqOptions.exclude
275
+ : [reqOptions.exclude];
276
+ // Brace patterns expand before matching, so one short pattern such as
277
+ // {1..100000} can keep the server busy for minutes.
278
+ if (
279
+ reqOptions.exclude !== operatorOptions.exclude &&
280
+ excludes.some(
281
+ (e) => typeof e === "string" && (e.includes("{") || e.length > 512),
282
+ )
283
+ ) {
284
+ return {
285
+ status: 400,
286
+ error: "Invalid Exclude Pattern",
287
+ details:
288
+ "Exclude patterns sent to the server cannot use braces or exceed 512 characters.",
289
+ };
290
+ }
291
+ if (
292
+ reqOptions.serverUrl &&
293
+ reqOptions.serverUrl !== operatorOptions.serverUrl
294
+ ) {
295
+ const requestedOrigin = urlOrigin(reqOptions.serverUrl);
296
+ if (!requestedOrigin) {
297
+ return {
298
+ status: 400,
299
+ error: "Invalid Server URL",
300
+ details: "The Dependency-Track server URL is invalid.",
301
+ };
302
+ }
303
+ if (requestedOrigin !== urlOrigin(operatorOptions.serverUrl)) {
304
+ // The operator's API key only ever goes to the operator's server.
305
+ if (
306
+ operatorOptions.apiKey &&
307
+ reqOptions.apiKey === operatorOptions.apiKey
308
+ ) {
309
+ return {
310
+ status: 400,
311
+ error: "API Key Required",
312
+ details:
313
+ "A request that names its own Dependency-Track server must send its own API key.",
314
+ };
315
+ }
316
+ // CDXGEN_SERVER_ALLOWED_HOSTS only covers git hosts, so in secure mode a
317
+ // server the operator did not configure must be on CDXGEN_ALLOWED_HOSTS.
318
+ if (isSecureMode && !readEnvironmentVariable("CDXGEN_ALLOWED_HOSTS")) {
319
+ return {
320
+ status: 403,
321
+ error: "Host Not Allowed",
322
+ details:
323
+ "Set CDXGEN_ALLOWED_HOSTS to let requests choose a Dependency-Track server.",
324
+ };
325
+ }
326
+ }
327
+ }
328
+ if (isSecureMode && reqOptions.includeFormulation && reqOptions.serverUrl) {
329
+ return {
330
+ status: 400,
331
+ error: "Formulation Not Allowed",
332
+ details:
333
+ "Formulation data may contain secrets and is not submitted to Dependency-Track in secure mode.",
334
+ };
335
+ }
336
+ return null;
337
+ }
338
+
339
+ function urlOrigin(value) {
340
+ try {
341
+ return new URL(value).origin;
342
+ } catch (_err) {
343
+ return undefined;
344
+ }
345
+ }
346
+
176
347
  /**
177
348
  * Extracts query parameters from an incoming HTTP request object.
178
349
  * Handles repeated keys by collecting their values into an array.
@@ -244,6 +415,26 @@ const configureServer = (cdxgenServer) => {
244
415
 
245
416
  const ALL_INTERFACES = new Set(["0.0.0.0", "::", "::/128", "::/0"]);
246
417
 
418
+ // Registry answers, recorded misses and local cache lookups last for one scan.
419
+ // They are emptied whenever no scan is running, so a scan neither starts from
420
+ // an earlier scan's answers, which would hide new releases and new downloads,
421
+ // nor has its own emptied by a scan running alongside it.
422
+ let activeScans = 0;
423
+
424
+ function beginScan() {
425
+ if (activeScans === 0) {
426
+ resetRunState();
427
+ }
428
+ activeScans++;
429
+ }
430
+
431
+ function endScan() {
432
+ activeScans--;
433
+ if (activeScans === 0) {
434
+ resetRunState();
435
+ }
436
+ }
437
+
247
438
  /**
248
439
  * Boot the cdxgen HTTP server.
249
440
  *
@@ -370,6 +561,18 @@ const start = (options) => {
370
561
  }),
371
562
  );
372
563
  }
564
+ const optionsError = validateRequestOptions(reqOptions, options);
565
+ if (optionsError) {
566
+ res.writeHead(optionsError.status, {
567
+ "Content-Type": "application/json",
568
+ });
569
+ return res.end(
570
+ JSON.stringify({
571
+ error: optionsError.error,
572
+ details: optionsError.details,
573
+ }),
574
+ );
575
+ }
373
576
  // Enforce the v13 CycloneDX spec floor on the HTTP entry point too, so the
374
577
  // server cannot be used to request a generation target the CLI rejects.
375
578
  if (reqOptions.specVersion !== undefined) {
@@ -393,6 +596,7 @@ const start = (options) => {
393
596
  }
394
597
  let cloneDir;
395
598
  let srcDir;
599
+ beginScan();
396
600
  try {
397
601
  let sourcePath = filePath;
398
602
  let purlResolution;
@@ -480,8 +684,11 @@ const start = (options) => {
480
684
  cleanup = true;
481
685
  } else {
482
686
  srcDir = sourcePath;
687
+ // Check where a symlinked path really points as well, so a link inside
688
+ // an allowed directory cannot open a scan of a directory outside it.
483
689
  if (
484
690
  !isAllowedPath(path.resolve(srcDir)) ||
691
+ !isAllowedRealPath(srcDir) ||
485
692
  (isWin && !isAllowedWinPath(srcDir))
486
693
  ) {
487
694
  res.writeHead(403, { "Content-Type": "application/json" });
@@ -606,6 +813,7 @@ const start = (options) => {
606
813
  }
607
814
  console.log("Error while generating SBOM response", err);
608
815
  } finally {
816
+ endScan();
609
817
  if (cleanup && cloneDir) {
610
818
  cleanupSourceDir(cloneDir);
611
819
  }
@@ -463,6 +463,15 @@ export function textualMetadata(bomJson) {
463
463
  const swidCount = bomJson?.components?.filter((c) =>
464
464
  c?.purl?.startsWith("pkg:swid"),
465
465
  ).length;
466
+ // Homebrew packages are pkg:brew, not pkg:swid, so they are not counted as
467
+ // applications; formulae and casks are told apart by a property.
468
+ const brewComponents =
469
+ bomJson?.components?.filter((c) => c?.purl?.startsWith("pkg:brew/")) || [];
470
+ const brewCaskCount = brewComponents.filter((c) =>
471
+ c.properties?.some(
472
+ (p) => p.name === "cdx:homebrew:type" && p.value === "cask",
473
+ ),
474
+ ).length;
466
475
  const { unpackagedExecutableCount, unpackagedSharedLibraryCount } =
467
476
  getContainerFileInventoryStats(bomJson?.components);
468
477
  const githubStats = getGitHubWorkflowStats(bomJson?.components);
@@ -711,7 +720,14 @@ export function textualMetadata(bomJson) {
711
720
  text = `${text} The system appears to be set up for remote development, with ${vsixCount} Visual Studio Code extensions installed.`;
712
721
  }
713
722
  if (swidCount > 0) {
714
- text = `${text} In addition, there are ${swidCount} applications installed on the system.`;
723
+ text = `${text} In addition, there ${swidCount === 1 ? "is 1 application" : `are ${swidCount} applications`} installed on the system.`;
724
+ }
725
+ if (brewComponents.length > 0) {
726
+ const brewCount = brewComponents.length;
727
+ const casks = brewCaskCount
728
+ ? `, of which ${brewCaskCount} ${brewCaskCount === 1 ? "is a cask" : "are casks"}`
729
+ : "";
730
+ text = `${text} The system also has ${brewCount} Homebrew package${brewCount === 1 ? "" : "s"} installed${casks}.`;
715
731
  }
716
732
  }
717
733
  if (bomType === "HBOM" && hbomSummary) {
@@ -137,7 +137,7 @@ export const ECOSYSTEM_MARKERS = Object.freeze({
137
137
  ocaml: { names: ["dune-project"], suffixes: [".opam"] },
138
138
  lua: { names: ["luarocks.lock"], suffixes: [".rockspec"] },
139
139
  spack: { names: ["spack.yaml", "spack.lock"], suffixes: [] },
140
- terraform: { names: [".terraform.lock.hcl"], suffixes: [] },
140
+ terraform: { names: [".terraform.lock.hcl"], suffixes: [".tf", ".tofu"] },
141
141
  });
142
142
 
143
143
  /** Marker file name → ecosystems claiming it, and marker suffix → claiming
@@ -36,6 +36,7 @@ import {
36
36
  isVersionedJvmToolProjectType,
37
37
  PROJECT_TYPE_ALIASES,
38
38
  } from "../../../core/env.js";
39
+ import { safeExistsSync } from "../../../core/fs.js";
39
40
  import { dirNameStr } from "../../../core/paths.js";
40
41
  import { CDXGEN_VERSION } from "../../../core/state.js";
41
42
  import { evaluateRules, loadRules } from "../ruleEngine.js";
@@ -389,7 +390,9 @@ function resolveLedgerEvents(context) {
389
390
  };
390
391
  }
391
392
  const sidecarPath = readEnvironmentVariable("CDXGEN_INTROSPECT_LEDGER");
392
- if (sidecarPath) {
393
+ // A sidecar the run could not create (the permission model denies writes
394
+ // outside the granted paths) holds nothing; the buffer still has the events.
395
+ if (sidecarPath && safeExistsSync(sidecarPath)) {
393
396
  return { events: loadLedgerFile(sidecarPath), source: "sidecar" };
394
397
  }
395
398
  const events = getLedgerEvents();
@@ -1,5 +1,5 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { basename, join, relative, sep } from "node:path";
2
+ import { join, relative } from "node:path";
3
3
  import process from "node:process";
4
4
 
5
5
  import { Purl } from "@cdxgen/cdx-purl";
@@ -756,6 +756,12 @@ export function applyMetadata(bomJson, options) {
756
756
  return;
757
757
  }
758
758
  if (comp.properties) {
759
+ // internal:LocalNodeModulesPath is a lookup path on the scanning host.
760
+ // Collectors outside the JS evidence pass (caxa, scalasem) keep it, so
761
+ // it is removed here for every component.
762
+ comp.properties = comp.properties.filter(
763
+ (aprop) => aprop.name !== "internal:LocalNodeModulesPath",
764
+ );
759
765
  for (const aprop of comp.properties) {
760
766
  if (aprop.name === "internal:SrcFile" && aprop.value) {
761
767
  const rdir = relativeDir(aprop.value, options);
@@ -822,7 +828,15 @@ export function applyMetadata(bomJson, options) {
822
828
  }
823
829
  collectSrcFiles(comp);
824
830
  }
825
- collectSrcFiles(bomJson.metadata?.component);
831
+ // The project's sub-components, the modules of a multi-module build, name
832
+ // their manifests the same way, at any depth.
833
+ const collectSrcFilesTree = (comp) => {
834
+ collectSrcFiles(comp);
835
+ for (const subComponent of comp?.components || []) {
836
+ collectSrcFilesTree(subComponent);
837
+ }
838
+ };
839
+ collectSrcFilesTree(bomJson.metadata?.component);
826
840
  if (!bomJson.metadata.properties) {
827
841
  bomJson.metadata.properties = [];
828
842
  }
@@ -929,10 +943,10 @@ function applyCustomMetadataProperties(bomJson, options) {
929
943
  export function applyStandards(bomJson, options) {
930
944
  if (options.standard && Array.isArray(options.standard)) {
931
945
  for (let astandard of options.standard) {
932
- // See issue: #1953
933
- if (astandard.includes(sep)) {
934
- astandard = basename(astandard);
935
- }
946
+ // See issue: #1953. Server requests can send either separator, and on
947
+ // Windows both "/" and "\" separate path segments, so keep only the
948
+ // last segment of either kind.
949
+ astandard = String(astandard).split(/[\\/]/).pop();
936
950
  const templateFile = join(
937
951
  dirNameStr,
938
952
  "data",
@@ -165,7 +165,18 @@ function hasProperty(obj, propName, expectedValue) {
165
165
  if (expectedValue === undefined) {
166
166
  return value !== null;
167
167
  }
168
- return value === String(expectedValue);
168
+ // A repeatable property (cdx:crypto:sourceType on a certificate found by
169
+ // several producers) matches when any of its values does.
170
+ return extractPropertyValues(obj, propName).includes(String(expectedValue));
171
+ }
172
+
173
+ function extractPropertyValues(obj, propName) {
174
+ if (!Array.isArray(obj?.properties)) {
175
+ return [];
176
+ }
177
+ return obj.properties
178
+ .filter((p) => p?.name === propName && p.value !== undefined)
179
+ .map((p) => String(p.value));
169
180
  }
170
181
 
171
182
  /**
@@ -315,6 +326,9 @@ function registerCdxHelpers(expression, helpers = {}) {
315
326
  expression.registerFunction("prop", (obj, propName) =>
316
327
  extractProperty(obj, propName),
317
328
  );
329
+ expression.registerFunction("propValues", (obj, propName) =>
330
+ extractPropertyValues(obj, propName),
331
+ );
318
332
  expression.registerFunction("nullSafeProp", (obj, propName) => {
319
333
  const value = extractProperty(obj, propName);
320
334
  return value === null ? "" : value;
@@ -385,6 +399,13 @@ function registerCdxHelpers(expression, helpers = {}) {
385
399
  expression.registerFunction("safeStr", (val) => {
386
400
  return val === null || val === undefined ? "" : String(val).trim();
387
401
  });
402
+ // End of validity in epoch milliseconds. A date-only value (2026-01-31)
403
+ // is valid through the end of that day in UTC; a full RFC 3339 timestamp
404
+ // is taken as is; anything else, or an impossible date, gives no value so
405
+ // the rule skips the component.
406
+ expression.registerFunction("certEndMillis", (val) =>
407
+ parseCertificateEndMillis(val),
408
+ );
388
409
  expression.registerFunction("parseSizeBytes", (val) => {
389
410
  if (val === null || val === undefined || val === "") {
390
411
  return null;
@@ -519,6 +540,42 @@ function registerCdxHelpers(expression, helpers = {}) {
519
540
  * @param {string} rulesDir - Path to directory containing .yaml rule files
520
541
  * @returns {Promise<Array>} Array of parsed rule objects
521
542
  */
543
+ const FULL_TIMESTAMP_RE =
544
+ /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?(Z|[+-]([01]\d|2[0-3]):[0-5]\d)$/;
545
+ const DATE_ONLY_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
546
+
547
+ /**
548
+ * Parse a certificate notValidAfter value.
549
+ *
550
+ * @param {*} value timestamp or date-only string
551
+ * @returns {number|undefined} epoch milliseconds, or undefined when the value
552
+ * does not parse
553
+ */
554
+ export function parseCertificateEndMillis(value) {
555
+ if (typeof value !== "string") {
556
+ return undefined;
557
+ }
558
+ const text = value.trim();
559
+ const dateOnly = DATE_ONLY_RE.exec(text);
560
+ if (dateOnly) {
561
+ const [year, month, day] = dateOnly.slice(1).map(Number);
562
+ const start = new Date(Date.UTC(year, month - 1, day));
563
+ if (
564
+ start.getUTCFullYear() !== year ||
565
+ start.getUTCMonth() !== month - 1 ||
566
+ start.getUTCDate() !== day
567
+ ) {
568
+ return undefined;
569
+ }
570
+ return start.getTime() + 24 * 60 * 60 * 1000 - 1;
571
+ }
572
+ if (!FULL_TIMESTAMP_RE.test(text)) {
573
+ return undefined;
574
+ }
575
+ const millis = Date.parse(text);
576
+ return Number.isNaN(millis) ? undefined : millis;
577
+ }
578
+
522
579
  export async function loadRules(rulesDir) {
523
580
  const rules = [];
524
581
  if (!safeExistsSync(rulesDir)) {
@@ -53,6 +53,17 @@ const DEPENDENCY_1_6_ONLY_FIELDS = new Set(["provides"]);
53
53
  // License and license expression objects gained these attributes only in the
54
54
  // given spec versions. CycloneDX forbids additional properties, so they must be
55
55
  // removed when downgrading. Ref: data/bom-1.{4,5,6}.schema.json
56
+ // The protocol types CycloneDX 1.6 defines; 1.7 added more.
57
+ const SPEC_1_6_PROTOCOL_TYPES = new Set([
58
+ "tls",
59
+ "ssh",
60
+ "ipsec",
61
+ "ike",
62
+ "sstp",
63
+ "wpa",
64
+ "other",
65
+ "unknown",
66
+ ]);
56
67
  const LICENSE_1_5_ONLY_FIELDS = new Set(["bom-ref", "licensing", "properties"]);
57
68
  const LICENSE_1_6_ONLY_FIELDS = new Set(["acknowledgement"]);
58
69
  const LICENSE_EXPRESSION_1_5_ONLY_FIELDS = new Set(["bom-ref"]);
@@ -593,17 +604,68 @@ function downgradeSubjectForSpecVersion(subject, specVersion, parentKey) {
593
604
  certificateProperties.certificateExtension =
594
605
  certificateProperties.certificateFileExtension;
595
606
  }
607
+ // `relatedCryptographicAssets` and `certificateExtensions` are 1.7-only;
608
+ // the deprecated `subjectPublicKeyRef`/`signatureAlgorithmRef` (valid in
609
+ // 1.6, see data/bom-1.6.schema.json) carry the same links, and the
610
+ // extension facts survive as `cdx:crypto:` properties.
611
+ const relatedAssets = certificateProperties.relatedCryptographicAssets;
612
+ if (Array.isArray(relatedAssets)) {
613
+ for (const asset of relatedAssets) {
614
+ if (
615
+ asset?.type === "publicKey" &&
616
+ !certificateProperties.subjectPublicKeyRef
617
+ ) {
618
+ certificateProperties.subjectPublicKeyRef = asset.ref;
619
+ } else if (
620
+ asset?.type === "algorithm" &&
621
+ !certificateProperties.signatureAlgorithmRef
622
+ ) {
623
+ certificateProperties.signatureAlgorithmRef = asset.ref;
624
+ }
625
+ }
626
+ delete certificateProperties.relatedCryptographicAssets;
627
+ }
628
+ delete certificateProperties.certificateExtensions;
596
629
  delete certificateProperties.serialNumber;
597
630
  delete certificateProperties.certificateFileExtension;
598
631
  delete certificateProperties.fingerprint;
632
+ } else if (
633
+ specVersion < 1.7 &&
634
+ subject.cryptoProperties?.assetType === "related-crypto-material" &&
635
+ subject.cryptoProperties.relatedCryptoMaterialProperties
636
+ ) {
637
+ // The public-key `fingerprint` object is 1.7-only; the SPKI digest stays
638
+ // available as the `cdx:crypto:spkiSha256` property.
639
+ delete subject.cryptoProperties.relatedCryptoMaterialProperties.fingerprint;
599
640
  }
600
641
  if (specVersion < 1.7 && subject.cryptoProperties?.algorithmProperties) {
601
642
  // `algorithmFamily` and `ellipticCurve` are CycloneDX 1.7 additions to
602
643
  // cryptoProperties.algorithmProperties. 1.6 keeps the deprecated free-text
603
644
  // `curve`, so that one is preserved. Ref: data/bom-1.6.schema.json.
604
645
  const algorithmProperties = subject.cryptoProperties.algorithmProperties;
646
+ // The curve stays known through the free-text field, by its name without
647
+ // the registry prefix (`secg/secp256r1` is `secp256r1`).
648
+ if (algorithmProperties.ellipticCurve && !algorithmProperties.curve) {
649
+ algorithmProperties.curve = String(algorithmProperties.ellipticCurve)
650
+ .split("/")
651
+ .pop();
652
+ }
605
653
  delete algorithmProperties.algorithmFamily;
606
654
  delete algorithmProperties.ellipticCurve;
655
+ // `key-wrap` joined the primitive enum in 1.7.
656
+ if (algorithmProperties.primitive === "key-wrap") {
657
+ algorithmProperties.primitive = "other";
658
+ }
659
+ }
660
+ if (
661
+ specVersion < 1.7 &&
662
+ subject.cryptoProperties?.protocolProperties?.type &&
663
+ !SPEC_1_6_PROTOCOL_TYPES.has(
664
+ subject.cryptoProperties.protocolProperties.type,
665
+ )
666
+ ) {
667
+ // 1.7 added protocol types such as `dtls` and `quic`.
668
+ subject.cryptoProperties.protocolProperties.type = "other";
607
669
  }
608
670
  Object.entries(subject).forEach(([key, value]) => {
609
671
  downgradeSubjectForSpecVersion(value, specVersion, key);