@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
@@ -1,20 +1,16 @@
1
- import { lstatSync, readFileSync } from "node:fs";
2
- import { homedir, tmpdir } from "node:os";
3
- import {
4
- delimiter as _delimiter,
5
- sep as _sep,
6
- basename,
7
- dirname,
8
- join,
9
- } from "node:path";
1
+ import { lstatSync, readFileSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { delimiter as _delimiter, basename, dirname, join } from "node:path";
10
4
 
11
5
  import { build, Purl } from "@cdxgen/cdx-purl";
12
6
  import StreamZip from "node-stream-zip";
13
7
 
14
8
  import { DEBUG_MODE, readEnvironmentVariable } from "../core/activity.js";
9
+ import { commandOutputText } from "../core/buildLedger.js";
15
10
  import { parseMavenArgs } from "../core/env.js";
16
11
  import {
17
12
  getAllFiles,
13
+ getTmpDir,
18
14
  multiChecksumFile,
19
15
  safeExistsSync,
20
16
  safeMkdtempSync,
@@ -23,15 +19,89 @@ import {
23
19
  } from "../core/fs.js";
24
20
  import { isWin } from "../core/paths.js";
25
21
  import { xml2js } from "../parsers/xml.js";
22
+ import { noteBuildToolRateLimit } from "./buildToolRateLimit.js";
23
+ import {
24
+ inferMavenCoordinatesFromPath,
25
+ mavenLocalRepositories,
26
+ splitArtifactFileName,
27
+ } from "./jvmLocalRepos.js";
26
28
  import { pypiBomRef } from "./purl.js";
29
+ import { findLicenseId, spdxLicenses } from "./spdx.js";
30
+
31
+ const jarNSMapping_cache = new Map();
32
+
33
+ /**
34
+ * Whether a jar holds sources or javadoc rather than classes.
35
+ *
36
+ * @param {string} jarName Jar file name.
37
+ * @returns {boolean}
38
+ */
39
+ export function isDocumentationJar(jarName) {
40
+ return jarName.endsWith("-sources.jar") || jarName.endsWith("-javadoc.jar");
41
+ }
27
42
 
28
- const jarNSMapping_cache = {};
43
+ /**
44
+ * Size and modification time of a file, used to tell whether a memoised
45
+ * reading of it is still current.
46
+ *
47
+ * @param {string} file File path.
48
+ * @returns {string} Stamp, or an empty string when the file cannot be read.
49
+ */
50
+ function jarFileStamp(file) {
51
+ try {
52
+ const stats = statSync(file);
53
+ return `${stats.size}:${stats.mtimeMs}`;
54
+ } catch (_err) {
55
+ return "";
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Build the purl of a jar. Eclipse p2 artifacts mirrored into a Maven
61
+ * repository keep their dedicated purl type qualifiers.
62
+ *
63
+ * @param {string} group groupId.
64
+ * @param {string} name artifactId.
65
+ * @param {string} version Version.
66
+ * @param {string} [classifier] Classifier.
67
+ * @returns {string} Purl string.
68
+ */
69
+ function jarPurl(group, name, version, classifier = undefined) {
70
+ let namespace = group || null;
71
+ let type = "jar";
72
+ // See https://github.com/CycloneDX/cyclonedx-maven-plugin/issues/137
73
+ // and https://github.com/cdxgen/cdxgen/pull/510#issuecomment-1702551615
74
+ for (const [prefix, p2Type] of [
75
+ ["p2.osgi.bundle", "osgi-bundle"],
76
+ ["p2.eclipse.plugin", "eclipse-plugin"],
77
+ ["p2.binary", "eclipse-executable"],
78
+ ["p2.org.eclipse.update.feature", "eclipse-feature"],
79
+ ]) {
80
+ if (namespace?.startsWith(prefix)) {
81
+ namespace = prefix;
82
+ type = p2Type;
83
+ break;
84
+ }
85
+ }
86
+ const qualifiers = { type };
87
+ if (classifier) {
88
+ qualifiers.classifier = classifier;
89
+ }
90
+ return new Purl({
91
+ type: "maven",
92
+ namespace,
93
+ name,
94
+ version: version || null,
95
+ qualifiers,
96
+ }).toString();
97
+ }
29
98
 
30
99
  /**
31
100
  * Collect maven dependencies
32
101
  *
33
102
  * @param {string} mavenCmd Maven command to use
34
- * @param {string} basePath Path to the maven project
103
+ * @param {string} basePath Path to the maven project. Without it Maven is not
104
+ * run, and only the local repository is read when includeCacheDir is set.
35
105
  * @param {boolean} cleanup Remove temporary directories
36
106
  * @param {boolean} includeCacheDir Include maven and gradle cache directories
37
107
  */
@@ -42,14 +112,20 @@ export async function collectMvnDependencies(
42
112
  includeCacheDir = false,
43
113
  ) {
44
114
  let jarNSMapping = {};
115
+ // MAVEN_CACHE_DIR when set, otherwise the local repository Maven itself
116
+ // uses for this project.
45
117
  const MAVEN_CACHE_DIR =
46
118
  readEnvironmentVariable("MAVEN_CACHE_DIR") ||
119
+ mavenLocalRepositories({ projectDir: basePath || undefined }).find((repo) =>
120
+ safeExistsSync(repo),
121
+ ) ||
47
122
  join(homedir(), ".m2", "repository");
48
- const tempDir = safeMkdtempSync(join(tmpdir(), "mvn-deps-"));
123
+ const tempDir = safeMkdtempSync(join(getTmpDir(), "mvn-deps-"));
124
+ // No -U: forcing update checks re-requests every maven-metadata.xml and
125
+ // every artifact Maven already knows is missing, once per module.
49
126
  let copyArgs = [
50
127
  "dependency:copy-dependencies",
51
128
  `-DoutputDirectory=${tempDir}`,
52
- "-U",
53
129
  "-Dmdep.copyPom=true",
54
130
  "-Dmdep.useRepositoryLayout=true",
55
131
  "-Dmdep.includeScope=compile",
@@ -66,31 +142,45 @@ export async function collectMvnDependencies(
66
142
  cwd: basePath,
67
143
  shell: isWin,
68
144
  });
145
+ const rateLimited = noteBuildToolRateLimit(
146
+ "maven",
147
+ commandOutputText(result),
148
+ {
149
+ command: `${basename(mavenCmd)} ${copyArgs.join(" ")}`,
150
+ exitCode: typeof result.status === "number" ? result.status : undefined,
151
+ },
152
+ );
69
153
  if (result.status !== 0 || result.error) {
70
- console.error(result.stderr, result.error);
71
- console.log(
72
- "You can try the following remediation tips to resolve this error:\n",
73
- );
74
- console.log(
75
- "1. Check if the correct version of maven is installed and available in the PATH. Check if the environment variable MVN_ARGS needs to be set.",
76
- );
77
- console.log(
78
- "2. Perform 'mvn compile package' before invoking this command. Fix any errors found during this invocation.",
79
- );
80
- console.log(
81
- "3. Ensure the temporary directory is available and has sufficient disk space to copy all the artifacts.",
82
- );
154
+ if (!rateLimited) {
155
+ console.error(result.stderr, result.error);
156
+ console.log(
157
+ "You can try the following remediation tips to resolve this error:\n",
158
+ );
159
+ console.log(
160
+ "1. Check if the correct version of maven is installed and available in the PATH. Check if the environment variable MVN_ARGS needs to be set.",
161
+ );
162
+ console.log(
163
+ "2. Perform 'mvn compile package' before invoking this command. Fix any errors found during this invocation.",
164
+ );
165
+ console.log(
166
+ "3. Ensure the temporary directory is available and has sufficient disk space to copy all the artifacts.",
167
+ );
168
+ }
83
169
  } else {
84
170
  jarNSMapping = await collectJarNS(tempDir);
85
171
  }
86
172
  }
87
173
  if (includeCacheDir || basePath === MAVEN_CACHE_DIR) {
88
- // slow operation
89
- jarNSMapping = await collectJarNS(MAVEN_CACHE_DIR);
174
+ // slow operation. The project's own dependencies, copied above, take
175
+ // precedence over the rest of the cache.
176
+ jarNSMapping = {
177
+ ...(await collectJarNS(MAVEN_CACHE_DIR)),
178
+ ...jarNSMapping,
179
+ };
90
180
  }
91
181
 
92
182
  // Clean up
93
- if (cleanup && tempDir?.startsWith(tmpdir())) {
183
+ if (cleanup && tempDir?.startsWith(getTmpDir())) {
94
184
  safeRmSync(tempDir, { recursive: true, force: true });
95
185
  }
96
186
  return jarNSMapping;
@@ -122,11 +212,18 @@ export async function collectJarNS(jarPath, pomPathMap = {}) {
122
212
  : getAllFiles(jarPath, "**/*.jar");
123
213
  if (jarFiles?.length) {
124
214
  for (const jf of jarFiles) {
215
+ const jarName = basename(jf);
216
+ // Sources and javadoc jars hold no runtime classes. Reading them would
217
+ // attach their hashes to the main artifact's purl.
218
+ if (isDocumentationJar(jarName)) {
219
+ continue;
220
+ }
125
221
  let pomname =
126
- pomPathMap[basename(jf).replace(".jar", ".pom")] ||
222
+ pomPathMap[jarName.replace(".jar", ".pom")] ||
127
223
  jf.replace(".jar", ".pom");
128
224
  let pomData;
129
225
  let purl;
226
+ let manifestLicenses;
130
227
  // In some cases, the pom name might be slightly different to the jar name
131
228
  if (!safeExistsSync(pomname)) {
132
229
  let searchDir = dirname(jf);
@@ -144,92 +241,54 @@ export async function collectJarNS(jarPath, pomPathMap = {}) {
144
241
  // TODO: Replace with parsePom which contains pomPurl
145
242
  pomData = parsePomXml(readFileSync(pomname, { encoding: "utf-8" }));
146
243
  if (pomData) {
147
- const purlObj = new Purl({
148
- type: "maven",
149
- namespace: pomData.groupId || "" || null,
150
- name: pomData.artifactId,
151
- version: pomData.version || null,
152
- qualifiers: { type: "jar" } || null,
153
- });
154
- purl = purlObj.toString();
244
+ purl = jarPurl(
245
+ pomData.groupId,
246
+ pomData.artifactId,
247
+ pomData.version,
248
+ pomData.version
249
+ ? splitArtifactFileName(
250
+ jarName,
251
+ pomData.artifactId,
252
+ pomData.version,
253
+ )?.classifier
254
+ : undefined,
255
+ );
256
+ }
257
+ } else {
258
+ const coordinates = inferMavenCoordinatesFromPath(jf);
259
+ if (coordinates?.extension === "jar") {
260
+ purl = jarPurl(
261
+ coordinates.group,
262
+ coordinates.name,
263
+ coordinates.version,
264
+ coordinates.classifier,
265
+ );
155
266
  }
156
- } else if (jf.includes(join(".m2", "repository"))) {
157
- // Let's try our best to construct a purl for .m2 cache entries of the form
158
- // .m2/repository/org/apache/logging/log4j/log4j-web/3.0.0-SNAPSHOT/log4j-web-3.0.0-SNAPSHOT.jar
159
- const tmpA = jf.split(join(".m2", "repository", ""));
160
- if (tmpA?.length) {
161
- const tmpJarPath = tmpA[tmpA.length - 1];
162
- // This would yield log4j-web-3.0.0-SNAPSHOT.jar
163
- const jarFileName = basename(tmpJarPath).replace(".jar", "");
164
- const tmpDirParts = dirname(tmpJarPath).split(_sep);
165
- // Retrieve the version
166
- let jarVersion = tmpDirParts.pop();
167
- if (jarVersion === "plugins") {
168
- jarVersion = tmpDirParts.pop();
169
- if (jarVersion === "eclipse") {
170
- jarVersion = tmpDirParts.pop();
267
+ // No POM sits beside this jar, but the jar carries its own Maven
268
+ // descriptor, so its metadata and manifest licence are read here,
269
+ // before any remote lookup. Only a jar whose path names its
270
+ // coordinates is read: they choose its descriptor, and an entry
271
+ // without a purl never becomes a component.
272
+ if (purl) {
273
+ const embedded = await readEmbeddedJarMetadata(jf, coordinates);
274
+ if (embedded?.pomXml) {
275
+ try {
276
+ pomData = parsePomXml(embedded.pomXml);
277
+ } catch (_err) {
278
+ pomData = undefined;
171
279
  }
172
280
  }
173
- // The result would form the group name
174
- let jarGroupName = tmpDirParts.join(".").replace(/^\./, "");
175
- let qualifierType = "jar";
176
- // Support for p2 bundles and plugins
177
- // See https://github.com/CycloneDX/cyclonedx-maven-plugin/issues/137
178
- // See https://github.com/cdxgen/cdxgen/pull/510#issuecomment-1702551615
179
- if (jarGroupName.startsWith("p2.osgi.bundle")) {
180
- jarGroupName = "p2.osgi.bundle";
181
- qualifierType = "osgi-bundle";
182
- } else if (jarGroupName.startsWith("p2.eclipse.plugin")) {
183
- jarGroupName = "p2.eclipse.plugin";
184
- qualifierType = "eclipse-plugin";
185
- } else if (jarGroupName.startsWith("p2.binary")) {
186
- jarGroupName = "p2.binary";
187
- qualifierType = "eclipse-executable";
188
- } else if (jarGroupName.startsWith("p2.org.eclipse.update.feature")) {
189
- jarGroupName = "p2.org.eclipse.update.feature";
190
- qualifierType = "eclipse-feature";
191
- }
192
- const purlObj = new Purl({
193
- type: "maven",
194
- namespace: jarGroupName || null,
195
- name: jarFileName.replace(`-${jarVersion}`, ""),
196
- version: jarVersion || null,
197
- qualifiers: { type: qualifierType } || null,
198
- });
199
- purl = purlObj.toString();
200
- }
201
- } else if (jf.includes(join(".gradle", "caches"))) {
202
- // Let's try our best to construct a purl for gradle cache entries of the form
203
- // .gradle/caches/modules-2/files-2.1/org.xmlresolver/xmlresolver/4.2.0/f4dbdaa83d636dcac91c9003ffa7fb173173fe8d/xmlresolver-4.2.0-data.jar
204
- const tmpA = jf.split(join("files-2.1", ""));
205
- if (tmpA?.length) {
206
- const tmpJarPath = tmpA[tmpA.length - 1];
207
- // This would yield xmlresolver-4.2.0-data.jar
208
- const jarFileName = basename(tmpJarPath).replace(".jar", "");
209
- const tmpDirParts = dirname(tmpJarPath).split(_sep);
210
- // This would remove the hash from the end of the directory name
211
- tmpDirParts.pop();
212
- // Retrieve the version
213
- const jarVersion = tmpDirParts.pop();
214
- const pkgName = jarFileName.replace(`-${jarVersion}`, "");
215
- // The result would form the group name
216
- let jarGroupName = tmpDirParts.join(".").replace(/^\./, "");
217
- if (jarGroupName.includes(pkgName)) {
218
- jarGroupName = jarGroupName.replace(`.${pkgName}`, "");
281
+ if (embedded?.manifestLicenses?.length) {
282
+ manifestLicenses = embedded.manifestLicenses;
219
283
  }
220
- const purlObj = new Purl({
221
- type: "maven",
222
- namespace: jarGroupName || null,
223
- name: pkgName,
224
- version: jarVersion || null,
225
- qualifiers: { type: "jar" } || null,
226
- });
227
- purl = purlObj.toString();
228
284
  }
229
285
  }
230
- // If we have a hit from the cache, use it.
231
- if (purl && jarNSMapping_cache[purl]) {
232
- jarNSMapping[purl] = jarNSMapping_cache[purl];
286
+ // If we have a hit from the cache, use it. The entry is reused only
287
+ // for the same file, unchanged, so a rebuilt SNAPSHOT is read again.
288
+ const fileStamp = jarFileStamp(jf);
289
+ const cached = purl ? jarNSMapping_cache.get(purl) : undefined;
290
+ if (cached && cached.jarFile === jf && cached.stamp === fileStamp) {
291
+ jarNSMapping[purl] = cached.entry;
233
292
  } else {
234
293
  if (DEBUG_MODE) {
235
294
  console.log(`Parsing ${jf}`);
@@ -254,10 +313,15 @@ export async function collectJarNS(jarPath, pomPathMap = {}) {
254
313
  pom: pomData,
255
314
  namespaces: nsList,
256
315
  hashes,
316
+ ...(manifestLicenses?.length ? { manifestLicenses } : {}),
257
317
  };
258
318
  // Retain in the global cache to speed up future lookups
259
319
  if (purl) {
260
- jarNSMapping_cache[purl] = jarNSMapping[purl];
320
+ jarNSMapping_cache.set(purl, {
321
+ jarFile: jf,
322
+ stamp: fileStamp,
323
+ entry: jarNSMapping[purl],
324
+ });
261
325
  }
262
326
  }
263
327
  }
@@ -398,15 +462,24 @@ export function parseJarManifest(jarMetadata) {
398
462
  if (!jarMetadata) {
399
463
  return metadata;
400
464
  }
401
- jarMetadata.split("\n").forEach((l) => {
402
- l = l.replaceAll("\r", "");
403
- if (l.includes(": ")) {
404
- const tmpA = l.split(": ");
405
- if (tmpA && tmpA.length === 2) {
406
- metadata[tmpA[0]] = tmpA[1].replaceAll("\r", "");
465
+ // Manifests wrap at 72 bytes: a line that starts with a single space
466
+ // continues the header above it.
467
+ let name;
468
+ for (const rawLine of jarMetadata.split("\n")) {
469
+ const l = rawLine.replaceAll("\r", "");
470
+ if (l.startsWith(" ")) {
471
+ if (name !== undefined) {
472
+ metadata[name] += l.slice(1);
407
473
  }
474
+ continue;
408
475
  }
409
- });
476
+ name = undefined;
477
+ const at = l.indexOf(": ");
478
+ if (at > 0) {
479
+ name = l.slice(0, at);
480
+ metadata[name] = l.slice(at + 2);
481
+ }
482
+ }
410
483
  return metadata;
411
484
  }
412
485
 
@@ -505,22 +578,328 @@ export function parsePomProperties(pomProperties) {
505
578
  /**
506
579
  * Method to get pom properties from maven directory
507
580
  *
581
+ * A shaded or fat jar carries a `pom.properties` for every artifact folded
582
+ * into it. When the jar's file name is known, the descriptor whose
583
+ * `artifactId-version` (or `artifactId`) starts the file name is the jar's
584
+ * own; otherwise the first descriptor is used, as before.
585
+ *
508
586
  * @param {string} mavenDir Path to maven directory
587
+ * @param {string} [jarName] File name of the jar the directory came from
509
588
  *
510
589
  * @return array with pom properties
511
590
  */
512
- export function getPomPropertiesFromMavenDir(mavenDir) {
513
- let pomProperties = {};
514
- if (safeExistsSync(mavenDir) && lstatSync(mavenDir).isDirectory()) {
515
- const pomPropertiesFiles = getAllFiles(mavenDir, "**/pom.properties");
516
- if (pomPropertiesFiles?.length) {
517
- const pomPropertiesString = readFileSync(pomPropertiesFiles[0], {
518
- encoding: "utf-8",
519
- });
520
- pomProperties = parsePomProperties(pomPropertiesString);
591
+ export function getPomPropertiesFromMavenDir(mavenDir, jarName = undefined) {
592
+ return selectEmbeddedDescriptor(mavenDir, jarName)?.properties ?? {};
593
+ }
594
+
595
+ /**
596
+ * Choose the embedded Maven descriptor of one jar from every descriptor an
597
+ * extracted `META-INF/maven` directory holds.
598
+ *
599
+ * @param {string} mavenDir Path to the extracted META-INF/maven directory
600
+ * @param {string} [jarName] File name of the jar the directory came from
601
+ * @returns {{file: string, properties: Object}|undefined} The chosen
602
+ * descriptor, or undefined when the directory holds none.
603
+ */
604
+ function selectEmbeddedDescriptor(mavenDir, jarName = undefined) {
605
+ if (!safeExistsSync(mavenDir) || !lstatSync(mavenDir).isDirectory()) {
606
+ return undefined;
607
+ }
608
+ const pomPropertiesFiles = getAllFiles(mavenDir, "**/pom.properties").sort();
609
+ if (!pomPropertiesFiles?.length) {
610
+ return undefined;
611
+ }
612
+ const candidates = pomPropertiesFiles.map((f) => ({
613
+ file: f,
614
+ properties: parsePomProperties(readFileSync(f, { encoding: "utf-8" })),
615
+ }));
616
+ const parsed = candidates.map((c) => c.properties);
617
+ if (parsed.length > 1 && jarName) {
618
+ const stem = jarName.replace(/\.[jwe]ar$/, "");
619
+ const exact = candidates.find(
620
+ (c) =>
621
+ c.properties.artifactId &&
622
+ c.properties.version &&
623
+ (stem === `${c.properties.artifactId}-${c.properties.version}` ||
624
+ stem.startsWith(
625
+ `${c.properties.artifactId}-${c.properties.version}-`,
626
+ )),
627
+ );
628
+ if (exact) {
629
+ return exact;
630
+ }
631
+ // The longest matching artifactId wins: netty-common-4.1.jar belongs to
632
+ // netty-common, not to an embedded netty descriptor.
633
+ const byName = candidates
634
+ .filter(
635
+ (c) =>
636
+ c.properties.artifactId &&
637
+ (stem === c.properties.artifactId ||
638
+ stem.startsWith(`${c.properties.artifactId}-`)),
639
+ )
640
+ .sort(
641
+ (a, b) =>
642
+ b.properties.artifactId.length - a.properties.artifactId.length,
643
+ );
644
+ if (
645
+ byName.length === 1 ||
646
+ (byName.length > 1 &&
647
+ byName[0].properties.artifactId.length >
648
+ byName[1].properties.artifactId.length)
649
+ ) {
650
+ return byName[0];
651
+ }
652
+ }
653
+ return candidates[0];
654
+ }
655
+
656
+ /** Per-entry size bounds for the Maven descriptor files read out of a jar.
657
+ * The jar is untrusted input, and its declared entry sizes are the only cheap
658
+ * defence against an archive that expands without bound. */
659
+ const EMBEDDED_POM_PROPERTIES_LIMIT = 64 * 1024;
660
+ const EMBEDDED_POM_XML_LIMIT = 1024 * 1024;
661
+ const EMBEDDED_MANIFEST_LIMIT = 256 * 1024;
662
+ /** A shaded jar can fold in thousands of descriptors; reading a bounded
663
+ * number keeps a hostile archive from turning one zip listing into
664
+ * unbounded work. */
665
+ const EMBEDDED_DESCRIPTOR_LIMIT = 500;
666
+
667
+ /**
668
+ * Read a file, refusing anything larger than the bound, so a jar whose
669
+ * descriptor declares a huge size is never fully read.
670
+ *
671
+ * @param {string} file File path.
672
+ * @param {number} limit Size bound in bytes.
673
+ * @returns {string|undefined} File contents, or undefined when missing or too large.
674
+ */
675
+ function readBoundedFile(file, limit) {
676
+ try {
677
+ if (!safeExistsSync(file) || statSync(file).size > limit) {
678
+ return undefined;
679
+ }
680
+ return readFileSync(file, { encoding: "utf-8" });
681
+ } catch (_err) {
682
+ return undefined;
683
+ }
684
+ }
685
+
686
+ /**
687
+ * Split a manifest header value on a separator that is not inside double
688
+ * quotes. Quoted strings hold commas and semicolons of their own, as in
689
+ * `description="Apache License, Version 2.0"`.
690
+ *
691
+ * @param {string} value Header value.
692
+ * @param {string} separator One character.
693
+ * @returns {string[]} The parts, quotes kept.
694
+ */
695
+ function splitOutsideQuotes(value, separator) {
696
+ const parts = [];
697
+ let current = "";
698
+ let quoted = false;
699
+ for (const ch of value) {
700
+ if (ch === '"') {
701
+ quoted = !quoted;
702
+ } else if (ch === separator && !quoted) {
703
+ parts.push(current);
704
+ current = "";
705
+ continue;
706
+ }
707
+ current += ch;
708
+ }
709
+ parts.push(current);
710
+ return parts;
711
+ }
712
+
713
+ /**
714
+ * Trim a manifest value and remove one pair of surrounding double quotes.
715
+ *
716
+ * @param {string} value Value.
717
+ * @returns {string} The bare value.
718
+ */
719
+ function unquoteManifestValue(value) {
720
+ const trimmed = value.trim();
721
+ return trimmed.length >= 2 && trimmed.startsWith('"') && trimmed.endsWith('"')
722
+ ? trimmed.slice(1, -1).trim()
723
+ : trimmed;
724
+ }
725
+
726
+ /**
727
+ * The licences a MANIFEST.MF `Bundle-License` value names. The value is a
728
+ * comma-separated list; each item is an SPDX id, a licence name or a URL,
729
+ * optionally followed by `;link=` and `;description=` attributes, and any
730
+ * part may be quoted. Each item is mapped through findLicenseId; an item it
731
+ * cannot map is replaced by its `link` URL when one is given, which the
732
+ * licence URL lookup resolves later. `<<EXTERNAL>>` names no licence.
733
+ *
734
+ * @param {string} value Raw Bundle-License value.
735
+ * @returns {string[]} Licence ids, names or URLs, without duplicates.
736
+ */
737
+ export function parseManifestLicenseList(value) {
738
+ if (!value || typeof value !== "string") {
739
+ return [];
740
+ }
741
+ const licenses = [];
742
+ for (const clause of splitOutsideQuotes(value, ",")) {
743
+ const [rawName, ...attributes] = splitOutsideQuotes(clause, ";");
744
+ const name = unquoteManifestValue(rawName);
745
+ if (!name || name === "<<EXTERNAL>>") {
746
+ continue;
747
+ }
748
+ let link;
749
+ for (const attribute of attributes) {
750
+ const at = attribute.indexOf("=");
751
+ if (at > 0 && attribute.slice(0, at).trim() === "link") {
752
+ link = unquoteManifestValue(attribute.slice(at + 1));
753
+ }
754
+ }
755
+ const id = findLicenseId(name);
756
+ const mapped = id !== name || spdxLicenses.includes(name);
757
+ const license = mapped ? id : link?.startsWith("http") ? link : name;
758
+ if (license && !licenses.includes(license)) {
759
+ licenses.push(license);
760
+ }
761
+ }
762
+ return licenses;
763
+ }
764
+
765
+ /**
766
+ * The Maven descriptor a jar carries for itself, read from an extracted
767
+ * `META-INF/maven` directory: the pom.properties that names the jar's own
768
+ * coordinates and the pom.xml stored beside it.
769
+ *
770
+ * @param {string} mavenDir Path to the extracted META-INF/maven directory
771
+ * @param {string} [jarName] File name of the jar the directory came from
772
+ * @returns {{properties: Object, pomXml?: string}|undefined} The chosen
773
+ * descriptor, with its pom.xml text when one is stored beside it.
774
+ */
775
+ export function readEmbeddedMavenDescriptor(mavenDir, jarName = undefined) {
776
+ const selected = selectEmbeddedDescriptor(mavenDir, jarName);
777
+ if (!selected) {
778
+ return undefined;
779
+ }
780
+ const pomXml = readBoundedFile(
781
+ join(dirname(selected.file), "pom.xml"),
782
+ EMBEDDED_POM_XML_LIMIT,
783
+ );
784
+ return pomXml
785
+ ? { properties: selected.properties, pomXml }
786
+ : { properties: selected.properties };
787
+ }
788
+
789
+ /**
790
+ * Choose the descriptor of the jar itself from the descriptors held inside
791
+ * its zip: the one whose pom.properties names the jar's own group and
792
+ * artifact, the matching version first. A shaded jar holds many descriptors
793
+ * whose coordinates belong to the folded-in artifacts, so when none matches,
794
+ * nothing is chosen rather than a dependency's descriptor.
795
+ *
796
+ * @param {Array<{name: string, properties: Object}>} descriptors Descriptors found in the zip.
797
+ * @param {{group: string, name: string, version: string}} coordinates The jar's own coordinates.
798
+ * @returns {{name: string, properties: Object}|undefined}
799
+ */
800
+ function chooseZipDescriptor(descriptors, coordinates) {
801
+ if (!coordinates?.group || !coordinates.name) {
802
+ return undefined;
803
+ }
804
+ const byCoordinates = descriptors.filter(
805
+ (d) =>
806
+ d.properties.groupId === coordinates.group &&
807
+ d.properties.artifactId === coordinates.name,
808
+ );
809
+ const byVersion = byCoordinates.find(
810
+ (d) => coordinates.version && d.properties.version === coordinates.version,
811
+ );
812
+ return byVersion || byCoordinates[0];
813
+ }
814
+
815
+ /**
816
+ * The Maven descriptor and manifest licence a jar carries for itself, read
817
+ * from its zip without extracting it. Entry names are only matched and
818
+ * paired, never used as paths, and each entry is read only under a size
819
+ * bound, because the archive is untrusted input.
820
+ *
821
+ * @param {string} jarFile Path to the jar.
822
+ * @param {{group: string, name: string, version: string}} coordinates The jar's own coordinates, which choose its descriptor.
823
+ * @returns {Promise<{properties?: Object, pomXml?: string, manifestLicenses?: string[]}|undefined>}
824
+ */
825
+ export async function readEmbeddedJarMetadata(jarFile, coordinates) {
826
+ let zip;
827
+ try {
828
+ zip = new StreamZip.async({ file: jarFile });
829
+ const entries = await zip.entries();
830
+ const decoder = new TextDecoder("utf-8");
831
+ const descriptors = [];
832
+ const pomEntries = new Map();
833
+ let manifestEntry;
834
+ for (const entry of Object.values(entries)) {
835
+ if (entry.isDirectory) {
836
+ continue;
837
+ }
838
+ if (
839
+ !manifestEntry &&
840
+ entry.name === "META-INF/MANIFEST.MF" &&
841
+ entry.size <= EMBEDDED_MANIFEST_LIMIT
842
+ ) {
843
+ manifestEntry = entry;
844
+ continue;
845
+ }
846
+ if (!entry.name.startsWith("META-INF/maven/")) {
847
+ continue;
848
+ }
849
+ if (entry.name.endsWith("/pom.properties")) {
850
+ if (
851
+ descriptors.length >= EMBEDDED_DESCRIPTOR_LIMIT ||
852
+ entry.size > EMBEDDED_POM_PROPERTIES_LIMIT
853
+ ) {
854
+ continue;
855
+ }
856
+ const text = decoder.decode(
857
+ Buffer.from(await zip.entryData(entry.name)),
858
+ );
859
+ descriptors.push({
860
+ name: entry.name,
861
+ properties: parsePomProperties(text),
862
+ });
863
+ } else if (entry.name.endsWith("/pom.xml")) {
864
+ const dir = entry.name.slice(0, -"pom.xml".length);
865
+ if (!pomEntries.has(dir)) {
866
+ pomEntries.set(dir, entry);
867
+ }
868
+ }
869
+ }
870
+ const chosen = chooseZipDescriptor(descriptors, coordinates);
871
+ const result = {};
872
+ if (chosen) {
873
+ result.properties = chosen.properties;
874
+ const dir = chosen.name.slice(0, -"pom.properties".length);
875
+ const pomEntry = pomEntries.get(dir);
876
+ if (pomEntry && pomEntry.size <= EMBEDDED_POM_XML_LIMIT) {
877
+ result.pomXml = decoder.decode(
878
+ Buffer.from(await zip.entryData(pomEntry.name)),
879
+ );
880
+ }
881
+ }
882
+ if (manifestEntry) {
883
+ const manifest = parseJarManifest(
884
+ decoder.decode(
885
+ Buffer.from(await zip.entryData("META-INF/MANIFEST.MF")),
886
+ ),
887
+ );
888
+ const licenses = parseManifestLicenseList(manifest["Bundle-License"]);
889
+ if (licenses.length) {
890
+ result.manifestLicenses = licenses;
891
+ }
892
+ }
893
+ return chosen || manifestEntry ? result : undefined;
894
+ } catch (_err) {
895
+ return undefined;
896
+ } finally {
897
+ try {
898
+ await zip.close();
899
+ } catch (_err) {
900
+ // An already-failed zip reports its close as well.
521
901
  }
522
902
  }
523
- return pomProperties;
524
903
  }
525
904
 
526
905
  /**