@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
@@ -79,12 +79,62 @@ export function parseModuleBazel(moduleFile) {
79
79
  });
80
80
  }
81
81
 
82
+ // Overrides replace where a bazel_dep comes from, and Bazel then ignores
83
+ // the version the bazel_dep names.
84
+ // https://bazel.build/external/module#overrides
85
+ const overrides = new Map();
86
+ for (const kind of [
87
+ "local_path_override",
88
+ "git_override",
89
+ "archive_override",
90
+ "single_version_override",
91
+ ]) {
92
+ for (const call of findAllCalls(src, kind)) {
93
+ const moduleName = scalarArg(call, "module_name");
94
+ if (moduleName && !overrides.has(moduleName)) {
95
+ overrides.set(moduleName, {
96
+ kind,
97
+ version: scalarArg(call, "version"),
98
+ remote: scalarArg(call, "remote"),
99
+ revision:
100
+ scalarArg(call, "commit") ||
101
+ scalarArg(call, "tag") ||
102
+ scalarArg(call, "branch"),
103
+ url: scalarArg(call, "urls") || scalarArg(call, "url"),
104
+ });
105
+ }
106
+ }
107
+ }
108
+
82
109
  for (const call of findAllCalls(src, "bazel_dep")) {
83
110
  const name = scalarArg(call, "name");
84
- const version = scalarArg(call, "version");
111
+ let version = scalarArg(call, "version");
85
112
  const repoName = scalarArg(call, "repo_name");
86
113
  if (!name || !version) continue;
87
- pkgList.push(buildBcrPackage(repoName || name, name, version, moduleFile));
114
+ const override = overrides.get(name);
115
+ // A module taken from a local directory is the project's own tree, not a
116
+ // BCR release, and the version it declares is not what gets built.
117
+ if (override?.kind === "local_path_override") continue;
118
+ if (override?.kind === "single_version_override" && override.version) {
119
+ version = override.version;
120
+ }
121
+ // A git or archive override fetches the module from elsewhere, so it is
122
+ // no BCR release: the purl names where it comes from instead of the BCR.
123
+ const source = overrideSource(override);
124
+ const pkg = buildBcrPackage(
125
+ repoName || name,
126
+ name,
127
+ source ? null : version,
128
+ moduleFile,
129
+ source,
130
+ );
131
+ if (override && override.kind !== "single_version_override") {
132
+ pkg.properties.push({
133
+ name: "cdx:bazel:override",
134
+ value: override.kind.replace(/_override$/, ""),
135
+ });
136
+ }
137
+ pkgList.push(pkg);
88
138
  }
89
139
 
90
140
  for (const call of findAllCalls(src, "maven.artifact")) {
@@ -425,6 +475,37 @@ function buildEcosystemPackage(coords, context) {
425
475
  return pkg;
426
476
  }
427
477
 
478
+ /**
479
+ * Where a git_override or archive_override takes a module from, as purl
480
+ * qualifiers and an external reference.
481
+ *
482
+ * @param {Object|undefined} override override recorded for the module
483
+ * @returns {{qualifiers: Object, externalReferences: Object[]}|undefined}
484
+ * undefined for no override, or one that keeps the module a BCR release
485
+ */
486
+ function overrideSource(override) {
487
+ if (override?.kind === "git_override") {
488
+ if (!override.remote) {
489
+ return { qualifiers: {}, externalReferences: [] };
490
+ }
491
+ const vcsUrl = `git+${override.remote}${override.revision ? `@${override.revision}` : ""}`;
492
+ return {
493
+ qualifiers: { vcs_url: vcsUrl },
494
+ externalReferences: [{ type: "vcs", url: override.remote }],
495
+ };
496
+ }
497
+ if (override?.kind === "archive_override") {
498
+ if (!override.url) {
499
+ return { qualifiers: {}, externalReferences: [] };
500
+ }
501
+ return {
502
+ qualifiers: { download_url: override.url },
503
+ externalReferences: [{ type: "distribution", url: override.url }],
504
+ };
505
+ }
506
+ return undefined;
507
+ }
508
+
428
509
  /**
429
510
  * Build a component record for a BCR (Bazel Central Registry) module.
430
511
  *
@@ -435,26 +516,46 @@ function buildEcosystemPackage(coords, context) {
435
516
  * @param {string} moduleName Canonical module name
436
517
  * @param {string} version Resolved version
437
518
  * @param {string} srcFile Source file for evidence
519
+ * @param {{qualifiers: Object, externalReferences: Object[]}} [source] where
520
+ * an override takes the module from, in place of the BCR
438
521
  * @returns {object} Package record
439
522
  */
440
- function buildBcrPackage(displayRepoName, moduleName, version, srcFile) {
523
+ function buildBcrPackage(
524
+ displayRepoName,
525
+ moduleName,
526
+ version,
527
+ srcFile,
528
+ source,
529
+ ) {
441
530
  const purl = tryBuildPurl({
442
531
  type: "bazel",
443
532
  name: moduleName,
444
533
  version,
445
- qualifiers: { repository_url: BCR_DEFAULT_REPOSITORY_URL },
534
+ qualifiers: source
535
+ ? source.qualifiers
536
+ : { repository_url: BCR_DEFAULT_REPOSITORY_URL },
446
537
  });
447
538
  return {
448
539
  name: moduleName,
449
- version,
540
+ ...(version ? { version } : {}),
450
541
  type: "library",
451
542
  scope: "required",
452
543
  purl,
453
544
  "bom-ref": decodeURIComponent(purl),
545
+ ...(source?.externalReferences.length
546
+ ? { externalReferences: source.externalReferences }
547
+ : {}),
454
548
  properties: [
455
549
  { name: "internal:SrcFile", value: srcFile },
456
550
  { name: "cdx:bazel:module", value: moduleName },
457
- { name: "cdx:bazel:repository_url", value: BCR_DEFAULT_REPOSITORY_URL },
551
+ ...(source
552
+ ? []
553
+ : [
554
+ {
555
+ name: "cdx:bazel:repository_url",
556
+ value: BCR_DEFAULT_REPOSITORY_URL,
557
+ },
558
+ ]),
458
559
  ...(displayRepoName !== moduleName
459
560
  ? [{ name: "cdx:bazel:repo_name", value: displayRepoName }]
460
561
  : []),
@@ -1,5 +1,13 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { basename, dirname, join, resolve } from "node:path";
2
+ import {
3
+ basename,
4
+ dirname,
5
+ isAbsolute,
6
+ join,
7
+ posix,
8
+ resolve,
9
+ win32,
10
+ } from "node:path";
3
11
 
4
12
  import { build } from "@cdxgen/cdx-purl";
5
13
 
@@ -182,7 +190,10 @@ export function resolveInstalledNugetVersion(range, installedVersions = []) {
182
190
  * @returns {string} Project directory
183
191
  */
184
192
  export function dotnetManifestProjectDir(manifestFile, projectPath) {
185
- if (projectPath) {
193
+ // A path recorded on another operating system, such as `D:\src\App.csproj`
194
+ // read on Linux, is not absolute here and would resolve against the working
195
+ // directory.
196
+ if (projectPath && isAbsolute(projectPath)) {
186
197
  const projectDir = dirname(resolve(projectPath));
187
198
  if (safeExistsSync(projectDir)) {
188
199
  return projectDir;
@@ -192,6 +203,55 @@ export function dotnetManifestProjectDir(manifestFile, projectPath) {
192
203
  return basename(dir) === "obj" ? dirname(dir) : dir;
193
204
  }
194
205
 
206
+ /**
207
+ * The path, on this machine, of the project file a project.assets.json belongs to.
208
+ *
209
+ * Restore records the project file and the directory it wrote the assets file
210
+ * to (`outputPath`) as absolute paths on the machine that ran it, which can be
211
+ * a CI agent, a container, another operating system, or this tree reached
212
+ * through another path. Where the project file sits relative to that
213
+ * directory does not change when the tree moves, so the project file is that
214
+ * offset applied to the directory the assets file is in. An assets file that
215
+ * records no output path is taken to be in its project's `obj/`. The recorded
216
+ * path itself is used only when no offset can be worked out, as when restore
217
+ * wrote to another drive than the project's.
218
+ *
219
+ * Nothing is read from disk: the name is spelled as restore recorded it, which
220
+ * can differ in case from the file a case-insensitive file system holds.
221
+ *
222
+ * @param {string} assetsFile project.assets.json path
223
+ * @param {string} [projectPath] Project file restore recorded
224
+ * @param {string} [outputPath] Directory restore recorded writing the assets file to
225
+ * @returns {string|undefined} Project file path, or undefined when none can be named
226
+ */
227
+ export function dotnetRestoredProjectFile(assetsFile, projectPath, outputPath) {
228
+ if (!assetsFile || typeof projectPath !== "string" || !projectPath.trim()) {
229
+ return undefined;
230
+ }
231
+ // Read the recorded paths the way the machine that wrote them would
232
+ const recorded =
233
+ win32.isAbsolute(projectPath) && !posix.isAbsolute(projectPath)
234
+ ? win32
235
+ : posix;
236
+ const assetsDir = dirname(resolve(assetsFile));
237
+ let offset;
238
+ if (typeof outputPath === "string" && outputPath.trim()) {
239
+ const relativePath = recorded.relative(outputPath, projectPath);
240
+ // Across two drives there is no relative path, only the recorded one
241
+ if (!recorded.isAbsolute(relativePath)) {
242
+ offset = relativePath.split(recorded.sep);
243
+ }
244
+ } else if (basename(assetsDir) === "obj") {
245
+ offset = ["..", recorded.basename(projectPath)];
246
+ }
247
+ // The offset must end at a file, not at the output directory or a parent
248
+ const fileName = offset?.at(-1);
249
+ if (fileName && fileName !== "." && fileName !== "..") {
250
+ return resolve(assetsDir, ...offset);
251
+ }
252
+ return isAbsolute(projectPath) ? resolve(projectPath) : undefined;
253
+ }
254
+
195
255
  /**
196
256
  * Index the MSBuild properties that props files define, by the directory each
197
257
  * file sits in and across the whole scan, so the candidates for every project
@@ -853,8 +913,12 @@ function evaluateMsbuildProperties(projFile, names) {
853
913
  * @param {Object} restoredNames Package ids as this project's restore output spells them,
854
914
  * keyed by lowercased id. NuGet ids are case-insensitive, so a reference spelled
855
915
  * differently names the same package and takes the restored spelling.
916
+ * @param {{name: string, version: (string|undefined)}} [projectIdentity] Package id and
917
+ * version this project's project.assets.json records for the project. They name the
918
+ * project in place of what the project file states.
856
919
  *
857
- * @returns {Object} Containing parent component, package, and dependencies
920
+ * @returns {Object} Containing parent component, package, dependencies, and the
921
+ * `$(Name)` version labels left unresolved without msbuild
858
922
  */
859
923
  export function parseCsProjData(
860
924
  csProjData,
@@ -865,6 +929,7 @@ export function parseCsProjData(
865
929
  centralVersions = {},
866
930
  fallbackVersions = {},
867
931
  restoredNames = {},
932
+ projectIdentity = undefined,
868
933
  ) {
869
934
  const pkgList = [];
870
935
  const parentComponent = { type: "application", properties: [] };
@@ -909,21 +974,21 @@ export function parseCsProjData(
909
974
  ? pkgVersionLabelCandidates[label][0]
910
975
  : undefined);
911
976
  let msbuildValues = {};
912
- if (msbuildInstalled) {
913
- const unresolved = new Set();
914
- for (const item of project.ItemGroup || []) {
915
- for (const reference of item.PackageReference || []) {
916
- const label = labelOf(
917
- reference.$?.VersionOverride ||
918
- reference.VersionOverride?.[0]._?.[0] ||
919
- reference.$?.Version ||
920
- reference.Version?.[0]._?.[0],
921
- );
922
- if (label && staticLabelValue(label) === undefined) {
923
- unresolved.add(label);
924
- }
977
+ const unresolved = new Set();
978
+ for (const item of project.ItemGroup || []) {
979
+ for (const reference of item.PackageReference || []) {
980
+ const label = labelOf(
981
+ reference.$?.VersionOverride ||
982
+ reference.VersionOverride?.[0]._?.[0] ||
983
+ reference.$?.Version ||
984
+ reference.Version?.[0]._?.[0],
985
+ );
986
+ if (label && staticLabelValue(label) === undefined) {
987
+ unresolved.add(label);
925
988
  }
926
989
  }
990
+ }
991
+ if (msbuildInstalled) {
927
992
  msbuildValues = evaluateMsbuildProperties(projFile, [...unresolved].sort());
928
993
  }
929
994
  // SDK-style projects declare their version through the MSBuild properties
@@ -1351,6 +1416,32 @@ export function parseCsProjData(
1351
1416
  // version set from a build-time property is unknown, not 1.0.0.
1352
1417
  parentComponent.version = "1.0.0";
1353
1418
  }
1419
+ // Only a build knows the value of a property that references another one
1420
+ const literal = (value) =>
1421
+ value && !value.includes("$(") ? value : undefined;
1422
+ // NuGet names a project's package by its PackageId, which defaults to the
1423
+ // assembly name, so a PackageId the project file states names the project.
1424
+ const declaredPackageId = literal(ownProperties.PackageId);
1425
+ if (declaredPackageId) {
1426
+ parentComponent.name = declaredPackageId;
1427
+ }
1428
+ // Restore evaluated the project with everything MSBuild imports and every
1429
+ // property it was given: a Version from Directory.Build.props, `-p:Version`
1430
+ // or `$(BuildNumber)`, a PackageId. Its project.assets.json roots the
1431
+ // restored dependency tree at that identity, so naming the project from its
1432
+ // file alone would make it two components.
1433
+ if (projectIdentity?.name) {
1434
+ parentComponent.name = projectIdentity.name;
1435
+ parentComponent.version = projectIdentity.version;
1436
+ }
1437
+ // The assembly the project builds keeps its name when the package differs
1438
+ const declaredAssemblyName = literal(ownProperties.AssemblyName);
1439
+ if (declaredAssemblyName && declaredAssemblyName !== parentComponent.name) {
1440
+ parentComponent.properties.push({
1441
+ name: "cdx:dotnet:assembly_name",
1442
+ value: declaredAssemblyName,
1443
+ });
1444
+ }
1354
1445
  // The purl is built once every PropertyGroup has been read, so a version
1355
1446
  // declared after OutputType is not lost. A project that states no version
1356
1447
  // gets a versionless purl: "latest" is not a version.
@@ -1370,6 +1461,8 @@ export function parseCsProjData(
1370
1461
  pkgList,
1371
1462
  parentComponent,
1372
1463
  dependencies,
1464
+ // Version labels no static source settled, which only msbuild could
1465
+ unresolvedVersionLabels: msbuildInstalled ? [] : [...unresolved].sort(),
1373
1466
  };
1374
1467
  }
1375
1468
 
@@ -1417,8 +1510,10 @@ export function isReferencedDotnetPackageFile(packageFile) {
1417
1510
  *
1418
1511
  * @param {string} csProjData Raw JSON string of the project.assets.json file
1419
1512
  * @param {string} assetsJsonFile Path to the project.assets.json file, used for evidence properties
1420
- * @returns {{ pkgList: Object[], dependenciesList: Object[], projectPath: (string|undefined) }}
1421
- * `projectPath` is the project file the restore output belongs to, as restore recorded it
1513
+ * @returns {{ pkgList: Object[], dependenciesList: Object[], projectPath: (string|undefined), outputPath: (string|undefined), projectIdentity: ({name: string, version: (string|undefined)}|undefined) }}
1514
+ * `projectPath` is the project file the restore output belongs to and `outputPath` the
1515
+ * directory restore wrote it to, both as restore recorded them. `projectIdentity` is the
1516
+ * package id and version restore evaluated for the project, which root the dependency tree.
1422
1517
  */
1423
1518
  export function parseCsProjAssetsData(csProjData, assetsJsonFile) {
1424
1519
  // extract name, operator, version from .NET package representation
@@ -1646,6 +1741,10 @@ export function parseCsProjAssetsData(csProjData, assetsJsonFile) {
1646
1741
  pkgList,
1647
1742
  dependenciesList,
1648
1743
  projectPath,
1744
+ outputPath: csProjData.project?.restore?.outputPath,
1745
+ projectIdentity: rootRef
1746
+ ? { name: rootPkg.name, version: rootPkg.version }
1747
+ : undefined,
1649
1748
  };
1650
1749
  }
1651
1750