@cdxgen/cdxgen 13.2.0 → 13.4.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 (311) hide show
  1. package/README.md +33 -14
  2. package/bin/cdxgen.js +310 -138
  3. package/bin/evinse.js +22 -0
  4. package/bin/repl.js +86 -0
  5. package/bin/sign.js +119 -15
  6. package/bin/tracebom.js +69 -5
  7. package/bin/validate.js +107 -19
  8. package/bin/verify.js +172 -63
  9. package/data/helpers/init.gradle +46 -21
  10. package/data/remediations.json +85 -0
  11. package/data/rules/dependency-sources.yaml +67 -0
  12. package/data/rules/scala-evidence.yaml +115 -0
  13. package/lib/audit/index.js +38 -6
  14. package/lib/cli/bomAssembly.js +105 -15
  15. package/lib/cli/cliOptions.js +93 -1
  16. package/lib/cli/index.js +156 -58
  17. package/lib/cli/jsBom.js +99 -53
  18. package/lib/cli/jvmBom.js +708 -147
  19. package/lib/cli/managedBom.js +415 -224
  20. package/lib/cli/nativeBom.js +264 -44
  21. package/lib/core/activity.js +12 -0
  22. package/lib/core/env.js +22 -15
  23. package/lib/core/fs.js +176 -7
  24. package/lib/core/httpClient.js +159 -24
  25. package/lib/core/metadataProperties.js +97 -0
  26. package/lib/core/pluginRun.js +184 -0
  27. package/lib/core/processTree.js +100 -0
  28. package/lib/core/projectConfig.js +31 -4
  29. package/lib/core/runState.js +39 -0
  30. package/lib/core/toml.js +72 -0
  31. package/lib/ecosystems/asarutils.js +4 -2
  32. package/lib/ecosystems/bunutils.js +274 -108
  33. package/lib/ecosystems/cargoCache.js +231 -8
  34. package/lib/ecosystems/caxa.js +434 -2
  35. package/lib/ecosystems/cmakeResolver.js +76 -21
  36. package/lib/ecosystems/cppBuildContext.js +631 -0
  37. package/lib/ecosystems/cppEvidence.js +399 -51
  38. package/lib/ecosystems/cppIncludeResolver.js +294 -0
  39. package/lib/ecosystems/denoutils.js +93 -66
  40. package/lib/ecosystems/ecosystems.js +1983 -793
  41. package/lib/ecosystems/golem.js +28 -12
  42. package/lib/ecosystems/gradleutils.js +356 -37
  43. package/lib/ecosystems/jsEvidence.js +104 -44
  44. package/lib/ecosystems/kosi.js +31 -7
  45. package/lib/ecosystems/npmutils.js +174 -9
  46. package/lib/ecosystems/parsers-dotnet.js +616 -159
  47. package/lib/ecosystems/parsers-elm.js +46 -28
  48. package/lib/ecosystems/parsers-gleam.js +3 -4
  49. package/lib/ecosystems/parsers-go.js +371 -70
  50. package/lib/ecosystems/parsers-js.js +263 -76
  51. package/lib/ecosystems/parsers-julia.js +2 -3
  52. package/lib/ecosystems/parsers-jvm.js +204 -12
  53. package/lib/ecosystems/parsers-misc.js +929 -216
  54. package/lib/ecosystems/parsers-python.js +167 -24
  55. package/lib/ecosystems/parsers-rust.js +28 -22
  56. package/lib/ecosystems/parsers-terraform.js +1573 -19
  57. package/lib/ecosystems/pythonutils.js +102 -6
  58. package/lib/ecosystems/remote/huggingface.js +3 -0
  59. package/lib/ecosystems/rubyutils.js +1492 -182
  60. package/lib/ecosystems/rusi.js +54 -10
  61. package/lib/ecosystems/sbtutils.js +243 -187
  62. package/lib/ecosystems/scalacliutils.js +342 -0
  63. package/lib/ecosystems/scalasem.js +2618 -0
  64. package/lib/ecosystems/terraformRegistry.js +288 -0
  65. package/lib/ecosystems/utils.js +2 -0
  66. package/lib/ecosystems/vendoredCode.js +156 -0
  67. package/lib/evinser/evinser.js +1008 -191
  68. package/lib/evinser/swiftsem.js +1914 -302
  69. package/lib/helpers/agenticToolutils.js +2 -2
  70. package/lib/helpers/bomSigner.js +1101 -222
  71. package/lib/inventory/aiCollector.js +4 -1
  72. package/lib/inventory/analyzer.js +110 -127
  73. package/lib/inventory/atomUtils.js +703 -43
  74. package/lib/inventory/auditCategories.js +7 -0
  75. package/lib/inventory/buildToolRateLimit.js +144 -0
  76. package/lib/inventory/cacheCommands.js +2 -1
  77. package/lib/inventory/cdxrs.js +103 -12
  78. package/lib/inventory/cmakeBuildDirs.js +254 -0
  79. package/lib/inventory/deps.js +501 -124
  80. package/lib/inventory/depsUtils.js +183 -11
  81. package/lib/inventory/display.js +4 -5
  82. package/lib/inventory/dosai.js +798 -57
  83. package/lib/inventory/dosaiParsers.js +310 -15
  84. package/lib/inventory/dynamic.js +90 -6
  85. package/lib/inventory/evidenceUtils.js +166 -113
  86. package/lib/inventory/fetchBatch.js +690 -55
  87. package/lib/inventory/fetchDiskCache.js +597 -0
  88. package/lib/inventory/forgeEnricher.js +14 -5
  89. package/lib/inventory/jvmLocalRepos.js +917 -0
  90. package/lib/inventory/mcpConfigParser.js +2 -3
  91. package/lib/inventory/parentSelection.js +146 -0
  92. package/lib/inventory/protobom.js +8 -1
  93. package/lib/inventory/purl.js +152 -3
  94. package/lib/inventory/rustFormulationParser.js +3 -4
  95. package/lib/inventory/sbomDocument.js +2 -70
  96. package/lib/inventory/scalaCoords.js +153 -0
  97. package/lib/inventory/source.js +45 -27
  98. package/lib/inventory/spdx.js +101 -0
  99. package/lib/inventory/traceRunner.js +295 -25
  100. package/lib/inventory/tracedCrypto.js +294 -0
  101. package/lib/managers/binary.js +115 -24
  102. package/lib/managers/docker.js +467 -46
  103. package/lib/managers/oci.js +63 -3
  104. package/lib/parsers/cmakeCache.js +69 -0
  105. package/lib/parsers/cmakeLists.js +466 -0
  106. package/lib/parsers/cmakePresets.js +400 -0
  107. package/lib/parsers/compileCommands.js +557 -0
  108. package/lib/parsers/largeJson.js +454 -0
  109. package/lib/parsers/npmrc.js +19 -1
  110. package/lib/parsers/strictJson.js +322 -0
  111. package/lib/parsers/terraformConfig.js +1073 -0
  112. package/lib/parsers/terraformSource.js +652 -0
  113. package/lib/server/server.js +23 -0
  114. package/lib/stages/postgen/introspection/markers.js +1 -1
  115. package/lib/stages/postgen/postgen.js +83 -16
  116. package/lib/stages/postgen/specVersionCompat.js +32 -0
  117. package/lib/validator/bomValidator.js +6 -16
  118. package/lib/validator/index.js +64 -11
  119. package/lib/validator/reporters/console.js +3 -0
  120. package/lib/validator/reporters/json.js +2 -0
  121. package/lib/validator/reporters/sarif.js +7 -0
  122. package/package.json +23 -23
  123. package/types/lib/audit/index.d.ts.map +1 -1
  124. package/types/lib/cli/bomAssembly.d.ts +2 -1
  125. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  126. package/types/lib/cli/cliOptions.d.ts +33 -1
  127. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  128. package/types/lib/cli/index.d.ts.map +1 -1
  129. package/types/lib/cli/jsBom.d.ts.map +1 -1
  130. package/types/lib/cli/jvmBom.d.ts +24 -1
  131. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  132. package/types/lib/cli/managedBom.d.ts +7 -4
  133. package/types/lib/cli/managedBom.d.ts.map +1 -1
  134. package/types/lib/cli/nativeBom.d.ts +3 -1
  135. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  136. package/types/lib/core/activity.d.ts.map +1 -1
  137. package/types/lib/core/env.d.ts +9 -0
  138. package/types/lib/core/env.d.ts.map +1 -1
  139. package/types/lib/core/fs.d.ts +55 -0
  140. package/types/lib/core/fs.d.ts.map +1 -1
  141. package/types/lib/core/httpClient.d.ts +13 -8
  142. package/types/lib/core/httpClient.d.ts.map +1 -1
  143. package/types/lib/core/metadataProperties.d.ts +39 -0
  144. package/types/lib/core/metadataProperties.d.ts.map +1 -0
  145. package/types/lib/core/pluginRun.d.ts +97 -0
  146. package/types/lib/core/pluginRun.d.ts.map +1 -0
  147. package/types/lib/core/processTree.d.ts +36 -0
  148. package/types/lib/core/processTree.d.ts.map +1 -0
  149. package/types/lib/core/projectConfig.d.ts +6 -2
  150. package/types/lib/core/projectConfig.d.ts.map +1 -1
  151. package/types/lib/core/runState.d.ts +29 -0
  152. package/types/lib/core/runState.d.ts.map +1 -0
  153. package/types/lib/core/toml.d.ts +20 -0
  154. package/types/lib/core/toml.d.ts.map +1 -0
  155. package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
  156. package/types/lib/ecosystems/bunutils.d.ts +12 -5
  157. package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
  158. package/types/lib/ecosystems/cargoCache.d.ts +12 -0
  159. package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
  160. package/types/lib/ecosystems/caxa.d.ts +14 -0
  161. package/types/lib/ecosystems/caxa.d.ts.map +1 -1
  162. package/types/lib/ecosystems/cmakeResolver.d.ts +28 -3
  163. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
  164. package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
  165. package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
  166. package/types/lib/ecosystems/cppEvidence.d.ts +17 -1
  167. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  168. package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
  169. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
  170. package/types/lib/ecosystems/denoutils.d.ts +9 -3
  171. package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
  172. package/types/lib/ecosystems/ecosystems.d.ts +62 -13
  173. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  174. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  175. package/types/lib/ecosystems/gradleutils.d.ts +70 -4
  176. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  177. package/types/lib/ecosystems/jsEvidence.d.ts +5 -2
  178. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  179. package/types/lib/ecosystems/kosi.d.ts +13 -0
  180. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  181. package/types/lib/ecosystems/npmutils.d.ts +57 -0
  182. package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
  183. package/types/lib/ecosystems/parsers-dotnet.d.ts +118 -4
  184. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  185. package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
  186. package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
  187. package/types/lib/ecosystems/parsers-go.d.ts +54 -2
  188. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  189. package/types/lib/ecosystems/parsers-js.d.ts +16 -5
  190. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  191. package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
  192. package/types/lib/ecosystems/parsers-jvm.d.ts +46 -1
  193. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  194. package/types/lib/ecosystems/parsers-misc.d.ts +70 -4
  195. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  196. package/types/lib/ecosystems/parsers-python.d.ts +53 -3
  197. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  198. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  199. package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
  200. package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
  201. package/types/lib/ecosystems/pythonutils.d.ts +27 -2
  202. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  203. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  204. package/types/lib/ecosystems/rubyutils.d.ts +164 -3
  205. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  206. package/types/lib/ecosystems/rusi.d.ts +13 -0
  207. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  208. package/types/lib/ecosystems/sbtutils.d.ts +88 -2
  209. package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
  210. package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
  211. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
  212. package/types/lib/ecosystems/scalasem.d.ts +311 -0
  213. package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
  214. package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
  215. package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
  216. package/types/lib/ecosystems/utils.d.ts +2 -2
  217. package/types/lib/ecosystems/utils.d.ts.map +1 -1
  218. package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
  219. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
  220. package/types/lib/evinser/evinser.d.ts +132 -15
  221. package/types/lib/evinser/evinser.d.ts.map +1 -1
  222. package/types/lib/evinser/swiftsem.d.ts +280 -15
  223. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  224. package/types/lib/helpers/bomSigner.d.ts +182 -13
  225. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  226. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  227. package/types/lib/inventory/analyzer.d.ts.map +1 -1
  228. package/types/lib/inventory/atomUtils.d.ts +219 -5
  229. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  230. package/types/lib/inventory/auditCategories.d.ts +3 -0
  231. package/types/lib/inventory/auditCategories.d.ts.map +1 -1
  232. package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
  233. package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
  234. package/types/lib/inventory/cacheCommands.d.ts +2 -1
  235. package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
  236. package/types/lib/inventory/cdxrs.d.ts +8 -3
  237. package/types/lib/inventory/cdxrs.d.ts.map +1 -1
  238. package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
  239. package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
  240. package/types/lib/inventory/deps.d.ts +59 -1
  241. package/types/lib/inventory/deps.d.ts.map +1 -1
  242. package/types/lib/inventory/depsUtils.d.ts +15 -0
  243. package/types/lib/inventory/depsUtils.d.ts.map +1 -1
  244. package/types/lib/inventory/display.d.ts.map +1 -1
  245. package/types/lib/inventory/dosai.d.ts +121 -9
  246. package/types/lib/inventory/dosai.d.ts.map +1 -1
  247. package/types/lib/inventory/dosaiParsers.d.ts +53 -7
  248. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  249. package/types/lib/inventory/dynamic.d.ts +10 -0
  250. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  251. package/types/lib/inventory/evidenceUtils.d.ts +19 -4
  252. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  253. package/types/lib/inventory/fetchBatch.d.ts +83 -14
  254. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  255. package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
  256. package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
  257. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
  258. package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
  259. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
  260. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  261. package/types/lib/inventory/parentSelection.d.ts +34 -0
  262. package/types/lib/inventory/parentSelection.d.ts.map +1 -0
  263. package/types/lib/inventory/plugins.d.ts.map +1 -1
  264. package/types/lib/inventory/protobom.d.ts.map +1 -1
  265. package/types/lib/inventory/purl.d.ts +71 -2
  266. package/types/lib/inventory/purl.d.ts.map +1 -1
  267. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  268. package/types/lib/inventory/sbomDocument.d.ts.map +1 -1
  269. package/types/lib/inventory/scalaCoords.d.ts +80 -0
  270. package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
  271. package/types/lib/inventory/source.d.ts.map +1 -1
  272. package/types/lib/inventory/spdx.d.ts +9 -0
  273. package/types/lib/inventory/spdx.d.ts.map +1 -1
  274. package/types/lib/inventory/traceRunner.d.ts +59 -1
  275. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  276. package/types/lib/inventory/tracedCrypto.d.ts +42 -0
  277. package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
  278. package/types/lib/managers/binary.d.ts +30 -1
  279. package/types/lib/managers/binary.d.ts.map +1 -1
  280. package/types/lib/managers/docker.d.ts +29 -0
  281. package/types/lib/managers/docker.d.ts.map +1 -1
  282. package/types/lib/managers/oci.d.ts +17 -1
  283. package/types/lib/managers/oci.d.ts.map +1 -1
  284. package/types/lib/parsers/cmakeCache.d.ts +16 -0
  285. package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
  286. package/types/lib/parsers/cmakeLists.d.ts +77 -0
  287. package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
  288. package/types/lib/parsers/cmakePresets.d.ts +78 -0
  289. package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
  290. package/types/lib/parsers/compileCommands.d.ts +115 -0
  291. package/types/lib/parsers/compileCommands.d.ts.map +1 -0
  292. package/types/lib/parsers/largeJson.d.ts +52 -0
  293. package/types/lib/parsers/largeJson.d.ts.map +1 -0
  294. package/types/lib/parsers/npmrc.d.ts +5 -0
  295. package/types/lib/parsers/npmrc.d.ts.map +1 -1
  296. package/types/lib/parsers/strictJson.d.ts +46 -0
  297. package/types/lib/parsers/strictJson.d.ts.map +1 -0
  298. package/types/lib/parsers/terraformConfig.d.ts +70 -0
  299. package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
  300. package/types/lib/parsers/terraformSource.d.ts +66 -0
  301. package/types/lib/parsers/terraformSource.d.ts.map +1 -0
  302. package/types/lib/server/server.d.ts.map +1 -1
  303. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  304. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  305. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  306. package/types/lib/validator/index.d.ts +18 -1
  307. package/types/lib/validator/index.d.ts.map +1 -1
  308. package/types/lib/validator/reporters/console.d.ts.map +1 -1
  309. package/types/lib/validator/reporters/json.d.ts.map +1 -1
  310. package/types/lib/validator/reporters/sarif.d.ts.map +1 -1
  311. package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
@@ -1,11 +1,14 @@
1
1
  import { readdirSync, readFileSync, statSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
- import { join, resolve } from "node:path";
3
+ import { join, posix, resolve } from "node:path";
4
+ import { gunzipSync } from "node:zlib";
4
5
 
5
- import * as toml from "smol-toml";
6
+ import { Parser as TarParser } from "tar";
6
7
 
7
8
  import { readEnvironmentVariable } from "../core/activity.js";
8
9
  import { safeExistsSync } from "../core/fs.js";
10
+ import { registerRunReset } from "../core/runState.js";
11
+ import { parseToml } from "../core/toml.js";
9
12
 
10
13
  /**
11
14
  * Crate metadata read from the local Cargo registry, without any network.
@@ -69,6 +72,8 @@ export function resetCargoCacheState() {
69
72
  _registryDirs = undefined;
70
73
  }
71
74
 
75
+ registerRunReset("cargo:local-registry", resetCargoCacheState);
76
+
72
77
  /**
73
78
  * Whether the local registry should be consulted before crates.io.
74
79
  *
@@ -101,15 +106,16 @@ export function getCargoRegistryDir() {
101
106
  * private registry has more than one, and the crate being looked up may live
102
107
  * in any of them, so all are searched.
103
108
  *
104
- * @returns {{src: string[], index: string[]}} Absolute directory paths.
109
+ * @returns {{src: string[], index: string[], cache: string[]}} Absolute
110
+ * directory paths.
105
111
  */
106
112
  function registryDirs() {
107
113
  if (_registryDirs) {
108
114
  return _registryDirs;
109
115
  }
110
116
  const root = getCargoRegistryDir();
111
- _registryDirs = { src: [], index: [] };
112
- for (const kind of ["src", "index"]) {
117
+ _registryDirs = { src: [], index: [], cache: [] };
118
+ for (const kind of ["src", "index", "cache"]) {
113
119
  const base = join(root, kind);
114
120
  try {
115
121
  for (const entry of readdirSync(base, { withFileTypes: true })) {
@@ -133,7 +139,7 @@ function registryDirs() {
133
139
  * @returns {CargoCacheMetadata|undefined} Metadata, or undefined when neither
134
140
  * local source has this crate.
135
141
  */
136
- export function readCargoCacheMetadata(name, version) {
142
+ export async function readCargoCacheMetadata(name, version) {
137
143
  if (!name || !version) {
138
144
  return undefined;
139
145
  }
@@ -144,6 +150,15 @@ export function readCargoCacheMetadata(name, version) {
144
150
  Object.assign(result, manifest.values);
145
151
  sources.push(manifest.source);
146
152
  }
153
+ const archive = await readCachedCrateArchive(name, version);
154
+ if (archive) {
155
+ for (const [key, value] of Object.entries(archive.values)) {
156
+ if (result[key] === undefined) {
157
+ result[key] = value;
158
+ }
159
+ }
160
+ sources.push(archive.source);
161
+ }
147
162
  const index = readIndexEntry(name, version);
148
163
  if (index) {
149
164
  // The manifest is authoritative for the fields both carry, since it is the
@@ -158,6 +173,198 @@ export function readCargoCacheMetadata(name, version) {
158
173
  return sources.length ? result : undefined;
159
174
  }
160
175
 
176
+ /**
177
+ * A `.crate` archive larger than this is not opened for its manifest. Crates
178
+ * this size are rare, and the archive may be untrusted input.
179
+ */
180
+ const CRATE_ARCHIVE_MAX_BYTES = 16 * 1024 * 1024;
181
+
182
+ /**
183
+ * An archive that unpacks to more than this is not read, so a small archive
184
+ * that expands without bound costs bounded time and memory.
185
+ */
186
+ const CRATE_UNPACKED_MAX_BYTES = 64 * 1024 * 1024;
187
+
188
+ /**
189
+ * A single entry larger than this is not read out of a `.crate` archive.
190
+ */
191
+ const CRATE_ENTRY_MAX_BYTES = 1024 * 1024;
192
+
193
+ /**
194
+ * The `license-file` of a manifest as a path inside the crate, or undefined
195
+ * when it points anywhere else. The manifest is the crate author's, so a path
196
+ * that climbs out of the crate must never be followed.
197
+ *
198
+ * @param {*} licenseFile The manifest's `license-file` value
199
+ * @returns {string|undefined} Normalised relative path
200
+ */
201
+ function crateLicenseFilePath(licenseFile) {
202
+ if (typeof licenseFile !== "string" || !licenseFile.trim()) {
203
+ return undefined;
204
+ }
205
+ const normalized = posix.normalize(licenseFile.trim().replaceAll("\\", "/"));
206
+ if (
207
+ normalized.startsWith("/") ||
208
+ normalized === ".." ||
209
+ normalized.startsWith("../") ||
210
+ /^[A-Za-z]:/.test(normalized)
211
+ ) {
212
+ return undefined;
213
+ }
214
+ return normalized;
215
+ }
216
+
217
+ /**
218
+ * The unpacked tar data of a `.crate` archive, within the size bounds.
219
+ *
220
+ * @param {string} crateFile Path to the `.crate` archive (a gzipped tar)
221
+ * @returns {Buffer|undefined}
222
+ */
223
+ function unpackCrateArchive(crateFile) {
224
+ try {
225
+ if (statSync(crateFile).size > CRATE_ARCHIVE_MAX_BYTES) {
226
+ return undefined;
227
+ }
228
+ return gunzipSync(readFileSync(crateFile), {
229
+ maxOutputLength: CRATE_UNPACKED_MAX_BYTES,
230
+ });
231
+ } catch {
232
+ // An unreadable archive, or one that unpacks past the bound, is the same
233
+ // as none: the network path answers.
234
+ return undefined;
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Read one file out of unpacked `.crate` tar data.
240
+ *
241
+ * @param {Buffer} tarData Unpacked tar data
242
+ * @param {string} entryName Entry path relative to the archive root
243
+ * @returns {Promise<string|undefined>} The entry's text, or undefined
244
+ */
245
+ function readCrateArchiveEntry(tarData, entryName) {
246
+ return new Promise((resolvePromise) => {
247
+ let content;
248
+ const parser = new TarParser({
249
+ onReadEntry: (entry) => {
250
+ const path = entry.path.startsWith("./")
251
+ ? entry.path.slice(2)
252
+ : entry.path;
253
+ if (
254
+ content !== undefined ||
255
+ path !== entryName ||
256
+ entry.size > CRATE_ENTRY_MAX_BYTES
257
+ ) {
258
+ entry.resume();
259
+ return;
260
+ }
261
+ const chunks = [];
262
+ entry.on("data", (chunk) => chunks.push(chunk));
263
+ entry.on("end", () => {
264
+ content = Buffer.concat(chunks).toString("utf-8");
265
+ });
266
+ },
267
+ });
268
+ parser.on("error", () => resolvePromise(undefined));
269
+ parser.on("close", () => resolvePromise(content));
270
+ parser.end(tarData);
271
+ });
272
+ }
273
+
274
+ /**
275
+ * The manifest values of a `.crate` archive, read without extracting it.
276
+ *
277
+ * @param {string} crateFile Path to the `.crate` archive
278
+ * @param {string} name Crate name, for the archive's inner directory
279
+ * @param {string} version Crate version
280
+ * @returns {Promise<{values: Object, source: string}|undefined>}
281
+ */
282
+ export async function readCrateArchiveValues(crateFile, name, version) {
283
+ if (!name || !version) {
284
+ return undefined;
285
+ }
286
+ const tarData = unpackCrateArchive(crateFile);
287
+ if (!tarData) {
288
+ return undefined;
289
+ }
290
+ const prefix = `${name}-${version}`;
291
+ const manifestData = await readCrateArchiveEntry(
292
+ tarData,
293
+ `${prefix}/Cargo.toml`,
294
+ );
295
+ if (!manifestData) {
296
+ return undefined;
297
+ }
298
+ let parsed;
299
+ try {
300
+ parsed = parseToml(manifestData);
301
+ } catch {
302
+ return undefined;
303
+ }
304
+ const pkg = parsed?.package;
305
+ if (!pkg || typeof pkg !== "object") {
306
+ return undefined;
307
+ }
308
+ const values = {};
309
+ assignString(values, "description", pkg.description);
310
+ assignString(values, "repository", pkg.repository);
311
+ assignString(values, "homepage", pkg.homepage);
312
+ assignString(values, "rustVersion", pkg["rust-version"]);
313
+ assignString(values, "license", pkg.license);
314
+ const licenseFile = crateLicenseFilePath(pkg["license-file"]);
315
+ if (licenseFile && !values.license) {
316
+ assignLicenseText(
317
+ values,
318
+ await readCrateArchiveEntry(tarData, `${prefix}/${licenseFile}`),
319
+ );
320
+ }
321
+ return { values, source: crateFile };
322
+ }
323
+
324
+ /**
325
+ * The `.crate` archive of a crate version held in the registry cache, which is
326
+ * the only local copy of a crate the build downloaded but never compiled.
327
+ *
328
+ * @param {string} name Crate name.
329
+ * @param {string} version Exact version.
330
+ * @returns {Promise<{values: Object, source: string}|undefined>}
331
+ */
332
+ async function readCachedCrateArchive(name, version) {
333
+ for (const dir of registryDirs().cache) {
334
+ const crateFile = join(dir, `${name}-${version}.crate`);
335
+ if (!safeExistsSync(crateFile)) {
336
+ continue;
337
+ }
338
+ const archive = await readCrateArchiveValues(crateFile, name, version);
339
+ if (archive) {
340
+ return archive;
341
+ }
342
+ }
343
+ return undefined;
344
+ }
345
+
346
+ /**
347
+ * Record a `license-file` notice as a component licence, following the shape
348
+ * cdxgen records licence file text in elsewhere: a CUSTOM licence name with
349
+ * the notice as its text.
350
+ *
351
+ * @param {Object} values Manifest values so far, updated in place
352
+ * @param {string|undefined} text The notice text
353
+ */
354
+ function assignLicenseText(values, text) {
355
+ if (!text?.length) {
356
+ return;
357
+ }
358
+ values.licenses = [
359
+ {
360
+ license: {
361
+ name: "CUSTOM",
362
+ text: { contentType: "text/plain", content: text },
363
+ },
364
+ },
365
+ ];
366
+ }
367
+
161
368
  /**
162
369
  * Read the normalised `Cargo.toml` of an extracted crate.
163
370
  *
@@ -173,7 +380,7 @@ function readExtractedManifest(name, version) {
173
380
  }
174
381
  let parsed;
175
382
  try {
176
- parsed = toml.parse(readFileSync(manifestFile, "utf-8"));
383
+ parsed = parseToml(readFileSync(manifestFile, "utf-8"));
177
384
  } catch {
178
385
  // A manifest that does not parse is not worth a warning: the network
179
386
  // path still has the answer.
@@ -189,8 +396,24 @@ function readExtractedManifest(name, version) {
189
396
  assignString(values, "homepage", pkg.homepage);
190
397
  assignString(values, "rustVersion", pkg["rust-version"]);
191
398
  // A crate may carry `license` or, for a non-SPDX license, `license-file`.
192
- // Only the expression is usable as a component license.
399
+ // The expression is used as the licence; a licence file is recorded as a
400
+ // CUSTOM licence carrying the notice text, the way cdxgen records licence
401
+ // file text elsewhere.
193
402
  assignString(values, "license", pkg.license);
403
+ const licenseFile = crateLicenseFilePath(pkg["license-file"]);
404
+ if (licenseFile && !values.license) {
405
+ try {
406
+ assignLicenseText(
407
+ values,
408
+ readFileSync(join(dir, `${name}-${version}`, licenseFile), {
409
+ encoding: "utf-8",
410
+ }),
411
+ );
412
+ } catch {
413
+ // A licence file that cannot be read leaves the licence to the network
414
+ // path, exactly as an absent one does.
415
+ }
416
+ }
194
417
  if (parsed.features && typeof parsed.features === "object") {
195
418
  values.features = parsed.features;
196
419
  }