@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
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Summarize Kiro CLI V3 permission documents into policy-safe posture facts.
3
+ *
4
+ * Kiro V3 describes what an agent may do with `capability`/`effect` rules that
5
+ * live in an agent definition's `permissions` object, in the user-scope
6
+ * `~/.kiro/settings/permissions.yaml`, and in the per-workspace
7
+ * `~/.kiro/workspace-roots/<hash>/permissions.yaml`. The rules carry `match`
8
+ * pattern lists, free-text reasons, and paths, none of which belong in a BOM.
9
+ * This module reduces a document to counts, allowlisted effect counts,
10
+ * validated capability names, and booleans, and never returns the patterns or
11
+ * any other free text.
12
+ */
13
+
14
+ // Effects documented at kiro.dev/docs/permissions. An unknown effect is
15
+ // counted by `ruleCount` alone and by no per-effect counter.
16
+ const KIRO_EFFECTS = new Set(["allow", "deny", "ask", "evaluate"]);
17
+
18
+ // Policy presets that may be listed under the top-level `policies` key.
19
+ // kiro.dev documents `approve-for-me`; other preset names are dropped rather
20
+ // than copied, because the full set is not documented.
21
+ const KIRO_POLICY_PRESET_ALLOWLIST = new Set(["approve-for-me"]);
22
+
23
+ // A capability is a short lowercase token such as `fs_read`, `shell`, or the
24
+ // meta-capability `all`. Anything outside this shape is dropped instead of
25
+ // being copied into the BOM.
26
+ const KIRO_CAPABILITY_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/u;
27
+
28
+ const isPlainEntry = (value) =>
29
+ value !== null && typeof value === "object" && !Array.isArray(value);
30
+
31
+ const sortedUnique = (values) => [...new Set(values)].sort();
32
+
33
+ /**
34
+ * Decide whether a rule's `match` list holds at least one non-empty pattern.
35
+ *
36
+ * @param {unknown} match The rule's match value
37
+ * @returns {boolean} True when a non-empty string pattern is present
38
+ */
39
+ const hasNonEmptyMatch = (match) =>
40
+ Array.isArray(match) &&
41
+ match.some((entry) => typeof entry === "string" && entry.trim() !== "");
42
+
43
+ /**
44
+ * Summarize a Kiro V3 permission document.
45
+ *
46
+ * Accepts the parsed `permissions` object of an agent definition or a parsed
47
+ * `permissions.yaml` document. A bare rules array is accepted as well. The
48
+ * result carries only counts, booleans, and validated token lists; `match`
49
+ * patterns, `exclude` lists, reasons, and paths are never returned.
50
+ *
51
+ * @param {Object|Array|undefined} rulesOrDoc Parsed permissions object, YAML
52
+ * document, or rules array
53
+ * @returns {{
54
+ * ruleCount: number,
55
+ * allowRuleCount: number,
56
+ * denyRuleCount: number,
57
+ * askRuleCount: number,
58
+ * evaluateRuleCount: number,
59
+ * capabilities: string[],
60
+ * allowsAllCapabilities: boolean,
61
+ * unrestrictedAllowCapabilities: string[],
62
+ * workspaceTrusted: boolean|undefined,
63
+ * policyPresets: string[],
64
+ * unknownPolicyPresetCount: number,
65
+ * }} Permission posture summary
66
+ */
67
+ export function summarizeKiroPermissions(rulesOrDoc) {
68
+ const doc = Array.isArray(rulesOrDoc) ? { rules: rulesOrDoc } : rulesOrDoc;
69
+ const rules = Array.isArray(doc?.rules) ? doc.rules : [];
70
+ let ruleCount = 0;
71
+ const effectCounts = { allow: 0, deny: 0, ask: 0, evaluate: 0 };
72
+ const capabilities = [];
73
+ const unrestrictedAllowCapabilities = [];
74
+ let allowsAllCapabilities = false;
75
+ for (const rule of rules) {
76
+ if (!isPlainEntry(rule)) {
77
+ continue;
78
+ }
79
+ ruleCount += 1;
80
+ if (typeof rule.effect === "string" && KIRO_EFFECTS.has(rule.effect)) {
81
+ effectCounts[rule.effect] += 1;
82
+ }
83
+ if (typeof rule.capability === "string") {
84
+ const capability = rule.capability;
85
+ if (KIRO_CAPABILITY_PATTERN.test(capability)) {
86
+ capabilities.push(capability);
87
+ if (rule.effect === "allow" && !hasNonEmptyMatch(rule.match)) {
88
+ unrestrictedAllowCapabilities.push(capability);
89
+ if (capability === "all") {
90
+ allowsAllCapabilities = true;
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ const listedPresets = Array.isArray(doc?.policies)
97
+ ? doc.policies.filter((entry) => typeof entry === "string")
98
+ : [];
99
+ // Preset names outside the allowlist are counted, never copied, so a
100
+ // reviewer still learns that an unrecognised preset is active.
101
+ const policyPresets = listedPresets.filter((entry) =>
102
+ KIRO_POLICY_PRESET_ALLOWLIST.has(entry),
103
+ );
104
+ const unknownPolicyPresetCount = new Set(
105
+ listedPresets.filter((entry) => !KIRO_POLICY_PRESET_ALLOWLIST.has(entry)),
106
+ ).size;
107
+ return {
108
+ allowRuleCount: effectCounts.allow,
109
+ allowsAllCapabilities,
110
+ askRuleCount: effectCounts.ask,
111
+ capabilities: sortedUnique(capabilities),
112
+ denyRuleCount: effectCounts.deny,
113
+ evaluateRuleCount: effectCounts.evaluate,
114
+ policyPresets: sortedUnique(policyPresets),
115
+ ruleCount,
116
+ unknownPolicyPresetCount,
117
+ unrestrictedAllowCapabilities: sortedUnique(unrestrictedAllowCapabilities),
118
+ ...(typeof doc?.workspaceTrusted === "boolean"
119
+ ? { workspaceTrusted: doc.workspaceTrusted }
120
+ : {}),
121
+ };
122
+ }
123
+
124
+ /**
125
+ * Flatten a permission summary into property suffix/value pairs.
126
+ *
127
+ * Both scans that consume Kiro permission documents emit the same suffixes;
128
+ * the host scan prefixes them with `cdx:agentic:` and the project scan with
129
+ * `cdx:agent:`. Values are numbers, booleans, or comma-separated validated
130
+ * tokens, so no free text reaches a BOM through this mapping.
131
+ *
132
+ * @param {ReturnType<summarizeKiroPermissions>} summary Permission posture summary
133
+ * @returns {Record<string, number|boolean|string>} Property suffix mapped to its value
134
+ */
135
+ export function kiroPermissionSummaryEntries(summary) {
136
+ const entries = {
137
+ permissionAllowRuleCount: summary.allowRuleCount,
138
+ permissionAllowsAll: Boolean(summary.allowsAllCapabilities),
139
+ permissionAskRuleCount: summary.askRuleCount,
140
+ permissionDenyRuleCount: summary.denyRuleCount,
141
+ permissionEvaluateRuleCount: summary.evaluateRuleCount,
142
+ permissionRuleCount: summary.ruleCount,
143
+ };
144
+ // An empty list carries no information, so the property is omitted instead
145
+ // of being emitted with an empty value.
146
+ for (const [suffix, list] of [
147
+ ["permissionCapabilities", summary.capabilities],
148
+ [
149
+ "permissionUnrestrictedAllowCapabilities",
150
+ summary.unrestrictedAllowCapabilities,
151
+ ],
152
+ ["permissionPolicyPresets", summary.policyPresets],
153
+ ]) {
154
+ if (list?.length) {
155
+ entries[suffix] = list.join(",");
156
+ }
157
+ }
158
+ if (summary.unknownPolicyPresetCount) {
159
+ entries.permissionUnknownPolicyPresetCount =
160
+ summary.unknownPolicyPresetCount;
161
+ }
162
+ if (typeof summary.workspaceTrusted === "boolean") {
163
+ entries.permissionWorkspaceTrusted = summary.workspaceTrusted;
164
+ }
165
+ return entries;
166
+ }
@@ -14,7 +14,12 @@ import {
14
14
  isSecureMode,
15
15
  readEnvironmentVariable,
16
16
  } from "../core/activity.js";
17
- import { PROJECT_TYPE_ALIASES } from "../core/env.js";
17
+ import { HOST_SCOPE_PROJECT_TYPES } from "../core/env.js";
18
+ import {
19
+ boundUntrustedGlobPatterns,
20
+ UNTRUSTED_GLOB_EXPANSION_BUDGET,
21
+ UNTRUSTED_GLOB_PATTERN_MAX_LENGTH,
22
+ } from "../core/globPatterns.js";
18
23
  import { isWin } from "../core/paths.js";
19
24
  import { isSecureModeActive } from "../core/projectTooling.js";
20
25
  import { resetRunState } from "../core/runState.js";
@@ -22,7 +27,11 @@ import { CDXGEN_VERSION } from "../core/state.js";
22
27
  import { installConsoleShim, ui } from "../core/ui.js";
23
28
  import { fetchPomXmlAsJson } from "../ecosystems/ecosystems.js";
24
29
  import { normalizeOutputFormats } from "../helpers/exportUtils.js";
25
- import { isCycloneDxBom } from "../inventory/bomUtils.js";
30
+ import {
31
+ isCycloneDx20SpecVersion,
32
+ isCycloneDxBom,
33
+ } from "../inventory/bomUtils.js";
34
+ import { DEPENDENCY_TRACK_CDX20_ERROR } from "../inventory/cyclonedx20.js";
26
35
  import {
27
36
  cleanupSourceDir,
28
37
  findGitRefForPurlVersion,
@@ -227,27 +236,6 @@ function restrictRequestOptions(options, operatorOptions) {
227
236
  }
228
237
  }
229
238
 
230
- // Project types that inventory the host the server runs on, such as installed
231
- // packages, users, shell history, IDE and browser extensions, or the Maven,
232
- // Gradle, sbt, Cargo and Helm caches in the server user's home directory.
233
- // They ignore the scan path, so the path allowlist does not limit them.
234
- const HOST_SCOPE_PROJECT_TYPES = new Set(
235
- [
236
- "os",
237
- "hbom",
238
- "cargo-cache",
239
- "helm-index",
240
- "gradle-index",
241
- "sbt-index",
242
- "maven-index",
243
- "vscode-extension",
244
- "chrome-extension",
245
- "agentic",
246
- ]
247
- .flatMap((key) => PROJECT_TYPE_ALIASES[key] || [key])
248
- .concat(["maven-repo"]),
249
- );
250
-
251
239
  /**
252
240
  * Check request options that the server must refuse outright.
253
241
  *
@@ -270,22 +258,18 @@ export function validateRequestOptions(reqOptions, operatorOptions = {}) {
270
258
  details: `The '${hostScopeType}' project type scans the server host. Start the server with this type to allow it.`,
271
259
  };
272
260
  }
273
- const excludes = Array.isArray(reqOptions.exclude)
274
- ? reqOptions.exclude
275
- : [reqOptions.exclude];
276
- // Brace patterns expand before matching, so one short pattern such as
277
- // {1..100000} can keep the server busy for minutes.
261
+ // Every exclude pattern is matched against every file the scan walks, and
262
+ // brace patterns expand before matching, so one short pattern such as
263
+ // {1..100000}, or a long enough list, can keep the server busy for minutes.
278
264
  if (
279
265
  reqOptions.exclude !== operatorOptions.exclude &&
280
- excludes.some(
281
- (e) => typeof e === "string" && (e.includes("{") || e.length > 512),
282
- )
266
+ boundUntrustedGlobPatterns(reqOptions.exclude, { allowBraces: false })
267
+ .refused.length
283
268
  ) {
284
269
  return {
285
270
  status: 400,
286
271
  error: "Invalid Exclude Pattern",
287
- details:
288
- "Exclude patterns sent to the server cannot use braces or exceed 512 characters.",
272
+ details: `Exclude patterns sent to the server cannot use braces, exceed ${UNTRUSTED_GLOB_PATTERN_MAX_LENGTH} characters, or number more than ${UNTRUSTED_GLOB_EXPANSION_BUDGET}.`,
289
273
  };
290
274
  }
291
275
  if (
@@ -333,6 +317,19 @@ export function validateRequestOptions(reqOptions, operatorOptions = {}) {
333
317
  "Formulation data may contain secrets and is not submitted to Dependency-Track in secure mode.",
334
318
  };
335
319
  }
320
+ // Dependency-Track ingests CycloneDX 1.x only, so a request that would
321
+ // upload (server URL plus API key) cannot ask for the 2.0 draft.
322
+ if (
323
+ reqOptions.serverUrl &&
324
+ reqOptions.apiKey &&
325
+ isCycloneDx20SpecVersion(reqOptions.specVersion)
326
+ ) {
327
+ return {
328
+ status: 400,
329
+ error: "Unsupported Spec Version For Dependency-Track",
330
+ details: DEPENDENCY_TRACK_CDX20_ERROR,
331
+ };
332
+ }
336
333
  return null;
337
334
  }
338
335
 
@@ -749,7 +746,12 @@ const start = (options) => {
749
746
  requestedFormats.includes("spdx") &&
750
747
  isCycloneDxBom(bomNSData?.bomJson)
751
748
  ) {
752
- responseBomJson = convertCycloneDxToSpdx(bomNSData.bomJson, reqOptions);
749
+ // The SPDX converter reads the 1.x shape; at 2.0 that is the
750
+ // internal model rather than the rendered document.
751
+ responseBomJson = convertCycloneDxToSpdx(
752
+ bomNSData.internalBomJson ?? bomNSData.bomJson,
753
+ reqOptions,
754
+ );
753
755
  }
754
756
  if (reqOptions.serverUrl && reqOptions.apiKey) {
755
757
  let serverHostname;
@@ -31,6 +31,7 @@ import {
31
31
  } from "../../inventory/aiInventory.js";
32
32
  import {
33
33
  DEFAULT_CDX_SPEC_VERSION,
34
+ isCycloneDx20SpecVersion,
34
35
  normalizeCycloneDxComponentTypeFilter,
35
36
  normalizeCycloneDxSpecVersion,
36
37
  } from "../../inventory/bomUtils.js";
@@ -40,8 +41,13 @@ import {
40
41
  createCitation,
41
42
  findCdxgenToolBomRef,
42
43
  } from "../../inventory/citations.js";
44
+ import {
45
+ CDX20_INTERNAL_SECTIONS_KEY,
46
+ renderCycloneDx20,
47
+ } from "../../inventory/cyclonedx20.js";
43
48
  import { mergeDependencies, mergeServices } from "../../inventory/depsUtils.js";
44
49
  import { addFormulationSection } from "../../inventory/formulationParsers.js";
50
+ import { hardwareRenderContext } from "../../inventory/hbomLoader.js";
45
51
  import { getContainerFileInventoryStats } from "../../inventory/inventoryStats.js";
46
52
  import { enhanceBom } from "../../inventory/licenseEnhancer.js";
47
53
  import { applyMcpPinningState } from "../../inventory/mcpPinning.js";
@@ -546,6 +552,13 @@ async function applyIntrospection(bomNSData, options, filePath) {
546
552
  /**
547
553
  * Filter and enhance BOM post generation.
548
554
  *
555
+ * At CycloneDX 2.0 the returned `bomNSData` carries two documents:
556
+ * `bomJson` is the rendered 2.0 document (what library users, the server and
557
+ * the writer see), and `internalBomJson` is the 1.x-shaped model the audit,
558
+ * evinse, display and SPDX-export readers use. `internalBomJson` is never
559
+ * serialized; `refreshRenderedBom` re-renders `bomJson` from it after any
560
+ * later mutation. At 1.x `internalBomJson` is unset.
561
+ *
549
562
  * @param {Object} bomNSData BOM with namespaces object
550
563
  * @param {Object} options CLI options
551
564
  * @param {string} [filePath] Source path used for formulation and metadata context
@@ -615,10 +628,37 @@ export async function postProcess(bomNSData, options, filePath) {
615
628
  ]);
616
629
  cleanupEnv(options);
617
630
  cleanupTmpDir();
618
- sortBomCollections(bomNSData.bomJson);
631
+ // A model read from another 2.0 document keeps that document's originals,
632
+ // keyed by the exact 1.x form of each object, so an unchanged object
633
+ // renders back as it was. Sorting would change those forms, so such a
634
+ // model keeps its order; cdxgen's own BOMs are sorted for determinism.
635
+ if (!bomNSData.bomJson?.[CDX20_INTERNAL_SECTIONS_KEY]?.shadows) {
636
+ sortBomCollections(bomNSData.bomJson);
637
+ }
619
638
  // Reflection reads the finished BOM, so it runs after sorting; it returns
620
639
  // its verdict alongside the BOM instead of mutating it.
621
640
  await applyIntrospection(bomNSData, options, filePath);
641
+ // CycloneDX 2.0: everything above produced the 1.x-shaped model. Keep it on
642
+ // `internalBomJson` for the readers that run after postProcess (audit,
643
+ // evinse, display, SPDX export) and render the 2.0 document once, here.
644
+ // `refreshRenderedBom` re-renders after any later mutation of the model,
645
+ // with the same render context (the optional cdx-hbom hardware mapper,
646
+ // loaded only when the model has hardware components).
647
+ // At 1.x both stay untouched, so those outputs are byte-identical. The
648
+ // document's own specVersion decides when the caller passed none, which is
649
+ // how an evinse run over a 2.0 input stays at 2.0.
650
+ if (
651
+ isCycloneDx20SpecVersion(
652
+ options.specVersion ?? bomNSData.bomJson?.specVersion,
653
+ )
654
+ ) {
655
+ bomNSData.renderContext = await hardwareRenderContext(bomNSData.bomJson);
656
+ bomNSData.internalBomJson = bomNSData.bomJson;
657
+ bomNSData.bomJson = renderCycloneDx20(
658
+ bomNSData.bomJson,
659
+ bomNSData.renderContext,
660
+ );
661
+ }
622
662
  return bomNSData;
623
663
  }
624
664
 
@@ -27,6 +27,8 @@ import {
27
27
  setCycloneDxFormat,
28
28
  toCycloneDxSpecVersionString,
29
29
  } from "../../inventory/bomUtils.js";
30
+ import { CDX20_INTERNAL_SECTIONS_KEY } from "../../inventory/cyclonedx20.js";
31
+ import { markInternalModel } from "../../inventory/cyclonedx20ReadContext.js";
30
32
 
31
33
  const COMPONENT_1_6_ONLY_FIELDS = new Set([
32
34
  "authors",
@@ -115,9 +117,17 @@ function normalizeMetadataForSpecVersion(subject, specVersion) {
115
117
  }
116
118
 
117
119
  function normalizeBomForSpecVersion(subject, specVersion) {
120
+ if (!subject) {
121
+ return;
122
+ }
118
123
  if (specVersion < 1.7) {
119
124
  deleteFields(subject, BOM_1_7_ONLY_FIELDS);
120
125
  }
126
+ if (specVersion < 2) {
127
+ // 2.0-only sections ride through the internal model under this key
128
+ // (see lib/inventory/cyclonedx20.js); a 1.x document never serializes it.
129
+ delete subject[CDX20_INTERNAL_SECTIONS_KEY];
130
+ }
121
131
  }
122
132
 
123
133
  function normalizeDependencyForSpecVersion(subject, specVersion) {
@@ -713,6 +723,9 @@ export function applySpecVersionCompatibility(bomJson, options) {
713
723
  downgradeSubjectForSpecVersion(bomJson, specVersion);
714
724
  } else if (isCycloneDx20SpecVersion(specVersion)) {
715
725
  upgradeSubjectForSpecVersion(bomJson, specVersion);
726
+ // The result is the 1.x-shaped model labelled 2.0, not a 2.0 document;
727
+ // the mark tells loadBomForAnalysis not to read it as one.
728
+ markInternalModel(bomJson);
716
729
  }
717
730
  return setCycloneDxFormat(bomJson, normalizedSpecVersion);
718
731
  }
@@ -763,3 +776,66 @@ export function diffRemovedFieldPaths(sourceBomJson, normalizedBomJson) {
763
776
  .filter((path) => !retainedPaths.has(path))
764
777
  .sort();
765
778
  }
779
+
780
+ /**
781
+ * Count the leaf values of a JSON document as `path=value` strings, using
782
+ * the dotted, index-free paths of collectFieldPaths. Array order is ignored,
783
+ * so two documents that differ only in member order give the same counts,
784
+ * but a repeated entry counts once per occurrence. Empty arrays and objects
785
+ * count as leaves.
786
+ *
787
+ * @param {*} subject JSON value
788
+ * @param {string} [prefix] Path so far
789
+ * @param {Map<string, number>} [leaves] Accumulator
790
+ * @returns {Map<string, number>} Occurrences of each `path=value` string
791
+ */
792
+ export function collectLeafValues(subject, prefix = "", leaves = new Map()) {
793
+ const add = (leaf) => {
794
+ leaves.set(leaf, (leaves.get(leaf) || 0) + 1);
795
+ };
796
+ if (Array.isArray(subject)) {
797
+ if (!subject.length) {
798
+ add(`${prefix}=[]`);
799
+ }
800
+ for (const entry of subject) {
801
+ collectLeafValues(entry, prefix, leaves);
802
+ }
803
+ return leaves;
804
+ }
805
+ if (isObjectRecord(subject)) {
806
+ const entries = Object.entries(subject);
807
+ if (!entries.length) {
808
+ add(`${prefix}={}`);
809
+ }
810
+ for (const [key, value] of entries) {
811
+ collectLeafValues(value, prefix ? `${prefix}.${key}` : key, leaves);
812
+ }
813
+ return leaves;
814
+ }
815
+ if (subject !== undefined) {
816
+ add(`${prefix}=${JSON.stringify(subject)}`);
817
+ }
818
+ return leaves;
819
+ }
820
+
821
+ /**
822
+ * Report the leaf values of `sourceBomJson` that `convertedBomJson` lacks,
823
+ * ignoring member order (see collectLeafValues). A value the source holds
824
+ * more often than the output is reported once for every missing occurrence,
825
+ * so dropping one of two identical entries counts.
826
+ *
827
+ * @param {Object} sourceBomJson BOM before conversion
828
+ * @param {Object} convertedBomJson BOM after conversion
829
+ * @returns {string[]} Sorted `path=value` strings missing from the output,
830
+ * repeated per missing occurrence
831
+ */
832
+ export function diffMissingLeafValues(sourceBomJson, convertedBomJson) {
833
+ const retained = collectLeafValues(convertedBomJson);
834
+ const missing = [];
835
+ for (const [leaf, count] of collectLeafValues(sourceBomJson)) {
836
+ for (let i = retained.get(leaf) || 0; i < count; i++) {
837
+ missing.push(leaf);
838
+ }
839
+ }
840
+ return missing.sort();
841
+ }
@@ -55,11 +55,18 @@ const compileSchemaValidator = (specVersion) => {
55
55
  const ajv = new Ajv2020(AJV_OPTIONS);
56
56
  useLinearUniqueItems(ajv);
57
57
  addCycloneDxFormats(ajv);
58
+ // The 2.0 draft pins its own cryptography definitions; the 1.7 schema
59
+ // keeps reading data/cryptography-defs.schema.json below.
58
60
  addDraft2020BundledSchema(
59
61
  ajv,
60
- readJsonSchema("cryptography-defs.schema.json"),
62
+ readJsonSchema("cyclonedx-2.0-cryptography-defs.schema.json"),
61
63
  "https://cyclonedx.org/schema/cryptography-defs.schema.json",
62
64
  );
65
+ addDraft2020BundledSchema(
66
+ ajv,
67
+ readJsonSchema("behavior-taxonomy.schema.json"),
68
+ "https://cyclonedx.org/schema/behavior-taxonomy.schema.json",
69
+ );
63
70
  addDraft2020BundledSchema(
64
71
  ajv,
65
72
  readJsonSchema("jsf-0.82.schema.json"),
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Orchestrates evaluation of internal compliance rule packs (SCVS + CRA) and
3
- * aggregates results into per-benchmark scorecards.
2
+ * Orchestrates evaluation of internal compliance rule packs (SCVS + CRA + CISA)
3
+ * and aggregates results into per-benchmark scorecards.
4
4
  *
5
5
  * This module is deliberately independent of the CycloneDX BOM audit engine
6
6
  * (lib/stages/postgen/auditBom.js). The two engines share similar *Finding*
@@ -9,6 +9,8 @@
9
9
 
10
10
  import {
11
11
  getAllComplianceRules,
12
+ getCisaAiRules,
13
+ getCisaRules,
12
14
  getCraRules,
13
15
  getScvsRules,
14
16
  } from "./complianceRules.js";
@@ -63,6 +65,25 @@ const BENCHMARKS = {
63
65
  filter: (rules) => rules.filter((r) => r.standard === "CRA"),
64
66
  levelPredicate: () => true,
65
67
  },
68
+ cisa: {
69
+ id: "cisa",
70
+ name: "CISA 2026 minimum elements for an SBOM",
71
+ standard: "CISA",
72
+ // The AI element rules share the CISA standard key but form their own
73
+ // benchmark, so both filters select by category.
74
+ filter: (rules) =>
75
+ rules.filter(
76
+ (r) => r.standard === "CISA" && r.category === "compliance-cisa",
77
+ ),
78
+ levelPredicate: () => true,
79
+ },
80
+ "cisa-ai": {
81
+ id: "cisa-ai",
82
+ name: "CISA and G7 minimum elements for an AI SBOM",
83
+ standard: "CISA",
84
+ filter: (rules) => rules.filter((r) => r.category === "compliance-cisa-ai"),
85
+ levelPredicate: () => true,
86
+ },
66
87
  };
67
88
 
68
89
  /**
@@ -238,4 +259,10 @@ export function buildBenchmarkReports(findings, requestedAliases) {
238
259
  return aliases.map((b) => scoreBenchmark(b, findings));
239
260
  }
240
261
 
241
- export { getAllComplianceRules, getCraRules, getScvsRules };
262
+ export {
263
+ getAllComplianceRules,
264
+ getCisaAiRules,
265
+ getCisaRules,
266
+ getCraRules,
267
+ getScvsRules,
268
+ };