@cdxgen/cdxgen 13.4.0 → 13.6.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 (305) hide show
  1. package/README.md +9 -9
  2. package/bin/cdxgen-secure.js +15 -0
  3. package/bin/cdxgen.js +29 -5
  4. package/bin/evinse.js +8 -0
  5. package/bin/hbom.js +15 -7
  6. package/bin/repl.js +29 -0
  7. package/bin/validate.js +6 -0
  8. package/data/cbomosdb-queries.json +13 -1
  9. package/data/component-tags.json +8 -0
  10. package/data/license-aliases.json +24 -2
  11. package/data/queries-darwin.json +25 -1
  12. package/data/queries-win.json +19 -1
  13. package/data/queries.json +41 -0
  14. package/data/remediations.json +407 -1
  15. package/data/rules/ai-bom.yaml +1 -1
  16. package/data/rules/brotli-decoder.yaml +107 -0
  17. package/data/rules/cbom-security.yaml +235 -4
  18. package/data/rules/go-binaries.yaml +46 -0
  19. package/data/rules/golem-go.yaml +80 -0
  20. package/data/rules/hbom-compliance.yaml +40 -22
  21. package/data/rules/hbom-performance.yaml +7 -1
  22. package/data/rules/host-topology.yaml +1 -1
  23. package/data/rules/obom-runtime.yaml +31 -2
  24. package/data/rules/php-runtime.yaml +143 -0
  25. package/data/rules/vscode-extensions.yaml +75 -0
  26. package/data/spdx-license-list.json +121 -7
  27. package/data/spdx-licenses.json +69 -0
  28. package/data/spdx.schema.json +845 -2
  29. package/lib/audit/index.js +14 -0
  30. package/lib/cli/bomAssembly.js +120 -6
  31. package/lib/cli/cliOptions.js +110 -3
  32. package/lib/cli/index.js +182 -6
  33. package/lib/cli/jsBom.js +153 -64
  34. package/lib/cli/jvmBom.js +363 -66
  35. package/lib/cli/managedBom.js +853 -87
  36. package/lib/cli/nativeBom.js +267 -33
  37. package/lib/core/boundedFile.js +344 -0
  38. package/lib/core/brotliProbe.js +182 -0
  39. package/lib/core/env.js +38 -8
  40. package/lib/core/fs.js +40 -19
  41. package/lib/core/httpClient.js +172 -46
  42. package/lib/core/lockPaths.js +38 -0
  43. package/lib/core/paths.js +24 -1
  44. package/lib/core/processTree.js +5 -0
  45. package/lib/core/projectConfig.js +1 -0
  46. package/lib/core/projectTooling.js +97 -0
  47. package/lib/core/propertySanitizer.js +72 -0
  48. package/lib/core/toolRegistry.js +170 -0
  49. package/lib/ecosystems/cppEvidence.js +263 -106
  50. package/lib/ecosystems/cppIncludeResolver.js +16 -5
  51. package/lib/ecosystems/ecosystems.js +25 -10
  52. package/lib/ecosystems/gemHostProbe.js +301 -0
  53. package/lib/ecosystems/golem.js +550 -6
  54. package/lib/ecosystems/gradleutils.js +858 -244
  55. package/lib/ecosystems/parsers-bazel.js +107 -6
  56. package/lib/ecosystems/parsers-dotnet.js +117 -18
  57. package/lib/ecosystems/parsers-go.js +1090 -367
  58. package/lib/ecosystems/parsers-js.js +505 -22
  59. package/lib/ecosystems/parsers-jvm.js +259 -17
  60. package/lib/ecosystems/parsers-misc.js +438 -64
  61. package/lib/ecosystems/parsers-python.js +100 -12
  62. package/lib/ecosystems/pythonutils.js +128 -2
  63. package/lib/ecosystems/rubyutils.js +544 -34
  64. package/lib/ecosystems/rusi.js +10 -0
  65. package/lib/ecosystems/scalacliutils.js +4 -1
  66. package/lib/ecosystems/scalasem.js +798 -151
  67. package/lib/ecosystems/vendoredCode.js +237 -3
  68. package/lib/ecosystems/venvProbe.js +360 -0
  69. package/lib/evinser/evinser.js +472 -61
  70. package/lib/evinser/swiftsem.js +68 -5
  71. package/lib/helpers/agenticToolutils.js +413 -93
  72. package/lib/helpers/vsixutils.js +1574 -315
  73. package/lib/inventory/agentSkillSpec.js +17 -0
  74. package/lib/inventory/apkInstalledDb.js +243 -0
  75. package/lib/inventory/atomUtils.js +110 -0
  76. package/lib/inventory/auditCategories.js +3 -3
  77. package/lib/inventory/brotliDecoder.js +142 -0
  78. package/lib/inventory/buildToolRateLimit.js +1 -1
  79. package/lib/inventory/cacheDir.js +52 -9
  80. package/lib/inventory/cbomutils.js +56 -7
  81. package/lib/inventory/certificates.js +2371 -0
  82. package/lib/inventory/communityAiConfigParser.js +4 -9
  83. package/lib/inventory/deps.js +41 -4
  84. package/lib/inventory/display.js +200 -3
  85. package/lib/inventory/dosai.js +639 -63
  86. package/lib/inventory/dotnetRuntime.js +217 -0
  87. package/lib/inventory/dynamic.js +45 -3
  88. package/lib/inventory/envcontext.js +475 -18
  89. package/lib/inventory/evidenceUtils.js +447 -23
  90. package/lib/inventory/fetchBatch.js +1 -1
  91. package/lib/inventory/formulationParsers.js +32 -3
  92. package/lib/inventory/goBuildInfo.js +140 -0
  93. package/lib/inventory/gtfobins.js +13 -0
  94. package/lib/inventory/hbom.js +67 -7
  95. package/lib/inventory/hbomAnalysis.js +16 -0
  96. package/lib/inventory/hostRuntimeProbe.js +686 -0
  97. package/lib/inventory/hostTopology.js +21 -0
  98. package/lib/inventory/jvmLocalRepos.js +9 -2
  99. package/lib/inventory/jvmToolEnv.js +29 -0
  100. package/lib/inventory/licenseEnhancer.js +12 -0
  101. package/lib/inventory/mavenCentralMirror.js +534 -0
  102. package/lib/inventory/nodeBuildInfo.js +218 -0
  103. package/lib/inventory/nodeHostProbe.js +202 -0
  104. package/lib/inventory/osPackagePurl.js +244 -0
  105. package/lib/inventory/osPackageResolver.js +271 -87
  106. package/lib/inventory/osinfo.js +79 -31
  107. package/lib/inventory/osqueryTransform.js +114 -5
  108. package/lib/inventory/phpBuildInfo.js +438 -0
  109. package/lib/inventory/phpHostProbe.js +185 -0
  110. package/lib/inventory/rootfsCerts.js +426 -0
  111. package/lib/inventory/rubyBuildInfo.js +972 -0
  112. package/lib/inventory/rubyHostProbe.js +218 -0
  113. package/lib/inventory/scalaCoords.js +4 -3
  114. package/lib/inventory/scalaDedupe.js +440 -0
  115. package/lib/inventory/source.js +256 -5
  116. package/lib/inventory/spdx.js +144 -0
  117. package/lib/inventory/traceRunner.js +5 -1
  118. package/lib/inventory/tracedCrypto.js +129 -0
  119. package/lib/managers/binary.js +866 -186
  120. package/lib/managers/docker.js +245 -12
  121. package/lib/parsers/email.js +277 -0
  122. package/lib/parsers/largeJson.js +62 -13
  123. package/lib/parsers/vscodeExtensionId.js +183 -0
  124. package/lib/server/server.js +198 -2
  125. package/lib/stages/postgen/annotator.js +17 -1
  126. package/lib/stages/postgen/introspection/reflect.js +4 -1
  127. package/lib/stages/postgen/postgen.js +5 -5
  128. package/lib/stages/postgen/ruleEngine.js +71 -6
  129. package/lib/stages/postgen/specVersionCompat.js +30 -0
  130. package/lib/stages/pregen/envAudit.js +1 -0
  131. package/lib/stages/pregen/pregen.js +231 -62
  132. package/lib/validator/bomValidator.js +32 -6
  133. package/lib/validator/generated/runtime.mjs +13 -0
  134. package/lib/validator/generated/validate-1.6.mjs +27 -8
  135. package/lib/validator/generated/validate-1.7.mjs +32 -13
  136. package/lib/validator/generated/validate-2.0.mjs +31 -12
  137. package/lib/validator/index.js +1 -1
  138. package/package.json +19 -18
  139. package/types/bin/cdxgen-secure.d.ts +3 -0
  140. package/types/bin/cdxgen-secure.d.ts.map +1 -0
  141. package/types/bin/repl.d.ts.map +1 -1
  142. package/types/lib/audit/index.d.ts.map +1 -1
  143. package/types/lib/cli/bomAssembly.d.ts +22 -3
  144. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  145. package/types/lib/cli/cliOptions.d.ts +43 -0
  146. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  147. package/types/lib/cli/index.d.ts.map +1 -1
  148. package/types/lib/cli/jsBom.d.ts +1 -17
  149. package/types/lib/cli/jsBom.d.ts.map +1 -1
  150. package/types/lib/cli/jvmBom.d.ts +20 -0
  151. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  152. package/types/lib/cli/managedBom.d.ts.map +1 -1
  153. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  154. package/types/lib/core/boundedFile.d.ts +70 -0
  155. package/types/lib/core/boundedFile.d.ts.map +1 -0
  156. package/types/lib/core/brotliProbe.d.ts +37 -0
  157. package/types/lib/core/brotliProbe.d.ts.map +1 -0
  158. package/types/lib/core/env.d.ts +22 -2
  159. package/types/lib/core/env.d.ts.map +1 -1
  160. package/types/lib/core/fs.d.ts.map +1 -1
  161. package/types/lib/core/httpClient.d.ts +24 -0
  162. package/types/lib/core/httpClient.d.ts.map +1 -1
  163. package/types/lib/core/lockPaths.d.ts +19 -0
  164. package/types/lib/core/lockPaths.d.ts.map +1 -0
  165. package/types/lib/core/processTree.d.ts +2 -0
  166. package/types/lib/core/processTree.d.ts.map +1 -1
  167. package/types/lib/core/projectConfig.d.ts.map +1 -1
  168. package/types/lib/core/projectTooling.d.ts +41 -0
  169. package/types/lib/core/projectTooling.d.ts.map +1 -0
  170. package/types/lib/core/propertySanitizer.d.ts +26 -0
  171. package/types/lib/core/propertySanitizer.d.ts.map +1 -1
  172. package/types/lib/core/toolRegistry.d.ts +36 -0
  173. package/types/lib/core/toolRegistry.d.ts.map +1 -0
  174. package/types/lib/ecosystems/cppEvidence.d.ts +40 -13
  175. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  176. package/types/lib/ecosystems/cppIncludeResolver.d.ts +2 -1
  177. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -1
  178. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  179. package/types/lib/ecosystems/gemHostProbe.d.ts +28 -0
  180. package/types/lib/ecosystems/gemHostProbe.d.ts.map +1 -0
  181. package/types/lib/ecosystems/golem.d.ts +81 -1
  182. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  183. package/types/lib/ecosystems/gradleutils.d.ts +57 -21
  184. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  185. package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -1
  186. package/types/lib/ecosystems/parsers-dotnet.d.ts +40 -4
  187. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  188. package/types/lib/ecosystems/parsers-go.d.ts +85 -13
  189. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  190. package/types/lib/ecosystems/parsers-js.d.ts +17 -20
  191. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  192. package/types/lib/ecosystems/parsers-jvm.d.ts +28 -2
  193. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  194. package/types/lib/ecosystems/parsers-misc.d.ts +37 -58
  195. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  196. package/types/lib/ecosystems/parsers-python.d.ts +14 -3
  197. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  198. package/types/lib/ecosystems/pythonutils.d.ts +19 -1
  199. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  200. package/types/lib/ecosystems/rubyutils.d.ts +144 -12
  201. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  202. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  203. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -1
  204. package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
  205. package/types/lib/ecosystems/vendoredCode.d.ts +26 -0
  206. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -1
  207. package/types/lib/ecosystems/venvProbe.d.ts +40 -0
  208. package/types/lib/ecosystems/venvProbe.d.ts.map +1 -0
  209. package/types/lib/evinser/evinser.d.ts +88 -8
  210. package/types/lib/evinser/evinser.d.ts.map +1 -1
  211. package/types/lib/evinser/swiftsem.d.ts +10 -0
  212. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  213. package/types/lib/inventory/agentSkillSpec.d.ts +13 -0
  214. package/types/lib/inventory/agentSkillSpec.d.ts.map +1 -0
  215. package/types/lib/inventory/apkInstalledDb.d.ts +42 -0
  216. package/types/lib/inventory/apkInstalledDb.d.ts.map +1 -0
  217. package/types/lib/inventory/atomUtils.d.ts +33 -0
  218. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  219. package/types/lib/inventory/brotliDecoder.d.ts +58 -0
  220. package/types/lib/inventory/brotliDecoder.d.ts.map +1 -0
  221. package/types/lib/inventory/cacheDir.d.ts +12 -4
  222. package/types/lib/inventory/cacheDir.d.ts.map +1 -1
  223. package/types/lib/inventory/cbomutils.d.ts +17 -0
  224. package/types/lib/inventory/cbomutils.d.ts.map +1 -1
  225. package/types/lib/inventory/certificates.d.ts +205 -0
  226. package/types/lib/inventory/certificates.d.ts.map +1 -0
  227. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  228. package/types/lib/inventory/deps.d.ts +2 -1
  229. package/types/lib/inventory/deps.d.ts.map +1 -1
  230. package/types/lib/inventory/display.d.ts +18 -0
  231. package/types/lib/inventory/display.d.ts.map +1 -1
  232. package/types/lib/inventory/dosai.d.ts +162 -7
  233. package/types/lib/inventory/dosai.d.ts.map +1 -1
  234. package/types/lib/inventory/dotnetRuntime.d.ts +44 -0
  235. package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -0
  236. package/types/lib/inventory/dynamic.d.ts +6 -1
  237. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  238. package/types/lib/inventory/envcontext.d.ts +92 -8
  239. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  240. package/types/lib/inventory/evidenceUtils.d.ts +29 -10
  241. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  242. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  243. package/types/lib/inventory/goBuildInfo.d.ts +10 -0
  244. package/types/lib/inventory/goBuildInfo.d.ts.map +1 -0
  245. package/types/lib/inventory/gtfobins.d.ts.map +1 -1
  246. package/types/lib/inventory/hbom.d.ts.map +1 -1
  247. package/types/lib/inventory/hbomAnalysis.d.ts +10 -0
  248. package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -1
  249. package/types/lib/inventory/hostRuntimeProbe.d.ts +44 -0
  250. package/types/lib/inventory/hostRuntimeProbe.d.ts.map +1 -0
  251. package/types/lib/inventory/hostTopology.d.ts.map +1 -1
  252. package/types/lib/inventory/jvmToolEnv.d.ts +12 -0
  253. package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
  254. package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -1
  255. package/types/lib/inventory/mavenCentralMirror.d.ts +170 -0
  256. package/types/lib/inventory/mavenCentralMirror.d.ts.map +1 -0
  257. package/types/lib/inventory/nodeBuildInfo.d.ts +95 -0
  258. package/types/lib/inventory/nodeBuildInfo.d.ts.map +1 -0
  259. package/types/lib/inventory/nodeHostProbe.d.ts +15 -0
  260. package/types/lib/inventory/nodeHostProbe.d.ts.map +1 -0
  261. package/types/lib/inventory/osPackagePurl.d.ts +99 -0
  262. package/types/lib/inventory/osPackagePurl.d.ts.map +1 -0
  263. package/types/lib/inventory/osPackageResolver.d.ts +44 -2
  264. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
  265. package/types/lib/inventory/osinfo.d.ts +31 -6
  266. package/types/lib/inventory/osinfo.d.ts.map +1 -1
  267. package/types/lib/inventory/osqueryTransform.d.ts +51 -0
  268. package/types/lib/inventory/osqueryTransform.d.ts.map +1 -1
  269. package/types/lib/inventory/phpBuildInfo.d.ts +142 -0
  270. package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -0
  271. package/types/lib/inventory/phpHostProbe.d.ts +35 -0
  272. package/types/lib/inventory/phpHostProbe.d.ts.map +1 -0
  273. package/types/lib/inventory/rootfsCerts.d.ts +27 -0
  274. package/types/lib/inventory/rootfsCerts.d.ts.map +1 -0
  275. package/types/lib/inventory/rubyBuildInfo.d.ts +271 -0
  276. package/types/lib/inventory/rubyBuildInfo.d.ts.map +1 -0
  277. package/types/lib/inventory/rubyHostProbe.d.ts +47 -0
  278. package/types/lib/inventory/rubyHostProbe.d.ts.map +1 -0
  279. package/types/lib/inventory/source.d.ts +38 -0
  280. package/types/lib/inventory/source.d.ts.map +1 -1
  281. package/types/lib/inventory/spdx.d.ts +15 -0
  282. package/types/lib/inventory/spdx.d.ts.map +1 -1
  283. package/types/lib/inventory/traceRunner.d.ts +4 -1
  284. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  285. package/types/lib/inventory/tracedCrypto.d.ts +22 -0
  286. package/types/lib/inventory/tracedCrypto.d.ts.map +1 -1
  287. package/types/lib/managers/binary.d.ts +10 -0
  288. package/types/lib/managers/binary.d.ts.map +1 -1
  289. package/types/lib/managers/docker.d.ts +24 -0
  290. package/types/lib/managers/docker.d.ts.map +1 -1
  291. package/types/lib/parsers/email.d.ts +19 -0
  292. package/types/lib/parsers/email.d.ts.map +1 -0
  293. package/types/lib/parsers/largeJson.d.ts +17 -3
  294. package/types/lib/parsers/largeJson.d.ts.map +1 -1
  295. package/types/lib/server/server.d.ts +8 -0
  296. package/types/lib/server/server.d.ts.map +1 -1
  297. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  298. package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -1
  299. package/types/lib/stages/postgen/ruleEngine.d.ts +7 -4
  300. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  301. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  302. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  303. package/types/lib/stages/pregen/pregen.d.ts +26 -9
  304. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  305. package/types/lib/validator/bomValidator.d.ts.map +1 -1
@@ -0,0 +1,217 @@
1
+ // Bounded reader for the .NET shared frameworks installed in a root file
2
+ // system.
3
+ //
4
+ // The .NET Docker images, dotnet-install.sh and the tarballs put the runtime
5
+ // under <dotnet root>/shared/<framework>/<version>/ without a package manager,
6
+ // so a BOM sees only its files. Each framework directory carries a
7
+ // <framework>.deps.json whose runtime target names the runtime pack it was
8
+ // built from, e.g. `Microsoft.NETCore.App.Runtime.linux-arm64/8.0.32`. That pack
9
+ // is a NuGet package, and it is the identity .NET security advisories list, so
10
+ // it becomes the component's purl.
11
+ // https://learn.microsoft.com/dotnet/core/dependency-loading/default-probing#how-are-the-properties-populated
12
+
13
+ import { closeSync, readSync } from "node:fs";
14
+ import { join } from "node:path";
15
+
16
+ import { globSync } from "glob";
17
+
18
+ import { openRegularFile } from "../core/boundedFile.js";
19
+ import { applyPurl, tryBuildPurl } from "./purl.js";
20
+
21
+ const MAX_DEPS_JSON_BYTES = 8 * 1024 * 1024;
22
+ const MAX_FRAMEWORKS = 64;
23
+ const FRAMEWORKS = new Set([
24
+ "Microsoft.NETCore.App",
25
+ "Microsoft.AspNetCore.App",
26
+ "Microsoft.WindowsDesktop.App",
27
+ ]);
28
+ // Where the .NET images, dotnet-install.sh, the tarballs and the distro
29
+ // packages put the dotnet root.
30
+ const DOTNET_ROOTS = [
31
+ "usr/share/dotnet",
32
+ "usr/lib/dotnet",
33
+ "usr/lib64/dotnet",
34
+ "usr/local/share/dotnet",
35
+ "opt/dotnet",
36
+ "root/.dotnet",
37
+ "home/*/.dotnet",
38
+ ];
39
+ const RUNTIME_PACK_RE =
40
+ /^(Microsoft\.[A-Za-z]+(?:\.[A-Za-z]+)*\.App\.Runtime\.[A-Za-z0-9.-]+)\/(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/;
41
+
42
+ function readJsonBounded(absPath, rootDir) {
43
+ const opened = openRegularFile(absPath, rootDir);
44
+ if (!opened) {
45
+ return undefined;
46
+ }
47
+ try {
48
+ if (opened.size <= 0 || opened.size > MAX_DEPS_JSON_BYTES) {
49
+ return undefined;
50
+ }
51
+ const buffer = Buffer.allocUnsafe(opened.size);
52
+ const read = readSync(opened.fd, buffer, 0, opened.size, 0);
53
+ return JSON.parse(buffer.toString("utf8", 0, read));
54
+ } catch {
55
+ return undefined;
56
+ } finally {
57
+ try {
58
+ closeSync(opened.fd);
59
+ } catch {
60
+ // already closed
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Read the runtime pack a shared framework's deps.json was built from.
67
+ *
68
+ * @param {Object} depsJson parsed <framework>.deps.json
69
+ * @param {string} framework framework directory name
70
+ * @returns {{pack: string, version: string, rid: string}|undefined}
71
+ */
72
+ export function runtimePackFromDepsJson(depsJson, framework) {
73
+ const targetName = depsJson?.runtimeTarget?.name;
74
+ if (typeof targetName !== "string") {
75
+ return undefined;
76
+ }
77
+ const target = depsJson?.targets?.[targetName];
78
+ if (!target || typeof target !== "object") {
79
+ return undefined;
80
+ }
81
+ for (const key of Object.keys(target)) {
82
+ const match = RUNTIME_PACK_RE.exec(key);
83
+ if (!match?.[1].startsWith(`${framework}.Runtime.`)) {
84
+ continue;
85
+ }
86
+ return {
87
+ pack: match[1],
88
+ version: match[2],
89
+ rid: match[1].slice(`${framework}.Runtime.`.length),
90
+ };
91
+ }
92
+ return undefined;
93
+ }
94
+
95
+ /**
96
+ * The CPE NVD uses for a shared framework version: `.net` from 5.0 on,
97
+ * `.net_core` before it, and `asp.net_core` for ASP.NET Core.
98
+ *
99
+ * @param {string} framework framework directory name
100
+ * @param {string} version runtime version
101
+ * @returns {string|undefined} CPE 2.3 string
102
+ */
103
+ export function dotnetCpe(framework, version) {
104
+ const base = /^(\d+)\.\d+\.\d+/.exec(version || "");
105
+ if (!base) {
106
+ return undefined;
107
+ }
108
+ const plain = base[0];
109
+ if (framework === "Microsoft.AspNetCore.App") {
110
+ return `cpe:2.3:a:microsoft:asp.net_core:${plain}:*:*:*:*:*:*:*`;
111
+ }
112
+ if (framework === "Microsoft.NETCore.App") {
113
+ const product = Number(base[1]) >= 5 ? ".net" : ".net_core";
114
+ return `cpe:2.3:a:microsoft:${product}:${plain}:*:*:*:*:*:*:*`;
115
+ }
116
+ return undefined;
117
+ }
118
+
119
+ /**
120
+ * Create the platform component for one installed shared framework.
121
+ *
122
+ * @param {string} framework framework directory name
123
+ * @param {{pack: string, version: string, rid: string}} runtime runtime pack
124
+ * @param {string} location root-relative path of the deps.json
125
+ * @returns {Object|undefined} component, or undefined when no purl can be built
126
+ */
127
+ export function createDotnetRuntimeComponent(framework, runtime, location) {
128
+ const component = {
129
+ type: "platform",
130
+ name: runtime.pack,
131
+ version: runtime.version,
132
+ properties: [
133
+ { name: "cdx:dotnet:sharedFramework", value: framework },
134
+ { name: "cdx:dotnet:runtimeIdentifier", value: runtime.rid },
135
+ ],
136
+ evidence: {
137
+ occurrences: [{ location: `/${location.replace(/^\/+/, "")}` }],
138
+ },
139
+ };
140
+ const cpe = dotnetCpe(framework, runtime.version);
141
+ if (cpe) {
142
+ component.cpe = cpe;
143
+ }
144
+ const purl = tryBuildPurl({
145
+ type: "nuget",
146
+ name: runtime.pack,
147
+ version: runtime.version,
148
+ });
149
+ if (!purl) {
150
+ return undefined;
151
+ }
152
+ return applyPurl(component, purl);
153
+ }
154
+
155
+ /**
156
+ * Find the .NET shared frameworks installed under a root that no package
157
+ * manager owns, and return one platform component per runtime pack.
158
+ *
159
+ * @param {string} rootDir extracted root file system
160
+ * @param {string[]} [ownedPaths] root-relative paths a package database owns
161
+ * @returns {Object[]} platform components
162
+ */
163
+ export function collectDotnetRuntimes(rootDir, ownedPaths = []) {
164
+ if (!rootDir) {
165
+ return [];
166
+ }
167
+ const owned = new Set(
168
+ (ownedPaths || []).map((p) => p.replace(/^\/+/, "").replaceAll("\\", "/")),
169
+ );
170
+ let depsFiles = [];
171
+ try {
172
+ depsFiles = globSync(
173
+ DOTNET_ROOTS.map((root) => `${root}/shared/*/*/*.deps.json`),
174
+ {
175
+ cwd: rootDir,
176
+ absolute: false,
177
+ nodir: true,
178
+ dot: true,
179
+ follow: false,
180
+ },
181
+ )
182
+ .map((file) => file.replaceAll("\\", "/"))
183
+ .sort();
184
+ } catch {
185
+ return [];
186
+ }
187
+ const components = [];
188
+ const seen = new Set();
189
+ for (const file of depsFiles.slice(0, MAX_FRAMEWORKS)) {
190
+ if (owned.has(file)) {
191
+ continue;
192
+ }
193
+ const parts = file.split("/");
194
+ const framework = parts[parts.length - 3];
195
+ if (
196
+ !FRAMEWORKS.has(framework) ||
197
+ parts.at(-1) !== `${framework}.deps.json`
198
+ ) {
199
+ continue;
200
+ }
201
+ const runtime = runtimePackFromDepsJson(
202
+ readJsonBounded(join(rootDir, file), rootDir),
203
+ framework,
204
+ );
205
+ // The directory a runtime lives in is named after its version.
206
+ if (!runtime || runtime.version !== parts[parts.length - 2]) {
207
+ continue;
208
+ }
209
+ const component = createDotnetRuntimeComponent(framework, runtime, file);
210
+ if (!component || seen.has(component["bom-ref"])) {
211
+ continue;
212
+ }
213
+ seen.add(component["bom-ref"]);
214
+ components.push(component);
215
+ }
216
+ return components;
217
+ }
@@ -7,6 +7,7 @@ import { applyPurl, tryBuildPurl } from "./purl.js";
7
7
  import {
8
8
  cryptoLibrariesByPath,
9
9
  normalizeTracedCryptoComponents,
10
+ observedChainComponents,
10
11
  } from "./tracedCrypto.js";
11
12
  import { executeAndTrace, groupHttpEntriesToServices } from "./traceRunner.js";
12
13
 
@@ -49,10 +50,14 @@ export function librarySubpath(libPath) {
49
50
  * Services are detected from HTTP request URLs collected during tracing and
50
51
  * follow the CycloneDX service schema with endpoints.
51
52
  *
53
+ * The certificate chains servers presented in TLS ≤ 1.2 handshakes become the
54
+ * shared certificate model, with `provides` edges from the TLS protocol
55
+ * components.
56
+ *
52
57
  * @param {string} commandStr - Shell command to execute and trace (e.g. "node --version")
53
58
  * @param {string} workingDir - Working directory for the traced process
54
59
  * @param {Object} [traceOptions] - Additional sandbox options forwarded to executeAndTrace
55
- * @returns {Promise<{components: Array<Object>, services: Array<Object>}>} Components and services
60
+ * @returns {Promise<{components: Array<Object>, services: Array<Object>, dependencies: Array<Object>}>} Components, services and dependencies
56
61
  */
57
62
  export async function buildDynamicComponents(
58
63
  commandStr,
@@ -172,9 +177,41 @@ export async function buildDynamicComponents(
172
177
  }
173
178
 
174
179
  // Append cryptographic assets
175
- for (const comp of normalizeTracedCryptoComponents(cryptoComponents)) {
180
+ const normalizedCryptoComponents =
181
+ normalizeTracedCryptoComponents(cryptoComponents);
182
+ // The chains servers presented in TLS ≤ 1.2 handshakes become the shared
183
+ // certificate model, linked from the TLS protocol components.
184
+ const protocolRefs = new Set(
185
+ normalizedCryptoComponents
186
+ .filter((comp) => comp.cryptoProperties?.assetType === "protocol")
187
+ .map((comp) => comp["bom-ref"]),
188
+ );
189
+ const observedModel = observedChainComponents(
190
+ result.cryptoResult,
191
+ protocolRefs,
192
+ );
193
+ // The traced CBOM names post-quantum algorithms after crypto-oid.json
194
+ // (ml-dsa-44) while the certificate model follows PLAN section 2.5
195
+ // (ML-DSA-44); one OID must still be one component, and the certificates
196
+ // reference the model's name, so a traced duplicate yields to it.
197
+ const observedAlgorithmOids = new Set(
198
+ observedModel.components
199
+ .filter((comp) => comp.cryptoProperties?.assetType === "algorithm")
200
+ .map((comp) => comp.cryptoProperties.oid),
201
+ );
202
+ for (const comp of normalizedCryptoComponents) {
203
+ if (
204
+ comp.cryptoProperties?.assetType === "algorithm" &&
205
+ observedAlgorithmOids.has(comp.cryptoProperties.oid)
206
+ ) {
207
+ continue;
208
+ }
209
+ components.push(comp);
210
+ }
211
+ for (const comp of observedModel.components) {
176
212
  components.push(comp);
177
213
  }
214
+ const dependencies = observedModel.dependencies;
178
215
 
179
216
  // Build services from collected HTTP URLs
180
217
  const servicesMap = groupHttpEntriesToServices(httpAccessEntries);
@@ -225,5 +262,10 @@ export async function buildDynamicComponents(
225
262
  }
226
263
  }
227
264
 
228
- return { components, services, dryRunSummary: result.dryRunSummary };
265
+ return {
266
+ components,
267
+ services,
268
+ dependencies,
269
+ dryRunSummary: result.dryRunSummary,
270
+ };
229
271
  }