@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
@@ -0,0 +1,426 @@
1
+ import {
2
+ closeSync,
3
+ lstatSync,
4
+ openSync,
5
+ readdirSync,
6
+ readSync,
7
+ realpathSync,
8
+ } from "node:fs";
9
+ import { basename, join, relative, sep } from "node:path";
10
+
11
+ import {
12
+ androidNetworkSecurityConfigPins,
13
+ CertificateCollector,
14
+ certRecordFromDer,
15
+ classifyCryptoFile,
16
+ kubernetesTlsSecretRecords,
17
+ linkFallbackIssuers,
18
+ } from "./certificates.js";
19
+
20
+ // Bounds mirror trustinspector's rootfs mode (PLAN section 4.1): 16 MiB per
21
+ // file, 20,000 files read and 500,000 entries visited per tree, depth 12.
22
+ export const ROOTFS_CERT_LIMITS = Object.freeze({
23
+ maxFileBytes: 16 * 1024 * 1024,
24
+ maxFiles: 20000,
25
+ maxEntries: 500000,
26
+ maxDepth: 12,
27
+ });
28
+
29
+ // Coverage table: the same locations and sourceTypes as trustinspector's
30
+ // rootfs mode (thirdparty/trustinspector/rootfs.go candidateDirs).
31
+ const CA_STORE_DIRS = [
32
+ "etc/ssl/certs",
33
+ "usr/local/share/ca-certificates",
34
+ "usr/share/ca-certificates",
35
+ "etc/pki/tls/certs",
36
+ "etc/pki/ca-trust/source/anchors",
37
+ "etc/pki/ca-trust/extracted",
38
+ "var/lib/ca-certificates",
39
+ "usr/share/pki/ca-trust-source/anchors",
40
+ ];
41
+ const CA_STORE_FILES = ["etc/ssl/cert.pem"];
42
+ const CA_BLOCKLIST_DIRS = [
43
+ "etc/pki/ca-trust/source/blocklist",
44
+ "etc/pki/ca-trust/source/blacklist",
45
+ "usr/share/pki/ca-trust-source/blocklist",
46
+ "usr/share/pki/ca-trust-source/blacklist",
47
+ ];
48
+ const SERVER_CONFIG_DIRS = [
49
+ "etc/nginx",
50
+ "etc/apache2",
51
+ "etc/httpd",
52
+ "etc/haproxy",
53
+ "etc/letsencrypt/live",
54
+ "etc/letsencrypt/archive",
55
+ "etc/kubernetes/pki",
56
+ "var/lib/kubelet/pki",
57
+ "etc/docker/certs.d",
58
+ "etc/containerd/certs.d",
59
+ "etc/envoy",
60
+ "etc/traefik",
61
+ ];
62
+ const JAVA_DIRS = [
63
+ "usr/lib/jvm",
64
+ "opt",
65
+ "etc/ssl/certs/java",
66
+ "etc/pki/java",
67
+ "usr/share/elasticsearch",
68
+ ];
69
+ const LANGUAGE_BUNDLE_DIRS = ["usr/lib", "usr/local/lib", "opt"];
70
+ // Kubernetes secrets and Android configs are cdxgen-side producers: the
71
+ // plugin has no YAML or Android parser.
72
+ const SECRET_YAML_DIRS = [
73
+ "etc/kubernetes",
74
+ "var/run/secrets",
75
+ "run/secrets",
76
+ "var/lib/kubelet",
77
+ "srv",
78
+ "app",
79
+ "opt",
80
+ "home",
81
+ "root",
82
+ ];
83
+ const ANDROID_DIRS = ["app", "opt", "srv", "data", "home", "root"];
84
+
85
+ const CERT_SUFFIXES = [
86
+ ".pem",
87
+ ".crt",
88
+ ".cer",
89
+ ".der",
90
+ ".p7b",
91
+ ".p7c",
92
+ ".p12",
93
+ ".pfx",
94
+ ".jks",
95
+ ".jceks",
96
+ ".truststore",
97
+ ".key",
98
+ ];
99
+
100
+ function isJavaKeystoreName(base) {
101
+ if (base === "cacerts" || base === "jssecacerts") {
102
+ return true;
103
+ }
104
+ return [".jks", ".jceks", ".truststore", ".p12", ".pfx"].some((suffix) =>
105
+ base.endsWith(suffix),
106
+ );
107
+ }
108
+
109
+ // Mirrors looksLikeTrustMaterialPath in trustinspector: private-key
110
+ // directories are never read.
111
+ function looksLikeTrustMaterialPath(rel, sourceType) {
112
+ const lower = rel.toLowerCase();
113
+ if (
114
+ lower.startsWith("etc/ssl/private/") ||
115
+ lower.startsWith("etc/pki/tls/private/")
116
+ ) {
117
+ return false;
118
+ }
119
+ const base = basename(lower);
120
+ if (sourceType === "language-bundle") {
121
+ return base === "cacert.pem";
122
+ }
123
+ if (sourceType === "java-truststore") {
124
+ return isJavaKeystoreName(base);
125
+ }
126
+ if (isJavaKeystoreName(base)) {
127
+ return true;
128
+ }
129
+ return (
130
+ CERT_SUFFIXES.some((suffix) => lower.endsWith(suffix)) ||
131
+ lower.includes("/certs/")
132
+ );
133
+ }
134
+
135
+ /**
136
+ * Read at most `maxBytes` of a regular file. The cap applies to the read
137
+ * itself, so a file that grows after the size check cannot exceed it. Files
138
+ * that are not regular (FIFOs, devices, sockets) are never opened.
139
+ */
140
+ function readCapped(absolute, maxBytes) {
141
+ const before = lstatSync(absolute);
142
+ if (!before.isFile() || before.size > maxBytes) {
143
+ return undefined;
144
+ }
145
+ const fd = openSync(absolute, "r");
146
+ try {
147
+ const buffer = Buffer.alloc(Math.min(before.size, maxBytes) + 1);
148
+ let total = 0;
149
+ while (total < buffer.length) {
150
+ const n = readSync(fd, buffer, total, buffer.length - total, null);
151
+ if (n === 0) {
152
+ break;
153
+ }
154
+ total += n;
155
+ }
156
+ if (total > maxBytes) {
157
+ return undefined;
158
+ }
159
+ return buffer.subarray(0, total);
160
+ } finally {
161
+ closeSync(fd);
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Pure-JS inventory of the certificate locations trustinspector's rootfs
167
+ * mode covers, plus Kubernetes TLS secrets and Android pins. Used when the
168
+ * plugin is not available. Produces components through the shared
169
+ * CertificateCollector, so bom-refs, names and deduplication match the other
170
+ * producers; locations are root-relative ("/etc/ssl/certs/x.crt").
171
+ *
172
+ * Every access stays inside the root: symlinks (files or directories) are
173
+ * skipped, only regular files are opened, and the walk is bounded by entry,
174
+ * file, size and depth limits.
175
+ *
176
+ * @param {string} rootDir extracted root filesystem
177
+ * @param {object} [limits] overrides for ROOTFS_CERT_LIMITS (tests)
178
+ * @returns {{components: object[], dependencies: object[], warnings: string[]}}
179
+ */
180
+ export function collectRootfsCertificates(rootDir, limits = {}) {
181
+ const bounds = { ...ROOTFS_CERT_LIMITS, ...limits };
182
+ const warnings = [];
183
+ let realRoot;
184
+ try {
185
+ realRoot = realpathSync(rootDir);
186
+ } catch {
187
+ return { components: [], dependencies: [], warnings };
188
+ }
189
+ const collector = new CertificateCollector();
190
+ const records = [];
191
+ const components = [];
192
+ const seenFiles = new Set();
193
+ let filesRead = 0;
194
+
195
+ // Resolve a root-relative directory to an absolute path that is proven to
196
+ // stay inside the root; undefined when it does not exist, is not a
197
+ // directory, or any symlink on the way leaves the root.
198
+ const resolveInside = (rel) => {
199
+ const absolute = join(realRoot, rel);
200
+ let real;
201
+ try {
202
+ real = realpathSync(absolute);
203
+ } catch {
204
+ return undefined;
205
+ }
206
+ const inside = relative(realRoot, real);
207
+ if (inside.startsWith("..") || inside.split(sep).includes("..")) {
208
+ return undefined;
209
+ }
210
+ return real;
211
+ };
212
+
213
+ const walk = (relBase, visit) => {
214
+ const start = resolveInside(relBase);
215
+ if (!start) {
216
+ return;
217
+ }
218
+ let startStat;
219
+ try {
220
+ startStat = lstatSync(start);
221
+ } catch {
222
+ return;
223
+ }
224
+ if (!startStat.isDirectory()) {
225
+ return;
226
+ }
227
+ let entries = 0;
228
+ const stack = [{ abs: start, rel: relBase, depth: 0 }];
229
+ while (stack.length) {
230
+ const { abs, rel, depth } = stack.pop();
231
+ let dirents;
232
+ try {
233
+ dirents = readdirSync(abs, { withFileTypes: true });
234
+ } catch {
235
+ continue;
236
+ }
237
+ dirents.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
238
+ for (const dirent of dirents) {
239
+ entries += 1;
240
+ if (entries > bounds.maxEntries) {
241
+ warnings.push(
242
+ `entry limit (${bounds.maxEntries}) reached in /${relBase}`,
243
+ );
244
+ return;
245
+ }
246
+ // Symlinks and special files are skipped outright.
247
+ if (dirent.isSymbolicLink()) {
248
+ continue;
249
+ }
250
+ const childRel = `${rel}/${dirent.name}`;
251
+ if (dirent.isDirectory()) {
252
+ if (depth + 1 >= bounds.maxDepth) {
253
+ warnings.push(
254
+ `depth limit (${bounds.maxDepth}) exceeded in /${relBase}`,
255
+ );
256
+ continue;
257
+ }
258
+ stack.push({
259
+ abs: join(abs, dirent.name),
260
+ rel: childRel,
261
+ depth: depth + 1,
262
+ });
263
+ } else if (dirent.isFile()) {
264
+ if (visit(childRel, join(abs, dirent.name)) === false) {
265
+ return;
266
+ }
267
+ }
268
+ }
269
+ }
270
+ };
271
+
272
+ const readRel = (rel, abs) => {
273
+ if (filesRead >= bounds.maxFiles) {
274
+ warnings.push(`file count limit (${bounds.maxFiles}) reached`);
275
+ return undefined;
276
+ }
277
+ filesRead += 1;
278
+ try {
279
+ const bytes = readCapped(abs, bounds.maxFileBytes);
280
+ if (!bytes) {
281
+ warnings.push(
282
+ `file over ${bounds.maxFileBytes} bytes skipped: /${rel}`,
283
+ );
284
+ }
285
+ return bytes;
286
+ } catch {
287
+ return undefined;
288
+ }
289
+ };
290
+
291
+ const consumeMaterial = (rel, abs, sourceType) => {
292
+ if (seenFiles.has(rel) || !looksLikeTrustMaterialPath(rel, sourceType)) {
293
+ return;
294
+ }
295
+ const bytes = readRel(rel, abs);
296
+ if (!bytes?.length) {
297
+ return;
298
+ }
299
+ seenFiles.add(rel);
300
+ const location = `/${rel}`;
301
+ const classification = classifyCryptoFile(bytes);
302
+ if (classification.kind === "certificates") {
303
+ const dot = basename(rel).lastIndexOf(".");
304
+ for (const der of classification.ders) {
305
+ const record = certRecordFromDer(der, { location, sourceType });
306
+ if (record) {
307
+ record.fileExtension =
308
+ dot > 0 ? basename(rel).slice(dot + 1) : undefined;
309
+ records.push(record);
310
+ }
311
+ }
312
+ } else if (classification.kind === "private-key") {
313
+ components.push(
314
+ rootfsMaterialComponent("private-key", location, {
315
+ format: classification.format,
316
+ sourceType,
317
+ }),
318
+ );
319
+ } else if (classification.kind === "keystore") {
320
+ components.push(
321
+ rootfsMaterialComponent("keystore", location, {
322
+ format: classification.format,
323
+ sourceType,
324
+ }),
325
+ );
326
+ }
327
+ };
328
+
329
+ // Most specific location first, so a file under two candidates takes the
330
+ // sourceType of the narrower one (same rule as the plugin).
331
+ const candidates = [
332
+ ...CA_STORE_DIRS.map((rel) => ({ rel, sourceType: "ca-store" })),
333
+ ...CA_BLOCKLIST_DIRS.map((rel) => ({ rel, sourceType: "ca-blocklist" })),
334
+ ...SERVER_CONFIG_DIRS.map((rel) => ({ rel, sourceType: "server-config" })),
335
+ ...JAVA_DIRS.map((rel) => ({ rel, sourceType: "java-truststore" })),
336
+ ...LANGUAGE_BUNDLE_DIRS.map((rel) => ({
337
+ rel,
338
+ sourceType: "language-bundle",
339
+ })),
340
+ ].sort((a, b) => b.rel.split("/").length - a.rel.split("/").length);
341
+ for (const file of CA_STORE_FILES) {
342
+ const abs = resolveInside(file);
343
+ if (abs && lstatSync(abs).isFile()) {
344
+ consumeMaterial(file, abs, "ca-store");
345
+ }
346
+ }
347
+ for (const { rel, sourceType } of candidates) {
348
+ walk(rel, (childRel, abs) => {
349
+ consumeMaterial(childRel, abs, sourceType);
350
+ });
351
+ }
352
+
353
+ const secretFiles = new Set();
354
+ for (const dir of SECRET_YAML_DIRS) {
355
+ walk(dir, (childRel, abs) => {
356
+ if (/\.ya?ml$/i.test(childRel) && !secretFiles.has(childRel)) {
357
+ secretFiles.add(childRel);
358
+ const bytes = readRel(childRel, abs);
359
+ const text = bytes?.toString("utf-8");
360
+ // Cheap pre-filter, as in the source scan.
361
+ if (text?.includes("kubernetes.io/tls")) {
362
+ records.push(
363
+ ...kubernetesTlsSecretRecords(text, { file: `/${childRel}` }),
364
+ );
365
+ }
366
+ }
367
+ });
368
+ }
369
+ const androidFiles = new Set();
370
+ for (const dir of ANDROID_DIRS) {
371
+ walk(dir, (childRel, abs) => {
372
+ if (
373
+ /\/res\/xml\/[^/]+\.xml$/i.test(childRel) &&
374
+ !androidFiles.has(childRel)
375
+ ) {
376
+ androidFiles.add(childRel);
377
+ const text = readRel(childRel, abs)?.toString("utf-8");
378
+ if (text?.includes("<network-security-config")) {
379
+ for (const pin of androidNetworkSecurityConfigPins(text, {
380
+ file: `/${childRel}`,
381
+ })) {
382
+ collector.addPin(pin);
383
+ }
384
+ }
385
+ }
386
+ });
387
+ }
388
+
389
+ if (records.length) {
390
+ linkFallbackIssuers(records);
391
+ collector.addRecords(records);
392
+ }
393
+ const built = collector.build();
394
+ return {
395
+ components: [...built.components, ...components],
396
+ dependencies: built.dependencies,
397
+ warnings,
398
+ };
399
+ }
400
+
401
+ // Same shape as the keystore and private-key components the other producers
402
+ // emit (managedBom sourceKeystoreComponent / sourcePrivateKeyComponent).
403
+ function rootfsMaterialComponent(kind, location, { format, sourceType }) {
404
+ return {
405
+ name: basename(location),
406
+ type: "cryptographic-asset",
407
+ "bom-ref": `crypto/related-crypto-material/${kind}/${encodeURIComponent(location)}`,
408
+ cryptoProperties: {
409
+ assetType: "related-crypto-material",
410
+ relatedCryptoMaterialProperties: {
411
+ type: kind === "keystore" ? "other" : "private-key",
412
+ ...(format ? { format } : {}),
413
+ },
414
+ },
415
+ evidence: { occurrences: [{ location }] },
416
+ properties: [
417
+ { name: "internal:SrcFile", value: location },
418
+ ...(sourceType
419
+ ? [{ name: "cdx:crypto:sourceType", value: sourceType }]
420
+ : []),
421
+ ...(kind === "keystore"
422
+ ? [{ name: "cdx:crypto:keystoreReadable", value: "false" }]
423
+ : []),
424
+ ],
425
+ };
426
+ }
@@ -1,9 +1,8 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { basename, dirname, join } from "node:path";
3
3
 
4
- import * as toml from "smol-toml";
5
-
6
4
  import { safeExistsSync } from "../core/fs.js";
5
+ import { parseToml } from "../core/toml.js";
7
6
 
8
7
  // Keep this list conservative and high-signal: it is meant to surface common
9
8
  // Rust native build helpers for audit triage, not to exhaustively model every
@@ -67,7 +66,7 @@ function createFormulationComponent(name, filePath, toolName) {
67
66
  function parseCargoManifest(filePath) {
68
67
  let cargoData;
69
68
  try {
70
- cargoData = toml.parse(readFileSync(filePath, { encoding: "utf-8" }));
69
+ cargoData = parseToml(readFileSync(filePath, { encoding: "utf-8" }));
71
70
  } catch {
72
71
  return undefined;
73
72
  }
@@ -252,7 +251,7 @@ function parseCargoManifest(filePath) {
252
251
  function parsePyProject(filePath) {
253
252
  let pyprojectData;
254
253
  try {
255
- pyprojectData = toml.parse(readFileSync(filePath, { encoding: "utf-8" }));
254
+ pyprojectData = parseToml(readFileSync(filePath, { encoding: "utf-8" }));
256
255
  } catch {
257
256
  return undefined;
258
257
  }
@@ -0,0 +1,153 @@
1
+ import { Purl } from "@cdxgen/cdx-purl";
2
+
3
+ // Scala libraries publish their Maven artifacts with a trailing Scala binary
4
+ // version suffix (`jwt-core_3`, `coursier_2.13`), optionally preceded by a
5
+ // platform suffix for Scala.js and Scala Native builds (`upickle_sjs1_3`,
6
+ // `upickle_native0.5_3`). sbt components strip the binary suffix and keep the
7
+ // platform suffix (`jwt-core`, `upickle_sjs1`), so the same library is named
8
+ // differently depending on the build tool that reported it.
9
+ const SCALA_BINARY_SUFFIX_REGEX = /_(2\.\d+|3)$/;
10
+ const SCALA_PLATFORM_SUFFIX_REGEX = /_(sjs1|sjs0\.6|native0\.\d+)$/;
11
+
12
+ /**
13
+ * Parse a Scala-published Maven artifact name into its coordinate parts.
14
+ *
15
+ * @param {string} name Maven artifactId, for example `upickle_sjs1_3`
16
+ * @returns {{ originalName: string, artifactBase: string, binaryVersion: string|null,
17
+ * platformSuffix: string, purlName: string }} The artifact name without any
18
+ * Scala suffix (`upickle`), the Scala binary version from the suffix (`3`),
19
+ * the platform suffix including the underscore (`_sjs1`) or an empty string,
20
+ * and the artifact name sbt-style purls emit (binary suffix dropped, platform
21
+ * suffix kept).
22
+ */
23
+ export function parseScalaArtifact(name) {
24
+ const result = {
25
+ originalName: name,
26
+ artifactBase: name,
27
+ binaryVersion: null,
28
+ platformSuffix: "",
29
+ purlName: name,
30
+ };
31
+ if (!name) {
32
+ return result;
33
+ }
34
+ let rest = name;
35
+ const binaryMatch = rest.match(SCALA_BINARY_SUFFIX_REGEX);
36
+ if (binaryMatch) {
37
+ result.binaryVersion = binaryMatch[1];
38
+ rest = rest.slice(0, rest.length - binaryMatch[0].length);
39
+ }
40
+ const platformMatch = rest.match(SCALA_PLATFORM_SUFFIX_REGEX);
41
+ if (platformMatch) {
42
+ result.platformSuffix = platformMatch[0];
43
+ rest = rest.slice(0, rest.length - platformMatch[0].length);
44
+ }
45
+ result.artifactBase = rest;
46
+ result.purlName = binaryMatch ? `${rest}${result.platformSuffix}` : name;
47
+ return result;
48
+ }
49
+
50
+ /**
51
+ * Build a qualifier-free coordinate key for a Scala-published artifact.
52
+ *
53
+ * The key ignores purl qualifiers such as `repository_url` and `type`, so the
54
+ * POM-coordinate keys of the jar namespace mapping and the sbt-style purls of
55
+ * the components resolve to the same entry.
56
+ *
57
+ * @param {Object} parts Coordinate parts
58
+ * @param {string} [parts.type] Purl type, defaults to `maven`
59
+ * @param {string} [parts.group] Maven groupId
60
+ * @param {string} parts.artifactBase Artifact name without any Scala suffix
61
+ * @param {string} [parts.platformSuffix] `_sjs1`, `_native0.5` or empty
62
+ * @param {string} [parts.version] Package version
63
+ * @returns {string} The coordinate key
64
+ */
65
+ export function scalaCoordinateKey({
66
+ type = "maven",
67
+ group = "",
68
+ artifactBase = "",
69
+ platformSuffix = "",
70
+ version = "",
71
+ } = {}) {
72
+ return [type, group, artifactBase, platformSuffix, version].join(":");
73
+ }
74
+
75
+ /**
76
+ * Build the qualifier-free coordinate key of a purl string.
77
+ *
78
+ * The artifact name is normalized with {@link parseScalaArtifact}, so
79
+ * `pkg:maven/g/foo_3@1.0` and the sbt-style `pkg:maven/g/foo@1.0` share a key,
80
+ * while the Scala.js build `foo_sjs1_3` keeps its own key (`foo` plus the
81
+ * `_sjs1` platform suffix) and never joins the plain `foo` component.
82
+ *
83
+ * @param {string} purlString Package URL to normalize
84
+ * @returns {string|undefined} The coordinate key, or undefined when the string
85
+ * is not a parseable purl
86
+ */
87
+ export function coordinateKeyFromPurl(purlString) {
88
+ return scalaCoordinateOfPurl(purlString)?.key;
89
+ }
90
+
91
+ /**
92
+ * The coordinate key of a purl together with the Scala binary version its
93
+ * artifact name carries, if any.
94
+ *
95
+ * @param {string} purlString Package URL to normalize
96
+ * @returns {{ key: string, binaryVersion: string|null }|undefined} The key
97
+ * and binary version, or undefined when the string is not a parseable purl
98
+ */
99
+ export function scalaCoordinateOfPurl(purlString) {
100
+ if (!purlString?.startsWith("pkg:")) {
101
+ return undefined;
102
+ }
103
+ let purlObj;
104
+ try {
105
+ purlObj = Purl.parse(purlString);
106
+ } catch (_err) {
107
+ return undefined;
108
+ }
109
+ if (!purlObj?.name) {
110
+ return undefined;
111
+ }
112
+ const scalaInfo = parseScalaArtifact(purlObj.name);
113
+ return {
114
+ key: scalaCoordinateKey({
115
+ type: purlObj.type,
116
+ group: purlObj.namespace || "",
117
+ artifactBase: scalaInfo.artifactBase,
118
+ platformSuffix: scalaInfo.platformSuffix,
119
+ version: purlObj.version || "",
120
+ }),
121
+ binaryVersion: scalaInfo.binaryVersion,
122
+ };
123
+ }
124
+
125
+ // An artifact name that already ends in a full Scala version, as scala-cli
126
+ // `:::` and sbt `CrossVersion.full` artifacts do (`_3.3.7`, `_2.13.16`). A
127
+ // binary suffix such as `_3` left on a name is part of the name: the
128
+ // component producers strip exactly one, into the compiler version.
129
+ const SCALA_FULL_VERSION_SUFFIX_REGEX = /_\d+\.\d+\.\d+(?:-[A-Za-z0-9.]+)?$/;
130
+
131
+ /**
132
+ * The artifactId the library is published under, for cache and repository
133
+ * lookups only. Components a Scala build tool reports carry the name with the
134
+ * Scala binary suffix stripped (the platform suffix kept) together with
135
+ * `cdx:scala:compilerVersion`; on disk and in the repository the artifact is
136
+ * `cats-core_2.13` or `upickle_sjs1_3`. Names that end in a full Scala version
137
+ * are used as they are.
138
+ *
139
+ * The component's own `name`, `purl` and `bom-ref` never change.
140
+ *
141
+ * @param {Object} pkg Package with `name` and `properties`.
142
+ * @returns {string} The artifactId to look up.
143
+ */
144
+ export function publishedArtifactId(pkg) {
145
+ const name = pkg?.name;
146
+ if (!name || SCALA_FULL_VERSION_SUFFIX_REGEX.test(name)) {
147
+ return name;
148
+ }
149
+ const binaryVersion = (pkg.properties || []).find(
150
+ (property) => property.name === "cdx:scala:compilerVersion",
151
+ )?.value;
152
+ return binaryVersion ? `${name}_${binaryVersion}` : name;
153
+ }