@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
@@ -5,6 +5,7 @@ import { parse as loadYaml } from "yaml";
5
5
 
6
6
  import { safeExistsSync } from "../core/fs.js";
7
7
  import { sanitizeBomPropertyValue } from "../core/propertySanitizer.js";
8
+ import { isAgentSkillSpecValid } from "./agentSkillSpec.js";
8
9
  import { parseJsonLike } from "./jsonLike.js";
9
10
  import {
10
11
  credentialIndicatorsForText,
@@ -279,18 +280,12 @@ function parseSkillFile(filePath, raw) {
279
280
  );
280
281
  }
281
282
  // Record whether the frontmatter satisfies the open Agent Skills constraints
282
- // (name: 1-64 lowercase-alnum-hyphen; description: 1-1024 chars) as a single
283
- // reviewer-friendly boolean rather than copying the raw values twice.
284
- const specValid =
285
- typeof metadata?.name === "string" &&
286
- /^[a-z0-9-]{1,64}$/u.test(metadata.name) &&
287
- typeof metadata?.description === "string" &&
288
- metadata.description.length >= 1 &&
289
- metadata.description.length <= 1024;
283
+ // as a single reviewer-friendly boolean rather than copying the raw values
284
+ // twice.
290
285
  addUniqueProperty(
291
286
  component.properties,
292
287
  "cdx:skill:specValid",
293
- specValid ? "true" : "false",
288
+ isAgentSkillSpecValid(metadata) ? "true" : "false",
294
289
  );
295
290
  const skillDir = dirname(filePath);
296
291
  for (const [subdir, property] of [
@@ -1,5 +1,5 @@
1
1
  import { lstatSync, readFileSync, statSync } from "node:fs";
2
- import { homedir, tmpdir } from "node:os";
2
+ import { homedir } from "node:os";
3
3
  import { delimiter as _delimiter, basename, dirname, join } from "node:path";
4
4
 
5
5
  import { build, Purl } from "@cdxgen/cdx-purl";
@@ -10,6 +10,7 @@ import { commandOutputText } from "../core/buildLedger.js";
10
10
  import { parseMavenArgs } from "../core/env.js";
11
11
  import {
12
12
  getAllFiles,
13
+ getTmpDir,
13
14
  multiChecksumFile,
14
15
  safeExistsSync,
15
16
  safeMkdtempSync,
@@ -24,6 +25,10 @@ import {
24
25
  mavenLocalRepositories,
25
26
  splitArtifactFileName,
26
27
  } from "./jvmLocalRepos.js";
28
+ import {
29
+ mavenMirrorSettingsArgs,
30
+ mavenWrapperMirrorEnv,
31
+ } from "./mavenCentralMirror.js";
27
32
  import { pypiBomRef } from "./purl.js";
28
33
  import { findLicenseId, spdxLicenses } from "./spdx.js";
29
34
 
@@ -99,7 +104,8 @@ function jarPurl(group, name, version, classifier = undefined) {
99
104
  * Collect maven dependencies
100
105
  *
101
106
  * @param {string} mavenCmd Maven command to use
102
- * @param {string} basePath Path to the maven project
107
+ * @param {string} basePath Path to the maven project. Without it Maven is not
108
+ * run, and only the local repository is read when includeCacheDir is set.
103
109
  * @param {boolean} cleanup Remove temporary directories
104
110
  * @param {boolean} includeCacheDir Include maven and gradle cache directories
105
111
  */
@@ -118,7 +124,7 @@ export async function collectMvnDependencies(
118
124
  safeExistsSync(repo),
119
125
  ) ||
120
126
  join(homedir(), ".m2", "repository");
121
- const tempDir = safeMkdtempSync(join(tmpdir(), "mvn-deps-"));
127
+ const tempDir = safeMkdtempSync(join(getTmpDir(), "mvn-deps-"));
122
128
  // No -U: forcing update checks re-requests every maven-metadata.xml and
123
129
  // every artifact Maven already knows is missing, once per module.
124
130
  let copyArgs = [
@@ -134,11 +140,13 @@ export async function collectMvnDependencies(
134
140
  const addArgs = parseMavenArgs(readEnvironmentVariable("MVN_ARGS"));
135
141
  copyArgs = copyArgs.concat(addArgs);
136
142
  }
143
+ copyArgs = copyArgs.concat(mavenMirrorSettingsArgs());
137
144
  if (basePath && basePath !== MAVEN_CACHE_DIR) {
138
145
  console.log(`Executing '${mavenCmd} in ${basePath}`);
139
146
  const result = safeSpawnSync(mavenCmd, copyArgs, {
140
147
  cwd: basePath,
141
148
  shell: isWin,
149
+ env: { ...process.env, ...mavenWrapperMirrorEnv() },
142
150
  });
143
151
  const rateLimited = noteBuildToolRateLimit(
144
152
  "maven",
@@ -178,7 +186,7 @@ export async function collectMvnDependencies(
178
186
  }
179
187
 
180
188
  // Clean up
181
- if (cleanup && tempDir?.startsWith(tmpdir())) {
189
+ if (cleanup && tempDir?.startsWith(getTmpDir())) {
182
190
  safeRmSync(tempDir, { recursive: true, force: true });
183
191
  }
184
192
  return jarNSMapping;
@@ -334,6 +342,35 @@ export async function collectJarNS(jarPath, pomPathMap = {}) {
334
342
  return jarNSMapping;
335
343
  }
336
344
 
345
+ /**
346
+ * The jar namespace map entries of components a jar scan produced, in the
347
+ * shape {@link collectJarNS} writes (`{ namespaces: string[] }`), from their
348
+ * `internal:Namespaces` properties. The scan reads each jar from a temporary
349
+ * copy, so no `jarFile` is recorded. Purls `existing` already maps keep the
350
+ * entry they have, which names the jar it was read from.
351
+ *
352
+ * @param {Object[]} components Components with `internal:Namespaces` properties
353
+ * @param {Object} [existing] Jar namespace map already collected
354
+ * @returns {Object} New entries keyed by purl
355
+ */
356
+ export function namespaceMappingOfComponents(components, existing = {}) {
357
+ const mapping = {};
358
+ for (const component of components || []) {
359
+ if (!component?.purl || existing[component.purl]) {
360
+ continue;
361
+ }
362
+ const namespaces = (component.properties || [])
363
+ .filter((property) => property.name === "internal:Namespaces")
364
+ .flatMap((property) => String(property.value || "").split("\n"))
365
+ .map((namespace) => namespace.trim())
366
+ .filter(Boolean);
367
+ if (namespaces.length) {
368
+ mapping[component.purl] = { namespaces: [...new Set(namespaces)] };
369
+ }
370
+ }
371
+ return mapping;
372
+ }
373
+
337
374
  /**
338
375
  * Convert a JAR namespace mapping (produced by {@link collectJarNS}) into an array
339
376
  * of CycloneDX package component objects.
@@ -14,6 +14,7 @@ import { readReachablesSlices } from "./atomUtils.js";
14
14
  import { formatOccurrenceEvidence } from "./evidenceUtils.js";
15
15
  import {
16
16
  formatHbomHardwareClassSummary,
17
+ getHbomPrivilegeGuidance,
17
18
  getHbomSummary,
18
19
  isHbomLikeBom,
19
20
  } from "./hbomAnalysis.js";
@@ -475,7 +476,9 @@ export const buildTableSummaryLines = (
475
476
  );
476
477
  if (hbomSummary.requiresPrivilegedEnrichment) {
477
478
  summaryLines.push(
478
- "Permission-sensitive enrichments were skipped or blocked. Re-run with --privileged where policy allows.",
479
+ hbomSummary.platform === "windows"
480
+ ? getHbomPrivilegeGuidance(hbomSummary.platform)
481
+ : "Permission-sensitive enrichments were skipped or blocked. Re-run with --privileged where policy allows.",
479
482
  );
480
483
  }
481
484
  }
@@ -526,6 +529,7 @@ const HBOM_COLUMN_PRIORITY = Object.freeze([
526
529
  ["cdx:hbom:securityMode", "securityMode"],
527
530
  ["cdx:hbom:health", "health"],
528
531
  ["cdx:hbom:smartStatus", "smartStatus"],
532
+ ["cdx:hbom:healthStatus", "healthStatus"],
529
533
  ["cdx:hbom:powerSource", "powerSource"],
530
534
  ["cdx:hbom:maximumCapacity", "maximumCapacity"],
531
535
  ["cdx:hbom:chargePercent", "chargePercent"],
@@ -546,6 +550,7 @@ const HBOM_COLUMN_PRIORITY = Object.freeze([
546
550
  ["cdx:hostview:kernel_modules:count", "kernelMods"],
547
551
  ["cdx:hostview:mount_hardening:count", "runtimeMounts"],
548
552
  ["cdx:hostview:runtime-storage:count", "runtimeStorage"],
553
+ ["cdx:hostview:logical_drives:count", "runtimeDrives"],
549
554
  ["cdx:hostview:linkedRuntimeCategoryCount", "runtimeLinks"],
550
555
  ]);
551
556
 
@@ -616,6 +621,7 @@ const HBOM_CLASS_PROPERTY_PRIORITY = Object.freeze({
616
621
  storage: Object.freeze([
617
622
  ["cdx:hbom:capacity", "capacity"],
618
623
  ["cdx:hbom:smartStatus", "smart"],
624
+ ["cdx:hbom:healthStatus", "healthStatus"],
619
625
  ["cdx:hbom:wearPercentageUsed", "wearUsed"],
620
626
  ["cdx:hbom:transport", "transport"],
621
627
  ["cdx:hbom:firmwareVersion", "firmware"],
@@ -630,6 +636,7 @@ const HBOM_CLASS_PROPERTY_PRIORITY = Object.freeze({
630
636
  ["cdx:hbom:isRemovable", "removable"],
631
637
  ["cdx:hostview:mount_hardening:count", "runtimeMounts"],
632
638
  ["cdx:hostview:runtime-storage:count", "runtimeStorage"],
639
+ ["cdx:hostview:logical_drives:count", "runtimeDrives"],
633
640
  ]),
634
641
  sensor: Object.freeze([
635
642
  ["cdx:hbom:temperatureCelsius", "tempC"],
@@ -870,8 +877,13 @@ export function printTable(
870
877
  }
871
878
  if (
872
879
  bomJson.metadata?.component &&
873
- ["operating-system", "platform"].includes(bomJson.metadata.component.type)
880
+ ["operating-system", "platform"].includes(
881
+ bomJson.metadata.component.type,
882
+ ) &&
883
+ !filterTypes?.includes("cryptographic-asset")
874
884
  ) {
885
+ // A filtered crypto view stays a crypto view even on an OS BOM; only the
886
+ // unfiltered component listing falls through to the OS table.
875
887
  return printOSTable(bomJson);
876
888
  }
877
889
  if (isHbomLikeBom(bomJson) && !filterTypes?.includes("cryptographic-asset")) {
@@ -1037,7 +1049,13 @@ const locationComparator = (a, b) => {
1037
1049
  const tmpB = b.split("#");
1038
1050
  if (tmpA.length === 2 && tmpB.length === 2) {
1039
1051
  if (tmpA[0] === tmpB[0]) {
1040
- return tmpA[1] - tmpB[1];
1052
+ // Line numbers sort numerically; other fragments (a secret key such
1053
+ // as data.tls.crt) by text, never NaN.
1054
+ const lineA = Number(tmpA[1]);
1055
+ const lineB = Number(tmpB[1]);
1056
+ return Number.isNaN(lineA) || Number.isNaN(lineB)
1057
+ ? tmpA[1].localeCompare(tmpB[1])
1058
+ : lineA - lineB;
1041
1059
  }
1042
1060
  }
1043
1061
  }
@@ -2125,3 +2143,182 @@ export function displaySelfThreatModel(
2125
2143
  process.exit(1);
2126
2144
  }
2127
2145
  }
2146
+
2147
+ function certificateComponents(bomJson) {
2148
+ return (bomJson?.components || []).filter(
2149
+ (component) => component?.cryptoProperties?.assetType === "certificate",
2150
+ );
2151
+ }
2152
+
2153
+ function auditedBomRefs(bomJson) {
2154
+ // Audit findings land as document annotations whose location names the
2155
+ // component; a certificate listed there is flagged in the table. The
2156
+ // annotation text is rendered as a markdown property table, so the rows
2157
+ // are parsed back out of it (the same way the REPL's audit view does).
2158
+ const refs = new Set();
2159
+ for (const annotation of bomJson?.annotations || []) {
2160
+ const text = typeof annotation?.text === "string" ? annotation.text : "";
2161
+ for (const line of text.split(/\r?\n/)) {
2162
+ if (!line.includes("cdx:audit:location:bomRef")) {
2163
+ continue;
2164
+ }
2165
+ const cells = line.split("|").map((cell) => cell.trim());
2166
+ if (
2167
+ cells.length >= 2 &&
2168
+ cells[1] === "cdx:audit:location:bomRef" &&
2169
+ cells[2]
2170
+ ) {
2171
+ refs.add(cells[2]);
2172
+ }
2173
+ }
2174
+ }
2175
+ return refs;
2176
+ }
2177
+
2178
+ /**
2179
+ * Print a table of the BOM's certificate components: role, name, issuer,
2180
+ * expiry, the SPKI prefix and how many locations each certificate appears
2181
+ * in, with a marker when the audit flagged it.
2182
+ *
2183
+ * @param {Object} bomJson CycloneDX BOM JSON object
2184
+ * @returns {void}
2185
+ */
2186
+ export function printCertificatesTable(bomJson) {
2187
+ const certificates = certificateComponents(bomJson);
2188
+ if (!certificates.length) {
2189
+ console.log(
2190
+ "No certificate components found. Generate a CBOM with --include-crypto to use this view.",
2191
+ );
2192
+ return;
2193
+ }
2194
+ const flagged = auditedBomRefs(bomJson);
2195
+ const stream = createStream({
2196
+ columnDefault: { width: 24 },
2197
+ columnCount: 6,
2198
+ columns: [
2199
+ { width: 13 },
2200
+ { width: 30 },
2201
+ { width: 30 },
2202
+ { width: 21 },
2203
+ { width: 18 },
2204
+ { width: 5, alignment: "center" },
2205
+ ],
2206
+ });
2207
+ stream.write([
2208
+ "Role",
2209
+ "Name",
2210
+ "Issuer CN",
2211
+ "Not valid after",
2212
+ "SPKI (first 16)",
2213
+ "Locs",
2214
+ ]);
2215
+ for (const certificate of certificates) {
2216
+ const issuerCn = commonNameFromIssuer(certificate);
2217
+ stream.write([
2218
+ getPropertyValue(certificate, "cdx:crypto:certRole") || "?",
2219
+ certificate.name || "",
2220
+ issuerCn ||
2221
+ certificate.cryptoProperties?.certificateProperties?.issuerName ||
2222
+ "",
2223
+ certificate.cryptoProperties?.certificateProperties?.notValidAfter || "",
2224
+ (getPropertyValue(certificate, "cdx:crypto:spkiSha256") || "").slice(
2225
+ 0,
2226
+ 16,
2227
+ ),
2228
+ `${certificate.evidence?.occurrences?.length || 0}${flagged.has(certificate["bom-ref"]) ? " ⚠" : ""}`,
2229
+ ]);
2230
+ }
2231
+ stream.end();
2232
+ console.log();
2233
+ console.log(`Found ${certificates.length} certificate component(s).`);
2234
+ }
2235
+
2236
+ function commonNameFromIssuer(certificate) {
2237
+ const issuer =
2238
+ certificate.cryptoProperties?.certificateProperties?.issuerName || "";
2239
+ const parts = issuer.split(",").map((part) => part.trim());
2240
+ const cn = parts.find((part) => part.startsWith("CN="));
2241
+ return cn ? cn.slice(3) : parts[0];
2242
+ }
2243
+
2244
+ /**
2245
+ * Print the issuer chain above a certificate and the certificates issued
2246
+ * under it, walking the verified `dependsOn` edges.
2247
+ *
2248
+ * @param {Object} bomJson CycloneDX BOM JSON object
2249
+ * @param {string} selector bom-ref, SPKI hex prefix or certificate ref prefix
2250
+ * @returns {void}
2251
+ */
2252
+ export function printCertificateChain(bomJson, selector) {
2253
+ const query = String(selector || "").trim();
2254
+ if (!query) {
2255
+ console.log("Usage: .certchain <bom-ref|spki-prefix|cert-prefix>");
2256
+ return;
2257
+ }
2258
+ const certificates = certificateComponents(bomJson);
2259
+ const byRef = new Map(certificates.map((c) => [c["bom-ref"], c]));
2260
+ const edges = new Map(
2261
+ (bomJson?.dependencies || []).map((dep) => [
2262
+ dep.ref,
2263
+ (dep.dependsOn || []).filter((ref) => byRef.has(ref)),
2264
+ ]),
2265
+ );
2266
+ const issuersOf = new Map();
2267
+ for (const [ref, issuerRefs] of edges) {
2268
+ for (const issuerRef of issuerRefs) {
2269
+ if (!issuersOf.has(issuerRef)) {
2270
+ issuersOf.set(issuerRef, []);
2271
+ }
2272
+ issuersOf.get(issuerRef).push(ref);
2273
+ }
2274
+ }
2275
+ let target;
2276
+ if (byRef.has(query)) {
2277
+ target = byRef.get(query);
2278
+ } else {
2279
+ target = certificates.find(
2280
+ (certificate) =>
2281
+ certificate["bom-ref"].includes(query) ||
2282
+ (
2283
+ getPropertyValue(certificate, "cdx:crypto:spkiSha256") || ""
2284
+ ).startsWith(query.toLowerCase()),
2285
+ );
2286
+ }
2287
+ if (!target) {
2288
+ console.log(`No certificate matches '${query}'.`);
2289
+ return;
2290
+ }
2291
+ const describe = (certificate) =>
2292
+ `${getPropertyValue(certificate, "cdx:crypto:certRole") || "?"} ${certificate.name} (${(getPropertyValue(certificate, "cdx:crypto:spkiSha256") || "").slice(0, 16)}…)`;
2293
+ const chain = [];
2294
+ let cursor = target["bom-ref"];
2295
+ const seen = new Set([cursor]);
2296
+ while (edges.has(cursor)) {
2297
+ const next = (edges.get(cursor) || []).filter((ref) => !seen.has(ref));
2298
+ if (!next.length) {
2299
+ break;
2300
+ }
2301
+ cursor = next[0];
2302
+ seen.add(cursor);
2303
+ chain.push(byRef.get(cursor));
2304
+ }
2305
+ console.log(`Chain above ${describe(target)}:`);
2306
+ if (chain.length) {
2307
+ chain.forEach((certificate, index) => {
2308
+ console.log(`${" ".repeat(index + 1)}← ${describe(certificate)}`);
2309
+ });
2310
+ } else {
2311
+ console.log(" (no verified issuer in this BOM)");
2312
+ }
2313
+ const issued = (issuersOf.get(target["bom-ref"]) || []).filter((ref) =>
2314
+ byRef.has(ref),
2315
+ );
2316
+ console.log(`Issued under ${describe(target)}:`);
2317
+ if (issued.length) {
2318
+ for (const ref of issued) {
2319
+ console.log(` → ${describe(byRef.get(ref))}`);
2320
+ }
2321
+ } else {
2322
+ console.log(" (none in this BOM)");
2323
+ }
2324
+ }