@cdxgen/cdxgen 13.5.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 (182) hide show
  1. package/README.md +6 -6
  2. package/bin/cdxgen.js +4 -0
  3. package/bin/evinse.js +3 -0
  4. package/bin/validate.js +6 -0
  5. package/data/license-aliases.json +24 -2
  6. package/data/remediations.json +124 -0
  7. package/data/rules/ai-bom.yaml +1 -1
  8. package/data/rules/brotli-decoder.yaml +107 -0
  9. package/data/rules/vscode-extensions.yaml +75 -0
  10. package/data/spdx-license-list.json +121 -7
  11. package/data/spdx-licenses.json +69 -0
  12. package/data/spdx.schema.json +845 -2
  13. package/lib/cli/bomAssembly.js +92 -3
  14. package/lib/cli/index.js +108 -1
  15. package/lib/cli/jsBom.js +153 -64
  16. package/lib/cli/jvmBom.js +237 -46
  17. package/lib/cli/managedBom.js +142 -16
  18. package/lib/cli/nativeBom.js +42 -5
  19. package/lib/core/boundedFile.js +344 -0
  20. package/lib/core/brotliProbe.js +182 -0
  21. package/lib/core/env.js +8 -0
  22. package/lib/core/fs.js +12 -0
  23. package/lib/core/httpClient.js +98 -1
  24. package/lib/core/lockPaths.js +38 -0
  25. package/lib/core/paths.js +24 -1
  26. package/lib/core/processTree.js +5 -0
  27. package/lib/core/toolRegistry.js +170 -0
  28. package/lib/ecosystems/cppEvidence.js +263 -106
  29. package/lib/ecosystems/cppIncludeResolver.js +16 -5
  30. package/lib/ecosystems/ecosystems.js +25 -10
  31. package/lib/ecosystems/gemHostProbe.js +301 -0
  32. package/lib/ecosystems/gradleutils.js +828 -224
  33. package/lib/ecosystems/parsers-bazel.js +107 -6
  34. package/lib/ecosystems/parsers-js.js +505 -22
  35. package/lib/ecosystems/parsers-misc.js +209 -20
  36. package/lib/ecosystems/parsers-python.js +89 -2
  37. package/lib/ecosystems/pythonutils.js +128 -2
  38. package/lib/ecosystems/rubyutils.js +538 -31
  39. package/lib/ecosystems/scalacliutils.js +2 -0
  40. package/lib/ecosystems/scalasem.js +796 -151
  41. package/lib/ecosystems/vendoredCode.js +237 -3
  42. package/lib/ecosystems/venvProbe.js +360 -0
  43. package/lib/evinser/evinser.js +346 -43
  44. package/lib/helpers/agenticToolutils.js +413 -93
  45. package/lib/helpers/vsixutils.js +1574 -315
  46. package/lib/inventory/atomUtils.js +77 -0
  47. package/lib/inventory/brotliDecoder.js +142 -0
  48. package/lib/inventory/buildToolRateLimit.js +1 -1
  49. package/lib/inventory/cbomutils.js +56 -7
  50. package/lib/inventory/deps.js +35 -0
  51. package/lib/inventory/dosai.js +139 -5
  52. package/lib/inventory/dotnetRuntime.js +217 -0
  53. package/lib/inventory/envcontext.js +307 -13
  54. package/lib/inventory/evidenceUtils.js +11 -0
  55. package/lib/inventory/fetchBatch.js +1 -1
  56. package/lib/inventory/formulationParsers.js +31 -3
  57. package/lib/inventory/gtfobins.js +13 -0
  58. package/lib/inventory/hostRuntimeProbe.js +686 -0
  59. package/lib/inventory/jvmLocalRepos.js +9 -2
  60. package/lib/inventory/jvmToolEnv.js +29 -0
  61. package/lib/inventory/licenseEnhancer.js +12 -0
  62. package/lib/inventory/mavenCentralMirror.js +534 -0
  63. package/lib/inventory/nodeBuildInfo.js +218 -0
  64. package/lib/inventory/nodeHostProbe.js +202 -0
  65. package/lib/inventory/osPackageResolver.js +182 -0
  66. package/lib/inventory/phpBuildInfo.js +10 -59
  67. package/lib/inventory/phpHostProbe.js +32 -488
  68. package/lib/inventory/rubyBuildInfo.js +972 -0
  69. package/lib/inventory/rubyHostProbe.js +218 -0
  70. package/lib/inventory/scalaCoords.js +4 -3
  71. package/lib/inventory/scalaDedupe.js +440 -0
  72. package/lib/inventory/source.js +49 -2
  73. package/lib/managers/binary.js +337 -3
  74. package/lib/managers/docker.js +79 -0
  75. package/lib/parsers/largeJson.js +28 -11
  76. package/lib/parsers/vscodeExtensionId.js +183 -0
  77. package/lib/server/server.js +12 -1
  78. package/lib/stages/postgen/ruleEngine.js +13 -5
  79. package/lib/stages/pregen/envAudit.js +1 -0
  80. package/lib/stages/pregen/pregen.js +114 -57
  81. package/lib/validator/bomValidator.js +6 -1
  82. package/lib/validator/generated/validate-1.6.mjs +1 -1
  83. package/lib/validator/generated/validate-1.7.mjs +1 -1
  84. package/lib/validator/generated/validate-2.0.mjs +1 -1
  85. package/lib/validator/index.js +1 -1
  86. package/package.json +3 -2
  87. package/types/lib/cli/bomAssembly.d.ts +13 -1
  88. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  89. package/types/lib/cli/index.d.ts.map +1 -1
  90. package/types/lib/cli/jsBom.d.ts +1 -17
  91. package/types/lib/cli/jsBom.d.ts.map +1 -1
  92. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  93. package/types/lib/cli/managedBom.d.ts.map +1 -1
  94. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  95. package/types/lib/core/boundedFile.d.ts +70 -0
  96. package/types/lib/core/boundedFile.d.ts.map +1 -0
  97. package/types/lib/core/brotliProbe.d.ts +37 -0
  98. package/types/lib/core/brotliProbe.d.ts.map +1 -0
  99. package/types/lib/core/env.d.ts +4 -0
  100. package/types/lib/core/env.d.ts.map +1 -1
  101. package/types/lib/core/fs.d.ts.map +1 -1
  102. package/types/lib/core/httpClient.d.ts +24 -0
  103. package/types/lib/core/httpClient.d.ts.map +1 -1
  104. package/types/lib/core/lockPaths.d.ts +19 -0
  105. package/types/lib/core/lockPaths.d.ts.map +1 -0
  106. package/types/lib/core/processTree.d.ts +2 -0
  107. package/types/lib/core/processTree.d.ts.map +1 -1
  108. package/types/lib/core/toolRegistry.d.ts +36 -0
  109. package/types/lib/core/toolRegistry.d.ts.map +1 -0
  110. package/types/lib/ecosystems/cppEvidence.d.ts +40 -13
  111. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  112. package/types/lib/ecosystems/cppIncludeResolver.d.ts +2 -1
  113. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -1
  114. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  115. package/types/lib/ecosystems/gemHostProbe.d.ts +28 -0
  116. package/types/lib/ecosystems/gemHostProbe.d.ts.map +1 -0
  117. package/types/lib/ecosystems/gradleutils.d.ts +47 -13
  118. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  119. package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -1
  120. package/types/lib/ecosystems/parsers-js.d.ts +17 -20
  121. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  122. package/types/lib/ecosystems/parsers-misc.d.ts +19 -0
  123. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  124. package/types/lib/ecosystems/parsers-python.d.ts +10 -0
  125. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  126. package/types/lib/ecosystems/pythonutils.d.ts +20 -2
  127. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  128. package/types/lib/ecosystems/rubyutils.d.ts +144 -12
  129. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  130. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -1
  131. package/types/lib/ecosystems/vendoredCode.d.ts +26 -0
  132. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -1
  133. package/types/lib/ecosystems/venvProbe.d.ts +40 -0
  134. package/types/lib/ecosystems/venvProbe.d.ts.map +1 -0
  135. package/types/lib/evinser/evinser.d.ts +63 -8
  136. package/types/lib/evinser/evinser.d.ts.map +1 -1
  137. package/types/lib/inventory/atomUtils.d.ts +19 -0
  138. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  139. package/types/lib/inventory/brotliDecoder.d.ts +58 -0
  140. package/types/lib/inventory/brotliDecoder.d.ts.map +1 -0
  141. package/types/lib/inventory/cbomutils.d.ts +17 -0
  142. package/types/lib/inventory/cbomutils.d.ts.map +1 -1
  143. package/types/lib/inventory/deps.d.ts.map +1 -1
  144. package/types/lib/inventory/dosai.d.ts +17 -1
  145. package/types/lib/inventory/dosai.d.ts.map +1 -1
  146. package/types/lib/inventory/dotnetRuntime.d.ts +44 -0
  147. package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -0
  148. package/types/lib/inventory/envcontext.d.ts +52 -6
  149. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  150. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  151. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  152. package/types/lib/inventory/gtfobins.d.ts.map +1 -1
  153. package/types/lib/inventory/hostRuntimeProbe.d.ts +44 -0
  154. package/types/lib/inventory/hostRuntimeProbe.d.ts.map +1 -0
  155. package/types/lib/inventory/jvmToolEnv.d.ts +12 -0
  156. package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
  157. package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -1
  158. package/types/lib/inventory/mavenCentralMirror.d.ts +170 -0
  159. package/types/lib/inventory/mavenCentralMirror.d.ts.map +1 -0
  160. package/types/lib/inventory/nodeBuildInfo.d.ts +95 -0
  161. package/types/lib/inventory/nodeBuildInfo.d.ts.map +1 -0
  162. package/types/lib/inventory/nodeHostProbe.d.ts +15 -0
  163. package/types/lib/inventory/nodeHostProbe.d.ts.map +1 -0
  164. package/types/lib/inventory/osPackageResolver.d.ts +38 -0
  165. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
  166. package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -1
  167. package/types/lib/inventory/phpHostProbe.d.ts.map +1 -1
  168. package/types/lib/inventory/rubyBuildInfo.d.ts +271 -0
  169. package/types/lib/inventory/rubyBuildInfo.d.ts.map +1 -0
  170. package/types/lib/inventory/rubyHostProbe.d.ts +47 -0
  171. package/types/lib/inventory/rubyHostProbe.d.ts.map +1 -0
  172. package/types/lib/inventory/source.d.ts +10 -0
  173. package/types/lib/inventory/source.d.ts.map +1 -1
  174. package/types/lib/managers/binary.d.ts.map +1 -1
  175. package/types/lib/managers/docker.d.ts +12 -0
  176. package/types/lib/managers/docker.d.ts.map +1 -1
  177. package/types/lib/parsers/largeJson.d.ts +4 -3
  178. package/types/lib/parsers/largeJson.d.ts.map +1 -1
  179. package/types/lib/server/server.d.ts.map +1 -1
  180. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  181. package/types/lib/stages/pregen/pregen.d.ts +12 -8
  182. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
@@ -25,6 +25,7 @@ import {
25
25
  CDXGEN_VERSION,
26
26
  frameworksList,
27
27
  } from "../core/state.js";
28
+ import { getExecutedTools } from "../core/toolRegistry.js";
28
29
  import {
29
30
  isPkgTypeOnlyImport,
30
31
  setNpmCleanedVersionProperty,
@@ -60,7 +61,7 @@ import {
60
61
  } from "../inventory/purl.js";
61
62
  import { repairPurl } from "../inventory/sbomDocument.js";
62
63
  import { getLicenses } from "../inventory/spdx.js";
63
- import { getBinaryBom } from "../managers/binary.js";
64
+ import { getBinaryBom, getPluginToolComponents } from "../managers/binary.js";
64
65
  import { isValidIriReference } from "../parsers/iri.js";
65
66
 
66
67
  /**
@@ -293,10 +294,85 @@ function anchorDetectedParent(
293
294
  return anchored;
294
295
  }
295
296
 
297
+ /**
298
+ * Builds the tool components for the external helpers and build tools this
299
+ * run executed, from the run-scoped registry (issue #598). Bundled plugin
300
+ * helpers are enriched with the manifest component of the plugin package that
301
+ * ships them, so the plugin package's version and identity travel with the
302
+ * helper. Empty when the run spawned nothing external, which keeps such BOMs
303
+ * byte-identical to the previous behaviour.
304
+ *
305
+ * @returns {object[]} Sorted CycloneDX tool components
306
+ */
307
+ export const buildExternalToolComponents = () => {
308
+ const recordedTools = getExecutedTools();
309
+ if (!recordedTools.length) {
310
+ return [];
311
+ }
312
+ const recordedNames = recordedTools.map((tool) => tool.name);
313
+ const pluginComponents = getPluginToolComponents(recordedNames);
314
+ const pluginByName = new Map(
315
+ pluginComponents.map((component) => [component.name, component]),
316
+ );
317
+ const components = [];
318
+ for (const tool of recordedTools) {
319
+ const pluginComponent = pluginByName.get(tool.name);
320
+ if (pluginComponent?.["bom-ref"]) {
321
+ components.push(pluginComponent);
322
+ continue;
323
+ }
324
+ const component = {
325
+ type: "application",
326
+ name: tool.name,
327
+ };
328
+ if (tool.version) {
329
+ component.version = tool.version;
330
+ }
331
+ components.push(component);
332
+ }
333
+ return components;
334
+ };
335
+
336
+ /**
337
+ * Drops the executed tools that are already present: a tool whose bom-ref or
338
+ * name matches an explicitly passed context tool, or whose bom-ref an earlier
339
+ * executed tool already carries (several bundled helpers can share one plugin
340
+ * package component). The context tools themselves are never touched.
341
+ *
342
+ * @param {object[]} contextTools Tool components passed in by the caller
343
+ * @param {object[]} executedTools Tool components from the run's registry
344
+ * @returns {object[]} The executed tools to append
345
+ */
346
+ const newExecutedTools = (contextTools, executedTools) => {
347
+ const seenRefs = new Set();
348
+ const seenNames = new Set();
349
+ for (const component of contextTools) {
350
+ if (component?.["bom-ref"]) {
351
+ seenRefs.add(component["bom-ref"]);
352
+ }
353
+ if (component?.name) {
354
+ seenNames.add(component.name);
355
+ }
356
+ }
357
+ const unique = [];
358
+ for (const component of executedTools) {
359
+ const ref = component["bom-ref"];
360
+ if ((ref && seenRefs.has(ref)) || seenNames.has(component.name)) {
361
+ continue;
362
+ }
363
+ if (ref) {
364
+ seenRefs.add(ref);
365
+ }
366
+ unique.push(component);
367
+ }
368
+ return unique;
369
+ };
370
+
296
371
  /**
297
372
  * Assembles the `metadata.tools` block, including the cdxgen tool entry and,
298
373
  * for spec versions prior to 1.5, the legacy tools array. For spec version
299
- * 1.6+ the author field is converted to the authors array.
374
+ * 1.6+ the author field is converted to the authors array. The tools this run
375
+ * executed follow the context tools, sorted by name, and cdxgen comes last.
300
376
  *
301
377
  * @param {object} options CLI options
302
378
  * @param {object} [context={}] Additional context carrying existing components
@@ -304,6 +380,7 @@ function anchorDetectedParent(
304
380
  * tools array (1.4) or a components array with tool components (1.5+)
305
381
  */
306
382
  export const addToolsSection = (options, context = {}) => {
383
+ const externalTools = buildExternalToolComponents();
307
384
  if (options.specVersion === 1.4) {
308
385
  return [
309
386
  {
@@ -311,6 +388,11 @@ export const addToolsSection = (options, context = {}) => {
311
388
  name: "cdxgen",
312
389
  version: CDXGEN_VERSION,
313
390
  },
391
+ ...newExecutedTools([], externalTools).map((tool) =>
392
+ tool.version
393
+ ? { name: tool.name, version: tool.version }
394
+ : { name: tool.name },
395
+ ),
314
396
  ];
315
397
  }
316
398
  let components = [];
@@ -331,6 +413,7 @@ export const addToolsSection = (options, context = {}) => {
331
413
  } else if (tools && Object.keys(tools).length && tools.components) {
332
414
  components = components.concat(tools.components);
333
415
  }
416
+ components = components.concat(newExecutedTools(components, externalTools));
334
417
  const cdxToolComponent = {
335
418
  group: CDXGEN_TOOL_GROUP,
336
419
  name: CDXGEN_TOOL_NAME,
@@ -524,7 +607,13 @@ export function addMetadata(parentComponent = {}, options = {}, context = {}) {
524
607
  // We cannot use purl or bom-ref here since they would not match
525
608
  // purl - could have application on one side and a different type
526
609
  // bom-ref could have qualifiers on one side
527
- if (fullName !== parentFullName) {
610
+ // A purl subpath marks a separate project that declares the
611
+ // parent's coordinates, such as a second Maven project or a Gradle
612
+ // subproject with the same group, name and version.
613
+ const separateProject =
614
+ comp.purl?.includes("#") &&
615
+ comp.purl.split("#")[1] !== parentComponent.purl?.split("#")[1];
616
+ if (fullName !== parentFullName || separateProject) {
528
617
  if (!comp["bom-ref"]) {
529
618
  comp["bom-ref"] = `pkg:${comp.type}/${decodeURIComponent(
530
619
  fullName,
package/lib/cli/index.js CHANGED
@@ -50,6 +50,7 @@ import {
50
50
  buildDependencyTrackBomRequest,
51
51
  getDependencyTrackBomApiUrl,
52
52
  } from "../helpers/remote/dependency-track.js";
53
+ import { collectObomIdeInventory } from "../helpers/vsixutils.js";
53
54
  import { optionIncludesAiInventoryProjectType } from "../inventory/aiInventory.js";
54
55
  import { readApkInstalledDb } from "../inventory/apkInstalledDb.js";
55
56
  import { isCycloneDxComponentTypeEnabled } from "../inventory/bomUtils.js";
@@ -70,16 +71,28 @@ import {
70
71
  hasHbomProjectType,
71
72
  } from "../inventory/hbom.js";
72
73
  import { mergeHostInventoryBoms } from "../inventory/hostTopology.js";
74
+ import { probeHostNode } from "../inventory/nodeHostProbe.js";
75
+ import { markOsInstalledLanguagePackages } from "../inventory/osPackageResolver.js";
73
76
  import { orderParentCandidates } from "../inventory/parentSelection.js";
74
77
  import { probeHostPhp } from "../inventory/phpHostProbe.js";
75
78
  // Imported directly rather than through the utils.js barrel: purl validity is
76
79
  // checked in a hot path and the barrel is already the root of several import
77
80
  // cycles.
78
81
  import { applyPurl, ociPurl } from "../inventory/purl.js";
82
+ import {
83
+ deriveOsPackagedRubyRuntimes,
84
+ linkDefaultGemsToRuntimes,
85
+ } from "../inventory/rubyBuildInfo.js";
86
+ import { probeHostRuby } from "../inventory/rubyHostProbe.js";
79
87
  import { table } from "../inventory/table.js";
80
88
 
81
89
  export { summarizeAiInventory } from "../inventory/aiInventory.js";
82
90
 
91
+ import { probeHostRubyGems } from "../ecosystems/gemHostProbe.js";
92
+ import {
93
+ mergeHostPythonEnvironmentPackages,
94
+ probeHostPythonEnvironments,
95
+ } from "../ecosystems/venvProbe.js";
83
96
  import {
84
97
  enrichOSComponentsWithTrustData,
85
98
  executeOsQuery,
@@ -240,6 +253,28 @@ switch (_platform()) {
240
253
  break;
241
254
  }
242
255
 
256
+ /**
257
+ * Home directories whose editor extension folders an OBOM reads: every user's
258
+ * home from osquery when cdxgen runs as root, and otherwise the current
259
+ * user's, which is the only one it can read.
260
+ *
261
+ * @returns {string[]} Home directories
262
+ */
263
+ function obomUserHomes() {
264
+ const ownHome = homedir();
265
+ if (typeof process.getuid !== "function" || process.getuid() !== 0) {
266
+ return [ownHome];
267
+ }
268
+ const homes = new Set([ownHome]);
269
+ for (const row of executeOsQuery("SELECT directory FROM users;") || []) {
270
+ const dir = row?.directory;
271
+ if (typeof dir === "string" && dir.startsWith("/") && safeExistsSync(dir)) {
272
+ homes.add(dir);
273
+ }
274
+ }
275
+ return [...homes];
276
+ }
277
+
243
278
  /**
244
279
  * Function to create obom string for the current OS using osquery
245
280
  *
@@ -247,7 +282,7 @@ switch (_platform()) {
247
282
  * @param {Object} options Parse options from the cli
248
283
  * @returns {Promise<Object>} Promise resolving to BOM object
249
284
  */
250
- export function createOSBom(_path, options) {
285
+ export async function createOSBom(_path, options) {
251
286
  console.warn(
252
287
  "About to generate OBOM for the current OS installation. This will take several minutes ...",
253
288
  );
@@ -309,6 +344,53 @@ export function createOSBom(_path, options) {
309
344
  if (hostPhp.components.length) {
310
345
  pkgList = pkgList.concat(hostPhp.components);
311
346
  }
347
+ // Nor a Node.js from a release tarball or a version manager, or the Brotli
348
+ // decoder compiled into it.
349
+ const hostNode = probeHostNode({
350
+ executeOsQuery,
351
+ packageComponents: pkgList,
352
+ });
353
+ if (hostNode.components.length) {
354
+ pkgList = pkgList.concat(hostNode.components);
355
+ }
356
+ // Nor a Ruby from ruby-build, a version manager or a toolcache tarball.
357
+ const hostRuby = probeHostRuby({
358
+ executeOsQuery,
359
+ packageComponents: pkgList,
360
+ });
361
+ if (hostRuby.components.length) {
362
+ pkgList = pkgList.concat(hostRuby.components);
363
+ }
364
+ // A Ruby a package manager installed is also named by its upstream version.
365
+ pkgList = pkgList.concat(deriveOsPackagedRubyRuntimes(pkgList));
366
+ // osquery has no table for RubyGems; the gems of the host's gem homes are
367
+ // read from their specifications.
368
+ const hostGems = await probeHostRubyGems({
369
+ executeOsQuery,
370
+ packageComponents: pkgList,
371
+ });
372
+ if (hostGems.length) {
373
+ const knownRefs = new Set(pkgList.map((component) => component["bom-ref"]));
374
+ pkgList = pkgList.concat(
375
+ hostGems.filter((gem) => !knownRefs.has(gem["bom-ref"])),
376
+ );
377
+ }
378
+ // osquery reads the interpreter's own site-packages; packages installed into
379
+ // a virtual environment or a pyenv interpreter are read from their METADATA.
380
+ pkgList = mergeHostPythonEnvironmentPackages(
381
+ pkgList,
382
+ probeHostPythonEnvironments(),
383
+ );
384
+ // osquery reads the extension registry of a fixed list of editors; the
385
+ // editors themselves, and the extensions of the others, come from the
386
+ // extension folders. A root scan reads every user's home, as osquery does.
387
+ try {
388
+ pkgList = pkgList.concat(
389
+ collectObomIdeInventory(pkgList, { homes: obomUserHomes() }),
390
+ );
391
+ } catch (err) {
392
+ thoughtLog(`Unable to read the editor extension folders: ${err.message}`);
393
+ }
312
394
  const hostTrustInventory = enrichOSComponentsWithTrustData(pkgList);
313
395
  if (hostTrustInventory?.components?.length) {
314
396
  pkgList = hostTrustInventory.components;
@@ -777,6 +859,7 @@ export async function createMultiXBom(pathList, options) {
777
859
  let metadataProperties = [];
778
860
  let parentComponent = determineParentComponent(options) || {};
779
861
  let parentSubComponents = [];
862
+ let osFileOwners;
780
863
  const setProjectTypeActivityContext = (projectType, sourcePath) => {
781
864
  setActivityContext({
782
865
  projectType,
@@ -797,6 +880,8 @@ export async function createMultiXBom(pathList, options) {
797
880
  const {
798
881
  osPackages,
799
882
  osPackageFiles,
883
+ nativeExtensionFiles,
884
+ ownerByPath,
800
885
  dependenciesList,
801
886
  allTypes,
802
887
  bundledSdks,
@@ -811,6 +896,7 @@ export async function createMultiXBom(pathList, options) {
811
896
  options.exportData?.inspectData?.Config,
812
897
  options,
813
898
  );
899
+ osFileOwners = ownerByPath;
814
900
  osPhase.succeed(
815
901
  summarizeCounts([
816
902
  [osPackages.length, "OS package", "OS packages"],
@@ -859,6 +945,7 @@ export async function createMultiXBom(pathList, options) {
859
945
  components = components.concat(osPackageFiles || []);
860
946
  components = components.concat(executables);
861
947
  components = components.concat(sharedLibs);
948
+ components = components.concat(nativeExtensionFiles || []);
862
949
  if (dependenciesList?.length) {
863
950
  dependencies = mergeDependencies(dependencies, dependenciesList);
864
951
  }
@@ -1975,6 +2062,26 @@ export async function createMultiXBom(pathList, options) {
1975
2062
  dependencies,
1976
2063
  metadataProperties,
1977
2064
  );
2065
+ // Language packages an OS package installed are judged by that package.
2066
+ // Duplicates have merged by now, so a component found both where the distro
2067
+ // put it and where pip did is seen whole and left unmarked.
2068
+ markOsInstalledLanguagePackages(
2069
+ multiResult.bomJson?.components,
2070
+ osFileOwners,
2071
+ options.allLayersExplodedDir,
2072
+ );
2073
+ // The default gems of an unpackaged Ruby, such as resolv in a Docker
2074
+ // Official image, ship with that Ruby and are updated by its releases.
2075
+ const defaultGemEdges = linkDefaultGemsToRuntimes(
2076
+ multiResult.bomJson?.components,
2077
+ options.allLayersExplodedDir,
2078
+ );
2079
+ if (defaultGemEdges.length && multiResult.bomJson) {
2080
+ multiResult.bomJson.dependencies = mergeDependencies(
2081
+ multiResult.bomJson.dependencies || [],
2082
+ defaultGemEdges,
2083
+ );
2084
+ }
1978
2085
  if (formulationList.length) {
1979
2086
  multiResult.formulationList = formulationList;
1980
2087
  }