@cdxgen/cdxgen 13.6.0 → 13.7.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 (264) hide show
  1. package/README.md +15 -8
  2. package/bin/audit.js +7 -4
  3. package/bin/cdxgen.js +256 -37
  4. package/bin/convert.js +146 -22
  5. package/bin/evinse.js +25 -3
  6. package/bin/repl.js +47 -3
  7. package/bin/sign.js +211 -34
  8. package/bin/tracebom.js +18 -6
  9. package/bin/validate.js +18 -3
  10. package/bin/verify.js +113 -5
  11. package/data/behavior-taxonomy.schema.json +1491 -0
  12. package/data/cyclonedx-2.0-bundled.schema.json +18606 -5528
  13. package/data/cyclonedx-2.0-cryptography-defs.schema.json +857 -0
  14. package/data/pqc-migration.json +239 -0
  15. package/data/remediations.json +52 -0
  16. package/data/rules/cbom-security.yaml +4 -3
  17. package/data/rules/package-integrity.yaml +28 -0
  18. package/lib/audit/index.js +25 -3
  19. package/lib/cli/bomAssembly.js +80 -1
  20. package/lib/cli/cliOptions.js +121 -17
  21. package/lib/cli/index.js +609 -898
  22. package/lib/cli/jsBom.js +3 -0
  23. package/lib/cli/jvmBom.js +365 -40
  24. package/lib/cli/managedBom.js +19 -3
  25. package/lib/cli/nativeBom.js +10 -0
  26. package/lib/core/env.js +26 -0
  27. package/lib/core/fs.js +126 -3
  28. package/lib/core/globPatterns.js +218 -0
  29. package/lib/core/processTree.js +99 -12
  30. package/lib/core/projectConfig.js +332 -25
  31. package/lib/core/toolRegistry.js +15 -1
  32. package/lib/ecosystems/denoutils.js +2 -2
  33. package/lib/ecosystems/golem.js +3 -8
  34. package/lib/ecosystems/gradleutils.js +1082 -6
  35. package/lib/ecosystems/jsEvidence.js +90 -38
  36. package/lib/ecosystems/kosi.js +3 -5
  37. package/lib/ecosystems/npmVersionResolution.js +376 -0
  38. package/lib/ecosystems/parsers-python.js +89 -28
  39. package/lib/ecosystems/parsers-rust.js +117 -15
  40. package/lib/ecosystems/remote/huggingface.js +22 -0
  41. package/lib/ecosystems/rusi.js +2 -4
  42. package/lib/ecosystems/scalasem.js +2 -1
  43. package/lib/evinser/evinser.js +196 -34
  44. package/lib/evinser/scalasem.js +5 -1
  45. package/lib/helpers/agenticToolutils.js +112 -1
  46. package/lib/helpers/bomSigner.js +43 -9
  47. package/lib/helpers/jssSigner.js +1276 -0
  48. package/lib/inventory/agentBlueprint.js +193 -0
  49. package/lib/inventory/agentToolNames.js +145 -0
  50. package/lib/inventory/aiCollector.js +153 -7
  51. package/lib/inventory/aiInventory.js +44 -8
  52. package/lib/inventory/aiProviders.js +324 -0
  53. package/lib/inventory/bomUtils.js +8 -1
  54. package/lib/inventory/ciParsers/githubActionsLock.js +821 -0
  55. package/lib/inventory/citations.js +31 -2
  56. package/lib/inventory/communityAiConfigParser.js +978 -80
  57. package/lib/inventory/cyclonedx20.js +152 -0
  58. package/lib/inventory/cyclonedx20Common.js +286 -0
  59. package/lib/inventory/cyclonedx20Derived.js +159 -0
  60. package/lib/inventory/cyclonedx20Parties.js +552 -0
  61. package/lib/inventory/cyclonedx20Read.js +768 -0
  62. package/lib/inventory/cyclonedx20ReadCommon.js +374 -0
  63. package/lib/inventory/cyclonedx20ReadComponents.js +692 -0
  64. package/lib/inventory/cyclonedx20ReadContext.js +380 -0
  65. package/lib/inventory/cyclonedx20ReadEvidence.js +466 -0
  66. package/lib/inventory/cyclonedx20ReadSections.js +599 -0
  67. package/lib/inventory/cyclonedx20Render.js +766 -0
  68. package/lib/inventory/cyclonedx20RenderComponents.js +716 -0
  69. package/lib/inventory/cyclonedx20RenderDefinitions.js +405 -0
  70. package/lib/inventory/cyclonedx20RenderEvidence.js +726 -0
  71. package/lib/inventory/cyclonedx20RenderHardware.js +203 -0
  72. package/lib/inventory/cyclonedx20RenderPatents.js +174 -0
  73. package/lib/inventory/cyclonedx20RenderRefIds.js +314 -0
  74. package/lib/inventory/cyclonedx20RenderSections.js +499 -0
  75. package/lib/inventory/cyclonedx20Tables.js +594 -0
  76. package/lib/inventory/deps.js +106 -13
  77. package/lib/inventory/dosai.js +236 -1
  78. package/lib/inventory/dosaiParsers.js +3 -6
  79. package/lib/inventory/dotnetRuntime.js +164 -14
  80. package/lib/inventory/ecosystemFormulationParsers.js +979 -0
  81. package/lib/inventory/envcontext.js +132 -38
  82. package/lib/inventory/evidenceUtils.js +2 -1
  83. package/lib/inventory/formulationParsers.js +95 -13
  84. package/lib/inventory/hbom.js +45 -6
  85. package/lib/inventory/hbomLoader.js +166 -0
  86. package/lib/inventory/mcpConfigParser.js +5 -0
  87. package/lib/inventory/occurrenceKey.js +90 -0
  88. package/lib/inventory/pqcMigration.js +426 -0
  89. package/lib/inventory/rustFormulationParser.js +21 -10
  90. package/lib/inventory/source.js +65 -6
  91. package/lib/parsers/huggingfaceManifest.js +9 -1
  92. package/lib/parsers/huggingfaceUtils.js +18 -0
  93. package/lib/parsers/kiroPermissions.js +166 -0
  94. package/lib/server/server.js +36 -34
  95. package/lib/stages/postgen/postgen.js +41 -1
  96. package/lib/stages/postgen/specVersionCompat.js +76 -0
  97. package/lib/validator/bomValidator.js +8 -1
  98. package/lib/validator/complianceEngine.js +30 -3
  99. package/lib/validator/complianceRules.js +1416 -4
  100. package/lib/validator/generated/validate-2.0.mjs +57554 -13851
  101. package/lib/validator/index.js +48 -7
  102. package/lib/validator/reporters/json.js +6 -0
  103. package/package.json +9 -9
  104. package/types/bin/repl.d.ts.map +1 -1
  105. package/types/lib/audit/index.d.ts +6 -2
  106. package/types/lib/audit/index.d.ts.map +1 -1
  107. package/types/lib/cli/bomAssembly.d.ts +16 -0
  108. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  109. package/types/lib/cli/cliOptions.d.ts +6 -0
  110. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  111. package/types/lib/cli/index.d.ts.map +1 -1
  112. package/types/lib/cli/jsBom.d.ts +2 -1
  113. package/types/lib/cli/jsBom.d.ts.map +1 -1
  114. package/types/lib/cli/jvmBom.d.ts +15 -0
  115. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  116. package/types/lib/cli/managedBom.d.ts.map +1 -1
  117. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  118. package/types/lib/core/boundedFile.d.ts +30 -0
  119. package/types/lib/core/boundedFile.d.ts.map +1 -1
  120. package/types/lib/core/env.d.ts +10 -0
  121. package/types/lib/core/env.d.ts.map +1 -1
  122. package/types/lib/core/fs.d.ts +4 -0
  123. package/types/lib/core/fs.d.ts.map +1 -1
  124. package/types/lib/core/globPatterns.d.ts +70 -0
  125. package/types/lib/core/globPatterns.d.ts.map +1 -0
  126. package/types/lib/core/paths.d.ts +9 -0
  127. package/types/lib/core/paths.d.ts.map +1 -1
  128. package/types/lib/core/processTree.d.ts +16 -5
  129. package/types/lib/core/processTree.d.ts.map +1 -1
  130. package/types/lib/core/projectConfig.d.ts +47 -8
  131. package/types/lib/core/projectConfig.d.ts.map +1 -1
  132. package/types/lib/core/toolRegistry.d.ts.map +1 -1
  133. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  134. package/types/lib/ecosystems/gradleutils.d.ts +248 -8
  135. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  136. package/types/lib/ecosystems/jsEvidence.d.ts +14 -1
  137. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  138. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  139. package/types/lib/ecosystems/npmVersionResolution.d.ts +119 -0
  140. package/types/lib/ecosystems/npmVersionResolution.d.ts.map +1 -0
  141. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  142. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  143. package/types/lib/ecosystems/pythonutils.d.ts +1 -1
  144. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  145. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  146. package/types/lib/ecosystems/scalasem.d.ts +58 -16
  147. package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
  148. package/types/lib/evinser/evinser.d.ts +61 -9
  149. package/types/lib/evinser/evinser.d.ts.map +1 -1
  150. package/types/lib/evinser/scalasem.d.ts.map +1 -1
  151. package/types/lib/helpers/agenticToolutils.d.ts +53 -19
  152. package/types/lib/helpers/agenticToolutils.d.ts.map +1 -1
  153. package/types/lib/helpers/bomSigner.d.ts +20 -3
  154. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  155. package/types/lib/helpers/jssSigner.d.ts +288 -0
  156. package/types/lib/helpers/jssSigner.d.ts.map +1 -0
  157. package/types/lib/helpers/vsixutils.d.ts +303 -19
  158. package/types/lib/helpers/vsixutils.d.ts.map +1 -1
  159. package/types/lib/inventory/agentBlueprint.d.ts +70 -0
  160. package/types/lib/inventory/agentBlueprint.d.ts.map +1 -0
  161. package/types/lib/inventory/agentToolNames.d.ts +51 -0
  162. package/types/lib/inventory/agentToolNames.d.ts.map +1 -0
  163. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  164. package/types/lib/inventory/aiInventory.d.ts.map +1 -1
  165. package/types/lib/inventory/aiProviders.d.ts +85 -0
  166. package/types/lib/inventory/aiProviders.d.ts.map +1 -0
  167. package/types/lib/inventory/bomUtils.d.ts.map +1 -1
  168. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts +101 -0
  169. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts.map +1 -0
  170. package/types/lib/inventory/citations.d.ts +5 -0
  171. package/types/lib/inventory/citations.d.ts.map +1 -1
  172. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  173. package/types/lib/inventory/cyclonedx20.d.ts +99 -0
  174. package/types/lib/inventory/cyclonedx20.d.ts.map +1 -0
  175. package/types/lib/inventory/cyclonedx20Common.d.ts +102 -0
  176. package/types/lib/inventory/cyclonedx20Common.d.ts.map +1 -0
  177. package/types/lib/inventory/cyclonedx20Derived.d.ts +74 -0
  178. package/types/lib/inventory/cyclonedx20Derived.d.ts.map +1 -0
  179. package/types/lib/inventory/cyclonedx20Parties.d.ts +91 -0
  180. package/types/lib/inventory/cyclonedx20Parties.d.ts.map +1 -0
  181. package/types/lib/inventory/cyclonedx20Read.d.ts +51 -0
  182. package/types/lib/inventory/cyclonedx20Read.d.ts.map +1 -0
  183. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts +69 -0
  184. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts.map +1 -0
  185. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts +77 -0
  186. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts.map +1 -0
  187. package/types/lib/inventory/cyclonedx20ReadContext.d.ts +118 -0
  188. package/types/lib/inventory/cyclonedx20ReadContext.d.ts.map +1 -0
  189. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts +40 -0
  190. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts.map +1 -0
  191. package/types/lib/inventory/cyclonedx20ReadSections.d.ts +45 -0
  192. package/types/lib/inventory/cyclonedx20ReadSections.d.ts.map +1 -0
  193. package/types/lib/inventory/cyclonedx20Render.d.ts +53 -0
  194. package/types/lib/inventory/cyclonedx20Render.d.ts.map +1 -0
  195. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts +73 -0
  196. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts.map +1 -0
  197. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts +29 -0
  198. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts.map +1 -0
  199. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts +110 -0
  200. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts.map +1 -0
  201. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts +42 -0
  202. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts.map +1 -0
  203. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts +26 -0
  204. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts.map +1 -0
  205. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts +55 -0
  206. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts.map +1 -0
  207. package/types/lib/inventory/cyclonedx20RenderSections.d.ts +45 -0
  208. package/types/lib/inventory/cyclonedx20RenderSections.d.ts.map +1 -0
  209. package/types/lib/inventory/cyclonedx20Tables.d.ts +134 -0
  210. package/types/lib/inventory/cyclonedx20Tables.d.ts.map +1 -0
  211. package/types/lib/inventory/deps.d.ts +35 -2
  212. package/types/lib/inventory/deps.d.ts.map +1 -1
  213. package/types/lib/inventory/dosai.d.ts +19 -0
  214. package/types/lib/inventory/dosai.d.ts.map +1 -1
  215. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  216. package/types/lib/inventory/dotnetRuntime.d.ts +51 -4
  217. package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -1
  218. package/types/lib/inventory/ecosystemFormulationParsers.d.ts +73 -0
  219. package/types/lib/inventory/ecosystemFormulationParsers.d.ts.map +1 -0
  220. package/types/lib/inventory/envcontext.d.ts +22 -6
  221. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  222. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  223. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  224. package/types/lib/inventory/hbom.d.ts +11 -0
  225. package/types/lib/inventory/hbom.d.ts.map +1 -1
  226. package/types/lib/inventory/hbomLoader.d.ts +54 -0
  227. package/types/lib/inventory/hbomLoader.d.ts.map +1 -1
  228. package/types/lib/inventory/jvmLocalRepos.d.ts +5 -1
  229. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -1
  230. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  231. package/types/lib/inventory/occurrenceKey.d.ts +52 -0
  232. package/types/lib/inventory/occurrenceKey.d.ts.map +1 -0
  233. package/types/lib/inventory/pqcMigration.d.ts +84 -0
  234. package/types/lib/inventory/pqcMigration.d.ts.map +1 -0
  235. package/types/lib/inventory/rustFormulationParser.d.ts +7 -2
  236. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  237. package/types/lib/inventory/scalaCoords.d.ts.map +1 -1
  238. package/types/lib/inventory/scalaDedupe.d.ts +43 -0
  239. package/types/lib/inventory/scalaDedupe.d.ts.map +1 -0
  240. package/types/lib/inventory/source.d.ts +15 -0
  241. package/types/lib/inventory/source.d.ts.map +1 -1
  242. package/types/lib/parsers/huggingfaceManifest.d.ts +10 -1
  243. package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -1
  244. package/types/lib/parsers/huggingfaceUtils.d.ts +12 -0
  245. package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
  246. package/types/lib/parsers/kiroPermissions.d.ts +62 -0
  247. package/types/lib/parsers/kiroPermissions.d.ts.map +1 -0
  248. package/types/lib/parsers/vscodeExtensionId.d.ts +48 -0
  249. package/types/lib/parsers/vscodeExtensionId.d.ts.map +1 -0
  250. package/types/lib/server/server.d.ts.map +1 -1
  251. package/types/lib/stages/postgen/postgen.d.ts +7 -0
  252. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  253. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  254. package/types/lib/stages/postgen/specVersionCompat.d.ts +25 -0
  255. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  256. package/types/lib/validator/bomValidator.d.ts +5 -1
  257. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  258. package/types/lib/validator/complianceEngine.d.ts +4 -4
  259. package/types/lib/validator/complianceEngine.d.ts.map +1 -1
  260. package/types/lib/validator/complianceRules.d.ts +14 -2
  261. package/types/lib/validator/complianceRules.d.ts.map +1 -1
  262. package/types/lib/validator/index.d.ts +10 -0
  263. package/types/lib/validator/index.d.ts.map +1 -1
  264. package/types/lib/validator/reporters/json.d.ts.map +1 -1
@@ -43,6 +43,7 @@ const AI_INVENTORY_FILE_KINDS = new Set([
43
43
  "agent-config",
44
44
  "agent-definition",
45
45
  "agent-instructions",
46
+ "agent-spec",
46
47
  "ai-agent-file",
47
48
  "copilot-instructions",
48
49
  "copilot-setup-workflow",
@@ -52,6 +53,10 @@ const AI_INVENTORY_FILE_KINDS = new Set([
52
53
  "custom-command",
53
54
  "custom-tool",
54
55
  "graph-definition",
56
+ "hook-file",
57
+ "permission-policy",
58
+ "settings",
59
+ "workflow-file",
55
60
  AI_SKILL_FILE_KIND,
56
61
  ]);
57
62
 
@@ -80,6 +85,11 @@ const AI_INVENTORY_PARSERS = [
80
85
  id: communityAiConfigParser.id,
81
86
  parser: communityAiConfigParser,
82
87
  types: ["ai-skill"],
88
+ // The community agent configurations (.kiro, .cursor/rules,
89
+ // .claude/agents, and similar) also belong in an AI-BOM next to the
90
+ // models and services, so `-t ai` runs this parser and keeps its
91
+ // ai-skill components.
92
+ aiOverlay: true,
83
93
  },
84
94
  ];
85
95
 
@@ -301,8 +311,23 @@ export function collectAiInventory(discoveryPath, options, types) {
301
311
  let components = [];
302
312
  const dependencies = [];
303
313
  let services = [];
314
+ // Output of an aiOverlay parser that runs only because `-t ai` was
315
+ // requested. It is filtered with ai-skill added to the requested types, and
316
+ // kept apart so the extra type never widens the filter for other parsers
317
+ // or the language collectors. `--exclude-type ai-skill` turns it off.
318
+ const overlayTypes = uniqueNonEmptyTypes([...requestedTypes, "ai-skill"]);
319
+ const overlayEnabled =
320
+ requestedTypes.includes("ai") &&
321
+ !requestedTypes.includes("ai-skill") &&
322
+ !optionIncludesAiInventoryProjectType(options?.excludeType, "ai-skill");
323
+ let overlayComponents = [];
324
+ let overlayServices = [];
304
325
  for (const parserEntry of AI_INVENTORY_PARSERS) {
305
- if (!parserEntry.types.some((type) => requestedTypes.includes(type))) {
326
+ const requested = parserEntry.types.some((type) =>
327
+ requestedTypes.includes(type),
328
+ );
329
+ const isOverlay = !requested && overlayEnabled && parserEntry.aiOverlay;
330
+ if (!requested && !isOverlay) {
306
331
  continue;
307
332
  }
308
333
  const matchedFiles = [];
@@ -326,11 +351,20 @@ export function collectAiInventory(discoveryPath, options, types) {
326
351
  );
327
352
  continue;
328
353
  }
329
- if (result?.components?.length) {
330
- components = components.concat(result.components);
331
- }
332
- if (result?.services?.length) {
333
- services = mergeServices(services, result.services);
354
+ if (isOverlay) {
355
+ overlayComponents = overlayComponents.concat(
356
+ filterInventorySubjectsByTypes(result?.components, overlayTypes),
357
+ );
358
+ overlayServices = overlayServices.concat(
359
+ filterInventorySubjectsByTypes(result?.services, overlayTypes),
360
+ );
361
+ } else {
362
+ if (result?.components?.length) {
363
+ components = components.concat(result.components);
364
+ }
365
+ if (result?.services?.length) {
366
+ services = mergeServices(services, result.services);
367
+ }
334
368
  }
335
369
  if (result?.dependencies?.length) {
336
370
  dependencies.push(...result.dependencies);
@@ -365,11 +399,13 @@ export function collectAiInventory(discoveryPath, options, types) {
365
399
  }
366
400
 
367
401
  components = trimComponents(
368
- filterInventorySubjectsByTypes(components, requestedTypes),
402
+ filterInventorySubjectsByTypes(components, requestedTypes).concat(
403
+ overlayComponents,
404
+ ),
369
405
  );
370
406
  services = mergeServices(
371
- [],
372
407
  filterInventorySubjectsByTypes(services, requestedTypes),
408
+ overlayServices,
373
409
  );
374
410
  return {
375
411
  components,
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Organisations that create AI models, keyed by the short creator id cdxgen
3
+ * uses internally. The value is the full organisation name written to the
4
+ * `manufacturer` of a model component, since the minimum elements guidance
5
+ * asks for full names rather than acronyms or product names.
6
+ */
7
+ export const MODEL_CREATOR_NAMES = new Map([
8
+ ["alibaba", "Alibaba Cloud"],
9
+ ["anthropic", "Anthropic"],
10
+ ["cohere", "Cohere"],
11
+ ["deepseek", "DeepSeek"],
12
+ ["google", "Google"],
13
+ ["meta", "Meta"],
14
+ ["mistral", "Mistral AI"],
15
+ ["openai", "OpenAI"],
16
+ ["xai", "xAI"],
17
+ ["zhipu", "Zhipu AI"],
18
+ ]);
19
+
20
+ /**
21
+ * Providers that are a creator's own SDK or API, mapped to that creator.
22
+ * Hosting, routing and local providers such as groq, together, fireworks,
23
+ * openrouter, replicate, aws-bedrock, azure-openai, vertex-ai, huggingface
24
+ * and ollama serve models other organisations made, so they are absent.
25
+ */
26
+ const CREATOR_OWN_PROVIDERS = new Map([
27
+ ["anthropic", "anthropic"],
28
+ ["cohere", "cohere"],
29
+ ["dashscope", "alibaba"],
30
+ ["deepseek", "deepseek"],
31
+ ["gemini", "google"],
32
+ ["google", "google"],
33
+ ["meta", "meta"],
34
+ ["mistral", "mistral"],
35
+ ["openai", "openai"],
36
+ ["xai", "xai"],
37
+ ["zhipu", "zhipu"],
38
+ ]);
39
+
40
+ // Creators whose own API serves only the models they made, so any model
41
+ // called through that API is theirs even when its name is not recognised.
42
+ // OpenAI-compatible clients, Google (Vertex Model Garden) and DashScope also
43
+ // serve models from other creators, so they are not in this set.
44
+ const SINGLE_CATALOGUE_CREATORS = new Set([
45
+ "anthropic",
46
+ "cohere",
47
+ "deepseek",
48
+ "mistral",
49
+ "xai",
50
+ "zhipu",
51
+ ]);
52
+
53
+ /**
54
+ * Local runtimes and inference servers. They serve whatever tag or served
55
+ * model name the user chose, so a model they run names no creator.
56
+ */
57
+ export const LOCAL_MODEL_RUNTIMES = new Set([
58
+ "gpt4all",
59
+ "jan",
60
+ "llama.cpp",
61
+ "llamafile",
62
+ "lm-studio",
63
+ "local",
64
+ "local-inference",
65
+ "mlc",
66
+ "ollama",
67
+ "vllm",
68
+ "xinference",
69
+ ]);
70
+
71
+ // Provider prefixes of model routes such as the litellm `groq/llama3-8b`
72
+ // form, mapped to the provider the route names. Matching is case-sensitive
73
+ // because the routes are lowercase while some Hugging Face organisations
74
+ // share the name in another case (Groq, Anthropic, Cohere). Prefixes that are
75
+ // also real lowercase Hub organisations (openai, google, databricks,
76
+ // cerebras, huggingface) are left out.
77
+ const MODEL_ROUTE_PROVIDERS = new Map([
78
+ ["anthropic", "anthropic"],
79
+ ["azure", "azure-openai"],
80
+ ["azure_ai", "azure-ai"],
81
+ ["bedrock", "aws-bedrock"],
82
+ ["codestral", "mistral"],
83
+ ["cohere", "cohere"],
84
+ ["cohere_chat", "cohere"],
85
+ ["dashscope", "dashscope"],
86
+ ["deepseek", "deepseek"],
87
+ ["fireworks_ai", "fireworks"],
88
+ ["friendliai", "friendliai"],
89
+ ["gemini", "gemini"],
90
+ ["groq", "groq"],
91
+ ["hosted_vllm", "vllm"],
92
+ ["llamafile", "llamafile"],
93
+ ["lm_studio", "lm-studio"],
94
+ ["mistral", "mistral"],
95
+ ["moonshot", "moonshot"],
96
+ ["nvidia_nim", "nvidia-nim"],
97
+ ["ollama", "ollama"],
98
+ ["ollama_chat", "ollama"],
99
+ ["openrouter", "openrouter"],
100
+ ["perplexity", "perplexity"],
101
+ ["replicate", "replicate"],
102
+ ["sagemaker", "aws-sagemaker"],
103
+ ["sambanova", "sambanova"],
104
+ ["together_ai", "together"],
105
+ ["vertex_ai", "vertex-ai"],
106
+ ["watsonx", "watsonx"],
107
+ ["xai", "xai"],
108
+ ["xinference", "xinference"],
109
+ ]);
110
+
111
+ // Google API resource collections that hold a model name, as in
112
+ // `models/gemini-1.5-flash` or `tunedModels/my-model`.
113
+ const GOOGLE_MODEL_COLLECTIONS = new Set(["models", "tunedModels"]);
114
+
115
+ // Model name prefixes that only one creator publishes under. A prefix, not a
116
+ // substring, so a community fine-tune such as openhermes-2.5-mistral-7b is
117
+ // not credited to Mistral AI. The OpenAI entries name its model lines,
118
+ // because a bare gpt prefix also covers open-weight families from other
119
+ // creators (gpt-j, gpt-neo, gpt-neox, gpt-sw3, gpt4all).
120
+ const MODEL_NAME_CREATOR_PREFIXES = [
121
+ ["chatgpt", "openai"],
122
+ ["claude", "anthropic"],
123
+ ["codestral", "mistral"],
124
+ ["command-r", "cohere"],
125
+ ["dall-e", "openai"],
126
+ ["deepseek", "deepseek"],
127
+ ["gemini", "google"],
128
+ ["gemma", "google"],
129
+ ["glm", "zhipu"],
130
+ ["gpt-3", "openai"],
131
+ ["gpt-4", "openai"],
132
+ ["gpt-5", "openai"],
133
+ ["gpt-audio", "openai"],
134
+ ["gpt-image", "openai"],
135
+ ["gpt-oss", "openai"],
136
+ ["gpt-realtime", "openai"],
137
+ ["gpt2", "openai"],
138
+ ["grok", "xai"],
139
+ ["llama", "meta"],
140
+ ["meta-llama", "meta"],
141
+ ["mistral", "mistral"],
142
+ ["mixtral", "mistral"],
143
+ ["qwen", "alibaba"],
144
+ ["text-embedding-3", "openai"],
145
+ ["text-embedding-ada", "openai"],
146
+ ];
147
+
148
+ // Spellings of a creator's name, compared after lowercasing and dropping
149
+ // everything but letters and digits. They cover the creator ids, the full
150
+ // names, the creators' own Hugging Face organisations and the way GGUF
151
+ // converters write general.organization ("Meta Llama", "Mistralai").
152
+ const MODEL_CREATOR_ALIASES = new Map([
153
+ ["alibaba", "alibaba"],
154
+ ["alibabacloud", "alibaba"],
155
+ ["qwen", "alibaba"],
156
+ ["anthropic", "anthropic"],
157
+ ["cohere", "cohere"],
158
+ ["cohereforai", "cohere"],
159
+ ["coherelabs", "cohere"],
160
+ ["deepseek", "deepseek"],
161
+ ["deepseekai", "deepseek"],
162
+ ["google", "google"],
163
+ ["googledeepmind", "google"],
164
+ ["facebook", "meta"],
165
+ ["meta", "meta"],
166
+ ["metallama", "meta"],
167
+ ["mistral", "mistral"],
168
+ ["mistralai", "mistral"],
169
+ ["openai", "openai"],
170
+ ["xai", "xai"],
171
+ ["xaiorg", "xai"],
172
+ ["thudm", "zhipu"],
173
+ ["zaiorg", "zhipu"],
174
+ ["zhipu", "zhipu"],
175
+ ["zhipuai", "zhipu"],
176
+ ]);
177
+
178
+ const normalizeProviderId = (provider) =>
179
+ typeof provider === "string" ? provider.trim().toLowerCase() : "";
180
+
181
+ const aliasKey = (value) =>
182
+ String(value || "")
183
+ .toLowerCase()
184
+ .replace(/[^a-z0-9]/gu, "");
185
+
186
+ /**
187
+ * Split a model reference written in source code into the route provider it
188
+ * names, if any, and the model name a creator lookup should read.
189
+ *
190
+ * `groq/llama3-8b-8192` names the groq route and the model `llama3-8b-8192`.
191
+ * `models/gemini-1.5-flash`, `tunedModels/x` and
192
+ * `projects/p/locations/l/publishers/google/models/gemini-1.5-pro` are Google
193
+ * API resource names, and the model is the part after the last `models`
194
+ * segment. Neither form is a Hugging Face repository id.
195
+ *
196
+ * @param {string} modelId Model reference as written in the source
197
+ * @returns {{ name: string, nonHub: boolean, route?: string, routeProvider?: string }}
198
+ * The model name, whether the reference is not a Hub repository id, and the
199
+ * route and its provider when one is named
200
+ */
201
+ export function splitModelReference(modelId) {
202
+ const value = String(modelId || "").trim();
203
+ const segments = value.split("/");
204
+ if (segments.length < 2 || segments.some((segment) => !segment)) {
205
+ return { name: value, nonHub: false };
206
+ }
207
+ if (GOOGLE_MODEL_COLLECTIONS.has(segments[0])) {
208
+ return { name: segments.slice(1).join("/"), nonHub: true };
209
+ }
210
+ const publishersIndex = segments.indexOf("publishers");
211
+ const modelsIndex = segments.lastIndexOf("models");
212
+ if (publishersIndex >= 0 && modelsIndex > publishersIndex) {
213
+ return { name: segments.slice(modelsIndex + 1).join("/"), nonHub: true };
214
+ }
215
+ const routeProvider = MODEL_ROUTE_PROVIDERS.get(segments[0]);
216
+ if (routeProvider) {
217
+ return {
218
+ name: segments.slice(1).join("/"),
219
+ nonHub: true,
220
+ route: segments[0],
221
+ routeProvider,
222
+ };
223
+ }
224
+ return { name: value, nonHub: false };
225
+ }
226
+
227
+ /**
228
+ * Name the creator of a model from its name alone, when only one creator
229
+ * publishes under that name.
230
+ *
231
+ * @param {string} modelName Model name without route or namespace
232
+ * @returns {string|undefined} Creator id
233
+ */
234
+ export function modelCreatorFromName(modelName) {
235
+ const normalized = String(modelName || "")
236
+ .trim()
237
+ .toLowerCase();
238
+ for (const [prefix, creator] of MODEL_NAME_CREATOR_PREFIXES) {
239
+ if (normalized.startsWith(prefix)) {
240
+ return creator;
241
+ }
242
+ }
243
+ return /^o[134](?:$|[-:])/u.test(normalized) ? "openai" : undefined;
244
+ }
245
+
246
+ /**
247
+ * Resolve a creator spelling, such as a Hugging Face organisation or a
248
+ * GGUF general.organization value, to a known creator id.
249
+ *
250
+ * @param {string} name Organisation name or namespace
251
+ * @returns {string|undefined} Creator id, or undefined when unknown
252
+ */
253
+ export function modelCreatorFromOrganization(name) {
254
+ return MODEL_CREATOR_ALIASES.get(aliasKey(name));
255
+ }
256
+
257
+ /**
258
+ * Pick the creator of a model that source code calls by name.
259
+ *
260
+ * The provider of such a model is the SDK, AI host or route the code uses,
261
+ * which names the client rather than the model: the openai SDK is the usual
262
+ * client for self-hosted Llama or DeepSeek servers, and a file may use
263
+ * several SDKs. So the creator is the one the model name names, when the
264
+ * provider is that creator, is a hosting or routing service, or the file
265
+ * also uses the creator's own SDK or host. A different creator's SDK leaves
266
+ * it unset. A model name that names no creator is credited only to a
267
+ * provider whose own API serves nothing but its own models. A local runtime
268
+ * serves whatever tag the user created, so it names no creator, and neither
269
+ * does a file that only uses a local runtime.
270
+ *
271
+ * @param {string} modelId Model reference as written in the source
272
+ * @param {{ provider?: string, fileProviders?: Iterable<string>, runtimes?: Iterable<string> }} [context]
273
+ * The provider the code declares through an SDK import, AI host or dosai
274
+ * report (never a guess from the model name), every provider the file
275
+ * references, and the runtimes it uses
276
+ * @returns {string|undefined} Creator id
277
+ */
278
+ export function resolveModelCreator(modelId, context = {}) {
279
+ const reference = splitModelReference(modelId);
280
+ const provider = normalizeProviderId(
281
+ reference.routeProvider || context.provider,
282
+ );
283
+ if (LOCAL_MODEL_RUNTIMES.has(provider)) {
284
+ return undefined;
285
+ }
286
+ if (
287
+ !provider &&
288
+ [...(context.runtimes || [])].some((runtime) =>
289
+ LOCAL_MODEL_RUNTIMES.has(normalizeProviderId(runtime)),
290
+ )
291
+ ) {
292
+ return undefined;
293
+ }
294
+ const nameCreator = modelCreatorFromName(reference.name);
295
+ const providerCreator = CREATOR_OWN_PROVIDERS.get(provider);
296
+ if (!nameCreator) {
297
+ return SINGLE_CATALOGUE_CREATORS.has(providerCreator)
298
+ ? providerCreator
299
+ : undefined;
300
+ }
301
+ if (!providerCreator || providerCreator === nameCreator) {
302
+ return nameCreator;
303
+ }
304
+ for (const fileProvider of context.fileProviders || []) {
305
+ if (
306
+ CREATOR_OWN_PROVIDERS.get(normalizeProviderId(fileProvider)) ===
307
+ nameCreator
308
+ ) {
309
+ return nameCreator;
310
+ }
311
+ }
312
+ return undefined;
313
+ }
314
+
315
+ /**
316
+ * Build the CycloneDX organisational entity for a creator id.
317
+ *
318
+ * @param {string} creator Creator id
319
+ * @returns {{ name: string }|undefined} Manufacturer entity
320
+ */
321
+ export function modelCreatorEntity(creator) {
322
+ const name = MODEL_CREATOR_NAMES.get(creator);
323
+ return name ? { name } : undefined;
324
+ }
@@ -43,6 +43,13 @@ const COMPONENT_TYPES_1_5 = [
43
43
  "data",
44
44
  ];
45
45
  const COMPONENT_TYPES_1_6 = [...COMPONENT_TYPES_1_5, "cryptographic-asset"];
46
+ // CycloneDX 2.0 keeps every 1.6 type and turns services into components of
47
+ // type `service` (`#/$defs/cyclonedx-component-2.0/$defs/component/properties/type`),
48
+ // next to the new physical type `material`. The draft's enum, quoted:
49
+ // application, framework, library, container, platform, operating-system,
50
+ // device, device-driver, firmware, file, machine-learning-model, data,
51
+ // cryptographic-asset, material, service.
52
+ const COMPONENT_TYPES_2_0 = [...COMPONENT_TYPES_1_6, "material", "service"];
46
53
 
47
54
  /**
48
55
  * Frozen map of CycloneDX spec versions (as "major.minor" strings) to the
@@ -53,7 +60,7 @@ export const CYCLONEDX_COMPONENT_TYPES_BY_SPEC_VERSION = Object.freeze({
53
60
  1.5: Object.freeze(COMPONENT_TYPES_1_5),
54
61
  1.6: Object.freeze(COMPONENT_TYPES_1_6),
55
62
  1.7: Object.freeze(COMPONENT_TYPES_1_6),
56
- "2.0": Object.freeze(COMPONENT_TYPES_1_6),
63
+ "2.0": Object.freeze(COMPONENT_TYPES_2_0),
57
64
  });
58
65
 
59
66
  /**