@cdxgen/cdxgen 13.5.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 (380) hide show
  1. package/README.md +17 -10
  2. package/bin/audit.js +7 -4
  3. package/bin/cdxgen.js +260 -37
  4. package/bin/convert.js +146 -22
  5. package/bin/evinse.js +28 -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 +24 -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/license-aliases.json +24 -2
  15. package/data/pqc-migration.json +239 -0
  16. package/data/remediations.json +176 -0
  17. package/data/rules/ai-bom.yaml +1 -1
  18. package/data/rules/brotli-decoder.yaml +107 -0
  19. package/data/rules/cbom-security.yaml +4 -3
  20. package/data/rules/package-integrity.yaml +28 -0
  21. package/data/rules/vscode-extensions.yaml +75 -0
  22. package/data/spdx-license-list.json +121 -7
  23. package/data/spdx-licenses.json +69 -0
  24. package/data/spdx.schema.json +845 -2
  25. package/lib/audit/index.js +25 -3
  26. package/lib/cli/bomAssembly.js +172 -4
  27. package/lib/cli/cliOptions.js +121 -17
  28. package/lib/cli/index.js +720 -902
  29. package/lib/cli/jsBom.js +156 -64
  30. package/lib/cli/jvmBom.js +602 -86
  31. package/lib/cli/managedBom.js +161 -19
  32. package/lib/cli/nativeBom.js +52 -5
  33. package/lib/core/boundedFile.js +344 -0
  34. package/lib/core/brotliProbe.js +182 -0
  35. package/lib/core/env.js +34 -0
  36. package/lib/core/fs.js +138 -3
  37. package/lib/core/globPatterns.js +218 -0
  38. package/lib/core/httpClient.js +98 -1
  39. package/lib/core/lockPaths.js +38 -0
  40. package/lib/core/paths.js +24 -1
  41. package/lib/core/processTree.js +100 -8
  42. package/lib/core/projectConfig.js +332 -25
  43. package/lib/core/toolRegistry.js +184 -0
  44. package/lib/ecosystems/cppEvidence.js +263 -106
  45. package/lib/ecosystems/cppIncludeResolver.js +16 -5
  46. package/lib/ecosystems/denoutils.js +2 -2
  47. package/lib/ecosystems/ecosystems.js +25 -10
  48. package/lib/ecosystems/gemHostProbe.js +301 -0
  49. package/lib/ecosystems/golem.js +3 -8
  50. package/lib/ecosystems/gradleutils.js +1909 -229
  51. package/lib/ecosystems/jsEvidence.js +90 -38
  52. package/lib/ecosystems/kosi.js +3 -5
  53. package/lib/ecosystems/npmVersionResolution.js +376 -0
  54. package/lib/ecosystems/parsers-bazel.js +107 -6
  55. package/lib/ecosystems/parsers-js.js +505 -22
  56. package/lib/ecosystems/parsers-misc.js +209 -20
  57. package/lib/ecosystems/parsers-python.js +178 -30
  58. package/lib/ecosystems/parsers-rust.js +117 -15
  59. package/lib/ecosystems/pythonutils.js +128 -2
  60. package/lib/ecosystems/remote/huggingface.js +22 -0
  61. package/lib/ecosystems/rubyutils.js +538 -31
  62. package/lib/ecosystems/rusi.js +2 -4
  63. package/lib/ecosystems/scalacliutils.js +2 -0
  64. package/lib/ecosystems/scalasem.js +798 -152
  65. package/lib/ecosystems/vendoredCode.js +237 -3
  66. package/lib/ecosystems/venvProbe.js +360 -0
  67. package/lib/evinser/evinser.js +536 -71
  68. package/lib/evinser/scalasem.js +5 -1
  69. package/lib/helpers/agenticToolutils.js +525 -94
  70. package/lib/helpers/bomSigner.js +43 -9
  71. package/lib/helpers/jssSigner.js +1276 -0
  72. package/lib/helpers/vsixutils.js +1574 -315
  73. package/lib/inventory/agentBlueprint.js +193 -0
  74. package/lib/inventory/agentToolNames.js +145 -0
  75. package/lib/inventory/aiCollector.js +153 -7
  76. package/lib/inventory/aiInventory.js +44 -8
  77. package/lib/inventory/aiProviders.js +324 -0
  78. package/lib/inventory/atomUtils.js +77 -0
  79. package/lib/inventory/bomUtils.js +8 -1
  80. package/lib/inventory/brotliDecoder.js +142 -0
  81. package/lib/inventory/buildToolRateLimit.js +1 -1
  82. package/lib/inventory/cbomutils.js +56 -7
  83. package/lib/inventory/ciParsers/githubActionsLock.js +821 -0
  84. package/lib/inventory/citations.js +31 -2
  85. package/lib/inventory/communityAiConfigParser.js +978 -80
  86. package/lib/inventory/cyclonedx20.js +152 -0
  87. package/lib/inventory/cyclonedx20Common.js +286 -0
  88. package/lib/inventory/cyclonedx20Derived.js +159 -0
  89. package/lib/inventory/cyclonedx20Parties.js +552 -0
  90. package/lib/inventory/cyclonedx20Read.js +768 -0
  91. package/lib/inventory/cyclonedx20ReadCommon.js +374 -0
  92. package/lib/inventory/cyclonedx20ReadComponents.js +692 -0
  93. package/lib/inventory/cyclonedx20ReadContext.js +380 -0
  94. package/lib/inventory/cyclonedx20ReadEvidence.js +466 -0
  95. package/lib/inventory/cyclonedx20ReadSections.js +599 -0
  96. package/lib/inventory/cyclonedx20Render.js +766 -0
  97. package/lib/inventory/cyclonedx20RenderComponents.js +716 -0
  98. package/lib/inventory/cyclonedx20RenderDefinitions.js +405 -0
  99. package/lib/inventory/cyclonedx20RenderEvidence.js +726 -0
  100. package/lib/inventory/cyclonedx20RenderHardware.js +203 -0
  101. package/lib/inventory/cyclonedx20RenderPatents.js +174 -0
  102. package/lib/inventory/cyclonedx20RenderRefIds.js +314 -0
  103. package/lib/inventory/cyclonedx20RenderSections.js +499 -0
  104. package/lib/inventory/cyclonedx20Tables.js +594 -0
  105. package/lib/inventory/deps.js +141 -13
  106. package/lib/inventory/dosai.js +375 -6
  107. package/lib/inventory/dosaiParsers.js +3 -6
  108. package/lib/inventory/dotnetRuntime.js +367 -0
  109. package/lib/inventory/ecosystemFormulationParsers.js +979 -0
  110. package/lib/inventory/envcontext.js +436 -48
  111. package/lib/inventory/evidenceUtils.js +13 -1
  112. package/lib/inventory/fetchBatch.js +1 -1
  113. package/lib/inventory/formulationParsers.js +124 -14
  114. package/lib/inventory/gtfobins.js +13 -0
  115. package/lib/inventory/hbom.js +45 -6
  116. package/lib/inventory/hbomLoader.js +166 -0
  117. package/lib/inventory/hostRuntimeProbe.js +686 -0
  118. package/lib/inventory/jvmLocalRepos.js +9 -2
  119. package/lib/inventory/jvmToolEnv.js +29 -0
  120. package/lib/inventory/licenseEnhancer.js +12 -0
  121. package/lib/inventory/mavenCentralMirror.js +534 -0
  122. package/lib/inventory/mcpConfigParser.js +5 -0
  123. package/lib/inventory/nodeBuildInfo.js +218 -0
  124. package/lib/inventory/nodeHostProbe.js +202 -0
  125. package/lib/inventory/occurrenceKey.js +90 -0
  126. package/lib/inventory/osPackageResolver.js +182 -0
  127. package/lib/inventory/phpBuildInfo.js +10 -59
  128. package/lib/inventory/phpHostProbe.js +32 -488
  129. package/lib/inventory/pqcMigration.js +426 -0
  130. package/lib/inventory/rubyBuildInfo.js +972 -0
  131. package/lib/inventory/rubyHostProbe.js +218 -0
  132. package/lib/inventory/rustFormulationParser.js +21 -10
  133. package/lib/inventory/scalaCoords.js +4 -3
  134. package/lib/inventory/scalaDedupe.js +440 -0
  135. package/lib/inventory/source.js +114 -8
  136. package/lib/managers/binary.js +337 -3
  137. package/lib/managers/docker.js +79 -0
  138. package/lib/parsers/huggingfaceManifest.js +9 -1
  139. package/lib/parsers/huggingfaceUtils.js +18 -0
  140. package/lib/parsers/kiroPermissions.js +166 -0
  141. package/lib/parsers/largeJson.js +28 -11
  142. package/lib/parsers/vscodeExtensionId.js +183 -0
  143. package/lib/server/server.js +48 -35
  144. package/lib/stages/postgen/postgen.js +41 -1
  145. package/lib/stages/postgen/ruleEngine.js +13 -5
  146. package/lib/stages/postgen/specVersionCompat.js +76 -0
  147. package/lib/stages/pregen/envAudit.js +1 -0
  148. package/lib/stages/pregen/pregen.js +114 -57
  149. package/lib/validator/bomValidator.js +14 -2
  150. package/lib/validator/complianceEngine.js +30 -3
  151. package/lib/validator/complianceRules.js +1416 -4
  152. package/lib/validator/generated/validate-1.6.mjs +1 -1
  153. package/lib/validator/generated/validate-1.7.mjs +1 -1
  154. package/lib/validator/generated/validate-2.0.mjs +57554 -13851
  155. package/lib/validator/index.js +49 -8
  156. package/lib/validator/reporters/json.js +6 -0
  157. package/package.json +11 -10
  158. package/types/bin/repl.d.ts.map +1 -1
  159. package/types/lib/audit/index.d.ts +6 -2
  160. package/types/lib/audit/index.d.ts.map +1 -1
  161. package/types/lib/cli/bomAssembly.d.ts +29 -1
  162. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  163. package/types/lib/cli/cliOptions.d.ts +6 -0
  164. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  165. package/types/lib/cli/index.d.ts.map +1 -1
  166. package/types/lib/cli/jsBom.d.ts +3 -18
  167. package/types/lib/cli/jsBom.d.ts.map +1 -1
  168. package/types/lib/cli/jvmBom.d.ts +15 -0
  169. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  170. package/types/lib/cli/managedBom.d.ts.map +1 -1
  171. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  172. package/types/lib/core/boundedFile.d.ts +100 -0
  173. package/types/lib/core/boundedFile.d.ts.map +1 -0
  174. package/types/lib/core/brotliProbe.d.ts +37 -0
  175. package/types/lib/core/brotliProbe.d.ts.map +1 -0
  176. package/types/lib/core/env.d.ts +14 -0
  177. package/types/lib/core/env.d.ts.map +1 -1
  178. package/types/lib/core/fs.d.ts +4 -0
  179. package/types/lib/core/fs.d.ts.map +1 -1
  180. package/types/lib/core/globPatterns.d.ts +70 -0
  181. package/types/lib/core/globPatterns.d.ts.map +1 -0
  182. package/types/lib/core/httpClient.d.ts +24 -0
  183. package/types/lib/core/httpClient.d.ts.map +1 -1
  184. package/types/lib/core/lockPaths.d.ts +19 -0
  185. package/types/lib/core/lockPaths.d.ts.map +1 -0
  186. package/types/lib/core/paths.d.ts +9 -0
  187. package/types/lib/core/paths.d.ts.map +1 -1
  188. package/types/lib/core/processTree.d.ts +17 -4
  189. package/types/lib/core/processTree.d.ts.map +1 -1
  190. package/types/lib/core/projectConfig.d.ts +47 -8
  191. package/types/lib/core/projectConfig.d.ts.map +1 -1
  192. package/types/lib/core/toolRegistry.d.ts +36 -0
  193. package/types/lib/core/toolRegistry.d.ts.map +1 -0
  194. package/types/lib/ecosystems/cppEvidence.d.ts +40 -13
  195. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  196. package/types/lib/ecosystems/cppIncludeResolver.d.ts +2 -1
  197. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -1
  198. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  199. package/types/lib/ecosystems/gemHostProbe.d.ts +28 -0
  200. package/types/lib/ecosystems/gemHostProbe.d.ts.map +1 -0
  201. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  202. package/types/lib/ecosystems/gradleutils.d.ts +294 -20
  203. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  204. package/types/lib/ecosystems/jsEvidence.d.ts +14 -1
  205. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  206. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  207. package/types/lib/ecosystems/npmVersionResolution.d.ts +119 -0
  208. package/types/lib/ecosystems/npmVersionResolution.d.ts.map +1 -0
  209. package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -1
  210. package/types/lib/ecosystems/parsers-js.d.ts +17 -20
  211. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  212. package/types/lib/ecosystems/parsers-misc.d.ts +19 -0
  213. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  214. package/types/lib/ecosystems/parsers-python.d.ts +10 -0
  215. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  216. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  217. package/types/lib/ecosystems/pythonutils.d.ts +19 -1
  218. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  219. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  220. package/types/lib/ecosystems/rubyutils.d.ts +144 -12
  221. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  222. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  223. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -1
  224. package/types/lib/ecosystems/scalasem.d.ts +58 -16
  225. package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
  226. package/types/lib/ecosystems/vendoredCode.d.ts +26 -0
  227. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -1
  228. package/types/lib/ecosystems/venvProbe.d.ts +40 -0
  229. package/types/lib/ecosystems/venvProbe.d.ts.map +1 -0
  230. package/types/lib/evinser/evinser.d.ts +120 -13
  231. package/types/lib/evinser/evinser.d.ts.map +1 -1
  232. package/types/lib/evinser/scalasem.d.ts.map +1 -1
  233. package/types/lib/helpers/agenticToolutils.d.ts +53 -19
  234. package/types/lib/helpers/agenticToolutils.d.ts.map +1 -1
  235. package/types/lib/helpers/bomSigner.d.ts +20 -3
  236. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  237. package/types/lib/helpers/jssSigner.d.ts +288 -0
  238. package/types/lib/helpers/jssSigner.d.ts.map +1 -0
  239. package/types/lib/helpers/vsixutils.d.ts +303 -19
  240. package/types/lib/helpers/vsixutils.d.ts.map +1 -1
  241. package/types/lib/inventory/agentBlueprint.d.ts +70 -0
  242. package/types/lib/inventory/agentBlueprint.d.ts.map +1 -0
  243. package/types/lib/inventory/agentToolNames.d.ts +51 -0
  244. package/types/lib/inventory/agentToolNames.d.ts.map +1 -0
  245. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  246. package/types/lib/inventory/aiInventory.d.ts.map +1 -1
  247. package/types/lib/inventory/aiProviders.d.ts +85 -0
  248. package/types/lib/inventory/aiProviders.d.ts.map +1 -0
  249. package/types/lib/inventory/atomUtils.d.ts +19 -0
  250. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  251. package/types/lib/inventory/bomUtils.d.ts.map +1 -1
  252. package/types/lib/inventory/brotliDecoder.d.ts +58 -0
  253. package/types/lib/inventory/brotliDecoder.d.ts.map +1 -0
  254. package/types/lib/inventory/cbomutils.d.ts +17 -0
  255. package/types/lib/inventory/cbomutils.d.ts.map +1 -1
  256. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts +101 -0
  257. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts.map +1 -0
  258. package/types/lib/inventory/citations.d.ts +5 -0
  259. package/types/lib/inventory/citations.d.ts.map +1 -1
  260. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  261. package/types/lib/inventory/cyclonedx20.d.ts +99 -0
  262. package/types/lib/inventory/cyclonedx20.d.ts.map +1 -0
  263. package/types/lib/inventory/cyclonedx20Common.d.ts +102 -0
  264. package/types/lib/inventory/cyclonedx20Common.d.ts.map +1 -0
  265. package/types/lib/inventory/cyclonedx20Derived.d.ts +74 -0
  266. package/types/lib/inventory/cyclonedx20Derived.d.ts.map +1 -0
  267. package/types/lib/inventory/cyclonedx20Parties.d.ts +91 -0
  268. package/types/lib/inventory/cyclonedx20Parties.d.ts.map +1 -0
  269. package/types/lib/inventory/cyclonedx20Read.d.ts +51 -0
  270. package/types/lib/inventory/cyclonedx20Read.d.ts.map +1 -0
  271. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts +69 -0
  272. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts.map +1 -0
  273. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts +77 -0
  274. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts.map +1 -0
  275. package/types/lib/inventory/cyclonedx20ReadContext.d.ts +118 -0
  276. package/types/lib/inventory/cyclonedx20ReadContext.d.ts.map +1 -0
  277. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts +40 -0
  278. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts.map +1 -0
  279. package/types/lib/inventory/cyclonedx20ReadSections.d.ts +45 -0
  280. package/types/lib/inventory/cyclonedx20ReadSections.d.ts.map +1 -0
  281. package/types/lib/inventory/cyclonedx20Render.d.ts +53 -0
  282. package/types/lib/inventory/cyclonedx20Render.d.ts.map +1 -0
  283. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts +73 -0
  284. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts.map +1 -0
  285. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts +29 -0
  286. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts.map +1 -0
  287. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts +110 -0
  288. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts.map +1 -0
  289. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts +42 -0
  290. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts.map +1 -0
  291. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts +26 -0
  292. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts.map +1 -0
  293. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts +55 -0
  294. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts.map +1 -0
  295. package/types/lib/inventory/cyclonedx20RenderSections.d.ts +45 -0
  296. package/types/lib/inventory/cyclonedx20RenderSections.d.ts.map +1 -0
  297. package/types/lib/inventory/cyclonedx20Tables.d.ts +134 -0
  298. package/types/lib/inventory/cyclonedx20Tables.d.ts.map +1 -0
  299. package/types/lib/inventory/deps.d.ts +35 -2
  300. package/types/lib/inventory/deps.d.ts.map +1 -1
  301. package/types/lib/inventory/dosai.d.ts +36 -1
  302. package/types/lib/inventory/dosai.d.ts.map +1 -1
  303. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  304. package/types/lib/inventory/dotnetRuntime.d.ts +91 -0
  305. package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -0
  306. package/types/lib/inventory/ecosystemFormulationParsers.d.ts +73 -0
  307. package/types/lib/inventory/ecosystemFormulationParsers.d.ts.map +1 -0
  308. package/types/lib/inventory/envcontext.d.ts +74 -12
  309. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  310. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  311. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  312. package/types/lib/inventory/gtfobins.d.ts.map +1 -1
  313. package/types/lib/inventory/hbom.d.ts +11 -0
  314. package/types/lib/inventory/hbom.d.ts.map +1 -1
  315. package/types/lib/inventory/hbomLoader.d.ts +54 -0
  316. package/types/lib/inventory/hbomLoader.d.ts.map +1 -1
  317. package/types/lib/inventory/hostRuntimeProbe.d.ts +44 -0
  318. package/types/lib/inventory/hostRuntimeProbe.d.ts.map +1 -0
  319. package/types/lib/inventory/jvmLocalRepos.d.ts +5 -1
  320. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -1
  321. package/types/lib/inventory/jvmToolEnv.d.ts +12 -0
  322. package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
  323. package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -1
  324. package/types/lib/inventory/mavenCentralMirror.d.ts +170 -0
  325. package/types/lib/inventory/mavenCentralMirror.d.ts.map +1 -0
  326. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  327. package/types/lib/inventory/nodeBuildInfo.d.ts +95 -0
  328. package/types/lib/inventory/nodeBuildInfo.d.ts.map +1 -0
  329. package/types/lib/inventory/nodeHostProbe.d.ts +15 -0
  330. package/types/lib/inventory/nodeHostProbe.d.ts.map +1 -0
  331. package/types/lib/inventory/occurrenceKey.d.ts +52 -0
  332. package/types/lib/inventory/occurrenceKey.d.ts.map +1 -0
  333. package/types/lib/inventory/osPackageResolver.d.ts +38 -0
  334. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
  335. package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -1
  336. package/types/lib/inventory/phpHostProbe.d.ts.map +1 -1
  337. package/types/lib/inventory/pqcMigration.d.ts +84 -0
  338. package/types/lib/inventory/pqcMigration.d.ts.map +1 -0
  339. package/types/lib/inventory/rubyBuildInfo.d.ts +271 -0
  340. package/types/lib/inventory/rubyBuildInfo.d.ts.map +1 -0
  341. package/types/lib/inventory/rubyHostProbe.d.ts +47 -0
  342. package/types/lib/inventory/rubyHostProbe.d.ts.map +1 -0
  343. package/types/lib/inventory/rustFormulationParser.d.ts +7 -2
  344. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  345. package/types/lib/inventory/scalaCoords.d.ts.map +1 -1
  346. package/types/lib/inventory/scalaDedupe.d.ts +43 -0
  347. package/types/lib/inventory/scalaDedupe.d.ts.map +1 -0
  348. package/types/lib/inventory/source.d.ts +25 -0
  349. package/types/lib/inventory/source.d.ts.map +1 -1
  350. package/types/lib/managers/binary.d.ts.map +1 -1
  351. package/types/lib/managers/docker.d.ts +12 -0
  352. package/types/lib/managers/docker.d.ts.map +1 -1
  353. package/types/lib/parsers/huggingfaceManifest.d.ts +10 -1
  354. package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -1
  355. package/types/lib/parsers/huggingfaceUtils.d.ts +12 -0
  356. package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
  357. package/types/lib/parsers/kiroPermissions.d.ts +62 -0
  358. package/types/lib/parsers/kiroPermissions.d.ts.map +1 -0
  359. package/types/lib/parsers/largeJson.d.ts +4 -3
  360. package/types/lib/parsers/largeJson.d.ts.map +1 -1
  361. package/types/lib/parsers/vscodeExtensionId.d.ts +48 -0
  362. package/types/lib/parsers/vscodeExtensionId.d.ts.map +1 -0
  363. package/types/lib/server/server.d.ts.map +1 -1
  364. package/types/lib/stages/postgen/postgen.d.ts +7 -0
  365. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  366. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  367. package/types/lib/stages/postgen/specVersionCompat.d.ts +25 -0
  368. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  369. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  370. package/types/lib/stages/pregen/pregen.d.ts +12 -8
  371. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  372. package/types/lib/validator/bomValidator.d.ts +5 -1
  373. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  374. package/types/lib/validator/complianceEngine.d.ts +4 -4
  375. package/types/lib/validator/complianceEngine.d.ts.map +1 -1
  376. package/types/lib/validator/complianceRules.d.ts +14 -2
  377. package/types/lib/validator/complianceRules.d.ts.map +1 -1
  378. package/types/lib/validator/index.d.ts +10 -0
  379. package/types/lib/validator/index.d.ts.map +1 -1
  380. 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
+ }
@@ -54,9 +54,20 @@ function applySpec(value, spec) {
54
54
  return value;
55
55
  }
56
56
  if (Array.isArray(value)) {
57
+ let elements = value;
58
+ if (spec.map) {
59
+ const mapped = [];
60
+ for (const element of elements) {
61
+ const transformed = spec.map(element);
62
+ if (transformed !== undefined) {
63
+ mapped.push(transformed);
64
+ }
65
+ }
66
+ elements = mapped;
67
+ }
57
68
  return spec.filter
58
- ? value.filter((element) => spec.filter(element))
59
- : value;
69
+ ? elements.filter((element) => spec.filter(element))
70
+ : elements;
60
71
  }
61
72
  if (!spec.members) {
62
73
  return value;
@@ -294,9 +305,10 @@ function scanObjectMembers(cursor, stopAt = undefined) {
294
305
  }
295
306
  }
296
307
 
297
- // Decode the array at the cursor in runs of whole elements, keeping those that
298
- // `filter` accepts.
299
- function readArrayElements(cursor, filter, batchBytes) {
308
+ // Decode the array at the cursor in runs of whole elements, mapping each one
309
+ // through `spec.map` (an undefined result drops it) and keeping those that
310
+ // `spec.filter` accepts.
311
+ function readArrayElements(cursor, spec, batchBytes) {
300
312
  if (cursor.nextToken() !== OPEN_BRACKET) {
301
313
  cursor.fail("Expected an array");
302
314
  }
@@ -310,8 +322,12 @@ function readArrayElements(cursor, filter, batchBytes) {
310
322
  for (const element of JSON.parse(
311
323
  `[${cursor.endCapture(cursor.pos - 1)}]`,
312
324
  )) {
313
- if (!filter || filter(element)) {
314
- elements.push(element);
325
+ const mapped = spec?.map ? spec.map(element) : element;
326
+ if (mapped === undefined) {
327
+ continue;
328
+ }
329
+ if (!spec?.filter || spec.filter(mapped)) {
330
+ elements.push(mapped);
315
331
  }
316
332
  }
317
333
  };
@@ -367,7 +383,7 @@ function decodeRange(fd, start, end, spec, options) {
367
383
  );
368
384
  }
369
385
  } else if (first === OPEN_BRACKET) {
370
- value = readArrayElements(cursor, spec?.filter, options.batchBytes);
386
+ value = readArrayElements(cursor, spec, options.batchBytes);
371
387
  } else {
372
388
  // A string or number this large has no smaller parts; JSON.parse reports
373
389
  // it the way it would for the whole file.
@@ -449,9 +465,10 @@ export function readJsonMember(filePath, name, options = {}) {
449
465
  * more than a bounded run of it in one string.
450
466
  *
451
467
  * `spec` narrows what is kept. `{ members: { name: spec } }` keeps only the
452
- * named members of an object, each narrowed by its own spec. `{ filter }`
453
- * keeps the elements of an array that `filter(element)` accepts. Anything else
454
- * keeps the whole value.
468
+ * named members of an object, each narrowed by its own spec. `{ map }`
469
+ * transforms each element of an array, an undefined result dropping it, and
470
+ * `{ filter }` keeps the mapped elements that `filter(element)` accepts.
471
+ * Anything else keeps the whole value.
455
472
  *
456
473
  * @param {string} filePath JSON file
457
474
  * @param {{start: number, end: number}} range Byte range of the value, such as one returned by indexJsonObject
@@ -0,0 +1,183 @@
1
+ // The one place that reads the identity of an installed VS Code-family
2
+ // extension from the name of its folder.
3
+ //
4
+ // An editor installs an extension into `<publisher>.<name>-<version>`, and a
5
+ // platform-specific build into `<publisher>.<name>-<version>-<platform>`, for
6
+ // example `anthropic.claude-code-2.1.313-darwin-arm64`. The extension scan and
7
+ // the osquery `vscode_extensions` rows both name the extension from this, so an
8
+ // extension found by `cdxgen -t vscode-extension` and by `obom` is the same
9
+ // component with the same purl.
10
+
11
+ /**
12
+ * Target platforms a VS Code-family marketplace publishes an extension for.
13
+ * `universal` and `web` builds are the same artefact on every platform and are
14
+ * not part of the extension's identity.
15
+ */
16
+ export const VSCODE_TARGET_PLATFORMS = new Set([
17
+ "win32-x64",
18
+ "win32-arm64",
19
+ "win32-ia32",
20
+ "linux-x64",
21
+ "linux-arm64",
22
+ "linux-armhf",
23
+ "alpine-x64",
24
+ "alpine-arm64",
25
+ "darwin-x64",
26
+ "darwin-arm64",
27
+ ]);
28
+
29
+ // Folder suffixes for builds that run on every platform.
30
+ const NEUTRAL_PLATFORMS = ["universal", "web"];
31
+
32
+ /**
33
+ * Normalize a target platform value from a manifest, an `extensions.json`
34
+ * record, or a folder name. Values that do not name a specific platform, such
35
+ * as `universal`, `web`, `undefined`, or an empty string, return an empty
36
+ * string.
37
+ *
38
+ * @param {string} value Raw target platform
39
+ * @returns {string} A value from VSCODE_TARGET_PLATFORMS, or an empty string
40
+ */
41
+ export function normalizeVscodeTargetPlatform(value) {
42
+ const platform = `${value || ""}`.trim().toLowerCase();
43
+ return VSCODE_TARGET_PLATFORMS.has(platform) ? platform : "";
44
+ }
45
+
46
+ /**
47
+ * Split an installed extension folder name into its publisher, name, version
48
+ * and target platform.
49
+ *
50
+ * @param {string} dirName Folder name, such as `ms-python.python-2025.4.0` or
51
+ * `anthropic.claude-code-2.1.313-darwin-arm64`
52
+ * @returns {{publisher: string, name: string, version: string, platform: string}|undefined}
53
+ * The parts, or undefined when the name does not follow the pattern
54
+ */
55
+ export function parseVscodeExtensionDirName(dirName) {
56
+ let value = `${dirName || ""}`.trim();
57
+ while (value.endsWith("/") || value.endsWith("\\")) {
58
+ value = value.slice(0, -1);
59
+ }
60
+ const dotIdx = value.indexOf(".");
61
+ if (dotIdx < 1) {
62
+ return undefined;
63
+ }
64
+ const publisher = value.substring(0, dotIdx);
65
+ let rest = value.substring(dotIdx + 1);
66
+ let platform = "";
67
+ for (const candidate of [...VSCODE_TARGET_PLATFORMS, ...NEUTRAL_PLATFORMS]) {
68
+ if (rest.toLowerCase().endsWith(`-${candidate}`)) {
69
+ platform = normalizeVscodeTargetPlatform(candidate);
70
+ rest = rest.substring(0, rest.length - candidate.length - 1);
71
+ break;
72
+ }
73
+ }
74
+ // Marketplaces require semver versions, so the version starts at the first
75
+ // hyphen whose remainder is a whole semver: `python-3.11-tools-1.0.0` is the
76
+ // name `python-3.11-tools` at 1.0.0, and `1.0.0-beta-2` stays one version.
77
+ // A folder whose version is not semver falls back to the first hyphen
78
+ // followed by digits and a dot.
79
+ let versionStart = -1;
80
+ let fallbackStart = -1;
81
+ for (let i = 1; i < rest.length - 2; i++) {
82
+ if (rest[i] !== "-" || !isDigit(rest[i + 1])) {
83
+ continue;
84
+ }
85
+ if (isSemver(rest.substring(i + 1))) {
86
+ versionStart = i;
87
+ break;
88
+ }
89
+ let j = i + 1;
90
+ while (j < rest.length && isDigit(rest[j])) {
91
+ j++;
92
+ }
93
+ if (fallbackStart < 0 && rest[j] === ".") {
94
+ fallbackStart = i;
95
+ }
96
+ }
97
+ if (versionStart < 0) {
98
+ versionStart = fallbackStart;
99
+ }
100
+ if (versionStart < 1) {
101
+ return undefined;
102
+ }
103
+ const name = rest.substring(0, versionStart);
104
+ const version = rest.substring(versionStart + 1);
105
+ if (!name || !version) {
106
+ return undefined;
107
+ }
108
+ return { publisher, name, version, platform };
109
+ }
110
+
111
+ function isDigit(character) {
112
+ return character >= "0" && character <= "9";
113
+ }
114
+
115
+ function isIdentifierList(text, numericNoLeadingZero) {
116
+ if (!text) {
117
+ return false;
118
+ }
119
+ return text.split(".").every((part) => {
120
+ if (!part.length) {
121
+ return false;
122
+ }
123
+ for (const character of part) {
124
+ const ok =
125
+ isDigit(character) ||
126
+ character === "-" ||
127
+ (character >= "a" && character <= "z") ||
128
+ (character >= "A" && character <= "Z");
129
+ if (!ok) {
130
+ return false;
131
+ }
132
+ }
133
+ if (numericNoLeadingZero && [...part].every(isDigit)) {
134
+ return part === "0" || part[0] !== "0";
135
+ }
136
+ return true;
137
+ });
138
+ }
139
+
140
+ /**
141
+ * Check a string is a semantic version: three numeric parts, then an optional
142
+ * `-prerelease` and `+build`.
143
+ *
144
+ * @param {string} text Candidate version
145
+ * @returns {boolean} true for a semver
146
+ */
147
+ export function isSemver(text) {
148
+ const plus = text.indexOf("+");
149
+ const core = plus >= 0 ? text.substring(0, plus) : text;
150
+ if (plus >= 0 && !isIdentifierList(text.substring(plus + 1), false)) {
151
+ return false;
152
+ }
153
+ const dash = core.indexOf("-");
154
+ const numbers = dash >= 0 ? core.substring(0, dash) : core;
155
+ if (dash >= 0 && !isIdentifierList(core.substring(dash + 1), true)) {
156
+ return false;
157
+ }
158
+ const parts = numbers.split(".");
159
+ return (
160
+ parts.length === 3 &&
161
+ parts.every(
162
+ (part) =>
163
+ part.length > 0 &&
164
+ [...part].every(isDigit) &&
165
+ (part === "0" || part[0] !== "0"),
166
+ )
167
+ );
168
+ }
169
+
170
+ /**
171
+ * Read the target platform from the path of an installed extension folder.
172
+ *
173
+ * @param {string} extensionPath Path to the extension folder, with either
174
+ * separator
175
+ * @returns {string} The target platform, or an empty string
176
+ */
177
+ export function vscodeExtensionPlatformFromPath(extensionPath) {
178
+ const segments = `${extensionPath || ""}`
179
+ .split(/[/\\]/u)
180
+ .filter((segment) => segment.length);
181
+ const dirName = segments[segments.length - 1];
182
+ return parseVscodeExtensionDirName(dirName)?.platform || "";
183
+ }
@@ -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
 
@@ -659,7 +656,18 @@ const start = (options) => {
659
656
  );
660
657
  }
661
658
  }
662
- cloneDir = gitClone(sourcePath, gitRef);
659
+ try {
660
+ cloneDir = gitClone(sourcePath, gitRef);
661
+ } catch (_err) {
662
+ console.log("Unable to clone repository. See the server log.");
663
+ res.writeHead(500, { "Content-Type": "application/json" });
664
+ return res.end(
665
+ JSON.stringify({
666
+ error: "Unable to clone repository",
667
+ details: "Cloning the repository failed. See the server log.",
668
+ }),
669
+ );
670
+ }
663
671
  srcDir = cloneDir;
664
672
  if (purlResolution?.type === "npm") {
665
673
  const cloneRootDir = cloneDir;
@@ -738,7 +746,12 @@ const start = (options) => {
738
746
  requestedFormats.includes("spdx") &&
739
747
  isCycloneDxBom(bomNSData?.bomJson)
740
748
  ) {
741
- 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
+ );
742
755
  }
743
756
  if (reqOptions.serverUrl && reqOptions.apiKey) {
744
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
 
@@ -672,16 +672,21 @@ async function interpolateTemplate(template, context, options = {}) {
672
672
  return template;
673
673
  }
674
674
  const templateRegex = /\{\{\s*([^}]+)\s*}}/g;
675
- let result = template;
676
- const matches = [...template.matchAll(templateRegex)];
677
- for (const match of matches) {
675
+ // The template is rebuilt from its own slices in one pass, so a value taken
676
+ // from the BOM is never scanned for {{ }} again and never read as a
677
+ // String.replace pattern such as `$&`.
678
+ let result = "";
679
+ let cursor = 0;
680
+ for (const match of template.matchAll(templateRegex)) {
678
681
  const [fullMatch, expr] = match;
682
+ let replacement = fullMatch;
679
683
  try {
680
684
  const expression = jsonata(expr.trim());
681
685
  registerCdxHelpers(expression, options);
682
686
  const value = await safeEvaluate(expression, context);
683
- const replacement = value !== undefined ? String(value) : fullMatch;
684
- result = result.replace(fullMatch, replacement);
687
+ if (value !== undefined) {
688
+ replacement = String(value);
689
+ }
685
690
  } catch (err) {
686
691
  if (DEBUG_MODE) {
687
692
  console.warn(
@@ -690,7 +695,10 @@ async function interpolateTemplate(template, context, options = {}) {
690
695
  );
691
696
  }
692
697
  }
698
+ result += template.slice(cursor, match.index) + replacement;
699
+ cursor = match.index + fullMatch.length;
693
700
  }
701
+ result += template.slice(cursor);
694
702
  return result;
695
703
  }
696
704