@cdxgen/cdxgen 0.0.1 → 13.0.1

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 (722) hide show
  1. package/README.md +921 -87
  2. package/bin/audit.js +239 -0
  3. package/bin/cdxgen.js +2335 -0
  4. package/bin/convert.js +220 -0
  5. package/bin/evinse.js +353 -0
  6. package/bin/hbom.js +504 -0
  7. package/bin/repl.js +2224 -0
  8. package/bin/sign.js +195 -0
  9. package/bin/tracebom.js +303 -0
  10. package/bin/validate.js +268 -0
  11. package/bin/verify.js +189 -0
  12. package/data/README.md +307 -0
  13. package/data/bom-1.4.schema.json +1605 -0
  14. package/data/bom-1.5.schema.json +3660 -0
  15. package/data/bom-1.6.schema.json +5511 -0
  16. package/data/bom-1.7.schema.json +6700 -0
  17. package/data/cbomosdb-queries.json +68 -0
  18. package/data/component-tags.json +339 -0
  19. package/data/container-knowledge-index.json +125 -0
  20. package/data/cosdb-queries.json +17 -0
  21. package/data/crypto-oid.json +1998 -0
  22. package/data/cryptography-defs.json +3793 -0
  23. package/data/cryptography-defs.schema.json +576 -0
  24. package/data/cyclonedx-2.0-bundled.schema.json +7182 -0
  25. package/data/frameworks-list.json +219 -0
  26. package/data/glibc-stdlib.json +117 -0
  27. package/data/gtfobins-index.json +6296 -0
  28. package/data/helpers/init.gradle +71 -0
  29. package/data/jsf-0.82.schema.json +211 -0
  30. package/data/known-licenses.json +82 -0
  31. package/data/lic-mapping.json +338 -0
  32. package/data/license-aliases.json +6624 -0
  33. package/data/license-db.json +39059 -0
  34. package/data/license-deprecations.json +302 -0
  35. package/data/lolbas-index.json +150 -0
  36. package/data/predictive-audit-allowlist.json +11 -0
  37. package/data/pypi-pkg-aliases.json +1199 -0
  38. package/data/python-stdlib.json +308 -0
  39. package/data/queries-darwin.json +193 -0
  40. package/data/queries-win.json +257 -0
  41. package/data/queries.json +268 -0
  42. package/data/ruby-known-modules.json +281 -0
  43. package/data/rules/ai-agent-governance.yaml +323 -0
  44. package/data/rules/ai-bom.yaml +268 -0
  45. package/data/rules/ai-oversight.yaml +186 -0
  46. package/data/rules/ai-provenance.yaml +92 -0
  47. package/data/rules/asar-archives.yaml +150 -0
  48. package/data/rules/cbom-security.yaml +165 -0
  49. package/data/rules/chrome-extensions.yaml +248 -0
  50. package/data/rules/ci-permissions.yaml +802 -0
  51. package/data/rules/container-risk.yaml +353 -0
  52. package/data/rules/dependency-sources.yaml +236 -0
  53. package/data/rules/golem-go.yaml +229 -0
  54. package/data/rules/hbom-compliance.yaml +325 -0
  55. package/data/rules/hbom-performance.yaml +307 -0
  56. package/data/rules/hbom-security.yaml +248 -0
  57. package/data/rules/host-topology.yaml +165 -0
  58. package/data/rules/mcp-servers.yaml +388 -0
  59. package/data/rules/obom-runtime.yaml +1776 -0
  60. package/data/rules/package-integrity.yaml +364 -0
  61. package/data/rules/rootfs-hardening.yaml +179 -0
  62. package/data/rules/vscode-extensions.yaml +237 -0
  63. package/data/spdx-export.schema.json +6794 -0
  64. package/data/spdx-license-list.json +7449 -0
  65. package/data/spdx-licenses.json +759 -0
  66. package/data/spdx.schema.json +819 -0
  67. package/data/templates/README.md +3 -0
  68. package/data/templates/asvs-4.0.3.cdx.json +2943 -0
  69. package/data/templates/asvs-5.0.cdx.json +3046 -0
  70. package/data/templates/bsimm-v13.cdx.json +1008 -0
  71. package/data/templates/masvs-2.0.0.cdx.json +225 -0
  72. package/data/templates/nist-ssdf-1.1.cdx.json +828 -0
  73. package/data/templates/pcissc-secure-slc-1.1.cdx.json +1027 -0
  74. package/data/templates/scvs-1.0.0.cdx.json +813 -0
  75. package/data/templates/ssaf-DRAFT-2023-11.cdx.json +127 -0
  76. package/data/vendor-alias.json +41967 -0
  77. package/data/wrapdb-releases.json +4227 -0
  78. package/index.cjs +15 -0
  79. package/lib/audit/index.js +2800 -0
  80. package/lib/audit/progress.js +114 -0
  81. package/lib/audit/reporters.js +937 -0
  82. package/lib/audit/scoring.js +560 -0
  83. package/lib/audit/targets.js +798 -0
  84. package/lib/cli/bomAssembly.js +1882 -0
  85. package/lib/cli/cliOptions.js +543 -0
  86. package/lib/cli/index.js +2759 -0
  87. package/lib/cli/jsBom.js +2087 -0
  88. package/lib/cli/jvmBom.js +1858 -0
  89. package/lib/cli/managedBom.js +2083 -0
  90. package/lib/cli/nativeBom.js +2125 -0
  91. package/lib/core/activity.js +1087 -0
  92. package/lib/core/env.js +719 -0
  93. package/lib/core/fs.js +1058 -0
  94. package/lib/core/httpClient.js +730 -0
  95. package/lib/core/logger.js +280 -0
  96. package/lib/core/parallel.js +323 -0
  97. package/lib/core/paths.js +70 -0
  98. package/lib/core/projectConfig.js +122 -0
  99. package/lib/core/propertySanitizer.js +174 -0
  100. package/lib/core/spdx.js +5 -0
  101. package/lib/core/state.js +59 -0
  102. package/lib/core/text.js +207 -0
  103. package/lib/core/ui.js +920 -0
  104. package/lib/core/urls.js +84 -0
  105. package/lib/ecosystems/asarutils.js +1636 -0
  106. package/lib/ecosystems/bunutils.js +402 -0
  107. package/lib/ecosystems/caxa.js +77 -0
  108. package/lib/ecosystems/chromextutils.js +1174 -0
  109. package/lib/ecosystems/cmakeResolver.js +587 -0
  110. package/lib/ecosystems/cppEvidence.js +305 -0
  111. package/lib/ecosystems/denoutils.js +1094 -0
  112. package/lib/ecosystems/dotnetutils.js +132 -0
  113. package/lib/ecosystems/ecosystems.js +2772 -0
  114. package/lib/ecosystems/golem.js +1807 -0
  115. package/lib/ecosystems/gradleutils.js +1048 -0
  116. package/lib/ecosystems/jsEvidence.js +317 -0
  117. package/lib/ecosystems/npmutils.js +586 -0
  118. package/lib/ecosystems/parsers-bazel.js +875 -0
  119. package/lib/ecosystems/parsers-dotnet.js +1430 -0
  120. package/lib/ecosystems/parsers-gleam.js +302 -0
  121. package/lib/ecosystems/parsers-go.js +818 -0
  122. package/lib/ecosystems/parsers-js.js +4222 -0
  123. package/lib/ecosystems/parsers-jvm.js +948 -0
  124. package/lib/ecosystems/parsers-misc.js +3191 -0
  125. package/lib/ecosystems/parsers-python.js +2070 -0
  126. package/lib/ecosystems/parsers-rust.js +1294 -0
  127. package/lib/ecosystems/parsers-zig.js +861 -0
  128. package/lib/ecosystems/pep770.js +341 -0
  129. package/lib/ecosystems/pylockutils.js +427 -0
  130. package/lib/ecosystems/pythonutils.js +1281 -0
  131. package/lib/ecosystems/registryProvenance.js +1003 -0
  132. package/lib/ecosystems/remote/huggingface.js +1343 -0
  133. package/lib/ecosystems/rubyutils.js +1629 -0
  134. package/lib/ecosystems/rusi.js +820 -0
  135. package/lib/ecosystems/sbtutils.js +972 -0
  136. package/lib/ecosystems/tea.js +607 -0
  137. package/lib/ecosystems/utils.js +583 -0
  138. package/lib/ecosystems/zigResolver.js +410 -0
  139. package/lib/evinser/db.js +145 -0
  140. package/lib/evinser/evinser.js +2362 -0
  141. package/lib/evinser/scalasem.js +65 -0
  142. package/lib/evinser/swiftsem.js +767 -0
  143. package/lib/helpers/annotationFormatter.js +84 -0
  144. package/lib/helpers/bomSigner.js +312 -0
  145. package/lib/helpers/exportUtils.js +160 -0
  146. package/lib/helpers/remote/dependency-track.js +117 -0
  147. package/lib/helpers/versutils.js +202 -0
  148. package/lib/helpers/vsixutils.js +1069 -0
  149. package/lib/inventory/agentFormulationParser.js +322 -0
  150. package/lib/inventory/aiCollector.js +2140 -0
  151. package/lib/inventory/aiInventory.js +414 -0
  152. package/lib/inventory/aiModelVariants.js +121 -0
  153. package/lib/inventory/aiOversightCollector.js +661 -0
  154. package/lib/inventory/aiProvenanceCollector.js +822 -0
  155. package/lib/inventory/analyzer.js +6089 -0
  156. package/lib/inventory/analyzerScope.js +807 -0
  157. package/lib/inventory/astWorker.js +20 -0
  158. package/lib/inventory/atomUtils.js +1092 -0
  159. package/lib/inventory/auditCategories.js +192 -0
  160. package/lib/inventory/bomUtils.js +369 -0
  161. package/lib/inventory/cacheCommands.js +182 -0
  162. package/lib/inventory/cacheDir.js +104 -0
  163. package/lib/inventory/cbomutils.js +590 -0
  164. package/lib/inventory/cdxrs.js +434 -0
  165. package/lib/inventory/ciParsers/azurePipelines.js +295 -0
  166. package/lib/inventory/ciParsers/circleCi.js +286 -0
  167. package/lib/inventory/ciParsers/common.js +24 -0
  168. package/lib/inventory/ciParsers/githubActions.js +2434 -0
  169. package/lib/inventory/ciParsers/gitlabCi.js +213 -0
  170. package/lib/inventory/ciParsers/jenkins.js +180 -0
  171. package/lib/inventory/citations.js +234 -0
  172. package/lib/inventory/communityAiConfigParser.js +756 -0
  173. package/lib/inventory/containerRisk.js +204 -0
  174. package/lib/inventory/cryptoAlgorithmFamily.js +258 -0
  175. package/lib/inventory/deps.js +807 -0
  176. package/lib/inventory/depsUtils.js +588 -0
  177. package/lib/inventory/display.js +2128 -0
  178. package/lib/inventory/dosai.js +601 -0
  179. package/lib/inventory/dosaiParsers.js +154 -0
  180. package/lib/inventory/dynamic.js +145 -0
  181. package/lib/inventory/envcontext.js +1793 -0
  182. package/lib/inventory/evidenceUtils.js +774 -0
  183. package/lib/inventory/fetchBatch.js +779 -0
  184. package/lib/inventory/fetchRate.js +255 -0
  185. package/lib/inventory/forgeEnricher.js +300 -0
  186. package/lib/inventory/formulationParsers.js +422 -0
  187. package/lib/inventory/gtfobins.js +339 -0
  188. package/lib/inventory/hbom.js +719 -0
  189. package/lib/inventory/hbomAnalysis.js +310 -0
  190. package/lib/inventory/hbomLoader.js +35 -0
  191. package/lib/inventory/hostTopology.js +835 -0
  192. package/lib/inventory/inventoryStats.js +100 -0
  193. package/lib/inventory/jsonLike.js +121 -0
  194. package/lib/inventory/licenseEnhancer.js +918 -0
  195. package/lib/inventory/lolbas.js +285 -0
  196. package/lib/inventory/mcp.js +253 -0
  197. package/lib/inventory/mcpConfigParser.js +683 -0
  198. package/lib/inventory/mcpDiscovery.js +112 -0
  199. package/lib/inventory/mcpPinning.js +209 -0
  200. package/lib/inventory/osPackageResolver.js +493 -0
  201. package/lib/inventory/osinfo.js +383 -0
  202. package/lib/inventory/osqueryTransform.js +274 -0
  203. package/lib/inventory/plugins.js +466 -0
  204. package/lib/inventory/protobom.js +231 -0
  205. package/lib/inventory/protobomLoader.js +43 -0
  206. package/lib/inventory/provenanceUtils.js +224 -0
  207. package/lib/inventory/purl.js +749 -0
  208. package/lib/inventory/rustFormulationParser.js +339 -0
  209. package/lib/inventory/sbomDocument.js +340 -0
  210. package/lib/inventory/source.js +1488 -0
  211. package/lib/inventory/spdx.js +361 -0
  212. package/lib/inventory/spdxExpression.js +512 -0
  213. package/lib/inventory/spdxUtils.js +107 -0
  214. package/lib/inventory/table.js +267 -0
  215. package/lib/inventory/traceRunner.js +439 -0
  216. package/lib/inventory/unicodeScan.js +147 -0
  217. package/lib/managers/binary.js +3459 -0
  218. package/lib/managers/containerutils.js +125 -0
  219. package/lib/managers/docker.js +2145 -0
  220. package/lib/managers/dockerConnection.js +162 -0
  221. package/lib/managers/oci.js +704 -0
  222. package/lib/managers/piptree.js +267 -0
  223. package/lib/parsers/cmakeCache.js +199 -0
  224. package/lib/parsers/gguf.js +492 -0
  225. package/lib/parsers/gitAiNotes.js +233 -0
  226. package/lib/parsers/gitmodules.js +239 -0
  227. package/lib/parsers/htmlExtract.js +610 -0
  228. package/lib/parsers/huggingfaceManifest.js +551 -0
  229. package/lib/parsers/huggingfaceUtils.js +506 -0
  230. package/lib/parsers/iri.js +618 -0
  231. package/lib/parsers/npmrc.js +99 -0
  232. package/lib/parsers/ollama.js +101 -0
  233. package/lib/parsers/xml.js +841 -0
  234. package/lib/server/openapi.yaml +433 -0
  235. package/lib/server/server.js +616 -0
  236. package/lib/stages/postgen/annotator.js +977 -0
  237. package/lib/stages/postgen/auditBom.js +468 -0
  238. package/lib/stages/postgen/postgen.js +1239 -0
  239. package/lib/stages/postgen/ruleEngine.js +731 -0
  240. package/lib/stages/postgen/sortBom.js +195 -0
  241. package/lib/stages/postgen/spdxConverter.js +796 -0
  242. package/lib/stages/postgen/specVersionCompat.js +703 -0
  243. package/lib/stages/pregen/envAudit.js +388 -0
  244. package/lib/stages/pregen/pregen.js +637 -0
  245. package/lib/third-party/README.md +9 -0
  246. package/lib/third-party/arborist/CHANGELOG.md +1109 -0
  247. package/lib/third-party/arborist/LICENSE.md +20 -0
  248. package/lib/third-party/arborist/README.md +315 -0
  249. package/lib/third-party/arborist/lib/arborist/index.js +258 -0
  250. package/lib/third-party/arborist/lib/arborist/load-actual.js +605 -0
  251. package/lib/third-party/arborist/lib/arborist/load-virtual.js +300 -0
  252. package/lib/third-party/arborist/lib/bin-links.js +120 -0
  253. package/lib/third-party/arborist/lib/calc-dep-flags.js +130 -0
  254. package/lib/third-party/arborist/lib/case-insensitive-map.js +51 -0
  255. package/lib/third-party/arborist/lib/consistent-resolve.js +42 -0
  256. package/lib/third-party/arborist/lib/debug.js +50 -0
  257. package/lib/third-party/arborist/lib/dep-valid.js +190 -0
  258. package/lib/third-party/arborist/lib/edge.js +417 -0
  259. package/lib/third-party/arborist/lib/from-path.js +36 -0
  260. package/lib/third-party/arborist/lib/gather-dep-set.js +43 -0
  261. package/lib/third-party/arborist/lib/index.js +22 -0
  262. package/lib/third-party/arborist/lib/inventory.js +138 -0
  263. package/lib/third-party/arborist/lib/link.js +169 -0
  264. package/lib/third-party/arborist/lib/node.js +1673 -0
  265. package/lib/third-party/arborist/lib/npm-extension.js +45 -0
  266. package/lib/third-party/arborist/lib/override-resolves.js +11 -0
  267. package/lib/third-party/arborist/lib/override-set.js +319 -0
  268. package/lib/third-party/arborist/lib/package-extensions.js +289 -0
  269. package/lib/third-party/arborist/lib/printable.js +210 -0
  270. package/lib/third-party/arborist/lib/proc-log.js +30 -0
  271. package/lib/third-party/arborist/lib/realpath.js +100 -0
  272. package/lib/third-party/arborist/lib/relpath.js +4 -0
  273. package/lib/third-party/arborist/lib/shrinkwrap.js +1291 -0
  274. package/lib/third-party/arborist/lib/spec-from-lock.js +34 -0
  275. package/lib/third-party/arborist/lib/tree-check.js +165 -0
  276. package/lib/third-party/arborist/lib/validate-npm-package-name.js +107 -0
  277. package/lib/third-party/arborist/lib/version-from-tgz.js +51 -0
  278. package/lib/third-party/arborist/lib/yarn-lock.js +397 -0
  279. package/lib/validator/bomValidator.js +985 -0
  280. package/lib/validator/complianceEngine.js +241 -0
  281. package/lib/validator/complianceRules.js +1680 -0
  282. package/lib/validator/generated/runtime.mjs +17 -0
  283. package/lib/validator/generated/validate-1.6.mjs +21258 -0
  284. package/lib/validator/generated/validate-1.7.mjs +24803 -0
  285. package/lib/validator/generated/validate-2.0.mjs +22931 -0
  286. package/lib/validator/index.js +246 -0
  287. package/lib/validator/reporters/annotations.js +142 -0
  288. package/lib/validator/reporters/console.js +160 -0
  289. package/lib/validator/reporters/index.js +41 -0
  290. package/lib/validator/reporters/json.js +37 -0
  291. package/lib/validator/reporters/sarif.js +184 -0
  292. package/package.json +209 -26
  293. package/types/bin/audit.d.ts +3 -0
  294. package/types/bin/audit.d.ts.map +1 -0
  295. package/types/bin/cdxgen.d.ts +3 -0
  296. package/types/bin/cdxgen.d.ts.map +1 -0
  297. package/types/bin/convert.d.ts +3 -0
  298. package/types/bin/convert.d.ts.map +1 -0
  299. package/types/bin/evinse.d.ts +3 -0
  300. package/types/bin/evinse.d.ts.map +1 -0
  301. package/types/bin/hbom.d.ts +3 -0
  302. package/types/bin/hbom.d.ts.map +1 -0
  303. package/types/bin/repl.d.ts +3 -0
  304. package/types/bin/repl.d.ts.map +1 -0
  305. package/types/bin/sign.d.ts +3 -0
  306. package/types/bin/sign.d.ts.map +1 -0
  307. package/types/bin/tracebom.d.ts +3 -0
  308. package/types/bin/tracebom.d.ts.map +1 -0
  309. package/types/bin/validate.d.ts +14 -0
  310. package/types/bin/validate.d.ts.map +1 -0
  311. package/types/bin/verify.d.ts +3 -0
  312. package/types/bin/verify.d.ts.map +1 -0
  313. package/types/lib/audit/index.d.ts +153 -0
  314. package/types/lib/audit/index.d.ts.map +1 -0
  315. package/types/lib/audit/progress.d.ts +31 -0
  316. package/types/lib/audit/progress.d.ts.map +1 -0
  317. package/types/lib/audit/reporters.d.ts +62 -0
  318. package/types/lib/audit/reporters.d.ts.map +1 -0
  319. package/types/lib/audit/scoring.d.ts +36 -0
  320. package/types/lib/audit/scoring.d.ts.map +1 -0
  321. package/types/lib/audit/targets.d.ts +77 -0
  322. package/types/lib/audit/targets.d.ts.map +1 -0
  323. package/types/lib/cli/bomAssembly.d.ts +329 -0
  324. package/types/lib/cli/bomAssembly.d.ts.map +1 -0
  325. package/types/lib/cli/cliOptions.d.ts +156 -0
  326. package/types/lib/cli/cliOptions.d.ts.map +1 -0
  327. package/types/lib/cli/index.d.ts +107 -0
  328. package/types/lib/cli/index.d.ts.map +1 -0
  329. package/types/lib/cli/jsBom.d.ts +94 -0
  330. package/types/lib/cli/jsBom.d.ts.map +1 -0
  331. package/types/lib/cli/jvmBom.d.ts +54 -0
  332. package/types/lib/cli/jvmBom.d.ts.map +1 -0
  333. package/types/lib/cli/managedBom.d.ts +105 -0
  334. package/types/lib/cli/managedBom.d.ts.map +1 -0
  335. package/types/lib/cli/nativeBom.d.ts +143 -0
  336. package/types/lib/cli/nativeBom.d.ts.map +1 -0
  337. package/types/lib/core/activity.d.ts +178 -0
  338. package/types/lib/core/activity.d.ts.map +1 -0
  339. package/types/lib/core/env.d.ts +192 -0
  340. package/types/lib/core/env.d.ts.map +1 -0
  341. package/types/lib/core/fs.d.ts +158 -0
  342. package/types/lib/core/fs.d.ts.map +1 -0
  343. package/types/lib/core/httpClient.d.ts +149 -0
  344. package/types/lib/core/httpClient.d.ts.map +1 -0
  345. package/types/lib/core/logger.d.ts +50 -0
  346. package/types/lib/core/logger.d.ts.map +1 -0
  347. package/types/lib/core/parallel.d.ts +95 -0
  348. package/types/lib/core/parallel.d.ts.map +1 -0
  349. package/types/lib/core/paths.d.ts +36 -0
  350. package/types/lib/core/paths.d.ts.map +1 -0
  351. package/types/lib/core/projectConfig.d.ts +23 -0
  352. package/types/lib/core/projectConfig.d.ts.map +1 -0
  353. package/types/lib/core/propertySanitizer.d.ts +23 -0
  354. package/types/lib/core/propertySanitizer.d.ts.map +1 -0
  355. package/types/lib/core/spdx.d.ts +5 -0
  356. package/types/lib/core/spdx.d.ts.map +1 -0
  357. package/types/lib/core/state.d.ts +20 -0
  358. package/types/lib/core/state.d.ts.map +1 -0
  359. package/types/lib/core/text.d.ts +78 -0
  360. package/types/lib/core/text.d.ts.map +1 -0
  361. package/types/lib/core/ui.d.ts +87 -0
  362. package/types/lib/core/ui.d.ts.map +1 -0
  363. package/types/lib/core/urls.d.ts +43 -0
  364. package/types/lib/core/urls.d.ts.map +1 -0
  365. package/types/lib/ecosystems/asarutils.d.ts +71 -0
  366. package/types/lib/ecosystems/asarutils.d.ts.map +1 -0
  367. package/types/lib/ecosystems/bunutils.d.ts +38 -0
  368. package/types/lib/ecosystems/bunutils.d.ts.map +1 -0
  369. package/types/lib/ecosystems/caxa.d.ts +8 -0
  370. package/types/lib/ecosystems/caxa.d.ts.map +1 -0
  371. package/types/lib/ecosystems/chromextutils.d.ts +97 -0
  372. package/types/lib/ecosystems/chromextutils.d.ts.map +1 -0
  373. package/types/lib/ecosystems/cmakeResolver.d.ts +176 -0
  374. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -0
  375. package/types/lib/ecosystems/cppEvidence.d.ts +35 -0
  376. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -0
  377. package/types/lib/ecosystems/denoutils.d.ts +76 -0
  378. package/types/lib/ecosystems/denoutils.d.ts.map +1 -0
  379. package/types/lib/ecosystems/dotnetutils.d.ts +45 -0
  380. package/types/lib/ecosystems/dotnetutils.d.ts.map +1 -0
  381. package/types/lib/ecosystems/ecosystems.d.ts +279 -0
  382. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -0
  383. package/types/lib/ecosystems/golem.d.ts +60 -0
  384. package/types/lib/ecosystems/golem.d.ts.map +1 -0
  385. package/types/lib/ecosystems/gradleutils.d.ts +139 -0
  386. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -0
  387. package/types/lib/ecosystems/jsEvidence.d.ts +17 -0
  388. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -0
  389. package/types/lib/ecosystems/npmutils.d.ts +183 -0
  390. package/types/lib/ecosystems/npmutils.d.ts.map +1 -0
  391. package/types/lib/ecosystems/parsers-bazel.d.ts +36 -0
  392. package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -0
  393. package/types/lib/ecosystems/parsers-dotnet.d.ts +116 -0
  394. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -0
  395. package/types/lib/ecosystems/parsers-gleam.d.ts +33 -0
  396. package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -0
  397. package/types/lib/ecosystems/parsers-go.d.ts +92 -0
  398. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -0
  399. package/types/lib/ecosystems/parsers-js.d.ts +242 -0
  400. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -0
  401. package/types/lib/ecosystems/parsers-jvm.d.ts +100 -0
  402. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -0
  403. package/types/lib/ecosystems/parsers-misc.d.ts +450 -0
  404. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -0
  405. package/types/lib/ecosystems/parsers-python.d.ts +145 -0
  406. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -0
  407. package/types/lib/ecosystems/parsers-rust.d.ts +56 -0
  408. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -0
  409. package/types/lib/ecosystems/parsers-zig.d.ts +83 -0
  410. package/types/lib/ecosystems/parsers-zig.d.ts.map +1 -0
  411. package/types/lib/ecosystems/pep770.d.ts +38 -0
  412. package/types/lib/ecosystems/pep770.d.ts.map +1 -0
  413. package/types/lib/ecosystems/pylockutils.d.ts +68 -0
  414. package/types/lib/ecosystems/pylockutils.d.ts.map +1 -0
  415. package/types/lib/ecosystems/pythonutils.d.ts +70 -0
  416. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -0
  417. package/types/lib/ecosystems/registryProvenance.d.ts +26 -0
  418. package/types/lib/ecosystems/registryProvenance.d.ts.map +1 -0
  419. package/types/lib/ecosystems/remote/huggingface.d.ts +31 -0
  420. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -0
  421. package/types/lib/ecosystems/rubyutils.d.ts +182 -0
  422. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -0
  423. package/types/lib/ecosystems/rusi.d.ts +40 -0
  424. package/types/lib/ecosystems/rusi.d.ts.map +1 -0
  425. package/types/lib/ecosystems/sbtutils.d.ts +179 -0
  426. package/types/lib/ecosystems/sbtutils.d.ts.map +1 -0
  427. package/types/lib/ecosystems/tea.d.ts +180 -0
  428. package/types/lib/ecosystems/tea.d.ts.map +1 -0
  429. package/types/lib/ecosystems/utils.d.ts +41 -0
  430. package/types/lib/ecosystems/utils.d.ts.map +1 -0
  431. package/types/lib/ecosystems/zigResolver.d.ts +70 -0
  432. package/types/lib/ecosystems/zigResolver.d.ts.map +1 -0
  433. package/types/lib/evinser/db.d.ts +17 -0
  434. package/types/lib/evinser/db.d.ts.map +1 -0
  435. package/types/lib/evinser/evinser.d.ts +354 -0
  436. package/types/lib/evinser/evinser.d.ts.map +1 -0
  437. package/types/lib/evinser/scalasem.d.ts +15 -0
  438. package/types/lib/evinser/scalasem.d.ts.map +1 -0
  439. package/types/lib/evinser/swiftsem.d.ts +103 -0
  440. package/types/lib/evinser/swiftsem.d.ts.map +1 -0
  441. package/types/lib/helpers/annotationFormatter.d.ts +23 -0
  442. package/types/lib/helpers/annotationFormatter.d.ts.map +1 -0
  443. package/types/lib/helpers/bomSigner.d.ts +28 -0
  444. package/types/lib/helpers/bomSigner.d.ts.map +1 -0
  445. package/types/lib/helpers/exportUtils.d.ts +52 -0
  446. package/types/lib/helpers/exportUtils.d.ts.map +1 -0
  447. package/types/lib/helpers/remote/dependency-track.d.ts +23 -0
  448. package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
  449. package/types/lib/helpers/versutils.d.ts +8 -0
  450. package/types/lib/helpers/versutils.d.ts.map +1 -0
  451. package/types/lib/helpers/vsixutils.d.ts +130 -0
  452. package/types/lib/helpers/vsixutils.d.ts.map +1 -0
  453. package/types/lib/inventory/agentFormulationParser.d.ts +21 -0
  454. package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -0
  455. package/types/lib/inventory/aiCollector.d.ts +61 -0
  456. package/types/lib/inventory/aiCollector.d.ts.map +1 -0
  457. package/types/lib/inventory/aiInventory.d.ts +103 -0
  458. package/types/lib/inventory/aiInventory.d.ts.map +1 -0
  459. package/types/lib/inventory/aiModelVariants.d.ts +31 -0
  460. package/types/lib/inventory/aiModelVariants.d.ts.map +1 -0
  461. package/types/lib/inventory/aiOversightCollector.d.ts +28 -0
  462. package/types/lib/inventory/aiOversightCollector.d.ts.map +1 -0
  463. package/types/lib/inventory/aiProvenanceCollector.d.ts +13 -0
  464. package/types/lib/inventory/aiProvenanceCollector.d.ts.map +1 -0
  465. package/types/lib/inventory/analyzer.d.ts +157 -0
  466. package/types/lib/inventory/analyzer.d.ts.map +1 -0
  467. package/types/lib/inventory/analyzerScope.d.ts +106 -0
  468. package/types/lib/inventory/analyzerScope.d.ts.map +1 -0
  469. package/types/lib/inventory/astWorker.d.ts +9 -0
  470. package/types/lib/inventory/astWorker.d.ts.map +1 -0
  471. package/types/lib/inventory/atomUtils.d.ts +159 -0
  472. package/types/lib/inventory/atomUtils.d.ts.map +1 -0
  473. package/types/lib/inventory/auditCategories.d.ts +80 -0
  474. package/types/lib/inventory/auditCategories.d.ts.map +1 -0
  475. package/types/lib/inventory/bomUtils.d.ts +145 -0
  476. package/types/lib/inventory/bomUtils.d.ts.map +1 -0
  477. package/types/lib/inventory/cacheCommands.d.ts +28 -0
  478. package/types/lib/inventory/cacheCommands.d.ts.map +1 -0
  479. package/types/lib/inventory/cacheDir.d.ts +55 -0
  480. package/types/lib/inventory/cacheDir.d.ts.map +1 -0
  481. package/types/lib/inventory/cbomutils.d.ts +37 -0
  482. package/types/lib/inventory/cbomutils.d.ts.map +1 -0
  483. package/types/lib/inventory/cdxrs.d.ts +90 -0
  484. package/types/lib/inventory/cdxrs.d.ts.map +1 -0
  485. package/types/lib/inventory/ciParsers/azurePipelines.d.ts +27 -0
  486. package/types/lib/inventory/ciParsers/azurePipelines.d.ts.map +1 -0
  487. package/types/lib/inventory/ciParsers/circleCi.d.ts +27 -0
  488. package/types/lib/inventory/ciParsers/circleCi.d.ts.map +1 -0
  489. package/types/lib/inventory/ciParsers/common.d.ts +11 -0
  490. package/types/lib/inventory/ciParsers/common.d.ts.map +1 -0
  491. package/types/lib/inventory/ciParsers/githubActions.d.ts +38 -0
  492. package/types/lib/inventory/ciParsers/githubActions.d.ts.map +1 -0
  493. package/types/lib/inventory/ciParsers/gitlabCi.d.ts +26 -0
  494. package/types/lib/inventory/ciParsers/gitlabCi.d.ts.map +1 -0
  495. package/types/lib/inventory/ciParsers/jenkins.d.ts +26 -0
  496. package/types/lib/inventory/ciParsers/jenkins.d.ts.map +1 -0
  497. package/types/lib/inventory/citations.d.ts +90 -0
  498. package/types/lib/inventory/citations.d.ts.map +1 -0
  499. package/types/lib/inventory/communityAiConfigParser.d.ts +14 -0
  500. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -0
  501. package/types/lib/inventory/containerRisk.d.ts +20 -0
  502. package/types/lib/inventory/containerRisk.d.ts.map +1 -0
  503. package/types/lib/inventory/cryptoAlgorithmFamily.d.ts +37 -0
  504. package/types/lib/inventory/cryptoAlgorithmFamily.d.ts.map +1 -0
  505. package/types/lib/inventory/deps.d.ts +140 -0
  506. package/types/lib/inventory/deps.d.ts.map +1 -0
  507. package/types/lib/inventory/depsUtils.d.ts +74 -0
  508. package/types/lib/inventory/depsUtils.d.ts.map +1 -0
  509. package/types/lib/inventory/display.d.ts +227 -0
  510. package/types/lib/inventory/display.d.ts.map +1 -0
  511. package/types/lib/inventory/dosai.d.ts +130 -0
  512. package/types/lib/inventory/dosai.d.ts.map +1 -0
  513. package/types/lib/inventory/dosaiParsers.d.ts +59 -0
  514. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -0
  515. package/types/lib/inventory/dynamic.d.ts +25 -0
  516. package/types/lib/inventory/dynamic.d.ts.map +1 -0
  517. package/types/lib/inventory/envcontext.d.ts +377 -0
  518. package/types/lib/inventory/envcontext.d.ts.map +1 -0
  519. package/types/lib/inventory/evidenceUtils.d.ts +74 -0
  520. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -0
  521. package/types/lib/inventory/fetchBatch.d.ts +127 -0
  522. package/types/lib/inventory/fetchBatch.d.ts.map +1 -0
  523. package/types/lib/inventory/fetchRate.d.ts +118 -0
  524. package/types/lib/inventory/fetchRate.d.ts.map +1 -0
  525. package/types/lib/inventory/forgeEnricher.d.ts +31 -0
  526. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -0
  527. package/types/lib/inventory/formulationParsers.d.ts +50 -0
  528. package/types/lib/inventory/formulationParsers.d.ts.map +1 -0
  529. package/types/lib/inventory/gtfobins.d.ts +27 -0
  530. package/types/lib/inventory/gtfobins.d.ts.map +1 -0
  531. package/types/lib/inventory/hbom.d.ts +58 -0
  532. package/types/lib/inventory/hbom.d.ts.map +1 -0
  533. package/types/lib/inventory/hbomAnalysis.d.ts +56 -0
  534. package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -0
  535. package/types/lib/inventory/hbomLoader.d.ts +7 -0
  536. package/types/lib/inventory/hbomLoader.d.ts.map +1 -0
  537. package/types/lib/inventory/hostTopology.d.ts +47 -0
  538. package/types/lib/inventory/hostTopology.d.ts.map +1 -0
  539. package/types/lib/inventory/inventoryStats.d.ts +42 -0
  540. package/types/lib/inventory/inventoryStats.d.ts.map +1 -0
  541. package/types/lib/inventory/jsonLike.d.ts +23 -0
  542. package/types/lib/inventory/jsonLike.d.ts.map +1 -0
  543. package/types/lib/inventory/licenseEnhancer.d.ts +70 -0
  544. package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -0
  545. package/types/lib/inventory/lolbas.d.ts +16 -0
  546. package/types/lib/inventory/lolbas.d.ts.map +1 -0
  547. package/types/lib/inventory/mcp.d.ts +29 -0
  548. package/types/lib/inventory/mcp.d.ts.map +1 -0
  549. package/types/lib/inventory/mcpConfigParser.d.ts +20 -0
  550. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -0
  551. package/types/lib/inventory/mcpDiscovery.d.ts +33 -0
  552. package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -0
  553. package/types/lib/inventory/mcpPinning.d.ts +11 -0
  554. package/types/lib/inventory/mcpPinning.d.ts.map +1 -0
  555. package/types/lib/inventory/osPackageResolver.d.ts +49 -0
  556. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -0
  557. package/types/lib/inventory/osinfo.d.ts +201 -0
  558. package/types/lib/inventory/osinfo.d.ts.map +1 -0
  559. package/types/lib/inventory/osqueryTransform.d.ts +84 -0
  560. package/types/lib/inventory/osqueryTransform.d.ts.map +1 -0
  561. package/types/lib/inventory/plugins.d.ts +58 -0
  562. package/types/lib/inventory/plugins.d.ts.map +1 -0
  563. package/types/lib/inventory/protobom.d.ts +71 -0
  564. package/types/lib/inventory/protobom.d.ts.map +1 -0
  565. package/types/lib/inventory/protobomLoader.d.ts +17 -0
  566. package/types/lib/inventory/protobomLoader.d.ts.map +1 -0
  567. package/types/lib/inventory/provenanceUtils.d.ts +98 -0
  568. package/types/lib/inventory/provenanceUtils.d.ts.map +1 -0
  569. package/types/lib/inventory/purl.d.ts +313 -0
  570. package/types/lib/inventory/purl.d.ts.map +1 -0
  571. package/types/lib/inventory/rustFormulationParser.d.ts +17 -0
  572. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -0
  573. package/types/lib/inventory/sbomDocument.d.ts +59 -0
  574. package/types/lib/inventory/sbomDocument.d.ts.map +1 -0
  575. package/types/lib/inventory/source.d.ts +163 -0
  576. package/types/lib/inventory/source.d.ts.map +1 -0
  577. package/types/lib/inventory/spdx.d.ts +66 -0
  578. package/types/lib/inventory/spdx.d.ts.map +1 -0
  579. package/types/lib/inventory/spdxExpression.d.ts +58 -0
  580. package/types/lib/inventory/spdxExpression.d.ts.map +1 -0
  581. package/types/lib/inventory/spdxUtils.d.ts +12 -0
  582. package/types/lib/inventory/spdxUtils.d.ts.map +1 -0
  583. package/types/lib/inventory/table.d.ts +22 -0
  584. package/types/lib/inventory/table.d.ts.map +1 -0
  585. package/types/lib/inventory/traceRunner.d.ts +80 -0
  586. package/types/lib/inventory/traceRunner.d.ts.map +1 -0
  587. package/types/lib/inventory/unicodeScan.d.ts +46 -0
  588. package/types/lib/inventory/unicodeScan.d.ts.map +1 -0
  589. package/types/lib/managers/binary.d.ts +147 -0
  590. package/types/lib/managers/binary.d.ts.map +1 -0
  591. package/types/lib/managers/containerutils.d.ts +30 -0
  592. package/types/lib/managers/containerutils.d.ts.map +1 -0
  593. package/types/lib/managers/docker.d.ts +157 -0
  594. package/types/lib/managers/docker.d.ts.map +1 -0
  595. package/types/lib/managers/dockerConnection.d.ts +42 -0
  596. package/types/lib/managers/dockerConnection.d.ts.map +1 -0
  597. package/types/lib/managers/oci.d.ts +21 -0
  598. package/types/lib/managers/oci.d.ts.map +1 -0
  599. package/types/lib/managers/piptree.d.ts +13 -0
  600. package/types/lib/managers/piptree.d.ts.map +1 -0
  601. package/types/lib/parsers/cmakeCache.d.ts +70 -0
  602. package/types/lib/parsers/cmakeCache.d.ts.map +1 -0
  603. package/types/lib/parsers/gguf.d.ts +39 -0
  604. package/types/lib/parsers/gguf.d.ts.map +1 -0
  605. package/types/lib/parsers/gitAiNotes.d.ts +15 -0
  606. package/types/lib/parsers/gitAiNotes.d.ts.map +1 -0
  607. package/types/lib/parsers/gitmodules.d.ts +88 -0
  608. package/types/lib/parsers/gitmodules.d.ts.map +1 -0
  609. package/types/lib/parsers/htmlExtract.d.ts +34 -0
  610. package/types/lib/parsers/htmlExtract.d.ts.map +1 -0
  611. package/types/lib/parsers/huggingfaceManifest.d.ts +153 -0
  612. package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -0
  613. package/types/lib/parsers/huggingfaceUtils.d.ts +155 -0
  614. package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -0
  615. package/types/lib/parsers/iri.d.ts +68 -0
  616. package/types/lib/parsers/iri.d.ts.map +1 -0
  617. package/types/lib/parsers/npmrc.d.ts +33 -0
  618. package/types/lib/parsers/npmrc.d.ts.map +1 -0
  619. package/types/lib/parsers/ollama.d.ts +22 -0
  620. package/types/lib/parsers/ollama.d.ts.map +1 -0
  621. package/types/lib/parsers/xml.d.ts +47 -0
  622. package/types/lib/parsers/xml.d.ts.map +1 -0
  623. package/types/lib/server/server.d.ts +51 -0
  624. package/types/lib/server/server.d.ts.map +1 -0
  625. package/types/lib/stages/postgen/annotator.d.ts +36 -0
  626. package/types/lib/stages/postgen/annotator.d.ts.map +1 -0
  627. package/types/lib/stages/postgen/auditBom.d.ts +92 -0
  628. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
  629. package/types/lib/stages/postgen/postgen.d.ts +59 -0
  630. package/types/lib/stages/postgen/postgen.d.ts.map +1 -0
  631. package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
  632. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
  633. package/types/lib/stages/postgen/sortBom.d.ts +34 -0
  634. package/types/lib/stages/postgen/sortBom.d.ts.map +1 -0
  635. package/types/lib/stages/postgen/spdxConverter.d.ts +11 -0
  636. package/types/lib/stages/postgen/spdxConverter.d.ts.map +1 -0
  637. package/types/lib/stages/postgen/specVersionCompat.d.ts +71 -0
  638. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -0
  639. package/types/lib/stages/pregen/envAudit.d.ts +14 -0
  640. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
  641. package/types/lib/stages/pregen/pregen.d.ts +59 -0
  642. package/types/lib/stages/pregen/pregen.d.ts.map +1 -0
  643. package/types/lib/third-party/arborist/lib/arborist/index.d.ts +47 -0
  644. package/types/lib/third-party/arborist/lib/arborist/index.d.ts.map +1 -0
  645. package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts +4 -0
  646. package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts.map +1 -0
  647. package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts +4 -0
  648. package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts.map +1 -0
  649. package/types/lib/third-party/arborist/lib/bin-links.d.ts +18 -0
  650. package/types/lib/third-party/arborist/lib/bin-links.d.ts.map +1 -0
  651. package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts +3 -0
  652. package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts.map +1 -0
  653. package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts +9 -0
  654. package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts.map +1 -0
  655. package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts +3 -0
  656. package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts.map +1 -0
  657. package/types/lib/third-party/arborist/lib/debug.d.ts +3 -0
  658. package/types/lib/third-party/arborist/lib/debug.d.ts.map +1 -0
  659. package/types/lib/third-party/arborist/lib/dep-valid.d.ts +3 -0
  660. package/types/lib/third-party/arborist/lib/dep-valid.d.ts.map +1 -0
  661. package/types/lib/third-party/arborist/lib/edge.d.ts +46 -0
  662. package/types/lib/third-party/arborist/lib/edge.d.ts.map +1 -0
  663. package/types/lib/third-party/arborist/lib/from-path.d.ts +3 -0
  664. package/types/lib/third-party/arborist/lib/from-path.d.ts.map +1 -0
  665. package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts +3 -0
  666. package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts.map +1 -0
  667. package/types/lib/third-party/arborist/lib/index.d.ts +3 -0
  668. package/types/lib/third-party/arborist/lib/index.d.ts.map +1 -0
  669. package/types/lib/third-party/arborist/lib/inventory.d.ts +14 -0
  670. package/types/lib/third-party/arborist/lib/inventory.d.ts.map +1 -0
  671. package/types/lib/third-party/arborist/lib/link.d.ts +18 -0
  672. package/types/lib/third-party/arborist/lib/link.d.ts.map +1 -0
  673. package/types/lib/third-party/arborist/lib/node.d.ts +112 -0
  674. package/types/lib/third-party/arborist/lib/node.d.ts.map +1 -0
  675. package/types/lib/third-party/arborist/lib/npm-extension.d.ts +18 -0
  676. package/types/lib/third-party/arborist/lib/npm-extension.d.ts.map +1 -0
  677. package/types/lib/third-party/arborist/lib/override-resolves.d.ts +3 -0
  678. package/types/lib/third-party/arborist/lib/override-resolves.d.ts.map +1 -0
  679. package/types/lib/third-party/arborist/lib/override-set.d.ts +27 -0
  680. package/types/lib/third-party/arborist/lib/override-set.d.ts.map +1 -0
  681. package/types/lib/third-party/arborist/lib/package-extensions.d.ts +36 -0
  682. package/types/lib/third-party/arborist/lib/package-extensions.d.ts.map +1 -0
  683. package/types/lib/third-party/arborist/lib/printable.d.ts +3 -0
  684. package/types/lib/third-party/arborist/lib/printable.d.ts.map +1 -0
  685. package/types/lib/third-party/arborist/lib/proc-log.d.ts +20 -0
  686. package/types/lib/third-party/arborist/lib/proc-log.d.ts.map +1 -0
  687. package/types/lib/third-party/arborist/lib/realpath.d.ts +3 -0
  688. package/types/lib/third-party/arborist/lib/realpath.d.ts.map +1 -0
  689. package/types/lib/third-party/arborist/lib/relpath.d.ts +3 -0
  690. package/types/lib/third-party/arborist/lib/relpath.d.ts.map +1 -0
  691. package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts +54 -0
  692. package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts.map +1 -0
  693. package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts +3 -0
  694. package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts.map +1 -0
  695. package/types/lib/third-party/arborist/lib/tree-check.d.ts +3 -0
  696. package/types/lib/third-party/arborist/lib/tree-check.d.ts.map +1 -0
  697. package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts +13 -0
  698. package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts.map +1 -0
  699. package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts +6 -0
  700. package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts.map +1 -0
  701. package/types/lib/third-party/arborist/lib/yarn-lock.d.ts +35 -0
  702. package/types/lib/third-party/arborist/lib/yarn-lock.d.ts.map +1 -0
  703. package/types/lib/validator/bomValidator.d.ts +40 -0
  704. package/types/lib/validator/bomValidator.d.ts.map +1 -0
  705. package/types/lib/validator/complianceEngine.d.ts +72 -0
  706. package/types/lib/validator/complianceEngine.d.ts.map +1 -0
  707. package/types/lib/validator/complianceRules.d.ts +61 -0
  708. package/types/lib/validator/complianceRules.d.ts.map +1 -0
  709. package/types/lib/validator/index.d.ts +101 -0
  710. package/types/lib/validator/index.d.ts.map +1 -0
  711. package/types/lib/validator/reporters/annotations.d.ts +37 -0
  712. package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
  713. package/types/lib/validator/reporters/console.d.ts +34 -0
  714. package/types/lib/validator/reporters/console.d.ts.map +1 -0
  715. package/types/lib/validator/reporters/index.d.ts +30 -0
  716. package/types/lib/validator/reporters/index.d.ts.map +1 -0
  717. package/types/lib/validator/reporters/json.d.ts +11 -0
  718. package/types/lib/validator/reporters/json.d.ts.map +1 -0
  719. package/types/lib/validator/reporters/sarif.d.ts +22 -0
  720. package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
  721. package/mod.d.ts +0 -7
  722. package/mod.js +0 -22
@@ -0,0 +1,2087 @@
1
+ import { lstatSync, readdirSync, readFileSync } from "node:fs";
2
+ import { platform as _platform, arch } from "node:os";
3
+ import { basename, dirname, join, relative, resolve, sep } from "node:path";
4
+ import process from "node:process";
5
+
6
+ import { build } from "@cdxgen/cdx-purl";
7
+
8
+ import {
9
+ DEBUG_MODE,
10
+ isSecureMode,
11
+ readEnvironmentVariable,
12
+ recordSensitiveFileRead,
13
+ } from "../core/activity.js";
14
+ import { hasAnyProjectType, isPackageManagerAllowed } from "../core/env.js";
15
+ import { getAllFiles, safeExistsSync, safeSpawnSync } from "../core/fs.js";
16
+ import { thoughtLog } from "../core/logger.js";
17
+ import {
18
+ cleanupAsarTempDir,
19
+ extractAsarToTempDir,
20
+ isAsarArchiveSync,
21
+ parseAsarArchive,
22
+ rewriteExtractedArchivePaths,
23
+ } from "../ecosystems/asarutils.js";
24
+ import { parseBunLock } from "../ecosystems/bunutils.js";
25
+ import { parseCaxaMetadata } from "../ecosystems/caxa.js";
26
+ import {
27
+ CHROME_EXTENSION_PURL_TYPE,
28
+ collectChromeExtensionsFromPath,
29
+ collectInstalledChromeExtensions,
30
+ discoverChromiumExtensionDirs,
31
+ } from "../ecosystems/chromextutils.js";
32
+ import {
33
+ findDenoJson,
34
+ parseDenoJsonFile,
35
+ parseDenoLock,
36
+ } from "../ecosystems/denoutils.js";
37
+ import { addEvidenceForImports } from "../ecosystems/jsEvidence.js";
38
+ import { createNpmWorkspacePurl } from "../ecosystems/npmutils.js";
39
+ import {
40
+ parseBowerJson,
41
+ parseMinJs,
42
+ parseNodeShrinkwrap,
43
+ parsePkgJson,
44
+ parsePkgLock,
45
+ parsePnpmLock,
46
+ parsePnpmWorkspace,
47
+ parseYarnLock,
48
+ parseYarnWorkspace,
49
+ } from "../ecosystems/parsers-js.js";
50
+ import {
51
+ fetchHuggingFaceAssetInventory,
52
+ normalizeHuggingFaceReference,
53
+ } from "../ecosystems/remote/huggingface.js";
54
+ import {
55
+ cleanupTempDir,
56
+ collectInstalledExtensions,
57
+ discoverIdeExtensionDirs,
58
+ extractVsixToTempDir,
59
+ parseVsixFile,
60
+ VSCODE_EXTENSION_PURL_TYPE,
61
+ } from "../helpers/vsixutils.js";
62
+ import {
63
+ collectAiInventory,
64
+ filterInventoryDependencies,
65
+ filterInventorySubjectsByTypes,
66
+ summarizeAiInventory,
67
+ } from "../inventory/aiInventory.js";
68
+ import {
69
+ detectMcpInventory,
70
+ findJSImportsExports,
71
+ } from "../inventory/analyzer.js";
72
+ import {
73
+ markNpmTypesPackagesAsExcluded,
74
+ mergeDependencies,
75
+ mergeServices,
76
+ propagateRequiredScopeFromDependencies,
77
+ trimComponents,
78
+ } from "../inventory/depsUtils.js";
79
+ import { GIT_COMMAND } from "../inventory/envcontext.js";
80
+ import { tryBuildPurl } from "../inventory/purl.js";
81
+ import { DEFAULT_NPMRC_BLOCKLIST, parseNpmrc } from "../parsers/npmrc.js";
82
+ import {
83
+ buildBomNSData,
84
+ createDefaultParentComponent,
85
+ filterIncludedAiInventoryTypes,
86
+ getExactAiInventoryType,
87
+ getExcludedAiInventoryTypes,
88
+ getIncludedAiInventoryTypes,
89
+ getRequestedAiInventoryTypes,
90
+ hasExplicitProjectTypeSelection,
91
+ shouldDetectMcpInventory,
92
+ } from "./bomAssembly.js";
93
+
94
+ const isWin = _platform() === "win32";
95
+
96
+ /**
97
+ * Detects an exact AI inventory type from a direct HuggingFace reference or a
98
+ * local Modelfile/`.gguf` file input. Returns the explicit selection from
99
+ * `getExactAiInventoryType` when one is present.
100
+ *
101
+ * @param {string} path Project or file path
102
+ * @param {object} options CLI options
103
+ * @returns {string|undefined} The detected AI inventory type (`"ai"`) or undefined
104
+ */
105
+ export function getDirectAiInventoryType(path, options) {
106
+ const exactAiInventoryType = getExactAiInventoryType(options);
107
+ if (exactAiInventoryType) {
108
+ return exactAiInventoryType;
109
+ }
110
+ if (normalizeHuggingFaceReference(path)) {
111
+ return "ai";
112
+ }
113
+ try {
114
+ const stat = lstatSync(path);
115
+ if (
116
+ stat.isFile() &&
117
+ (basename(path) === "Modelfile" ||
118
+ basename(path).startsWith("Modelfile.") ||
119
+ path.toLowerCase().endsWith(".gguf"))
120
+ ) {
121
+ return "ai";
122
+ }
123
+ } catch {
124
+ // ignore invalid local direct inputs
125
+ }
126
+ return undefined;
127
+ }
128
+
129
+ /**
130
+ * Main Node.js/npm BOM generator. Parses manifests, lockfiles, and import
131
+ * evidence to assemble components, dependencies, formulation data, AI inventory,
132
+ * and the parent component for a Node.js project.
133
+ *
134
+ * @param {string} path Path to the project
135
+ * @param {object} options CLI options
136
+ * @returns {Promise<object>} Promise resolving to a BOM namespace data object
137
+ */
138
+ export async function createNodejsBom(path, options) {
139
+ let pkgList = [];
140
+ let manifestFiles = [];
141
+ let dependencies = [];
142
+ let parentComponent = {};
143
+ const parentSubComponents = [];
144
+ let ppurl = "";
145
+ const exactAiInventoryType = getDirectAiInventoryType(path, options);
146
+ const requestedAiInventoryTypes = getRequestedAiInventoryTypes(options);
147
+ const excludedAiInventoryTypes = getExcludedAiInventoryTypes(options);
148
+ const includedAiInventoryTypes = exactAiInventoryType
149
+ ? filterIncludedAiInventoryTypes(
150
+ [exactAiInventoryType],
151
+ excludedAiInventoryTypes,
152
+ )
153
+ : filterIncludedAiInventoryTypes(
154
+ [...getIncludedAiInventoryTypes(options), ...requestedAiInventoryTypes],
155
+ excludedAiInventoryTypes,
156
+ );
157
+ let aiInventory = { components: [], dependencies: [], services: [] };
158
+ const directHuggingFaceSource =
159
+ exactAiInventoryType === "ai"
160
+ ? normalizeHuggingFaceReference(path)
161
+ : undefined;
162
+ if (directHuggingFaceSource?.repoId) {
163
+ const inventory = await fetchHuggingFaceAssetInventory(
164
+ directHuggingFaceSource.assetType,
165
+ directHuggingFaceSource.repoId,
166
+ {
167
+ ...options,
168
+ resolveHuggingFaceRemote: true,
169
+ version: directHuggingFaceSource.version,
170
+ },
171
+ );
172
+ if (inventory?.primaryComponent) {
173
+ parentComponent = createDefaultParentComponent(path, "generic", options);
174
+ return buildBomNSData(options, inventory.components, "generic", {
175
+ dependencies: inventory.dependencies || [],
176
+ filename: path,
177
+ parentComponent,
178
+ projectType: exactAiInventoryType,
179
+ services: [],
180
+ src: path,
181
+ });
182
+ }
183
+ }
184
+ if (exactAiInventoryType === "ai" || exactAiInventoryType === "ai-skill") {
185
+ aiInventory = collectAiInventory(path, options, includedAiInventoryTypes);
186
+ const exactComponents = trimComponents([...(aiInventory.components || [])]);
187
+ const exactDependencies = mergeDependencies([], aiInventory.dependencies);
188
+ const exactServices = mergeServices([], aiInventory.services);
189
+ parentComponent = createDefaultParentComponent(path, "generic", options);
190
+ return buildBomNSData(options, exactComponents, "generic", {
191
+ dependencies: exactDependencies,
192
+ filename: path,
193
+ parentComponent,
194
+ projectType: exactAiInventoryType,
195
+ services: exactServices,
196
+ src: path,
197
+ });
198
+ }
199
+ // Docker mode requires special handling
200
+ if (hasAnyProjectType(["docker", "oci", "container", "os"], options, false)) {
201
+ const pkgJsonFiles = getAllFiles(path, "**/package.json", options);
202
+ // Are there any package.json files in the container?
203
+ if (pkgJsonFiles.length) {
204
+ for (const pj of pkgJsonFiles) {
205
+ const dlist = await parsePkgJson(pj);
206
+ if (dlist?.length) {
207
+ pkgList = pkgList.concat(dlist);
208
+ }
209
+ }
210
+ if (includedAiInventoryTypes.length) {
211
+ aiInventory = collectAiInventory(
212
+ path,
213
+ options,
214
+ includedAiInventoryTypes,
215
+ );
216
+ }
217
+ if (aiInventory.components?.length) {
218
+ pkgList = trimComponents(pkgList.concat(aiInventory.components));
219
+ }
220
+ return buildBomNSData(options, pkgList, "npm", {
221
+ allImports: {},
222
+ src: path,
223
+ filename: "package.json",
224
+ dependencies: mergeDependencies(
225
+ [],
226
+ aiInventory.dependencies,
227
+ parentComponent,
228
+ ),
229
+ parentComponent,
230
+ services: aiInventory.services,
231
+ });
232
+ }
233
+ }
234
+ let allImports = {};
235
+ let allExports = {};
236
+ let mcpInventory = {};
237
+ if (
238
+ !hasAnyProjectType(["docker", "oci", "container", "os"], options, false) &&
239
+ !options.noBabel
240
+ ) {
241
+ if (DEBUG_MODE) {
242
+ console.log(
243
+ `Performing babel-based package usage analysis with source code at ${path}`,
244
+ );
245
+ }
246
+ const retData = await findJSImportsExports(path, options);
247
+ allImports = retData.allImports;
248
+ allExports = retData.allExports;
249
+ if (shouldDetectMcpInventory(includedAiInventoryTypes)) {
250
+ mcpInventory = detectMcpInventory(path, options.deep);
251
+ }
252
+ }
253
+ if (includedAiInventoryTypes.length) {
254
+ aiInventory = collectAiInventory(path, options, includedAiInventoryTypes);
255
+ }
256
+ const aiInventorySummary = summarizeAiInventory(aiInventory);
257
+ if (!exactAiInventoryType) {
258
+ if (
259
+ aiInventorySummary.aiComponentCount ||
260
+ aiInventorySummary.aiServiceCount
261
+ ) {
262
+ thoughtLog(
263
+ `I found ${aiInventorySummary.aiComponentCount} AI asset component(s) and ${aiInventorySummary.aiServiceCount} AI service(s) from JavaScript usage signals. Use --exclude-type ai to drop them from the BOM.`,
264
+ );
265
+ }
266
+ if (aiInventorySummary.instructionCount || aiInventorySummary.skillCount) {
267
+ thoughtLog(
268
+ `I found ${aiInventorySummary.instructionCount + aiInventorySummary.skillCount} AI skill/instruction file component(s). Use '--exclude-type ai-skill' for a package-only BOM, or '--bom-audit --bom-audit-categories ai-inventory' for review-friendly reporting.`,
269
+ );
270
+ }
271
+ if (aiInventorySummary.mcpConfigCount) {
272
+ thoughtLog(
273
+ `I found ${aiInventorySummary.mcpConfigCount} MCP config component(s). Use '--exclude-type mcp' to drop them, or '--bom-audit --bom-audit-categories ai-inventory --tlp-classification AMBER' to keep and flag them.`,
274
+ );
275
+ }
276
+ }
277
+ // Committed lockfiles and their manifests can live under dot-directories
278
+ // (eg: .github/scripts), so include hidden paths when discovering them -
279
+ // otherwise the dependencies of those nested projects are silently dropped
280
+ // from the BOM (see #4224). node_modules and .git stay ignored by getAllFiles.
281
+ const lockSearchOptions = { ...options, includeDot: true };
282
+ let yarnLockFiles = getAllFiles(
283
+ path,
284
+ `${options.multiProject ? "**/" : ""}yarn.lock`,
285
+ lockSearchOptions,
286
+ );
287
+ const shrinkwrapFiles = getAllFiles(
288
+ path,
289
+ `${options.multiProject ? "**/" : ""}npm-shrinkwrap.json`,
290
+ lockSearchOptions,
291
+ );
292
+ let pkgLockFiles = getAllFiles(
293
+ path,
294
+ `${options.multiProject ? "**/" : ""}package-lock.json`,
295
+ lockSearchOptions,
296
+ );
297
+ if (shrinkwrapFiles.length) {
298
+ pkgLockFiles = pkgLockFiles.concat(shrinkwrapFiles);
299
+ }
300
+ let pnpmLockFiles = getAllFiles(
301
+ path,
302
+ `${options.multiProject ? "**/" : ""}pnpm-lock.yaml`,
303
+ lockSearchOptions,
304
+ );
305
+ const bunLockFiles = getAllFiles(
306
+ path,
307
+ `${options.multiProject ? "**/" : ""}bun.lock`,
308
+ lockSearchOptions,
309
+ );
310
+ // Warn about the binary bun lockfile which cdxgen cannot parse. Users should
311
+ // regenerate a text lockfile with `bun install --save-text-lockfile`.
312
+ const bunBinaryLockFiles = getAllFiles(
313
+ path,
314
+ `${options.multiProject ? "**/" : ""}bun.lockb`,
315
+ lockSearchOptions,
316
+ );
317
+ if (bunBinaryLockFiles.length && !bunLockFiles.length) {
318
+ console.log(
319
+ "Found a binary bun lockfile (bun.lockb) which cdxgen cannot parse. Regenerate a text lockfile with 'bun install --save-text-lockfile' (bun >= 1.2) and try again.",
320
+ );
321
+ }
322
+ const denoLockFiles = getAllFiles(
323
+ path,
324
+ `${options.multiProject ? "**/" : ""}deno.lock`,
325
+ lockSearchOptions,
326
+ );
327
+ if (
328
+ !denoLockFiles?.length &&
329
+ isPackageManagerAllowed("deno", ["npm", "pnpm", "yarn", "bun"], options)
330
+ ) {
331
+ const denoManifestFiles = getAllFiles(
332
+ path,
333
+ `${options.multiProject ? "**/" : ""}deno.{json,jsonc}`,
334
+ lockSearchOptions,
335
+ );
336
+ if (denoManifestFiles?.length) {
337
+ console.log(
338
+ "Found a Deno manifest (deno.json/deno.jsonc) without a deno.lock. Run 'deno install' to generate a lockfile so cdxgen can capture the resolved dependencies.",
339
+ );
340
+ }
341
+ }
342
+ let pnpmWorkspaceFiles = getAllFiles(
343
+ path,
344
+ `${options.multiProject ? "**/" : ""}pnpm-workspace.yaml`,
345
+ lockSearchOptions,
346
+ );
347
+ const rootPnpmLockFile = resolve(path, "pnpm-lock.yaml");
348
+ const rootPnpmWorkspaceFile = resolve(path, "pnpm-workspace.yaml");
349
+ const workspaceFilesCache = new Map();
350
+ if (
351
+ safeExistsSync(rootPnpmLockFile) &&
352
+ safeExistsSync(rootPnpmWorkspaceFile) &&
353
+ pnpmLockFiles.includes(rootPnpmLockFile)
354
+ ) {
355
+ // The root pnpm-lock.yaml resolves the dependencies of every declared
356
+ // workspace member, so their nested lockfiles are redundant. However,
357
+ // independent nested projects that are NOT listed in pnpm-workspace.yaml
358
+ // keep their own committed lockfile, and those must still be parsed -
359
+ // otherwise their dependencies go missing from the BOM.
360
+ const workspaceObj = parsePnpmWorkspace(rootPnpmWorkspaceFile);
361
+ const workspaceMemberDirs = new Set();
362
+ const workspacePackages = workspaceObj?.packagePatterns || [];
363
+ const workspaceSearchOptions = {
364
+ ...options,
365
+ exclude: [
366
+ ...(options.exclude || []),
367
+ ...(workspaceObj?.excludePackages || []),
368
+ ],
369
+ includeNodeModulesDir: false,
370
+ };
371
+ for (const awp of workspacePackages) {
372
+ const workspacePackagePattern = awp.endsWith("package.json")
373
+ ? awp
374
+ : `${awp.replace(/\/+$/, "")}/package.json`;
375
+ const wpkgJsonFiles = getAllFiles(
376
+ path,
377
+ workspacePackagePattern,
378
+ workspaceSearchOptions,
379
+ );
380
+ workspaceFilesCache.set(workspacePackagePattern, wpkgJsonFiles);
381
+ for (const apj of wpkgJsonFiles || []) {
382
+ workspaceMemberDirs.add(resolve(dirname(apj)));
383
+ }
384
+ }
385
+ // A nested lockfile is redundant only when it sits in a declared workspace
386
+ // member directory. The root lockfile itself is always retained.
387
+ const isRedundantNestedLock = (lockFile) => {
388
+ const resolvedLockFile = resolve(lockFile);
389
+ if (resolvedLockFile === rootPnpmLockFile) {
390
+ return false;
391
+ }
392
+ return workspaceMemberDirs.has(resolve(dirname(lockFile)));
393
+ };
394
+ pnpmLockFiles = pnpmLockFiles.filter((f) => !isRedundantNestedLock(f));
395
+ yarnLockFiles = yarnLockFiles.filter((f) => !isRedundantNestedLock(f));
396
+ pkgLockFiles = pkgLockFiles.filter((f) => !isRedundantNestedLock(f));
397
+ pnpmWorkspaceFiles = [rootPnpmWorkspaceFile];
398
+ }
399
+ const minJsFiles = getAllFiles(
400
+ path,
401
+ `${options.multiProject ? "**/" : ""}*min.js`,
402
+ options,
403
+ );
404
+ const bowerFiles = getAllFiles(
405
+ path,
406
+ `${options.multiProject ? "**/" : ""}bower.json`,
407
+ options,
408
+ );
409
+ if (DEBUG_MODE) {
410
+ const wasmFiles = getAllFiles(
411
+ path,
412
+ `${options.multiProject ? "**/" : ""}*.wasm`,
413
+ {
414
+ ...options,
415
+ includeNodeModulesDir: true,
416
+ },
417
+ );
418
+ if (wasmFiles?.length) {
419
+ console.log(
420
+ `Found ${wasmFiles.length} wasm files in this project. cdxgen will make a best attempt to identify the exports and imports from these files.`,
421
+ );
422
+ }
423
+ }
424
+ // Parse min js files
425
+ if (minJsFiles?.length) {
426
+ manifestFiles = manifestFiles.concat(minJsFiles);
427
+ for (const f of minJsFiles) {
428
+ const dlist = await parseMinJs(f);
429
+ if (dlist?.length) {
430
+ pkgList = pkgList.concat(dlist);
431
+ }
432
+ }
433
+ }
434
+ // Parse bower json files
435
+ if (bowerFiles?.length) {
436
+ manifestFiles = manifestFiles.concat(bowerFiles);
437
+ for (const f of bowerFiles) {
438
+ const dlist = await parseBowerJson(f);
439
+ if (dlist?.length) {
440
+ pkgList = pkgList.concat(dlist);
441
+ }
442
+ }
443
+ }
444
+ const pkgJsonLockFiles = getAllFiles(
445
+ path,
446
+ `${options.multiProject ? "**/" : ""}package-lock.json`,
447
+ lockSearchOptions,
448
+ );
449
+ const pkgJsonFiles = getAllFiles(
450
+ path,
451
+ `${options.multiProject ? "**/" : ""}package.json`,
452
+ lockSearchOptions,
453
+ );
454
+ const npmInstallCount =
455
+ Number.parseInt(readEnvironmentVariable("NPM_INSTALL_COUNT"), 10) || 2;
456
+ let anyInstallSuccess = false;
457
+ // Automatic npm install logic.
458
+ // Only perform npm install for smaller projects (< 2 package.json) without the correct number of lock files
459
+ if (
460
+ (pkgJsonLockFiles?.length === 0 ||
461
+ pkgJsonLockFiles?.length < pkgJsonFiles?.length - 1) &&
462
+ yarnLockFiles?.length === 0 &&
463
+ pnpmLockFiles?.length === 0 &&
464
+ bunLockFiles?.length === 0 &&
465
+ denoLockFiles?.length === 0 &&
466
+ pkgJsonFiles?.length <= npmInstallCount &&
467
+ options.installDeps
468
+ ) {
469
+ for (const apkgJson of pkgJsonFiles) {
470
+ let pkgMgr = "npm";
471
+ const supPkgMgrs = ["npm", "yarn", "yarnpkg", "pnpm", "pnpx"];
472
+ const pkgData = JSON.parse(readFileSync(apkgJson, "utf8"));
473
+ const mgrData = pkgData.packageManager;
474
+ let mgr = "";
475
+ if (mgrData) {
476
+ mgr = mgrData.split("@")[0];
477
+ }
478
+ // Try harder to identify the correct package manager
479
+ if (options?.projectType?.includes("npm")) {
480
+ pkgMgr = "npm";
481
+ } else if (supPkgMgrs.includes(mgr)) {
482
+ pkgMgr = mgr;
483
+ } else if (pkgData?.engines?.yarn) {
484
+ pkgMgr = "yarn";
485
+ } else if (
486
+ isPackageManagerAllowed("npm", ["yarn", "pnpm", "rush"], options)
487
+ ) {
488
+ pkgMgr = "npm";
489
+ } else if (
490
+ isPackageManagerAllowed("yarn", ["npm", "pnpm", "rush"], options)
491
+ ) {
492
+ pkgMgr = "yarn";
493
+ } else if (
494
+ isPackageManagerAllowed("pnpm", ["npm", "yarn", "rush"], options)
495
+ ) {
496
+ pkgMgr = "pnpm";
497
+ }
498
+ let installCommand = "install";
499
+ if (pkgMgr === "npm" && isSecureMode && pkgJsonLockFiles?.length > 0) {
500
+ installCommand = "ci";
501
+ }
502
+ let installArgs = [installCommand];
503
+ // Support for passing additional args to the install command
504
+ if (readEnvironmentVariable(`${pkgMgr.toUpperCase()}_INSTALL_ARGS`)) {
505
+ const addArgs = readEnvironmentVariable(
506
+ `${pkgMgr.toUpperCase()}_INSTALL_ARGS`,
507
+ ).split(" ");
508
+ installArgs = installArgs.concat(addArgs);
509
+ }
510
+ // Always invoke the install command with ignore-scripts to guard against version spoofing
511
+ if (["npm", "pnpm", "yarn"].includes(pkgMgr)) {
512
+ if (!installArgs.includes("--ignore-scripts")) {
513
+ installArgs.push("--ignore-scripts");
514
+ }
515
+ if (pkgMgr === "pnpm") {
516
+ installArgs.push("--ignore-pnpmfile");
517
+ }
518
+ if (pkgMgr === "npm") {
519
+ for (const c of ["--no-audit", "--no-bin-links"]) {
520
+ if (!installArgs.includes(c)) {
521
+ installArgs.push(c);
522
+ }
523
+ }
524
+ installArgs.push(`--git=${GIT_COMMAND}`);
525
+ }
526
+ }
527
+ if (
528
+ pkgMgr === "npm" &&
529
+ isSecureMode &&
530
+ !installArgs.join(" ").includes("--allow-git")
531
+ ) {
532
+ console.log(
533
+ "Consider passing '--allow-git=none' via the environment variable NPM_INSTALL_ARGS to prevent any git dependencies from being fetched and installed via npm.",
534
+ );
535
+ }
536
+ const basePath = dirname(apkgJson);
537
+ let npmrcData;
538
+ const npmrcFile = join(basePath, ".npmrc");
539
+ if (safeExistsSync(npmrcFile)) {
540
+ thoughtLog(
541
+ "Wait, there is a .npmrc file here! I'm going to check if it has anything malicious.",
542
+ );
543
+ npmrcData = readFileSync(npmrcFile, "utf-8");
544
+ recordSensitiveFileRead(npmrcFile, {
545
+ label: "npm registry configuration",
546
+ });
547
+ const npmrcObj = parseNpmrc(npmrcData);
548
+ for (const [key, value] of Object.entries(npmrcObj)) {
549
+ const baseKey = key.replace(/^(?:\/\/[^/]+\/|@[^:]+:)/, "");
550
+ if (
551
+ DEFAULT_NPMRC_BLOCKLIST.has(baseKey) ||
552
+ DEFAULT_NPMRC_BLOCKLIST.has(key)
553
+ ) {
554
+ console.warn(
555
+ `\x1b[1;35mSECURE MODE: Dangerous configuration ${key}=${value} detected in .npmrc! Verify if this is a trusted project. Remove this setting or any other problematic configurations to proceed.\x1b[0m`,
556
+ );
557
+ process.exit(1);
558
+ }
559
+ }
560
+ }
561
+ // juice-shop mode
562
+ // Projects such as juice-shop prevent lockfile creations using .npmrc files
563
+ // Plus, they might require specific npm install args such as --legacy-peer-deps that could lead to strange node_modules structure
564
+ // To keep life simple, let's look for any .npmrc file that has package-lock=false to toggle before npm install
565
+ if (pkgMgr === "npm") {
566
+ if (
567
+ npmrcData?.includes("package-lock=false") &&
568
+ !installArgs.includes("--package-lock")
569
+ ) {
570
+ installArgs.push("--package-lock");
571
+ }
572
+ }
573
+ if (pkgMgr === "npm" && yarnLockFiles.length) {
574
+ thoughtLog(
575
+ `Wait, there are ${yarnLockFiles.length} yarn.lock files in this project; however, I'm about to invoke the '${pkgMgr} ${installArgs[0]}' command.`,
576
+ );
577
+ }
578
+ if (pkgMgr !== "npm") {
579
+ thoughtLog(
580
+ `**PACKAGE MANAGER**: Let's run the '${pkgMgr}' command with the arguments '${installArgs.join(" ")}' to generate the needed lock files.`,
581
+ );
582
+ }
583
+ console.warn(
584
+ "\x1b[1;35mNotice: Generating an SBOM without a lockfile is risky and non-deterministic. Consider generating and committing the lockfile to your repository to ensure reproducible builds and SBOMs.\x1b[0m",
585
+ );
586
+ console.log(
587
+ `Executing '${pkgMgr} ${installArgs.join(" ")}' in`,
588
+ basePath,
589
+ );
590
+ const result = safeSpawnSync(pkgMgr, installArgs, {
591
+ cwd: basePath,
592
+ shell: isWin,
593
+ });
594
+ if (result.status !== 0 || result.error) {
595
+ console.error(
596
+ `${pkgMgr} install has failed. Generated SBOM will be empty or with a lower precision.`,
597
+ );
598
+ thoughtLog(
599
+ "It looks like the install command has failed. I'm considering some troubleshooting ideas.",
600
+ );
601
+ if (DEBUG_MODE && result.stdout) {
602
+ if (result.stdout.includes("EBADENGINE Unsupported engine")) {
603
+ console.log(
604
+ "TIP: The current version of node.js is incompatible with this project. Re-run cdxgen with an install-version type to install a matching node.js for the project. Eg: `-t node20`",
605
+ );
606
+ }
607
+ console.log("---------------");
608
+ console.log(result.stdout);
609
+ }
610
+ if (result.stderr) {
611
+ if (result.stderr.includes("--legacy-peer-deps")) {
612
+ console.log(
613
+ "Set the environment variable `NPM_INSTALL_ARGS=--legacy-peer-deps` to resolve the dependency resolution issue reported.",
614
+ );
615
+ }
616
+ if (
617
+ result.stderr.includes(
618
+ "npm error command sh -c node-pre-gyp install",
619
+ )
620
+ ) {
621
+ console.log(
622
+ "cdxgen has detected errors with the native build using node-gyp.",
623
+ );
624
+ if (readEnvironmentVariable("CDXGEN_IN_CONTAINER") === "true") {
625
+ if (arch() !== "x64") {
626
+ console.log(
627
+ `INFO: Many npm packages have limited support for ${arch()} architecture. Run the cdxgen container image with --platform=linux/amd64 for best experience.`,
628
+ );
629
+ } else {
630
+ console.log(
631
+ "TIP: The default image bundles node >= 24, which might be incompatible with this project. Re-run cdxgen with an install-version type to install an older node.js for the project. Eg: `-t node20`",
632
+ );
633
+ }
634
+ } else {
635
+ console.log(
636
+ "TIP: Try running the cdxgen container image with --platform=linux/amd64, and pass an install-version type such as `-t node20` to build the project with an older node.js.",
637
+ );
638
+ }
639
+ }
640
+ console.log("---------------");
641
+ console.log(result.stderr);
642
+ }
643
+ options.failOnError && process.exit(1);
644
+ } else {
645
+ anyInstallSuccess = true;
646
+ }
647
+ }
648
+ pkgLockFiles = getAllFiles(
649
+ path,
650
+ `${options.multiProject ? "**/" : ""}package-lock.json`,
651
+ options,
652
+ );
653
+ pnpmLockFiles = getAllFiles(
654
+ path,
655
+ `${options.multiProject ? "**/" : ""}pnpm-lock.yaml`,
656
+ options,
657
+ );
658
+ yarnLockFiles = getAllFiles(
659
+ path,
660
+ `${options.multiProject ? "**/" : ""}yarn.lock`,
661
+ options,
662
+ );
663
+ if (
664
+ anyInstallSuccess &&
665
+ !pkgLockFiles.length &&
666
+ !pnpmLockFiles.length &&
667
+ !yarnLockFiles.length
668
+ ) {
669
+ thoughtLog(
670
+ `Despite a successful installation step, I didn't find any lock files. Perhaps they're being created elsewhere, such as in the root directory. I am currently checking the directory at ${path}.`,
671
+ );
672
+ }
673
+ }
674
+ if (
675
+ pnpmLockFiles?.length &&
676
+ isPackageManagerAllowed("pnpm", ["npm", "yarn", "rush"], options)
677
+ ) {
678
+ manifestFiles = manifestFiles.concat(pnpmLockFiles);
679
+ const workspacePackages = [];
680
+ const workspaceSrcFiles = {};
681
+ const workspaceDirectDeps = {};
682
+ const depsWorkspaceRefs = {};
683
+ let workspaceCatalogs = {};
684
+ const seenPkgJsonFiles = {};
685
+ // Is this a pnpm workspace?
686
+ for (const f of pnpmWorkspaceFiles) {
687
+ if (DEBUG_MODE) {
688
+ console.log(`Parsing workspace definition ${f}`);
689
+ }
690
+ const workspaceObj = parsePnpmWorkspace(f);
691
+ if (workspaceObj?.packages) {
692
+ const workspaceBasePath = dirname(f);
693
+ const workspacePatterns =
694
+ workspaceObj.packagePatterns || workspaceObj.packages;
695
+ // We need the precise purl for all workspace packages and their direct dependencies
696
+ for (const awp of workspacePatterns) {
697
+ const workspaceExcludes = [...(workspaceObj.excludePackages || [])];
698
+ const workspaceSearchOptions = {
699
+ ...options,
700
+ exclude: [...(options.exclude || []), ...workspaceExcludes],
701
+ includeNodeModulesDir: false,
702
+ };
703
+ const workspacePackagePattern = awp.endsWith("package.json")
704
+ ? awp
705
+ : `${awp.replace(/\/+$/, "")}/package.json`;
706
+ let wpkgJsonFiles = workspaceFilesCache.get(workspacePackagePattern);
707
+ if (!wpkgJsonFiles) {
708
+ wpkgJsonFiles = getAllFiles(
709
+ workspaceBasePath,
710
+ workspacePackagePattern,
711
+ workspaceSearchOptions,
712
+ );
713
+ }
714
+ if (!wpkgJsonFiles?.length) {
715
+ continue;
716
+ }
717
+ for (const apj of wpkgJsonFiles) {
718
+ if (seenPkgJsonFiles[apj]) {
719
+ continue;
720
+ }
721
+ seenPkgJsonFiles[apj] = true;
722
+ let pkgData;
723
+ try {
724
+ pkgData = JSON.parse(readFileSync(apj, "utf-8"));
725
+ } catch (_err) {
726
+ continue;
727
+ }
728
+ if (pkgData?.name) {
729
+ const relativePkgJsonFile = relative(path, apj);
730
+ let workspaceRef = `pkg:npm/${pkgData.name}`;
731
+ if (pkgData?.version) {
732
+ workspaceRef = `${workspaceRef}@${pkgData.version}`;
733
+ }
734
+ // Track all workspace purls. When we face duplicates, let's try to expand the purl to
735
+ // include the subpath.
736
+ if (!workspacePackages.includes(workspaceRef)) {
737
+ workspacePackages.push(workspaceRef);
738
+ } else {
739
+ console.log(
740
+ `Found a duplicate workspace with the name: ${pkgData.name}, ref: ${workspaceRef} at ${relativePkgJsonFile} and ${workspaceSrcFiles[workspaceRef]}. This is likely an error in the project that needs fixing.`,
741
+ );
742
+ workspaceRef = `${workspaceRef}#${relativePkgJsonFile.replace(`${sep}package.json`, "")}`;
743
+ if (!workspacePackages.includes(workspaceRef)) {
744
+ workspacePackages.push(workspaceRef);
745
+ console.log(
746
+ `Duplicate workspace tracked as ${workspaceRef} under metadata.component.components`,
747
+ );
748
+ }
749
+ }
750
+ workspaceSrcFiles[workspaceRef] = relativePkgJsonFile;
751
+ // Track the direct dependencies of each workspace and workspace refs for each direct deps.
752
+ const allDeps = {
753
+ ...(pkgData.dependencies || {}),
754
+ ...(pkgData.devDependencies || {}),
755
+ ...(pkgData.peerDependencies || {}),
756
+ };
757
+ for (const adep of Object.keys(allDeps)) {
758
+ if (!workspaceDirectDeps[workspaceRef]) {
759
+ workspaceDirectDeps[workspaceRef] = new Set();
760
+ }
761
+ const apkgRef = `pkg:npm/${adep}`;
762
+ workspaceDirectDeps[workspaceRef].add(apkgRef);
763
+ if (!depsWorkspaceRefs[apkgRef]) {
764
+ depsWorkspaceRefs[apkgRef] = [];
765
+ }
766
+ depsWorkspaceRefs[apkgRef].push(workspaceRef);
767
+ }
768
+ }
769
+ }
770
+ }
771
+ }
772
+ workspaceCatalogs = {
773
+ ...workspaceCatalogs,
774
+ ...(workspaceObj.catalogs || {}),
775
+ };
776
+ }
777
+ if (DEBUG_MODE && Object.keys(seenPkgJsonFiles).length) {
778
+ console.log(
779
+ `${Object.keys(seenPkgJsonFiles).length} package.json files were parsed to identify workspace names. Total number of package.json files: ${pkgJsonFiles.length}`,
780
+ );
781
+ }
782
+ for (const f of pnpmLockFiles) {
783
+ if (DEBUG_MODE) {
784
+ console.log(`Parsing ${f}`);
785
+ }
786
+ const basePath = dirname(f);
787
+ // Determine the parent component
788
+ const packageJsonF = join(basePath, "package.json");
789
+ const pnpmCjsHooks = join(basePath, ".pnpmfile.cjs");
790
+ const pnpmMjsHooks = join(basePath, ".pnpmfile.mjs");
791
+ if (safeExistsSync(pnpmMjsHooks) || safeExistsSync(pnpmCjsHooks)) {
792
+ thoughtLog("Wait, this pnpm project uses install hooks.");
793
+ }
794
+ if (!Object.keys(parentComponent).length) {
795
+ if (safeExistsSync(packageJsonF)) {
796
+ const pcs = await parsePkgJson(packageJsonF, true, true);
797
+ if (pcs.length && Object.keys(pcs[0]).length) {
798
+ parentComponent = { ...pcs[0] };
799
+ parentComponent.type = "application";
800
+ ppurl = build({
801
+ type: "npm",
802
+ namespace: options.projectGroup || parentComponent.group || null,
803
+ name: parentComponent.name,
804
+ version:
805
+ options.projectVersion || parentComponent.version || null,
806
+ });
807
+ parentComponent["bom-ref"] = decodeURIComponent(ppurl);
808
+ parentComponent["purl"] = ppurl;
809
+ }
810
+ } else {
811
+ let dirName = dirname(f);
812
+ const tmpA = dirName.split(sep);
813
+ dirName = tmpA[tmpA.length - 1];
814
+ parentComponent = {
815
+ group: "",
816
+ name: dirName,
817
+ type: "application",
818
+ };
819
+ ppurl = build({
820
+ type: "npm",
821
+ namespace: options.projectGroup || parentComponent.group || null,
822
+ name:
823
+ "project-name" in options
824
+ ? options.projectName
825
+ : parentComponent.name,
826
+ version: options.projectVersion || parentComponent.version || null,
827
+ });
828
+ parentComponent["bom-ref"] = decodeURIComponent(ppurl);
829
+ parentComponent["purl"] = ppurl;
830
+ }
831
+ }
832
+ // Parse the pnpm file
833
+ const parsedList = await parsePnpmLock(
834
+ f,
835
+ parentComponent,
836
+ workspacePackages,
837
+ workspaceSrcFiles,
838
+ workspaceCatalogs,
839
+ workspaceDirectDeps,
840
+ depsWorkspaceRefs,
841
+ path,
842
+ );
843
+ const dlist = parsedList.pkgList;
844
+ if (dlist?.length) {
845
+ pkgList = pkgList.concat(dlist);
846
+ }
847
+ if (parsedList?.parentSubComponents?.length) {
848
+ parentComponent.components = parsedList.parentSubComponents;
849
+ }
850
+ if (parsedList?.dependenciesList?.length) {
851
+ dependencies = mergeDependencies(
852
+ dependencies,
853
+ parsedList.dependenciesList,
854
+ parentComponent,
855
+ );
856
+ }
857
+ }
858
+ }
859
+ if (
860
+ pkgLockFiles?.length &&
861
+ isPackageManagerAllowed("npm", ["pnpm", "yarn"], options)
862
+ ) {
863
+ if (anyInstallSuccess) {
864
+ thoughtLog(
865
+ `I have ${pkgLockFiles.length} package-lock.json file(s) now after a successful npm install.`,
866
+ );
867
+ }
868
+ manifestFiles = manifestFiles.concat(pkgLockFiles);
869
+ for (const f of pkgLockFiles) {
870
+ if (DEBUG_MODE) {
871
+ console.log(`Parsing ${f}`);
872
+ }
873
+ // Parse package-lock.json if available
874
+ const parsedList = await parsePkgLock(f, options);
875
+ const dlist = parsedList.pkgList;
876
+ let tmpParentComponent = dlist.splice(0, 1)[0] || {};
877
+ if (!Object.keys(parentComponent).length) {
878
+ const basePath = dirname(f);
879
+ const packageJsonF = join(basePath, "package.json");
880
+ if (safeExistsSync(packageJsonF)) {
881
+ const pcs = await parsePkgJson(packageJsonF, true, true);
882
+ if (pcs.length && Object.keys(pcs[0]).length) {
883
+ tmpParentComponent = { ...pcs[0] };
884
+ tmpParentComponent.type = "application";
885
+ tmpParentComponent.name =
886
+ "project-name" in options
887
+ ? options.projectName
888
+ : tmpParentComponent.name;
889
+ ppurl = build({
890
+ type: "npm",
891
+ namespace:
892
+ options.projectGroup || tmpParentComponent.group || null,
893
+ name:
894
+ "project-name" in options
895
+ ? options.projectName
896
+ : tmpParentComponent.name,
897
+ version:
898
+ options.projectVersion || tmpParentComponent.version || null,
899
+ });
900
+ tmpParentComponent["bom-ref"] = decodeURIComponent(ppurl);
901
+ tmpParentComponent["purl"] = ppurl;
902
+ }
903
+ }
904
+ parentComponent = tmpParentComponent;
905
+ } else {
906
+ parentSubComponents.push(tmpParentComponent);
907
+ }
908
+ if (dlist?.length) {
909
+ pkgList = pkgList.concat(dlist);
910
+ }
911
+ if (parsedList?.dependenciesList?.length) {
912
+ dependencies = mergeDependencies(
913
+ dependencies,
914
+ parsedList.dependenciesList,
915
+ parentComponent,
916
+ );
917
+ }
918
+ }
919
+ }
920
+ if (
921
+ safeExistsSync(join(path, "rush.json")) &&
922
+ isPackageManagerAllowed("rush", ["npm", "yarn", "pnpm"], options)
923
+ ) {
924
+ // Rush.js creates node_modules inside common/temp directory
925
+ const nmDir = join(path, "common", "temp", "node_modules");
926
+ // Do rush install if we don't have node_modules directory
927
+ if (!safeExistsSync(nmDir)) {
928
+ console.log("Executing 'rush install --no-link'", path);
929
+ const result = safeSpawnSync(
930
+ "rush",
931
+ ["install", "--no-link", "--bypass-policy"],
932
+ {
933
+ cwd: path,
934
+ shell: isWin,
935
+ },
936
+ );
937
+ if (result.status === 1 || result.error) {
938
+ console.error(result.stdout, result.stderr);
939
+ options.failOnError && process.exit(1);
940
+ }
941
+ }
942
+ // Look for shrinkwrap file
943
+ const swFile = join(
944
+ path,
945
+ "tools",
946
+ "build-tasks",
947
+ ".rush",
948
+ "temp",
949
+ "shrinkwrap-deps.json",
950
+ );
951
+ const pnpmLock = join(path, "common", "config", "rush", "pnpm-lock.yaml");
952
+ if (safeExistsSync(swFile)) {
953
+ let pkgList = await parseNodeShrinkwrap(swFile);
954
+ pkgList = addWasmComponentsFromImports(pkgList, allImports);
955
+ if (allImports && Object.keys(allImports).length) {
956
+ pkgList = await addEvidenceForImports(
957
+ pkgList,
958
+ allImports,
959
+ allExports,
960
+ options.deep,
961
+ );
962
+ }
963
+ return buildBomNSData(options, pkgList, "npm", {
964
+ allImports,
965
+ src: path,
966
+ filename: "shrinkwrap-deps.json",
967
+ });
968
+ }
969
+ if (safeExistsSync(pnpmLock)) {
970
+ const pnpmLockObj = await parsePnpmLock(
971
+ pnpmLock,
972
+ null,
973
+ [],
974
+ {},
975
+ {},
976
+ {},
977
+ {},
978
+ path,
979
+ );
980
+ let pkgList = addWasmComponentsFromImports(
981
+ pnpmLockObj.pkgList,
982
+ allImports,
983
+ );
984
+ let dependencies = [];
985
+ if (pnpmLockObj?.dependenciesList?.length) {
986
+ dependencies = mergeDependencies(
987
+ dependencies,
988
+ pnpmLockObj.dependenciesList,
989
+ );
990
+ }
991
+ if (allImports && Object.keys(allImports).length) {
992
+ pkgList = await addEvidenceForImports(
993
+ pkgList,
994
+ allImports,
995
+ allExports,
996
+ options.deep,
997
+ );
998
+ }
999
+ pkgList = propagateRequiredScopeFromDependencies(pkgList, dependencies);
1000
+ pkgList = markNpmTypesPackagesAsExcluded(pkgList);
1001
+ return buildBomNSData(options, pkgList, "npm", {
1002
+ allImports,
1003
+ allExports,
1004
+ dependencies,
1005
+ src: path,
1006
+ filename: "pnpm-lock.yaml",
1007
+ });
1008
+ }
1009
+ console.log(
1010
+ "Neither shrinkwrap file: ",
1011
+ swFile,
1012
+ " nor pnpm lockfile",
1013
+ pnpmLock,
1014
+ "was found!",
1015
+ );
1016
+ options.failOnError && process.exit(1);
1017
+ }
1018
+ if (
1019
+ yarnLockFiles?.length &&
1020
+ isPackageManagerAllowed("yarn", ["npm", "pnpm"], options)
1021
+ ) {
1022
+ manifestFiles = manifestFiles.concat(yarnLockFiles);
1023
+ const workspacePackages = [];
1024
+ const workspaceSrcFiles = {};
1025
+ const workspaceDirectDeps = {};
1026
+ const depsWorkspaceRefs = {};
1027
+ const seenPkgJsonFiles = {};
1028
+
1029
+ // Check if this is a yarn workspace by examining package.json files for workspace definitions
1030
+ const packageJsonFilesWithWorkspaces = yarnLockFiles
1031
+ .map((f) => join(dirname(f), "package.json"))
1032
+ .filter((pkgFile) => safeExistsSync(pkgFile));
1033
+
1034
+ for (const packageJsonFile of packageJsonFilesWithWorkspaces) {
1035
+ const workspaceObj = parseYarnWorkspace(packageJsonFile);
1036
+ if (workspaceObj?.packages) {
1037
+ if (DEBUG_MODE) {
1038
+ console.log(`Found yarn workspace definition in ${packageJsonFile}`);
1039
+ }
1040
+ // We need the precise purl for all workspace packages and their direct dependencies
1041
+ const workspaceBasePath = dirname(packageJsonFile);
1042
+ for (const awp of workspaceObj.packages) {
1043
+ let wpkgJsonFiles = [];
1044
+
1045
+ // Handle different yarn workspace patterns
1046
+ if (awp.includes("*")) {
1047
+ // Replace all '*' with '**' for recursive glob matching and ensure package.json suffix
1048
+ const pattern =
1049
+ awp.replaceAll("*", "**") +
1050
+ (awp.endsWith(".json") ? "" : "/package.json");
1051
+ wpkgJsonFiles = getAllFiles(workspaceBasePath, pattern, {
1052
+ ...options,
1053
+ includeNodeModulesDir: false,
1054
+ });
1055
+ } else {
1056
+ // Direct path pattern
1057
+ wpkgJsonFiles = getAllFiles(
1058
+ join(workspaceBasePath, awp),
1059
+ "**/package.json",
1060
+ {
1061
+ ...options,
1062
+ includeNodeModulesDir: false,
1063
+ },
1064
+ );
1065
+ }
1066
+ for (const apj of wpkgJsonFiles) {
1067
+ if (seenPkgJsonFiles[apj]) {
1068
+ continue;
1069
+ }
1070
+ seenPkgJsonFiles[apj] = true;
1071
+ const pkgData = JSON.parse(readFileSync(apj, "utf-8"));
1072
+ if (pkgData?.name) {
1073
+ const relativePkgJsonFile = relative(path, apj);
1074
+ // Create properly encoded PURL using helper function
1075
+ const workspaceRef = createNpmWorkspacePurl(
1076
+ pkgData.name,
1077
+ pkgData.version,
1078
+ );
1079
+ workspacePackages.push(workspaceRef);
1080
+ workspaceSrcFiles[workspaceRef] = relativePkgJsonFile;
1081
+ if (pkgData?.dependencies || pkgData?.devDependencies) {
1082
+ const dlist = new Set();
1083
+ for (const [k, v] of Object.entries({
1084
+ ...(pkgData.dependencies || {}),
1085
+ ...(pkgData.devDependencies || {}),
1086
+ })) {
1087
+ if (v.match(/^\d/)) {
1088
+ dlist.add(`pkg:npm/${k}@${v}`);
1089
+ } else {
1090
+ dlist.add(`pkg:npm/${k}`);
1091
+ }
1092
+ }
1093
+ workspaceDirectDeps[workspaceRef] = Array.from(dlist);
1094
+ for (const dep of workspaceDirectDeps[workspaceRef]) {
1095
+ if (!depsWorkspaceRefs[dep]) {
1096
+ depsWorkspaceRefs[dep] = [];
1097
+ }
1098
+ depsWorkspaceRefs[dep].push(workspaceRef);
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ }
1104
+ }
1105
+ }
1106
+ for (const f of yarnLockFiles) {
1107
+ if (DEBUG_MODE) {
1108
+ console.log(`Parsing ${f}`);
1109
+ }
1110
+ const basePath = dirname(f);
1111
+ // Determine the parent component
1112
+ const packageJsonF = join(basePath, "package.json");
1113
+ if (safeExistsSync(packageJsonF)) {
1114
+ const pcs = await parsePkgJson(packageJsonF, true, true);
1115
+ if (pcs.length && Object.keys(pcs[0]).length) {
1116
+ const tmpParentComponent = { ...pcs[0] };
1117
+ tmpParentComponent.type = "application";
1118
+ ppurl = build({
1119
+ type: "npm",
1120
+ namespace: options.projectGroup || tmpParentComponent.group || null,
1121
+ name: tmpParentComponent.name,
1122
+ version:
1123
+ options.projectVersion || tmpParentComponent.version || null,
1124
+ });
1125
+ tmpParentComponent["bom-ref"] = decodeURIComponent(ppurl);
1126
+ tmpParentComponent["purl"] = ppurl;
1127
+ if (!Object.keys(parentComponent).length) {
1128
+ parentComponent = tmpParentComponent;
1129
+ } else {
1130
+ parentSubComponents.push(tmpParentComponent);
1131
+ }
1132
+ }
1133
+ } else {
1134
+ let dirName = dirname(f);
1135
+ const tmpA = dirName.split(sep);
1136
+ dirName = tmpA[tmpA.length - 1];
1137
+ const tmpParentComponent = {
1138
+ group: options.projectGroup || "",
1139
+ name: "project-name" in options ? options.projectName : dirName,
1140
+ type: "application",
1141
+ };
1142
+ ppurl = build({
1143
+ type: "npm",
1144
+ namespace: tmpParentComponent.group || null,
1145
+ name: tmpParentComponent.name,
1146
+ version: options.projectVersion || tmpParentComponent.version || null,
1147
+ });
1148
+ tmpParentComponent["bom-ref"] = decodeURIComponent(ppurl);
1149
+ tmpParentComponent["purl"] = ppurl;
1150
+ if (!Object.keys(parentComponent).length) {
1151
+ parentComponent = tmpParentComponent;
1152
+ } else {
1153
+ parentSubComponents.push(tmpParentComponent);
1154
+ }
1155
+ }
1156
+ // Parse yarn.lock if available. This check is after rush.json since
1157
+ // rush.js could include yarn.lock :(
1158
+ const parsedList = await parseYarnLock(
1159
+ f,
1160
+ parentComponent,
1161
+ workspacePackages,
1162
+ workspaceSrcFiles,
1163
+ workspaceDirectDeps,
1164
+ depsWorkspaceRefs,
1165
+ );
1166
+ const dlist = parsedList.pkgList;
1167
+ if (dlist?.length) {
1168
+ pkgList = pkgList.concat(dlist);
1169
+ }
1170
+ const rdeplist = [];
1171
+ if (parsedList?.dependenciesList?.length) {
1172
+ // Inject parent component to the dependency tree to make it complete
1173
+ // In case of yarn, yarn list command lists every root package as a direct dependency
1174
+ // The same logic is matched with this for loop although this is incorrect since even dev dependencies would get included here
1175
+ for (const dobj of parsedList.dependenciesList) {
1176
+ rdeplist.push(dobj.ref);
1177
+ }
1178
+ // Fixes: 212. Handle case where there are no package.json to determine the parent package
1179
+ // Bug fix: We need to consistently override the parent component group, name and version here
1180
+ if (Object.keys(parentComponent).length && parentComponent.name) {
1181
+ const ppurl = build({
1182
+ type: "npm",
1183
+ namespace: options.projectGroup || parentComponent.group || null,
1184
+ name: parentComponent.name,
1185
+ version: options.projectVersion || parentComponent.version || null,
1186
+ });
1187
+ parsedList.dependenciesList.push({
1188
+ ref: decodeURIComponent(ppurl),
1189
+ dependsOn: [...new Set(rdeplist)].sort(),
1190
+ });
1191
+ }
1192
+ dependencies = mergeDependencies(
1193
+ dependencies,
1194
+ parsedList.dependenciesList,
1195
+ parentComponent,
1196
+ );
1197
+ }
1198
+ }
1199
+ }
1200
+ if (
1201
+ bunLockFiles?.length &&
1202
+ isPackageManagerAllowed("bun", ["npm", "pnpm", "yarn"], options)
1203
+ ) {
1204
+ manifestFiles = manifestFiles.concat(bunLockFiles);
1205
+ for (const f of bunLockFiles) {
1206
+ if (DEBUG_MODE) {
1207
+ console.log(`Parsing ${f}`);
1208
+ }
1209
+ const basePath = dirname(f);
1210
+ // Determine the parent component from the adjacent package.json.
1211
+ const packageJsonF = join(basePath, "package.json");
1212
+ let bunParentComponent = {};
1213
+ if (safeExistsSync(packageJsonF)) {
1214
+ const pcs = await parsePkgJson(packageJsonF, true, true);
1215
+ if (pcs.length && Object.keys(pcs[0]).length) {
1216
+ bunParentComponent = { ...pcs[0] };
1217
+ bunParentComponent.type = "application";
1218
+ ppurl = build({
1219
+ type: "npm",
1220
+ namespace: options.projectGroup || bunParentComponent.group || null,
1221
+ name: bunParentComponent.name,
1222
+ version:
1223
+ options.projectVersion || bunParentComponent.version || null,
1224
+ });
1225
+ bunParentComponent["bom-ref"] = decodeURIComponent(ppurl);
1226
+ bunParentComponent["purl"] = ppurl;
1227
+ }
1228
+ } else {
1229
+ let dirName = dirname(f);
1230
+ const tmpA = dirName.split(sep);
1231
+ dirName = tmpA[tmpA.length - 1];
1232
+ bunParentComponent = {
1233
+ group: options.projectGroup || "",
1234
+ name: "project-name" in options ? options.projectName : dirName,
1235
+ type: "application",
1236
+ };
1237
+ ppurl = build({
1238
+ type: "npm",
1239
+ namespace: bunParentComponent.group || null,
1240
+ name: bunParentComponent.name,
1241
+ version: options.projectVersion || bunParentComponent.version || null,
1242
+ });
1243
+ bunParentComponent["bom-ref"] = decodeURIComponent(ppurl);
1244
+ bunParentComponent["purl"] = ppurl;
1245
+ }
1246
+ if (Object.keys(bunParentComponent).length) {
1247
+ if (!Object.keys(parentComponent).length) {
1248
+ parentComponent = bunParentComponent;
1249
+ } else if (
1250
+ bunParentComponent["bom-ref"] !== parentComponent["bom-ref"]
1251
+ ) {
1252
+ parentSubComponents.push(bunParentComponent);
1253
+ }
1254
+ }
1255
+ const parsedList = await parseBunLock(f, {
1256
+ ...options,
1257
+ projectRoot: basePath,
1258
+ parentComponent: bunParentComponent,
1259
+ });
1260
+ if (parsedList.pkgList?.length) {
1261
+ pkgList = pkgList.concat(parsedList.pkgList);
1262
+ }
1263
+ if (parsedList.dependenciesList?.length) {
1264
+ dependencies = mergeDependencies(
1265
+ dependencies,
1266
+ parsedList.dependenciesList,
1267
+ bunParentComponent,
1268
+ );
1269
+ }
1270
+ }
1271
+ }
1272
+ if (
1273
+ denoLockFiles?.length &&
1274
+ isPackageManagerAllowed("deno", ["npm", "pnpm", "yarn", "bun"], options)
1275
+ ) {
1276
+ manifestFiles = manifestFiles.concat(denoLockFiles);
1277
+ for (const f of denoLockFiles) {
1278
+ if (DEBUG_MODE) {
1279
+ console.log(`Parsing ${f}`);
1280
+ }
1281
+ const basePath = dirname(f);
1282
+ // Derive the parent component from the adjacent deno.json(c), falling
1283
+ // back to the directory name like the bun block does.
1284
+ const denoJsonFile = findDenoJson(basePath);
1285
+ let denoParentComponent = {};
1286
+ if (denoJsonFile) {
1287
+ const denoConfig = parseDenoJsonFile(denoJsonFile);
1288
+ if (denoConfig?.name) {
1289
+ // deno.json names are frequently scoped (e.g. "@demo/deno-app").
1290
+ // Split the scope into the purl group so the name does not end up
1291
+ // carrying an encoded slash.
1292
+ let denoGroup = options.projectGroup || "";
1293
+ let denoName = denoConfig.name;
1294
+ if (!denoGroup && denoName.startsWith("@")) {
1295
+ const slashIndex = denoName.indexOf("/");
1296
+ if (slashIndex > 0) {
1297
+ denoGroup = denoName.substring(0, slashIndex);
1298
+ denoName = denoName.substring(slashIndex + 1);
1299
+ }
1300
+ }
1301
+ denoParentComponent = {
1302
+ group: denoGroup,
1303
+ name: denoName,
1304
+ version: options.projectVersion || denoConfig.version || "",
1305
+ type: "application",
1306
+ };
1307
+ ppurl = build({
1308
+ type: "npm",
1309
+ namespace: denoParentComponent.group || null,
1310
+ name: denoParentComponent.name,
1311
+ version: denoParentComponent.version || null,
1312
+ });
1313
+ denoParentComponent["bom-ref"] = decodeURIComponent(ppurl);
1314
+ denoParentComponent["purl"] = ppurl;
1315
+ }
1316
+ }
1317
+ if (!Object.keys(denoParentComponent).length) {
1318
+ let dirName = basePath;
1319
+ const tmpA = dirName.split(sep);
1320
+ dirName = tmpA[tmpA.length - 1];
1321
+ denoParentComponent = {
1322
+ group: options.projectGroup || "",
1323
+ name: "project-name" in options ? options.projectName : dirName,
1324
+ type: "application",
1325
+ };
1326
+ ppurl = build({
1327
+ type: "npm",
1328
+ namespace: denoParentComponent.group || null,
1329
+ name: denoParentComponent.name,
1330
+ version: denoParentComponent.version || null,
1331
+ });
1332
+ denoParentComponent["bom-ref"] = decodeURIComponent(ppurl);
1333
+ denoParentComponent["purl"] = ppurl;
1334
+ }
1335
+ if (Object.keys(denoParentComponent).length) {
1336
+ if (!Object.keys(parentComponent).length) {
1337
+ parentComponent = denoParentComponent;
1338
+ } else if (
1339
+ denoParentComponent["bom-ref"] !== parentComponent["bom-ref"]
1340
+ ) {
1341
+ parentSubComponents.push(denoParentComponent);
1342
+ }
1343
+ }
1344
+ const parsedList = await parseDenoLock(f, {
1345
+ ...options,
1346
+ projectRoot: basePath,
1347
+ parentComponent: denoParentComponent,
1348
+ });
1349
+ if (parsedList.pkgList?.length) {
1350
+ pkgList = pkgList.concat(parsedList.pkgList);
1351
+ }
1352
+ if (parsedList.dependenciesList?.length) {
1353
+ dependencies = mergeDependencies(
1354
+ dependencies,
1355
+ parsedList.dependenciesList,
1356
+ denoParentComponent,
1357
+ );
1358
+ }
1359
+ }
1360
+ }
1361
+ // We might reach here if the project has no lock files
1362
+ // Eg: juice-shop
1363
+ if (!pkgList.length && safeExistsSync(join(path, "node_modules"))) {
1364
+ // Collect all package.json files from all node_modules directory
1365
+ const pkgJsonFiles = getAllFiles(
1366
+ path,
1367
+ "**/node_modules/**/package.json",
1368
+ options,
1369
+ );
1370
+ manifestFiles = manifestFiles.concat(pkgJsonFiles);
1371
+ for (const pkgjf of pkgJsonFiles) {
1372
+ const dlist = await parsePkgJson(pkgjf);
1373
+ if (dlist?.length) {
1374
+ pkgList = pkgList.concat(dlist);
1375
+ }
1376
+ }
1377
+ if (!parentComponent || !Object.keys(parentComponent).length) {
1378
+ if (safeExistsSync(join(path, "package.json"))) {
1379
+ const pcs = await parsePkgJson(join(path, "package.json"), true, true);
1380
+ if (pcs.length && Object.keys(pcs[0]).length) {
1381
+ parentComponent = { ...pcs[0] };
1382
+ parentComponent.type = "application";
1383
+ ppurl = build({
1384
+ type: "npm",
1385
+ namespace: options.projectGroup || parentComponent.group || null,
1386
+ name: parentComponent.name,
1387
+ version: options.projectVersion || parentComponent.version || null,
1388
+ });
1389
+ parentComponent["bom-ref"] = decodeURIComponent(ppurl);
1390
+ parentComponent["purl"] = ppurl;
1391
+ }
1392
+ }
1393
+ }
1394
+ }
1395
+ if (
1396
+ !pkgList.length &&
1397
+ (yarnLockFiles.length ||
1398
+ pkgLockFiles.length ||
1399
+ bunLockFiles.length ||
1400
+ denoLockFiles.length)
1401
+ ) {
1402
+ if (options.projectType?.length) {
1403
+ thoughtLog(
1404
+ `Despite seeing some lock files, I didn't find any components in this Node.js project. Is there an issue with the project type '${options.projectType?.join(", ")}' used 🤔? I recommend trying again with a different type.`,
1405
+ );
1406
+ } else {
1407
+ thoughtLog(
1408
+ "Despite seeing some lock files, I didn't find any components in this Node.js project. Feels like a bug.",
1409
+ );
1410
+ }
1411
+ }
1412
+ // Retain the components of parent component
1413
+ if (parentSubComponents.length) {
1414
+ parentComponent.components = parentSubComponents;
1415
+ }
1416
+ // We need to set this to force our version to be used rather than the directory name based one.
1417
+ // Fix #1550. Do not blindly force the npm parent to always become the overall parent.
1418
+ if ("project-name" in options && !options.parentComponent) {
1419
+ options.parentComponent = parentComponent;
1420
+ }
1421
+ if (allImports && Object.keys(allImports).length) {
1422
+ pkgList = addWasmComponentsFromImports(pkgList, allImports);
1423
+ pkgList = await addEvidenceForImports(
1424
+ pkgList,
1425
+ allImports,
1426
+ allExports,
1427
+ options.deep,
1428
+ );
1429
+ }
1430
+ if (mcpInventory.components?.length) {
1431
+ pkgList = trimComponents(pkgList.concat(mcpInventory.components));
1432
+ }
1433
+ if (mcpInventory.dependencies?.length) {
1434
+ dependencies = mergeDependencies(
1435
+ dependencies,
1436
+ mcpInventory.dependencies,
1437
+ parentComponent,
1438
+ );
1439
+ }
1440
+ if (aiInventory.components?.length) {
1441
+ pkgList = trimComponents(pkgList.concat(aiInventory.components));
1442
+ }
1443
+ if (aiInventory.dependencies?.length) {
1444
+ dependencies = mergeDependencies(
1445
+ dependencies,
1446
+ aiInventory.dependencies,
1447
+ parentComponent,
1448
+ );
1449
+ }
1450
+ const inventoryServices = mergeServices(
1451
+ mergeServices([], mcpInventory.services || []),
1452
+ aiInventory.services || [],
1453
+ );
1454
+ pkgList = propagateRequiredScopeFromDependencies(pkgList, dependencies);
1455
+ pkgList = markNpmTypesPackagesAsExcluded(pkgList);
1456
+ if (exactAiInventoryType === "mcp") {
1457
+ pkgList = trimComponents(filterInventorySubjectsByTypes(pkgList, ["mcp"]));
1458
+ dependencies = filterInventoryDependencies(
1459
+ dependencies,
1460
+ pkgList,
1461
+ inventoryServices,
1462
+ );
1463
+ if (!parentComponent || !Object.keys(parentComponent).length) {
1464
+ parentComponent = createDefaultParentComponent(path, "generic", options);
1465
+ }
1466
+ }
1467
+ return buildBomNSData(options, pkgList, "npm", {
1468
+ allImports,
1469
+ allExports,
1470
+ src: path,
1471
+ filename: manifestFiles.join(", "),
1472
+ dependencies,
1473
+ parentComponent,
1474
+ services: inventoryServices,
1475
+ });
1476
+ }
1477
+
1478
+ /**
1479
+ * Regex matching `.wasm` import paths in analyzer output, including optional
1480
+ * query/fragment suffixes.
1481
+ *
1482
+ * @type {RegExp}
1483
+ */
1484
+ export const WASM_IMPORT_PATTERN = /\.wasm([?#].*)?$/i;
1485
+
1486
+ /**
1487
+ * Adds generic wasm components from discovered source imports.
1488
+ *
1489
+ * @param {Array<Object>} pkgList Node.js package list
1490
+ * @param {Object} allImports analyzer imports map
1491
+ * @returns {Array<Object>} pkgList enriched with wasm components
1492
+ */
1493
+ export const addWasmComponentsFromImports = (pkgList, allImports) => {
1494
+ if (!allImports || !Object.keys(allImports).length) {
1495
+ return pkgList;
1496
+ }
1497
+ const existingPurls = new Set();
1498
+ for (const pkg of pkgList) {
1499
+ if (pkg?.purl) {
1500
+ existingPurls.add(pkg.purl);
1501
+ }
1502
+ }
1503
+ for (const [importPath, occurrences] of Object.entries(allImports)) {
1504
+ if (!WASM_IMPORT_PATTERN.test(importPath)) {
1505
+ continue;
1506
+ }
1507
+ const cleanImportPath = importPath.replace(/[?#].*$/, "");
1508
+ const normalizedImportPath = cleanImportPath
1509
+ .replace(/\\/g, "/")
1510
+ .replace(/^\.\//, "");
1511
+ const wasmComponentName = normalizedImportPath || cleanImportPath;
1512
+ const wasmFileName = basename(cleanImportPath);
1513
+ if (!allImports[wasmComponentName]) {
1514
+ allImports[wasmComponentName] = new Set();
1515
+ }
1516
+ for (const occurrence of occurrences) {
1517
+ allImports[wasmComponentName].add(occurrence);
1518
+ }
1519
+ // The import path is the file's location within the project, which is what a
1520
+ // purl subpath means. It was previously passed as a `path` qualifier, which
1521
+ // the generic type does not allow (it permits only checksum, download_url,
1522
+ // repository_url and vcs_url) — that threw out of createBom for any project
1523
+ // with a wasm import.
1524
+ const wasmPurl = tryBuildPurl({
1525
+ type: "generic",
1526
+ name: wasmFileName,
1527
+ subpath: normalizedImportPath
1528
+ ? normalizedImportPath.replace(/^\/+/, "")
1529
+ : null,
1530
+ });
1531
+ if (existingPurls.has(wasmPurl)) {
1532
+ continue;
1533
+ }
1534
+ const firstOccurrence = Array.from(occurrences)[0];
1535
+ const srcFile = firstOccurrence?.importedAs || importPath;
1536
+ pkgList.push({
1537
+ name: wasmComponentName,
1538
+ type: "library",
1539
+ ...(wasmPurl ? { purl: wasmPurl, "bom-ref": wasmPurl } : {}),
1540
+ properties: [
1541
+ {
1542
+ name: "internal:SrcFile",
1543
+ value: srcFile,
1544
+ },
1545
+ ],
1546
+ evidence: {
1547
+ identity: {
1548
+ field: "purl",
1549
+ confidence: 0.3,
1550
+ methods: [
1551
+ {
1552
+ technique: "filename",
1553
+ confidence: 0.3,
1554
+ value: srcFile,
1555
+ },
1556
+ ],
1557
+ },
1558
+ },
1559
+ });
1560
+ existingPurls.add(wasmPurl);
1561
+ }
1562
+ return pkgList;
1563
+ };
1564
+
1565
+ /**
1566
+ * Function to create bom string for caxa SEA binaries
1567
+ *
1568
+ * @param {string} path to the project
1569
+ * @param {Object} options Parse options from the cli
1570
+ * @returns {Promise<Object>} Promise resolving to BOM object
1571
+ */
1572
+ export async function createCaxaBom(path, options) {
1573
+ let pkgList = [];
1574
+ let allDependencies = [];
1575
+ let finalParentComponent;
1576
+ const caxaMetadataFiles = getAllFiles(
1577
+ path,
1578
+ `${options.multiProject ? "**/" : ""}*metadata.json`,
1579
+ { ...options, includeDot: true },
1580
+ );
1581
+ for (const mfile of caxaMetadataFiles) {
1582
+ if (DEBUG_MODE) {
1583
+ console.log(`Parsing ${mfile}`);
1584
+ }
1585
+ const { parentComponent, components, dependencies } =
1586
+ await parseCaxaMetadata(mfile);
1587
+ if (parentComponent) {
1588
+ if (!finalParentComponent) {
1589
+ finalParentComponent = parentComponent;
1590
+ if (!finalParentComponent.type) {
1591
+ finalParentComponent.type = "application";
1592
+ }
1593
+ } else {
1594
+ finalParentComponent.components = finalParentComponent.components || [];
1595
+ finalParentComponent.components.push(parentComponent);
1596
+ }
1597
+ }
1598
+ if (components?.length) {
1599
+ pkgList = pkgList.concat(components);
1600
+ }
1601
+ if (dependencies?.length) {
1602
+ allDependencies = mergeDependencies(
1603
+ allDependencies,
1604
+ dependencies,
1605
+ finalParentComponent,
1606
+ );
1607
+ }
1608
+ }
1609
+ return buildBomNSData(options, pkgList, "npm", {
1610
+ src: path,
1611
+ filename: caxaMetadataFiles.join(", "),
1612
+ dependencies: allDependencies,
1613
+ parentComponent: finalParentComponent,
1614
+ });
1615
+ }
1616
+
1617
+ /**
1618
+ * Function to create BOM for VS Code / IDE extensions.
1619
+ * Supports two modes:
1620
+ * 1. Directory scan: Discovers `.vsix` files and installed extension directories
1621
+ * 2. IDE discovery: Automatically finds extensions installed by known IDEs
1622
+ *
1623
+ * @param {string} path to the project or directory to scan
1624
+ * @param {Object} options Parse options from the cli
1625
+ * @returns {Promise<Object>} Promise resolving to BOM object
1626
+ */
1627
+ export async function createVscodeExtensionBom(path, options) {
1628
+ let pkgList = [];
1629
+ let dependencies = [];
1630
+ const tempDirs = [];
1631
+ const shouldDiscoverInstalledIdeExtensions = hasExplicitProjectTypeSelection(
1632
+ options,
1633
+ "vscode-extension",
1634
+ );
1635
+
1636
+ // Mode 1: Scan for .vsix files in the given directory, or treat the input
1637
+ // path as a single .vsix file.
1638
+ let vsixFiles = [];
1639
+ if (path.endsWith(".vsix")) {
1640
+ vsixFiles = [resolve(path)];
1641
+ } else {
1642
+ vsixFiles = getAllFiles(
1643
+ path,
1644
+ `${options.multiProject ? "**/" : ""}*.vsix`,
1645
+ options,
1646
+ );
1647
+ }
1648
+ if (vsixFiles.length) {
1649
+ if (DEBUG_MODE) {
1650
+ console.log(`Found ${vsixFiles.length} .vsix file(s) to parse`);
1651
+ }
1652
+ for (const f of vsixFiles) {
1653
+ if (DEBUG_MODE) {
1654
+ console.log(`Parsing ${f}`);
1655
+ }
1656
+ // Get the extension component metadata
1657
+ const component = await parseVsixFile(f);
1658
+ if (component) {
1659
+ pkgList.push(component);
1660
+ }
1661
+ // Extract the vsix to a temp dir and run deep analysis
1662
+ const extractedDir = await extractVsixToTempDir(f);
1663
+ if (extractedDir) {
1664
+ tempDirs.push(extractedDir);
1665
+ const deepResult = await analyzeExtensionDir(extractedDir, options);
1666
+ if (deepResult.pkgList.length) {
1667
+ pkgList = pkgList.concat(deepResult.pkgList);
1668
+ }
1669
+ if (deepResult.dependencies.length) {
1670
+ dependencies = mergeDependencies(
1671
+ dependencies,
1672
+ deepResult.dependencies,
1673
+ );
1674
+ }
1675
+ }
1676
+ }
1677
+ }
1678
+
1679
+ // Mode 2: Auto-discover extensions from known IDE locations
1680
+ if (shouldDiscoverInstalledIdeExtensions) {
1681
+ const ideDirs = discoverIdeExtensionDirs();
1682
+ if (ideDirs.length) {
1683
+ if (DEBUG_MODE) {
1684
+ console.log(
1685
+ `Discovered IDE extension directories: ${ideDirs.map((d) => `${d.name}: ${d.dir}`).join(", ")}`,
1686
+ );
1687
+ }
1688
+ const ideExtensions = collectInstalledExtensions(ideDirs);
1689
+ if (ideExtensions.length) {
1690
+ if (DEBUG_MODE) {
1691
+ console.log(
1692
+ `Found ${ideExtensions.length} IDE extension(s) from ${ideDirs.length} IDE location(s)`,
1693
+ );
1694
+ }
1695
+ pkgList = pkgList.concat(ideExtensions);
1696
+ // Deep analysis for IDE extension directories
1697
+ for (const ideDir of ideDirs) {
1698
+ await analyzeInstalledExtensionDirs(
1699
+ ideDir.dir,
1700
+ options,
1701
+ pkgList,
1702
+ dependencies,
1703
+ );
1704
+ }
1705
+ }
1706
+ }
1707
+ }
1708
+
1709
+ // Clean up temp directories from vsix extraction
1710
+ for (const td of tempDirs) {
1711
+ cleanupTempDir(td);
1712
+ }
1713
+ pkgList = trimComponents(pkgList);
1714
+ return buildBomNSData(options, pkgList, VSCODE_EXTENSION_PURL_TYPE, {
1715
+ src: path,
1716
+ filename: vsixFiles.join(", "),
1717
+ nsMapping: {},
1718
+ dependencies,
1719
+ });
1720
+ }
1721
+
1722
+ /**
1723
+ * Function to create BOM for Electron ASAR archives.
1724
+ *
1725
+ * @param {string} path to a single archive or a directory to scan
1726
+ * @param {Object} options Parse options from the cli
1727
+ * @returns {Promise<Object>} Promise resolving to BOM object
1728
+ */
1729
+ export async function createAsarBom(path, options) {
1730
+ let pkgList = [];
1731
+ let dependencies = [];
1732
+ let parentComponent = {};
1733
+ const tempDirs = [];
1734
+ const processedArchives = new Set();
1735
+ const maxNestedAsarDepth = 4;
1736
+ const explicitAsarPath = path.endsWith(".asar") ? resolve(path) : undefined;
1737
+ let asarFiles = explicitAsarPath
1738
+ ? [explicitAsarPath]
1739
+ : getAllFiles(path, `${options.multiProject ? "**/" : ""}*.asar`, options);
1740
+
1741
+ if (!explicitAsarPath) {
1742
+ asarFiles = asarFiles.filter((f) => isAsarArchiveSync(f));
1743
+ }
1744
+
1745
+ const aggregateArchiveResults = (
1746
+ archiveAnalysis,
1747
+ isPrimaryArchive = false,
1748
+ ) => {
1749
+ if (
1750
+ archiveAnalysis.parentComponent &&
1751
+ Object.keys(archiveAnalysis.parentComponent).length
1752
+ ) {
1753
+ if (isPrimaryArchive && !Object.keys(parentComponent).length) {
1754
+ parentComponent = archiveAnalysis.parentComponent;
1755
+ } else {
1756
+ pkgList.push(archiveAnalysis.parentComponent);
1757
+ }
1758
+ }
1759
+ if (archiveAnalysis.components?.length) {
1760
+ pkgList = pkgList.concat(archiveAnalysis.components);
1761
+ }
1762
+ if (archiveAnalysis.dependencies?.length) {
1763
+ dependencies = mergeDependencies(
1764
+ dependencies,
1765
+ archiveAnalysis.dependencies,
1766
+ parentComponent,
1767
+ );
1768
+ }
1769
+ };
1770
+
1771
+ const analyzeExtractedArchive = async (
1772
+ extractedDir,
1773
+ archiveAnalysis,
1774
+ archiveIdentityPath,
1775
+ ) => {
1776
+ if (!archiveAnalysis.packageManifestPaths?.length) {
1777
+ return undefined;
1778
+ }
1779
+ const nodeBomOptions = {
1780
+ ...options,
1781
+ installDeps: false,
1782
+ multiProject: true,
1783
+ noBabel: false,
1784
+ path: extractedDir,
1785
+ projectType: ["js"],
1786
+ };
1787
+ const nodeBomData = await createNodejsBom(extractedDir, nodeBomOptions);
1788
+ if (nodeBomData?.bomJson?.components?.length) {
1789
+ rewriteExtractedArchivePaths(
1790
+ nodeBomData.bomJson.components,
1791
+ extractedDir,
1792
+ archiveIdentityPath,
1793
+ );
1794
+ pkgList = pkgList.concat(nodeBomData.bomJson.components);
1795
+ }
1796
+ if (nodeBomData?.bomJson?.dependencies?.length) {
1797
+ dependencies = mergeDependencies(
1798
+ dependencies,
1799
+ nodeBomData.bomJson.dependencies,
1800
+ );
1801
+ }
1802
+ if (
1803
+ archiveAnalysis.parentComponent?.["bom-ref"] &&
1804
+ nodeBomData?.parentComponent?.["bom-ref"] &&
1805
+ archiveAnalysis.parentComponent["bom-ref"] !==
1806
+ nodeBomData.parentComponent["bom-ref"]
1807
+ ) {
1808
+ rewriteExtractedArchivePaths(
1809
+ nodeBomData.parentComponent,
1810
+ extractedDir,
1811
+ archiveIdentityPath,
1812
+ );
1813
+ dependencies = mergeDependencies(dependencies, [
1814
+ {
1815
+ ref: archiveAnalysis.parentComponent["bom-ref"],
1816
+ dependsOn: [nodeBomData.parentComponent["bom-ref"]],
1817
+ },
1818
+ ]);
1819
+ }
1820
+ return nodeBomData;
1821
+ };
1822
+
1823
+ const processAsarArchive = async (
1824
+ archivePath,
1825
+ archiveIdentityPath,
1826
+ isPrimaryArchive = false,
1827
+ depth = 0,
1828
+ ) => {
1829
+ const processedKey = archiveIdentityPath;
1830
+ if (processedArchives.has(processedKey)) {
1831
+ return undefined;
1832
+ }
1833
+ processedArchives.add(processedKey);
1834
+ const archiveAnalysis = await parseAsarArchive(archivePath, {
1835
+ ...options,
1836
+ asarVirtualPath: archiveIdentityPath,
1837
+ });
1838
+ aggregateArchiveResults(archiveAnalysis, isPrimaryArchive);
1839
+ const shouldExtract =
1840
+ archiveAnalysis.packageManifestPaths?.length ||
1841
+ (depth < maxNestedAsarDepth &&
1842
+ archiveAnalysis.summary?.nestedArchiveCount > 0);
1843
+ if (!shouldExtract) {
1844
+ return archiveAnalysis.parentComponent?.["bom-ref"];
1845
+ }
1846
+ const extractedDir = await extractAsarToTempDir(archivePath);
1847
+ if (!extractedDir) {
1848
+ return archiveAnalysis.parentComponent?.["bom-ref"];
1849
+ }
1850
+ tempDirs.push(extractedDir);
1851
+ await analyzeExtractedArchive(
1852
+ extractedDir,
1853
+ archiveAnalysis,
1854
+ archiveIdentityPath,
1855
+ );
1856
+ if (depth < maxNestedAsarDepth) {
1857
+ const nestedAsarFiles = getAllFiles(extractedDir, "**/*.asar", options);
1858
+ for (const nestedArchivePath of nestedAsarFiles) {
1859
+ const relativeNestedArchivePath = relative(
1860
+ extractedDir,
1861
+ nestedArchivePath,
1862
+ ).replaceAll("\\", "/");
1863
+ if (
1864
+ !relativeNestedArchivePath ||
1865
+ relativeNestedArchivePath.startsWith("..")
1866
+ ) {
1867
+ continue;
1868
+ }
1869
+ const nestedArchiveIdentityPath = `${archiveIdentityPath}#/${relativeNestedArchivePath}`;
1870
+ let nestedParentRef;
1871
+ try {
1872
+ nestedParentRef = await processAsarArchive(
1873
+ nestedArchivePath,
1874
+ nestedArchiveIdentityPath,
1875
+ false,
1876
+ depth + 1,
1877
+ );
1878
+ } catch (err) {
1879
+ if (options.failOnError) {
1880
+ console.error(
1881
+ `Error processing nested ASAR archive ${nestedArchivePath}: ${err.message}`,
1882
+ );
1883
+ process.exit(1);
1884
+ }
1885
+ console.warn(
1886
+ `Skipping nested ASAR archive ${nestedArchivePath}: ${err.message}`,
1887
+ );
1888
+ }
1889
+ if (
1890
+ archiveAnalysis.parentComponent?.["bom-ref"] &&
1891
+ nestedParentRef &&
1892
+ archiveAnalysis.parentComponent["bom-ref"] !== nestedParentRef
1893
+ ) {
1894
+ dependencies = mergeDependencies(dependencies, [
1895
+ {
1896
+ ref: archiveAnalysis.parentComponent["bom-ref"],
1897
+ dependsOn: [nestedParentRef],
1898
+ },
1899
+ ]);
1900
+ }
1901
+ }
1902
+ }
1903
+ return archiveAnalysis.parentComponent?.["bom-ref"];
1904
+ };
1905
+ try {
1906
+ for (const archivePath of asarFiles) {
1907
+ const isPrimaryArchive =
1908
+ explicitAsarPath && resolve(archivePath) === explicitAsarPath;
1909
+ try {
1910
+ await processAsarArchive(
1911
+ archivePath,
1912
+ resolve(archivePath),
1913
+ isPrimaryArchive,
1914
+ 0,
1915
+ );
1916
+ } catch (err) {
1917
+ if (options.failOnError) {
1918
+ console.error(
1919
+ `Error processing ASAR archive ${archivePath}: ${err.message}`,
1920
+ );
1921
+ process.exit(1);
1922
+ }
1923
+ console.warn(`Skipping ASAR archive ${archivePath}: ${err.message}`);
1924
+ }
1925
+ }
1926
+ } finally {
1927
+ for (const tempDir of tempDirs) {
1928
+ cleanupAsarTempDir(tempDir);
1929
+ }
1930
+ }
1931
+ pkgList = trimComponents(pkgList);
1932
+ return buildBomNSData(options, pkgList, "asar", {
1933
+ src: path,
1934
+ filename: asarFiles.join(", "),
1935
+ nsMapping: {},
1936
+ dependencies,
1937
+ parentComponent,
1938
+ });
1939
+ }
1940
+
1941
+ /**
1942
+ * Function to create BOM for installed Chrome and Chromium-based browser extensions.
1943
+ *
1944
+ * @param {string} path to the project path or a directly provided extension path
1945
+ * @param {Object} options Parse options from the cli
1946
+ * @returns {Promise<Object>} Promise resolving to BOM object
1947
+ */
1948
+ export async function createChromeExtensionBom(path, options) {
1949
+ let dependencies = [];
1950
+ let sourcePaths = [];
1951
+ const directResult = collectChromeExtensionsFromPath(path);
1952
+ const shouldDiscoverInstalledChromeExtensions =
1953
+ hasExplicitProjectTypeSelection(options, "chrome-extension");
1954
+ let pkgList = directResult.components || [];
1955
+ if (directResult.extensionDirs?.length) {
1956
+ sourcePaths = directResult.extensionDirs.slice();
1957
+ for (const extDir of directResult.extensionDirs) {
1958
+ const deepResult = await analyzeExtensionDir(extDir, options);
1959
+ if (deepResult.pkgList.length) {
1960
+ pkgList = pkgList.concat(deepResult.pkgList);
1961
+ }
1962
+ if (deepResult.dependencies.length) {
1963
+ dependencies = mergeDependencies(dependencies, deepResult.dependencies);
1964
+ }
1965
+ }
1966
+ }
1967
+ if (pkgList.length && DEBUG_MODE) {
1968
+ thoughtLog(
1969
+ `Found ${pkgList.length} component(s) from direct Chrome extension path scan`,
1970
+ );
1971
+ }
1972
+ if (shouldDiscoverInstalledChromeExtensions) {
1973
+ const chromeDirs = discoverChromiumExtensionDirs();
1974
+ if (chromeDirs.length) {
1975
+ if (DEBUG_MODE) {
1976
+ thoughtLog(
1977
+ `Discovered Chromium extension directories: ${chromeDirs.map((d) => `${d.browser} (${d.channel}): ${d.dir}`).join(", ")}`,
1978
+ );
1979
+ }
1980
+ if (!pkgList.length) {
1981
+ pkgList = collectInstalledChromeExtensions(chromeDirs);
1982
+ sourcePaths = chromeDirs.map((d) => d.dir);
1983
+ }
1984
+ if (DEBUG_MODE && pkgList.length && !directResult.components?.length) {
1985
+ thoughtLog(
1986
+ `Found ${pkgList.length} Chrome/Chromium extension(s) from ${chromeDirs.length} browser location(s)`,
1987
+ );
1988
+ }
1989
+ }
1990
+ }
1991
+ pkgList = trimComponents(pkgList);
1992
+ return buildBomNSData(options, pkgList, CHROME_EXTENSION_PURL_TYPE, {
1993
+ src: path,
1994
+ filename: sourcePaths.join(", "),
1995
+ nsMapping: {},
1996
+ dependencies,
1997
+ });
1998
+ }
1999
+
2000
+ /**
2001
+ * Analyze an extracted extension directory for bundled dependencies.
2002
+ * Looks for npm lock files, node_modules, package.json files, minified JS,
2003
+ * and runs the babel-based analyzer on the source.
2004
+ *
2005
+ * @param {string} extDir Path to the extracted extension directory
2006
+ * @param {Object} options CLI options
2007
+ * @returns {Promise<{pkgList: Object[], dependencies: Object[]}>}
2008
+ */
2009
+ export async function analyzeExtensionDir(extDir, options) {
2010
+ const pkgList = [];
2011
+ let dependencies = [];
2012
+ // Check if the extension directory contains node.js project artifacts
2013
+ const hasPackageJson = safeExistsSync(join(extDir, "package.json"));
2014
+ const hasNodeModules = safeExistsSync(join(extDir, "node_modules"));
2015
+ const hasLockFile =
2016
+ safeExistsSync(join(extDir, "package-lock.json")) ||
2017
+ safeExistsSync(join(extDir, "yarn.lock")) ||
2018
+ safeExistsSync(join(extDir, "pnpm-lock.yaml"));
2019
+
2020
+ // If there are lock files or node_modules, run the full Node.js BOM generator
2021
+ if (hasPackageJson && (hasLockFile || hasNodeModules)) {
2022
+ if (DEBUG_MODE) {
2023
+ console.log(
2024
+ `Running Node.js BOM analysis on extension directory: ${extDir}`,
2025
+ );
2026
+ }
2027
+ const nodeBomOptions = {
2028
+ ...options,
2029
+ path: extDir,
2030
+ multiProject: true,
2031
+ installDeps: false,
2032
+ noBabel: false,
2033
+ projectType: ["js"],
2034
+ };
2035
+ const bomData = await createNodejsBom(extDir, nodeBomOptions);
2036
+ if (bomData?.bomJson?.components?.length) {
2037
+ for (const comp of bomData.bomJson.components) {
2038
+ pkgList.push(comp);
2039
+ }
2040
+ }
2041
+ if (bomData?.bomJson?.dependencies?.length) {
2042
+ dependencies = mergeDependencies(
2043
+ dependencies,
2044
+ bomData.bomJson.dependencies,
2045
+ );
2046
+ }
2047
+ return { pkgList, dependencies };
2048
+ }
2049
+ return { pkgList, dependencies };
2050
+ }
2051
+
2052
+ /**
2053
+ * Run deep analysis on installed extension subdirectories within a parent
2054
+ * extensions directory. Each subdirectory represents an installed extension.
2055
+ *
2056
+ * @param {string} extensionsDir Parent directory containing extension subdirs
2057
+ * @param {Object} options CLI options
2058
+ * @param {Object[]} pkgList Mutable array to push discovered components into
2059
+ * @param {Object[]} dependencies Mutable array to merge dependencies into
2060
+ */
2061
+ export async function analyzeInstalledExtensionDirs(
2062
+ extensionsDir,
2063
+ options,
2064
+ pkgList,
2065
+ dependencies,
2066
+ ) {
2067
+ let entries;
2068
+ try {
2069
+ entries = readdirSync(extensionsDir, { withFileTypes: true });
2070
+ } catch (_e) {
2071
+ return;
2072
+ }
2073
+ for (const entry of entries) {
2074
+ if (!entry.isDirectory() || entry.name.startsWith(".")) {
2075
+ continue;
2076
+ }
2077
+ const extDir = join(extensionsDir, entry.name);
2078
+ const deepResult = await analyzeExtensionDir(extDir, options);
2079
+ if (deepResult.pkgList.length) {
2080
+ pkgList.push(...deepResult.pkgList);
2081
+ }
2082
+ if (deepResult.dependencies.length) {
2083
+ const merged = mergeDependencies(dependencies, deepResult.dependencies);
2084
+ dependencies.splice(0, dependencies.length, ...merged);
2085
+ }
2086
+ }
2087
+ }