@cdxgen/cdxgen 13.0.1 → 13.2.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 (286) hide show
  1. package/README.md +30 -16
  2. package/bin/audit.js +6 -0
  3. package/bin/cdxgen.js +141 -7
  4. package/bin/evinse.js +3 -1
  5. package/data/component-tags.json +8 -1
  6. package/data/crypto-oid.json +88 -12
  7. package/data/frameworks-list.json +86 -1
  8. package/data/remediations.json +1167 -0
  9. package/data/rules/ai-bom.yaml +78 -0
  10. package/data/rules/asar-archives.yaml +1 -1
  11. package/data/rules/build-fidelity.yaml +782 -0
  12. package/data/rules/cargo-rust.yaml +132 -0
  13. package/data/rules/mcp-servers.yaml +122 -0
  14. package/data/rules/package-integrity.yaml +13 -13
  15. package/lib/audit/index.js +48 -4
  16. package/lib/audit/scoring.js +2 -8
  17. package/lib/audit/targets.js +6 -1
  18. package/lib/cli/bomAssembly.js +32 -1
  19. package/lib/cli/cliOptions.js +94 -7
  20. package/lib/cli/index.js +268 -49
  21. package/lib/cli/jsBom.js +91 -5
  22. package/lib/cli/jvmBom.js +1515 -1314
  23. package/lib/cli/managedBom.js +249 -28
  24. package/lib/cli/nativeBom.js +986 -10
  25. package/lib/core/activity.js +120 -2
  26. package/lib/core/buildLedger.js +799 -0
  27. package/lib/core/deferredExit.js +141 -0
  28. package/lib/core/env.js +108 -2
  29. package/lib/core/fs.js +60 -0
  30. package/lib/core/logger.js +12 -99
  31. package/lib/core/severity.js +16 -0
  32. package/lib/core/syncFileWriter.js +106 -0
  33. package/lib/core/userAgent.js +151 -0
  34. package/lib/ecosystems/cargoCache.js +364 -0
  35. package/lib/ecosystems/caxa.js +13 -5
  36. package/lib/ecosystems/cppEvidence.js +40 -2
  37. package/lib/ecosystems/ecosystems.js +250 -91
  38. package/lib/ecosystems/golem.js +11 -1
  39. package/lib/ecosystems/gradleutils.js +498 -17
  40. package/lib/ecosystems/kosi.js +1256 -0
  41. package/lib/ecosystems/parsers-crystal.js +179 -0
  42. package/lib/ecosystems/parsers-dotnet.js +69 -39
  43. package/lib/ecosystems/parsers-elm.js +816 -0
  44. package/lib/ecosystems/parsers-gleam.js +1 -1
  45. package/lib/ecosystems/parsers-js.js +26 -0
  46. package/lib/ecosystems/parsers-julia.js +268 -0
  47. package/lib/ecosystems/parsers-jvm.js +9 -0
  48. package/lib/ecosystems/parsers-lua.js +218 -0
  49. package/lib/ecosystems/parsers-misc.js +188 -2
  50. package/lib/ecosystems/parsers-nim.js +221 -0
  51. package/lib/ecosystems/parsers-opam.js +180 -0
  52. package/lib/ecosystems/parsers-perl.js +277 -0
  53. package/lib/ecosystems/parsers-python.js +172 -36
  54. package/lib/ecosystems/parsers-r.js +148 -0
  55. package/lib/ecosystems/parsers-rebar.js +411 -0
  56. package/lib/ecosystems/parsers-rust.js +944 -19
  57. package/lib/ecosystems/parsers-spack.js +204 -0
  58. package/lib/ecosystems/parsers-stack.js +264 -0
  59. package/lib/ecosystems/parsers-terraform.js +194 -0
  60. package/lib/ecosystems/pypiClassifiers.js +326 -0
  61. package/lib/ecosystems/pythonutils.js +49 -1
  62. package/lib/ecosystems/rubyutils.js +13 -0
  63. package/lib/ecosystems/rusi.js +126 -6
  64. package/lib/evinser/evinser.js +141 -13
  65. package/lib/helpers/agenticToolutils.js +925 -0
  66. package/lib/helpers/remote/dependency-track.js +81 -14
  67. package/lib/inventory/agentFormulationParser.js +57 -4
  68. package/lib/inventory/aiCollector.js +504 -10
  69. package/lib/inventory/aiInventory.js +12 -0
  70. package/lib/inventory/analyzer.js +488 -30
  71. package/lib/inventory/astWorker.js +6 -0
  72. package/lib/inventory/auditCategories.js +17 -0
  73. package/lib/inventory/cbomutils.js +30 -0
  74. package/lib/inventory/cdxrs.js +7 -2
  75. package/lib/inventory/communityAiConfigParser.js +215 -2
  76. package/lib/inventory/depsUtils.js +72 -0
  77. package/lib/inventory/dosai.js +508 -22
  78. package/lib/inventory/envcontext.js +215 -24
  79. package/lib/inventory/evidenceUtils.js +13 -0
  80. package/lib/inventory/fetchBatch.js +131 -2
  81. package/lib/inventory/fetchRate.js +74 -11
  82. package/lib/inventory/forgeEnricher.js +3 -2
  83. package/lib/inventory/jvmToolEnv.js +594 -0
  84. package/lib/inventory/mcpConfigParser.js +166 -2
  85. package/lib/inventory/mcpDiscovery.js +11 -0
  86. package/lib/inventory/mcpServerManifest.js +389 -0
  87. package/lib/inventory/mcpbBundle.js +419 -0
  88. package/lib/inventory/osinfo.js +1 -0
  89. package/lib/inventory/plugins.js +3 -0
  90. package/lib/inventory/protobom.js +54 -88
  91. package/lib/inventory/protobomLoader.js +4 -0
  92. package/lib/inventory/rustFormulationParser.js +1 -1
  93. package/lib/inventory/source.js +10 -4
  94. package/lib/inventory/stylePackageRefs.js +41 -0
  95. package/lib/inventory/svelteUtils.js +524 -0
  96. package/lib/inventory/toolRequirements.js +903 -0
  97. package/lib/managers/binary.js +24 -0
  98. package/lib/managers/docker.js +26 -5
  99. package/lib/parsers/huggingfaceUtils.js +15 -7
  100. package/lib/parsers/onnx.js +294 -0
  101. package/lib/parsers/safetensors.js +114 -0
  102. package/lib/server/server.js +1 -1
  103. package/lib/stages/postgen/annotationBuilder.js +97 -0
  104. package/lib/stages/postgen/auditBom.js +76 -79
  105. package/lib/stages/postgen/introspection/annotate.js +320 -0
  106. package/lib/stages/postgen/introspection/commandFacts.js +293 -0
  107. package/lib/stages/postgen/introspection/emit.js +192 -0
  108. package/lib/stages/postgen/introspection/formulationEvidence.js +427 -0
  109. package/lib/stages/postgen/introspection/markers.js +250 -0
  110. package/lib/stages/postgen/introspection/reflect.js +1214 -0
  111. package/lib/stages/postgen/introspection/report.js +1208 -0
  112. package/lib/stages/postgen/introspection/score.js +1067 -0
  113. package/lib/stages/postgen/introspection/shapeCommand.js +304 -0
  114. package/lib/stages/postgen/parentEdge.js +156 -0
  115. package/lib/stages/postgen/postgen.js +284 -3
  116. package/lib/stages/postgen/ruleEngine.js +17 -0
  117. package/lib/stages/pregen/envAudit.js +42 -2
  118. package/lib/stages/pregen/pregen.js +1171 -6
  119. package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +462 -0
  120. package/lib/validator/bomValidator.js +11 -2
  121. package/package.json +26 -26
  122. package/types/lib/audit/index.d.ts.map +1 -1
  123. package/types/lib/audit/scoring.d.ts +2 -8
  124. package/types/lib/audit/scoring.d.ts.map +1 -1
  125. package/types/lib/audit/targets.d.ts.map +1 -1
  126. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  127. package/types/lib/cli/cliOptions.d.ts +2 -1
  128. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  129. package/types/lib/cli/index.d.ts +10 -2
  130. package/types/lib/cli/index.d.ts.map +1 -1
  131. package/types/lib/cli/jsBom.d.ts +23 -0
  132. package/types/lib/cli/jsBom.d.ts.map +1 -1
  133. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  134. package/types/lib/cli/managedBom.d.ts +33 -0
  135. package/types/lib/cli/managedBom.d.ts.map +1 -1
  136. package/types/lib/cli/nativeBom.d.ts +88 -8
  137. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  138. package/types/lib/core/activity.d.ts.map +1 -1
  139. package/types/lib/core/buildLedger.d.ts +272 -0
  140. package/types/lib/core/buildLedger.d.ts.map +1 -0
  141. package/types/lib/core/deferredExit.d.ts +84 -0
  142. package/types/lib/core/deferredExit.d.ts.map +1 -0
  143. package/types/lib/core/env.d.ts +43 -1
  144. package/types/lib/core/env.d.ts.map +1 -1
  145. package/types/lib/core/fs.d.ts +21 -0
  146. package/types/lib/core/fs.d.ts.map +1 -1
  147. package/types/lib/core/logger.d.ts +2 -11
  148. package/types/lib/core/logger.d.ts.map +1 -1
  149. package/types/lib/core/severity.d.ts +11 -0
  150. package/types/lib/core/severity.d.ts.map +1 -0
  151. package/types/lib/core/syncFileWriter.d.ts +33 -0
  152. package/types/lib/core/syncFileWriter.d.ts.map +1 -0
  153. package/types/lib/core/userAgent.d.ts +56 -0
  154. package/types/lib/core/userAgent.d.ts.map +1 -0
  155. package/types/lib/ecosystems/cargoCache.d.ts +75 -0
  156. package/types/lib/ecosystems/cargoCache.d.ts.map +1 -0
  157. package/types/lib/ecosystems/caxa.d.ts.map +1 -1
  158. package/types/lib/ecosystems/cppEvidence.d.ts +1 -1
  159. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  160. package/types/lib/ecosystems/ecosystems.d.ts +15 -1
  161. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  162. package/types/lib/ecosystems/gradleutils.d.ts +53 -0
  163. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  164. package/types/lib/ecosystems/kosi.d.ts +73 -0
  165. package/types/lib/ecosystems/kosi.d.ts.map +1 -0
  166. package/types/lib/ecosystems/parsers-crystal.d.ts +27 -0
  167. package/types/lib/ecosystems/parsers-crystal.d.ts.map +1 -0
  168. package/types/lib/ecosystems/parsers-dotnet.d.ts +19 -0
  169. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  170. package/types/lib/ecosystems/parsers-elm.d.ts +79 -0
  171. package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -0
  172. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  173. package/types/lib/ecosystems/parsers-julia.d.ts +57 -0
  174. package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -0
  175. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  176. package/types/lib/ecosystems/parsers-lua.d.ts +50 -0
  177. package/types/lib/ecosystems/parsers-lua.d.ts.map +1 -0
  178. package/types/lib/ecosystems/parsers-misc.d.ts +23 -0
  179. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  180. package/types/lib/ecosystems/parsers-nim.d.ts +43 -0
  181. package/types/lib/ecosystems/parsers-nim.d.ts.map +1 -0
  182. package/types/lib/ecosystems/parsers-opam.d.ts +31 -0
  183. package/types/lib/ecosystems/parsers-opam.d.ts.map +1 -0
  184. package/types/lib/ecosystems/parsers-perl.d.ts +36 -0
  185. package/types/lib/ecosystems/parsers-perl.d.ts.map +1 -0
  186. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  187. package/types/lib/ecosystems/parsers-r.d.ts +35 -0
  188. package/types/lib/ecosystems/parsers-r.d.ts.map +1 -0
  189. package/types/lib/ecosystems/parsers-rebar.d.ts +42 -0
  190. package/types/lib/ecosystems/parsers-rebar.d.ts.map +1 -0
  191. package/types/lib/ecosystems/parsers-rust.d.ts +199 -0
  192. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  193. package/types/lib/ecosystems/parsers-spack.d.ts +33 -0
  194. package/types/lib/ecosystems/parsers-spack.d.ts.map +1 -0
  195. package/types/lib/ecosystems/parsers-stack.d.ts +35 -0
  196. package/types/lib/ecosystems/parsers-stack.d.ts.map +1 -0
  197. package/types/lib/ecosystems/parsers-terraform.d.ts +34 -0
  198. package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -0
  199. package/types/lib/ecosystems/pypiClassifiers.d.ts +80 -0
  200. package/types/lib/ecosystems/pypiClassifiers.d.ts.map +1 -0
  201. package/types/lib/ecosystems/pythonutils.d.ts +21 -1
  202. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  203. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  204. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  205. package/types/lib/evinser/evinser.d.ts +34 -1
  206. package/types/lib/evinser/evinser.d.ts.map +1 -1
  207. package/types/lib/helpers/agenticToolutils.d.ts +87 -0
  208. package/types/lib/helpers/agenticToolutils.d.ts.map +1 -0
  209. package/types/lib/helpers/remote/dependency-track.d.ts +45 -4
  210. package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
  211. package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -1
  212. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  213. package/types/lib/inventory/aiInventory.d.ts.map +1 -1
  214. package/types/lib/inventory/analyzer.d.ts.map +1 -1
  215. package/types/lib/inventory/auditCategories.d.ts +12 -0
  216. package/types/lib/inventory/auditCategories.d.ts.map +1 -1
  217. package/types/lib/inventory/cbomutils.d.ts.map +1 -1
  218. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  219. package/types/lib/inventory/depsUtils.d.ts.map +1 -1
  220. package/types/lib/inventory/dosai.d.ts +43 -0
  221. package/types/lib/inventory/dosai.d.ts.map +1 -1
  222. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  223. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  224. package/types/lib/inventory/fetchBatch.d.ts +43 -0
  225. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  226. package/types/lib/inventory/fetchRate.d.ts +9 -6
  227. package/types/lib/inventory/fetchRate.d.ts.map +1 -1
  228. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
  229. package/types/lib/inventory/jvmToolEnv.d.ts +190 -0
  230. package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -0
  231. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  232. package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -1
  233. package/types/lib/inventory/mcpServerManifest.d.ts +19 -0
  234. package/types/lib/inventory/mcpServerManifest.d.ts.map +1 -0
  235. package/types/lib/inventory/mcpbBundle.d.ts +19 -0
  236. package/types/lib/inventory/mcpbBundle.d.ts.map +1 -0
  237. package/types/lib/inventory/osinfo.d.ts.map +1 -1
  238. package/types/lib/inventory/plugins.d.ts.map +1 -1
  239. package/types/lib/inventory/protobom.d.ts +18 -13
  240. package/types/lib/inventory/protobom.d.ts.map +1 -1
  241. package/types/lib/inventory/protobomLoader.d.ts.map +1 -1
  242. package/types/lib/inventory/source.d.ts.map +1 -1
  243. package/types/lib/inventory/stylePackageRefs.d.ts +17 -0
  244. package/types/lib/inventory/stylePackageRefs.d.ts.map +1 -0
  245. package/types/lib/inventory/svelteUtils.d.ts +124 -0
  246. package/types/lib/inventory/svelteUtils.d.ts.map +1 -0
  247. package/types/lib/inventory/toolRequirements.d.ts +216 -0
  248. package/types/lib/inventory/toolRequirements.d.ts.map +1 -0
  249. package/types/lib/managers/binary.d.ts.map +1 -1
  250. package/types/lib/managers/docker.d.ts.map +1 -1
  251. package/types/lib/parsers/huggingfaceUtils.d.ts +8 -1
  252. package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
  253. package/types/lib/parsers/onnx.d.ts +28 -0
  254. package/types/lib/parsers/onnx.d.ts.map +1 -0
  255. package/types/lib/parsers/safetensors.d.ts +22 -0
  256. package/types/lib/parsers/safetensors.d.ts.map +1 -0
  257. package/types/lib/stages/postgen/annotationBuilder.d.ts +53 -0
  258. package/types/lib/stages/postgen/annotationBuilder.d.ts.map +1 -0
  259. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
  260. package/types/lib/stages/postgen/introspection/annotate.d.ts +81 -0
  261. package/types/lib/stages/postgen/introspection/annotate.d.ts.map +1 -0
  262. package/types/lib/stages/postgen/introspection/commandFacts.d.ts +32 -0
  263. package/types/lib/stages/postgen/introspection/commandFacts.d.ts.map +1 -0
  264. package/types/lib/stages/postgen/introspection/emit.d.ts +71 -0
  265. package/types/lib/stages/postgen/introspection/emit.d.ts.map +1 -0
  266. package/types/lib/stages/postgen/introspection/formulationEvidence.d.ts +154 -0
  267. package/types/lib/stages/postgen/introspection/formulationEvidence.d.ts.map +1 -0
  268. package/types/lib/stages/postgen/introspection/markers.d.ts +58 -0
  269. package/types/lib/stages/postgen/introspection/markers.d.ts.map +1 -0
  270. package/types/lib/stages/postgen/introspection/reflect.d.ts +77 -0
  271. package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -0
  272. package/types/lib/stages/postgen/introspection/report.d.ts +85 -0
  273. package/types/lib/stages/postgen/introspection/report.d.ts.map +1 -0
  274. package/types/lib/stages/postgen/introspection/score.d.ts +149 -0
  275. package/types/lib/stages/postgen/introspection/score.d.ts.map +1 -0
  276. package/types/lib/stages/postgen/introspection/shapeCommand.d.ts +79 -0
  277. package/types/lib/stages/postgen/introspection/shapeCommand.d.ts.map +1 -0
  278. package/types/lib/stages/postgen/parentEdge.d.ts +35 -0
  279. package/types/lib/stages/postgen/parentEdge.d.ts.map +1 -0
  280. package/types/lib/stages/postgen/postgen.d.ts +35 -2
  281. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  282. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  283. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  284. package/types/lib/stages/pregen/pregen.d.ts +131 -0
  285. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  286. package/types/lib/validator/bomValidator.d.ts.map +1 -1
@@ -25,6 +25,15 @@ import {
25
25
  getGradleCommand,
26
26
  getMavenCommand,
27
27
  } from "../ecosystems/gradleutils.js";
28
+ import {
29
+ analyzeKosiProject,
30
+ collectKosiApiEndpoints,
31
+ collectKosiEvidence,
32
+ collectKosiServices,
33
+ isKosiKotlinLanguage,
34
+ kosiWorkspaceComponent,
35
+ mergeKosiEvidence,
36
+ } from "../ecosystems/kosi.js";
28
37
  import {
29
38
  analyzeRusiProject,
30
39
  collectRusiEvidence,
@@ -42,12 +51,16 @@ import {
42
51
  import { collectMvnDependencies } from "../inventory/deps.js";
43
52
  import { mergeServices } from "../inventory/depsUtils.js";
44
53
  import {
54
+ applyDosaiReachabilityEvidence,
55
+ collectDosaiAiComponents,
45
56
  collectDosaiDataFlowFrames,
46
57
  collectDosaiPurlEvidence,
58
+ collectDosaiServiceComponents,
47
59
  collectDosaiServicesFromMethods,
48
60
  createDosaiDataFlowSlice,
49
61
  createDosaiMethodsSlice,
50
62
  isDosaiDotnetLanguage,
63
+ normalizeDosaiServiceMap,
51
64
  persistDosaiSemanticsReport,
52
65
  } from "../inventory/dosai.js";
53
66
  import { parseOccurrenceEvidenceLocation } from "../inventory/evidenceUtils.js";
@@ -613,8 +626,13 @@ export function initFromSbom(components, language) {
613
626
  });
614
627
  }
615
628
  if (comp.evidence.occurrences) {
629
+ // Keep the `location#line` shape so a re-run over a cdxgen BOM does not
630
+ // degrade seeded occurrences to file-only entries and duplicate the
631
+ // richer locations the fresh slice merge adds to the same set.
616
632
  purlLocationMap[comp.purl] = new Set(
617
- comp.evidence.occurrences.map((v) => v.location),
633
+ comp.evidence.occurrences.map((v) =>
634
+ v.line ? `${v.location}#${v.line}` : v.location,
635
+ ),
618
636
  );
619
637
  }
620
638
  }
@@ -662,6 +680,7 @@ export async function analyzeProject(dbObjMap, options) {
662
680
  const bomJson = JSON.parse(fs.readFileSync(bomFile, "utf8"));
663
681
  const components = bomJson.components || [];
664
682
  let cryptoComponents = [];
683
+ let aiComponents = [];
665
684
  let cryptoGeneratePurls = {};
666
685
  let openapiSpecFile;
667
686
  // Load any existing purl-location information from the sbom.
@@ -720,6 +739,84 @@ export async function analyzeProject(dbObjMap, options) {
720
739
  };
721
740
  }
722
741
 
742
+ if (isKosiKotlinLanguage(language)) {
743
+ const kosiReports = analyzeKosiProject(dirPath, options);
744
+ if (kosiReports?.report && Object.keys(kosiReports.report).length) {
745
+ // The workspace component: cdxgen's Kotlin BOM carries no project
746
+ // component, so every workspace-anchored slice (reachability, the
747
+ // app's own flows) would have nothing to attach to. createEvinseFile
748
+ // re-reads the BOM from disk, so the candidate rides the artefacts
749
+ // instead of a mutation here — applied when the BOM lacks a project
750
+ // component OR carries one with no purl: every kosi evidence join is
751
+ // keyed by purl, so a purl-less component anchors nothing and is, for
752
+ // this purpose, no anchor at all (found on the sample app: Gradle
753
+ // identity with empty group and version "latest" emits no purl, and
754
+ // the reachableFromRoots/cryptoFlow evidence silently attached to
755
+ // nothing while the dependency-joined kinds landed).
756
+ const metadataComponentHasPurl = Boolean(
757
+ bomJson.metadata?.component?.purl,
758
+ );
759
+ let workspaceComponent;
760
+ if (!metadataComponentHasPurl) {
761
+ // kosi's modules[] holds the project's OWN Gradle/Maven modules
762
+ // (dependencies never appear there), so the project component is
763
+ // its root: the shortest modulePath, ties broken by name so the
764
+ // choice is deterministic. `workspaceMember` is not the selector —
765
+ // it is a String naming the owning workspace member in kosi's
766
+ // schema, empty for a single-module build and then omitted from the
767
+ // JSON entirely, so testing it against `undefined` picked nothing
768
+ // on exactly the single-module projects this fallback exists for.
769
+ const workspaceModule = (kosiReports.report.modules || [])
770
+ .filter((candidate) => candidate?.purl)
771
+ .sort(
772
+ (a, b) =>
773
+ (a.modulePath || "").length - (b.modulePath || "").length ||
774
+ (a.name || "").localeCompare(b.name || ""),
775
+ )[0];
776
+ if (workspaceModule?.purl) {
777
+ workspaceComponent = kosiWorkspaceComponent(workspaceModule);
778
+ }
779
+ }
780
+ const analysisComponents = [
781
+ bomJson.metadata?.component,
782
+ workspaceComponent,
783
+ ...components,
784
+ ].filter(Boolean);
785
+ const kosiEvidence = collectKosiEvidence(
786
+ kosiReports.report,
787
+ analysisComponents,
788
+ );
789
+ mergeKosiEvidence(
790
+ kosiEvidence,
791
+ collectKosiEvidence(
792
+ kosiReports.reachableReport || {},
793
+ analysisComponents,
794
+ ),
795
+ );
796
+ servicesMap = collectKosiServices(kosiReports.report, servicesMap);
797
+ // The INBOUND surface: the routes the app serves, with the
798
+ // authentication kosi found declared on them.
799
+ servicesMap = collectKosiApiEndpoints(kosiReports.report, servicesMap);
800
+ return {
801
+ purlLocationMap: kosiEvidence.purlLocationMap,
802
+ dataFlowFrames: kosiEvidence.dataFlowFrames,
803
+ componentPropertiesMap: kosiEvidence.componentPropertiesMap,
804
+ metadataProperties: kosiEvidence.metadataProperties,
805
+ cryptoComponents: kosiEvidence.cryptoComponents,
806
+ cryptoGeneratePurls: kosiEvidence.cryptoGeneratePurls,
807
+ servicesMap,
808
+ userDefinedTypesMap,
809
+ workspaceComponent,
810
+ };
811
+ }
812
+ return {
813
+ purlLocationMap,
814
+ servicesMap,
815
+ dataFlowFrames,
816
+ userDefinedTypesMap,
817
+ };
818
+ }
819
+
723
820
  if (isDosaiDotnetLanguage(language)) {
724
821
  if (options.profile === "research") {
725
822
  options.withDataFlow = true;
@@ -742,6 +839,10 @@ export async function analyzeProject(dbObjMap, options) {
742
839
  }
743
840
  if (usageSlice && Object.keys(usageSlice).length) {
744
841
  const dosaiEvidence = collectDosaiPurlEvidence(usageSlice, components);
842
+ // Confidence/evidence facts ride along as properties so an unbuilt tree (Low
843
+ // confidence, unresolved evidence) stays distinguishable from an only-imported
844
+ // package in the emitted BOM.
845
+ applyDosaiReachabilityEvidence(usageSlice, components);
745
846
  for (const [purl, locations] of Object.entries(
746
847
  dosaiEvidence.purlLocationMap,
747
848
  )) {
@@ -750,6 +851,13 @@ export async function analyzeProject(dbObjMap, options) {
750
851
  purlLocationMap[purl].add(location);
751
852
  }
752
853
  }
854
+ // Rich Services[] inventory first (bom-refs, trust zones, data); endpoint
855
+ // derivation fills any services the providers did not emit.
856
+ // AI components must be carried out of analyzeProject explicitly. Mutating the local
857
+ // `components` array here had no effect: the return below omits it and createEvinseFile
858
+ // re-reads the BOM from disk, so the whole AI-BOM contribution was silently discarded.
859
+ collectDosaiAiComponents(usageSlice, aiComponents);
860
+ servicesMap = collectDosaiServiceComponents(usageSlice, servicesMap);
753
861
  servicesMap = collectDosaiServicesFromMethods(usageSlice, servicesMap);
754
862
  userDefinedTypesMap = {};
755
863
  }
@@ -802,6 +910,7 @@ export async function analyzeProject(dbObjMap, options) {
802
910
  tempDirOwned: retMap?.tempDirOwned,
803
911
  userDefinedTypesMap,
804
912
  cryptoComponents,
913
+ aiComponents,
805
914
  cryptoGeneratePurls,
806
915
  };
807
916
  }
@@ -832,6 +941,7 @@ export async function analyzeProject(dbObjMap, options) {
832
941
  const retMap = collectReachableFrames(language, reachablesSlice);
833
942
  dataFlowFrames = retMap.dataFlowFrames;
834
943
  cryptoComponents = retMap.cryptoComponents;
944
+ aiComponents = retMap.aiComponents || [];
835
945
  cryptoGeneratePurls = retMap.cryptoGeneratePurls;
836
946
  }
837
947
  // Reuse existing usages slices
@@ -960,6 +1070,7 @@ export async function analyzeProject(dbObjMap, options) {
960
1070
  tempDirOwned: retMap?.tempDirOwned,
961
1071
  userDefinedTypesMap,
962
1072
  cryptoComponents,
1073
+ aiComponents,
963
1074
  cryptoGeneratePurls,
964
1075
  openapiSpecFile,
965
1076
  };
@@ -1804,7 +1915,7 @@ export function extractEndpoints(language, code) {
1804
1915
  * @param {Object} options Command line options
1805
1916
  * @returns
1806
1917
  */
1807
- export function createEvinseFile(sliceArtefacts, options) {
1918
+ export async function createEvinseFile(sliceArtefacts, options) {
1808
1919
  const {
1809
1920
  tempDir,
1810
1921
  tempDirOwned,
@@ -1817,7 +1928,9 @@ export function createEvinseFile(sliceArtefacts, options) {
1817
1928
  componentPropertiesMap = {},
1818
1929
  metadataProperties = [],
1819
1930
  cryptoComponents,
1931
+ aiComponents,
1820
1932
  cryptoGeneratePurls,
1933
+ workspaceComponent,
1821
1934
  } = sliceArtefacts;
1822
1935
  const bomFile = options.input;
1823
1936
  const evinseOutFile = options.output;
@@ -1825,6 +1938,18 @@ export function createEvinseFile(sliceArtefacts, options) {
1825
1938
  const components = bomJson.components || [];
1826
1939
  // Clear existing annotations
1827
1940
  bomJson.annotations = [];
1941
+ if (workspaceComponent && !bomJson.metadata?.component?.purl) {
1942
+ if (bomJson.metadata?.component) {
1943
+ // A purl-less project component: keep cdxgen's own identity fields
1944
+ // and supply the purl kosi's module discovery published, so the
1945
+ // evidence loop below can anchor workspace evidence to it.
1946
+ bomJson.metadata.component.purl = workspaceComponent.purl;
1947
+ bomJson.metadata.component["bom-ref"] ??= workspaceComponent.purl;
1948
+ } else {
1949
+ bomJson.metadata ??= {};
1950
+ bomJson.metadata.component = workspaceComponent;
1951
+ }
1952
+ }
1828
1953
  appendComponentProperties(bomJson.metadata?.component, metadataProperties);
1829
1954
  let occEvidencePresent = false;
1830
1955
  let csEvidencePresent = false;
@@ -1873,16 +1998,12 @@ export function createEvinseFile(sliceArtefacts, options) {
1873
1998
  }
1874
1999
  } // for
1875
2000
  if (servicesMap && Object.keys(servicesMap).length) {
1876
- const services = [];
1877
- for (const serviceName of Object.keys(servicesMap)) {
1878
- services.push({
1879
- name: serviceName,
1880
- endpoints: Array.from(servicesMap[serviceName].endpoints),
1881
- authenticated: servicesMap[serviceName].authenticated,
1882
- "x-trust-boundary": servicesMap[serviceName].xTrustBoundary,
1883
- properties: servicesMap[serviceName].properties,
1884
- });
1885
- }
2001
+ // normalizeDosaiServiceMap is the single mapping from the internal service
2002
+ // definitions to CycloneDX services[]. The OpenAPI/Java/Python detectors set
2003
+ // the camelCase `xTrustBoundary` while dosai's provider inventory (schema
2004
+ // 4.0.0) carries stable bom-refs, trust zones, data classifications, and
2005
+ // evidence occurrences; both shapes flow through the same normalizer.
2006
+ const services = normalizeDosaiServiceMap(servicesMap);
1886
2007
  // Add to existing services while preserving CycloneDX uniqueItems validity
1887
2008
  bomJson.services = mergeServices(bomJson.services || [], services);
1888
2009
  servicesPresent = true;
@@ -1891,6 +2012,10 @@ export function createEvinseFile(sliceArtefacts, options) {
1891
2012
  if (cryptoComponents?.length) {
1892
2013
  bomJson.components = bomJson.components.concat(cryptoComponents);
1893
2014
  }
2015
+ // Add the AI components (machine-learning-model, dataset) discovered by dosai
2016
+ if (aiComponents?.length) {
2017
+ bomJson.components = bomJson.components.concat(aiComponents);
2018
+ }
1894
2019
  // Fix the dependencies section with provides information
1895
2020
  if (
1896
2021
  cryptoGeneratePurls &&
@@ -1943,7 +2068,10 @@ export function createEvinseFile(sliceArtefacts, options) {
1943
2068
  // Redo post-processing with evinse data. `executeOsQuery` has to be injected
1944
2069
  // because postgen no longer imports it directly (stages is below managers);
1945
2070
  // without it the crypto formulation path receives `undefined` and throws.
1946
- const bomNSData = postProcess({ bomJson }, { ...options, executeOsQuery });
2071
+ const bomNSData = await postProcess(
2072
+ { bomJson },
2073
+ { ...options, executeOsQuery },
2074
+ );
1947
2075
  safeWriteSync(
1948
2076
  evinseOutFile,
1949
2077
  JSON.stringify(bomNSData.bomJson, null, options.jsonPretty ? 2 : null),