@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,2070 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { basename, dirname, join, relative } from "node:path";
3
+ import process from "node:process";
4
+ import { URL } from "node:url";
5
+
6
+ import { build } from "@cdxgen/cdx-purl";
7
+ import toml from "@iarna/toml";
8
+ import { parse as _load } from "yaml";
9
+
10
+ import { DEBUG_MODE } from "../core/activity.js";
11
+ import { getAllFiles, safeExistsSync, safeSpawnSync } from "../core/fs.js";
12
+ import { PYTHON_STD_MODULES } from "../core/state.js";
13
+ import { tryBuildPurl } from "../inventory/purl.js";
14
+ import {
15
+ createExternalReferenceKey,
16
+ getPyMetadata,
17
+ mergeExternalReferences,
18
+ } from "./ecosystems.js";
19
+ import {
20
+ collectPyLockDependencyRelationships,
21
+ collectPyLockFileComponents,
22
+ collectPyLockPackageProperties,
23
+ collectPyLockTopLevelProperties,
24
+ getPyLockPackages,
25
+ isDefaultPypiRegistry,
26
+ isPyLockObject,
27
+ normalizePyLockRegistry,
28
+ } from "./pylockutils.js";
29
+
30
+ /**
31
+ * Method to parse python requires_dist attribute found in pypi setup.py
32
+ *
33
+ * @param {String} dist_string string
34
+ */
35
+ export function parsePyRequiresDist(dist_string) {
36
+ if (!dist_string) {
37
+ return undefined;
38
+ }
39
+ const tmpA = dist_string.split(" ");
40
+ let name = "";
41
+ let version = "";
42
+ if (!tmpA) {
43
+ return undefined;
44
+ }
45
+ if (tmpA.length === 1) {
46
+ name = tmpA[0];
47
+ } else if (tmpA.length > 1) {
48
+ name = tmpA[0];
49
+ const tmpVersion = tmpA[1];
50
+ version = tmpVersion.split(",")[0].replace(/[();=&glt><]/g, "");
51
+ }
52
+ return {
53
+ name,
54
+ version,
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Method to parse pipfile.lock data
60
+ *
61
+ * @param {Object} lockData JSON data from Pipfile.lock
62
+ */
63
+ export async function parsePiplockData(lockData) {
64
+ const pkgList = [];
65
+ Object.keys(lockData)
66
+ .filter((i) => i !== "_meta")
67
+ .forEach((k) => {
68
+ const depBlock = lockData[k];
69
+ Object.keys(depBlock).forEach((p) => {
70
+ const pkg = depBlock[p];
71
+ if (Object.hasOwn(pkg, "version")) {
72
+ const versionStr = pkg.version.replace("==", "");
73
+ pkgList.push({ name: p, version: versionStr });
74
+ }
75
+ });
76
+ });
77
+ return await getPyMetadata(pkgList, false);
78
+ }
79
+
80
+ /**
81
+ * Append a deduplicated name/value property to a component's properties array.
82
+ *
83
+ * @param {object} component Component to mutate.
84
+ * @param {string} name Property name.
85
+ * @param {string} value Property value.
86
+ * @returns {void}
87
+ */
88
+ export function addComponentProperty(component, name, value) {
89
+ if (value === undefined || value === null || value === "" || !component) {
90
+ return;
91
+ }
92
+ component.properties = component.properties || [];
93
+ if (
94
+ component.properties.some(
95
+ (property) => property.name === name && property.value === value,
96
+ )
97
+ ) {
98
+ return;
99
+ }
100
+ component.properties.push({
101
+ name,
102
+ value,
103
+ });
104
+ }
105
+
106
+ const PYTHON_DIRECT_REFERENCE_PATTERN =
107
+ /^([A-Za-z0-9_.-]+)(?:\[[^\]]+])?\s*@\s*(\S+)$/;
108
+
109
+ function isWindowsAbsolutePath(value) {
110
+ return /^[a-zA-Z]:[\\/]/.test(value) || value.startsWith("\\\\");
111
+ }
112
+
113
+ function normalizePythonDependencyKey(value) {
114
+ if (typeof value !== "string" || !value.trim()) {
115
+ return undefined;
116
+ }
117
+ return value.trim().toLowerCase().replaceAll("_", "-");
118
+ }
119
+
120
+ function extractPythonDependencyKey(value) {
121
+ const manifestSource = parsePyProjectDependencySourceString(value);
122
+ if (manifestSource?.name) {
123
+ return normalizePythonDependencyKey(manifestSource.name);
124
+ }
125
+ const packageMatch =
126
+ typeof value === "string"
127
+ ? value.trim().match(/^([A-Za-z0-9_.-]+)(?:\[[^\]]+])?/)
128
+ : undefined;
129
+ return normalizePythonDependencyKey(packageMatch?.[1]);
130
+ }
131
+
132
+ function classifyPythonManifestSourceValue(value) {
133
+ if (typeof value !== "string" || !value.trim()) {
134
+ return undefined;
135
+ }
136
+ const normalizedValue = value.trim();
137
+ const lowerValue = normalizedValue.toLowerCase();
138
+ if (
139
+ lowerValue.startsWith("git+") ||
140
+ lowerValue.startsWith("git://") ||
141
+ lowerValue.startsWith("git@") ||
142
+ lowerValue.startsWith("ssh://git@")
143
+ ) {
144
+ return {
145
+ type: "git",
146
+ value: normalizedValue,
147
+ };
148
+ }
149
+ if (
150
+ lowerValue.startsWith("http://") ||
151
+ lowerValue.startsWith("https://") ||
152
+ lowerValue.startsWith("ftp://")
153
+ ) {
154
+ return {
155
+ type: "url",
156
+ value: normalizedValue,
157
+ };
158
+ }
159
+ if (
160
+ lowerValue.startsWith("file:") ||
161
+ normalizedValue.startsWith("./") ||
162
+ normalizedValue.startsWith("../") ||
163
+ normalizedValue.startsWith("/") ||
164
+ isWindowsAbsolutePath(normalizedValue)
165
+ ) {
166
+ return {
167
+ type: "path",
168
+ value: normalizedValue,
169
+ };
170
+ }
171
+ return undefined;
172
+ }
173
+
174
+ function applyManifestSourceProperties(
175
+ component,
176
+ propertyPrefix,
177
+ manifestSource,
178
+ ) {
179
+ if (!manifestSource?.type || !manifestSource?.value) {
180
+ return;
181
+ }
182
+ addComponentProperty(
183
+ component,
184
+ `${propertyPrefix}:manifestSourceType`,
185
+ manifestSource.type,
186
+ );
187
+ addComponentProperty(
188
+ component,
189
+ `${propertyPrefix}:manifestSource`,
190
+ manifestSource.value,
191
+ );
192
+ }
193
+
194
+ function recordPythonDependencySource(
195
+ dependencySourceMap,
196
+ dependencyName,
197
+ sourceType,
198
+ sourceValue,
199
+ ) {
200
+ const normalizedKey = normalizePythonDependencyKey(dependencyName);
201
+ if (!normalizedKey || !sourceType || !sourceValue) {
202
+ return;
203
+ }
204
+ dependencySourceMap[normalizedKey] = {
205
+ type: sourceType,
206
+ value: sourceValue,
207
+ };
208
+ }
209
+
210
+ function parsePyProjectDependencySourceString(value) {
211
+ if (typeof value !== "string" || !value.includes("@")) {
212
+ return undefined;
213
+ }
214
+ const directReferenceMatch = value
215
+ .trim()
216
+ .match(PYTHON_DIRECT_REFERENCE_PATTERN);
217
+ if (!directReferenceMatch) {
218
+ return undefined;
219
+ }
220
+ const manifestSource = classifyPythonManifestSourceValue(
221
+ directReferenceMatch[2],
222
+ );
223
+ if (!manifestSource) {
224
+ return undefined;
225
+ }
226
+ return {
227
+ name: directReferenceMatch[1],
228
+ ...manifestSource,
229
+ };
230
+ }
231
+
232
+ function collectPythonManifestSource(pkg) {
233
+ const sourceCandidates = [
234
+ { kind: "git", value: pkg?.source?.git },
235
+ { kind: "git", value: pkg?.vcs?.git },
236
+ { kind: "url", value: pkg?.vcs?.url },
237
+ { kind: "url", value: pkg?.source?.url },
238
+ { kind: "path", value: pkg?.source?.path },
239
+ { kind: "path", value: pkg?.source?.editable },
240
+ { kind: "path", value: pkg?.source?.virtual },
241
+ ];
242
+ for (const candidate of sourceCandidates) {
243
+ if (typeof candidate.value !== "string" || !candidate.value.trim()) {
244
+ continue;
245
+ }
246
+ const normalizedValue = candidate.value.trim();
247
+ if (candidate.kind === "git") {
248
+ return {
249
+ type: "git",
250
+ value: normalizedValue.startsWith("git+")
251
+ ? normalizedValue
252
+ : `git+${normalizedValue}`,
253
+ };
254
+ }
255
+ const manifestSource = classifyPythonManifestSourceValue(normalizedValue);
256
+ if (manifestSource) {
257
+ return manifestSource;
258
+ }
259
+ return {
260
+ type: candidate.kind,
261
+ value: normalizedValue,
262
+ };
263
+ }
264
+ return undefined;
265
+ }
266
+
267
+ function parsePythonRequirementManifestSource(value) {
268
+ if (typeof value !== "string" || !value.trim()) {
269
+ return undefined;
270
+ }
271
+ const normalizedValue = value.trim();
272
+ const directReferenceMatch = normalizedValue.match(
273
+ PYTHON_DIRECT_REFERENCE_PATTERN,
274
+ );
275
+ if (directReferenceMatch) {
276
+ const manifestSource = classifyPythonManifestSourceValue(
277
+ directReferenceMatch[2],
278
+ );
279
+ if (manifestSource) {
280
+ return {
281
+ name: directReferenceMatch[1],
282
+ ...manifestSource,
283
+ };
284
+ }
285
+ }
286
+ const vcsRequirementMatch = normalizedValue.match(
287
+ /^(git\+\S+?)(?:#.*egg=([A-Za-z0-9_.-]+))?$/,
288
+ );
289
+ if (vcsRequirementMatch?.[2]) {
290
+ return {
291
+ name: vcsRequirementMatch[2],
292
+ type: "git",
293
+ value: vcsRequirementMatch[1],
294
+ };
295
+ }
296
+ return undefined;
297
+ }
298
+
299
+ /**
300
+ * Method to parse python pyproject.toml file
301
+ *
302
+ * @param {string} tomlFile pyproject.toml file
303
+ * @returns {Object} Object with parent component, root dependencies, and metadata.
304
+ */
305
+ export function parsePyProjectTomlFile(tomlFile) {
306
+ function handleBlock(pkg, atool) {
307
+ for (const k of ["name", "version", "description", "license"]) {
308
+ // We can copy string values as-is
309
+ if (
310
+ !pkg[k] &&
311
+ atool[k] &&
312
+ (typeof atool[k] === "string" || atool[k] instanceof String)
313
+ ) {
314
+ pkg[k] = atool[k];
315
+ }
316
+ }
317
+ if (atool.authors) {
318
+ if (Array.isArray(atool.authors) && atool.authors.length > 0) {
319
+ // Multiple author objects
320
+ if (
321
+ Object.keys(atool.authors[0]).length &&
322
+ (atool.authors[0]?.name || atool.authors[0]?.email)
323
+ ) {
324
+ pkg.authors = atool.authors;
325
+ } else {
326
+ pkg.author = atool.authors.join(", ");
327
+ }
328
+ } else if (
329
+ typeof atool.authors === "string" ||
330
+ atool.authors instanceof String
331
+ ) {
332
+ pkg.author = atool.authors.trim();
333
+ }
334
+ }
335
+ if (atool.homepage) {
336
+ pkg.homepage = { url: atool.homepage };
337
+ }
338
+ if (atool.repository) {
339
+ pkg.repository = { url: atool.repository };
340
+ }
341
+ if (atool.keywords && Array.isArray(atool.keywords)) {
342
+ pkg.tags = atool.keywords.sort();
343
+ }
344
+ if (atool["requires-python"]) {
345
+ pkg.properties = [
346
+ { name: "cdx:pypi:requiresPython", value: atool["requires-python"] },
347
+ ];
348
+ }
349
+ }
350
+
351
+ let poetryMode = false;
352
+ let uvMode = false;
353
+ let hatchMode = false;
354
+ const workspacePaths = [];
355
+ let tomlData;
356
+ const directDepsKeys = {};
357
+ const groupDepsKeys = {};
358
+ const dependencySourceMap = {};
359
+ try {
360
+ tomlData = toml.parse(readFileSync(tomlFile, { encoding: "utf-8" }));
361
+ } catch (err) {
362
+ console.log(`Error while parsing the pyproject file ${tomlFile}.`, err);
363
+ }
364
+ const pkg = {};
365
+ if (!tomlData) {
366
+ return {};
367
+ }
368
+ if (
369
+ tomlData?.tool?.poetry ||
370
+ tomlData?.["build-system"]?.["build-backend"]?.startsWith("poetry.core")
371
+ ) {
372
+ poetryMode = true;
373
+ }
374
+ if (tomlData?.tool?.uv) {
375
+ uvMode = true;
376
+ }
377
+ if (tomlData?.["build-system"]?.["build-backend"]?.startsWith("hatchling.")) {
378
+ hatchMode = true;
379
+ }
380
+ if (
381
+ uvMode &&
382
+ tomlData.tool.uv.workspace &&
383
+ Array.isArray(tomlData.tool.uv.workspace?.members)
384
+ ) {
385
+ for (const amember of tomlData.tool.uv.workspace.members) {
386
+ const memberPyProjPaths = amember.endsWith("/*")
387
+ ? amember.replace(/\/\*$/, "/**/pyproject.toml")
388
+ : `${amember}/**/pyproject.toml`;
389
+ workspacePaths.push(memberPyProjPaths);
390
+ }
391
+ }
392
+ // uv and others
393
+ if (tomlData?.project && Object.keys(tomlData.project).length) {
394
+ handleBlock(pkg, tomlData.project);
395
+ }
396
+ if (tomlData?.tool && Object.keys(tomlData.tool).length) {
397
+ for (const atoolKey of Object.keys(tomlData.tool)) {
398
+ const atool = tomlData.tool[atoolKey];
399
+ handleBlock(pkg, atool);
400
+ }
401
+ }
402
+ if (pkg.name) {
403
+ pkg.type = "application";
404
+ const ppurl = build({
405
+ type: "pypi",
406
+ namespace: pkg.group || "" || null,
407
+ name: pkg.name,
408
+ version: pkg.version || "latest" || null,
409
+ });
410
+ pkg["bom-ref"] = decodeURIComponent(ppurl);
411
+ pkg["purl"] = ppurl;
412
+ pkg.evidence = {
413
+ identity: {
414
+ field: "purl",
415
+ confidence: 1,
416
+ methods: [
417
+ {
418
+ technique: "manifest-analysis",
419
+ confidence: 1,
420
+ value: tomlFile,
421
+ },
422
+ ],
423
+ },
424
+ };
425
+ }
426
+ if (tomlData?.project?.dependencies) {
427
+ for (const adep of tomlData.project.dependencies) {
428
+ const dependencyKey = extractPythonDependencyKey(adep);
429
+ if (dependencyKey) {
430
+ directDepsKeys[dependencyKey] = true;
431
+ }
432
+ const manifestSource = parsePyProjectDependencySourceString(adep);
433
+ if (manifestSource) {
434
+ recordPythonDependencySource(
435
+ dependencySourceMap,
436
+ manifestSource.name,
437
+ manifestSource.type,
438
+ manifestSource.value,
439
+ );
440
+ }
441
+ }
442
+ }
443
+ if (tomlData["dependency-groups"]) {
444
+ for (const agroup of Object.keys(tomlData["dependency-groups"])) {
445
+ tomlData["dependency-groups"][agroup].forEach((p) => {
446
+ if (typeof p === "string" || p instanceof String) {
447
+ const pname = p.split(/(==|<=|~=|>=)/)[0].split(" ")[0];
448
+ if (!groupDepsKeys[pname]) {
449
+ groupDepsKeys[pname] = [];
450
+ }
451
+ groupDepsKeys[pname].push(agroup);
452
+ const manifestSource = parsePyProjectDependencySourceString(p);
453
+ if (manifestSource) {
454
+ recordPythonDependencySource(
455
+ dependencySourceMap,
456
+ manifestSource.name,
457
+ manifestSource.type,
458
+ manifestSource.value,
459
+ );
460
+ }
461
+ } else {
462
+ return;
463
+ }
464
+ });
465
+ }
466
+ }
467
+ if (tomlData?.tool?.poetry?.dependencies) {
468
+ for (const adep of Object.keys(tomlData?.tool?.poetry?.dependencies)) {
469
+ if (
470
+ ![
471
+ "python",
472
+ "py",
473
+ "pytest",
474
+ "pylint",
475
+ "ruff",
476
+ "setuptools",
477
+ "bandit",
478
+ ].includes(adep)
479
+ ) {
480
+ directDepsKeys[adep] = true;
481
+ const poetryDependency = tomlData.tool.poetry.dependencies[adep];
482
+ if (poetryDependency?.git) {
483
+ recordPythonDependencySource(
484
+ dependencySourceMap,
485
+ adep,
486
+ "git",
487
+ poetryDependency.git,
488
+ );
489
+ } else if (poetryDependency?.url) {
490
+ recordPythonDependencySource(
491
+ dependencySourceMap,
492
+ adep,
493
+ "url",
494
+ poetryDependency.url,
495
+ );
496
+ } else if (poetryDependency?.path) {
497
+ recordPythonDependencySource(
498
+ dependencySourceMap,
499
+ adep,
500
+ "path",
501
+ poetryDependency.path,
502
+ );
503
+ }
504
+ }
505
+ } // for
506
+ if (tomlData?.tool?.poetry?.group) {
507
+ for (const agroup of Object.keys(tomlData.tool.poetry.group)) {
508
+ for (const adep of Object.keys(
509
+ tomlData.tool.poetry.group[agroup]?.dependencies,
510
+ )) {
511
+ if (!groupDepsKeys[adep]) {
512
+ groupDepsKeys[adep] = [];
513
+ }
514
+ groupDepsKeys[adep].push(agroup);
515
+ const poetryDependency =
516
+ tomlData.tool.poetry.group[agroup]?.dependencies?.[adep];
517
+ if (poetryDependency?.git) {
518
+ recordPythonDependencySource(
519
+ dependencySourceMap,
520
+ adep,
521
+ "git",
522
+ poetryDependency.git,
523
+ );
524
+ } else if (poetryDependency?.url) {
525
+ recordPythonDependencySource(
526
+ dependencySourceMap,
527
+ adep,
528
+ "url",
529
+ poetryDependency.url,
530
+ );
531
+ } else if (poetryDependency?.path) {
532
+ recordPythonDependencySource(
533
+ dependencySourceMap,
534
+ adep,
535
+ "path",
536
+ poetryDependency.path,
537
+ );
538
+ }
539
+ }
540
+ } // for
541
+ }
542
+ }
543
+ if (tomlData?.tool?.uv?.sources) {
544
+ for (const adep of Object.keys(tomlData.tool.uv.sources)) {
545
+ const uvSource = Array.isArray(tomlData.tool.uv.sources[adep])
546
+ ? tomlData.tool.uv.sources[adep][0]
547
+ : tomlData.tool.uv.sources[adep];
548
+ if (uvSource?.git) {
549
+ recordPythonDependencySource(
550
+ dependencySourceMap,
551
+ adep,
552
+ "git",
553
+ uvSource.git,
554
+ );
555
+ } else if (uvSource?.url) {
556
+ recordPythonDependencySource(
557
+ dependencySourceMap,
558
+ adep,
559
+ "url",
560
+ uvSource.url,
561
+ );
562
+ } else if (uvSource?.path) {
563
+ recordPythonDependencySource(
564
+ dependencySourceMap,
565
+ adep,
566
+ "path",
567
+ uvSource.path,
568
+ );
569
+ }
570
+ }
571
+ }
572
+ return {
573
+ parentComponent: pkg,
574
+ poetryMode,
575
+ uvMode,
576
+ hatchMode,
577
+ workspacePaths,
578
+ directDepsKeys,
579
+ groupDepsKeys,
580
+ dependencySourceMap,
581
+ };
582
+ }
583
+
584
+ function collectPythonLockDistributionReferences(pkg) {
585
+ const externalReferences = [];
586
+ const seen = new Set();
587
+
588
+ function addExternalReference(type, url, comment) {
589
+ if (typeof url !== "string" || !url.trim()) {
590
+ return;
591
+ }
592
+ const normalizedUrl = url.trim();
593
+ const reference = {
594
+ type,
595
+ url: normalizedUrl,
596
+ comment,
597
+ };
598
+ const referenceKey = createExternalReferenceKey(reference);
599
+ if (seen.has(referenceKey)) {
600
+ return;
601
+ }
602
+ seen.add(referenceKey);
603
+ externalReferences.push(reference);
604
+ }
605
+
606
+ addExternalReference("distribution", pkg?.archive?.url, "archive");
607
+ addExternalReference("distribution", pkg?.sdist?.url, "sdist");
608
+ if (Array.isArray(pkg?.wheels)) {
609
+ for (const wheel of pkg.wheels) {
610
+ addExternalReference(
611
+ "distribution",
612
+ wheel?.url,
613
+ wheel?.file || wheel?.name || wheel?.filename || "wheel",
614
+ );
615
+ }
616
+ }
617
+ const vcsSource = [
618
+ { kind: "url", value: pkg?.vcs?.url },
619
+ { kind: "git", value: pkg?.vcs?.git },
620
+ { kind: "git", value: pkg?.source?.git },
621
+ ].find(
622
+ (entry) => typeof entry.value === "string" && entry.value.trim().length > 0,
623
+ );
624
+ if (vcsSource) {
625
+ const vcsUrl = vcsSource.value.trim();
626
+ const normalizedVcsUrl =
627
+ vcsSource.kind === "git" && !vcsUrl.startsWith("git+")
628
+ ? `git+${vcsUrl}`
629
+ : vcsUrl;
630
+ addExternalReference("vcs", normalizedVcsUrl, "vcs");
631
+ }
632
+ if (pkg?.source?.url) {
633
+ const manifestSource = classifyPythonManifestSourceValue(pkg.source.url);
634
+ addExternalReference(
635
+ manifestSource?.type === "git" ? "vcs" : "distribution",
636
+ pkg.source.url,
637
+ "source",
638
+ );
639
+ }
640
+ return externalReferences;
641
+ }
642
+
643
+ function collectPythonLockMetadataFileEntries(lockTomlObj, pkg) {
644
+ if (!lockTomlObj?.metadata?.files || !pkg?.name) {
645
+ return [];
646
+ }
647
+ const expectedKeys = new Set([normalizePythonDependencyKey(pkg.name)]);
648
+ if (pkg.version) {
649
+ expectedKeys.add(
650
+ `${normalizePythonDependencyKey(pkg.name)} ${`${pkg.version}`.trim().toLowerCase()}`,
651
+ );
652
+ }
653
+ const matchingEntries = [];
654
+ for (const [entryKey, entryValues] of Object.entries(
655
+ lockTomlObj.metadata.files,
656
+ )) {
657
+ if (!Array.isArray(entryValues)) {
658
+ continue;
659
+ }
660
+ if (expectedKeys.has(normalizePythonDependencyKey(entryKey))) {
661
+ matchingEntries.push(...entryValues);
662
+ }
663
+ }
664
+ return matchingEntries;
665
+ }
666
+
667
+ /**
668
+ * Derive a file name for a file entry of a python lock file.
669
+ *
670
+ * - poetry.lock `[metadata.files]` entries carry a `file` key.
671
+ * - pdm.lock `[metadata.files]` entries carry a `url` key (no `file`).
672
+ * - pylock.toml / uv.lock artifacts can carry an explicit `name`, a local
673
+ * `path`, and/or a `url`.
674
+ *
675
+ * @param {object} fileEntry A single lock-file file entry.
676
+ * @returns {string | undefined} The derived file name, or undefined when none can be derived.
677
+ */
678
+ export function derivePythonLockMetadataFileName(fileEntry) {
679
+ if (!fileEntry || typeof fileEntry !== "object") {
680
+ return undefined;
681
+ }
682
+ // Explicit filenames (pylock `name`, poetry `file`) win over derived ones.
683
+ for (const key of ["file", "name"]) {
684
+ const value = fileEntry[key];
685
+ if (typeof value === "string" && value.trim()) {
686
+ return basename(value.trim());
687
+ }
688
+ }
689
+ // Local artifact paths (pylock `path`).
690
+ if (typeof fileEntry.path === "string" && fileEntry.path.trim()) {
691
+ const name = basename(fileEntry.path.trim());
692
+ if (name) {
693
+ return name;
694
+ }
695
+ }
696
+ // Remote artifact URLs (pdm `url`, uv/pylock `url`). Strip the query string
697
+ // and fragment by reading the pathname, and percent-decode the basename.
698
+ if (typeof fileEntry.url === "string" && fileEntry.url.trim()) {
699
+ const rawUrl = fileEntry.url.trim();
700
+ let name;
701
+ try {
702
+ name = basename(new URL(rawUrl).pathname);
703
+ } catch (_err) {
704
+ // Not an absolute URL - treat it as a path-like string.
705
+ name = basename(rawUrl);
706
+ }
707
+ if (name) {
708
+ try {
709
+ name = decodeURIComponent(name);
710
+ } catch (_err) {
711
+ // Ignore malformed URLs and fall through to undefined.
712
+ }
713
+ if (name) {
714
+ return name;
715
+ }
716
+ }
717
+ }
718
+ return undefined;
719
+ }
720
+
721
+ function collectPythonLockMetadataDistributionReferences(fileEntries) {
722
+ const distributionReferences = [];
723
+ for (const fileEntry of fileEntries || []) {
724
+ if (typeof fileEntry?.url !== "string" || !fileEntry.url.trim()) {
725
+ continue;
726
+ }
727
+ distributionReferences.push({
728
+ type: "distribution",
729
+ url: fileEntry.url.trim(),
730
+ comment: fileEntry.file,
731
+ });
732
+ }
733
+ return distributionReferences;
734
+ }
735
+
736
+ /**
737
+ * Method to parse python lock files such as poetry.lock, pdm.lock, uv.lock, and pylock.toml.
738
+ *
739
+ * @param {string} lockData Raw TOML text from poetry.lock, pdm.lock, uv.lock, or pylock.toml
740
+ * @param {string} lockFile Lock file name for evidence
741
+ * @param {string} pyProjectFile pyproject.toml file
742
+ */
743
+ export async function parsePyLockData(lockData, lockFile, pyProjectFile) {
744
+ let pkgList = [];
745
+ const rootList = [];
746
+ const dependenciesList = [];
747
+ const depsMap = {};
748
+ const existingPkgMap = {};
749
+ const pkgBomRefMap = {};
750
+ let directDepsKeys = {};
751
+ let groupDepsKeys = {};
752
+ let dependencySourceMap = {};
753
+ let parentComponent;
754
+ let workspacePaths;
755
+ let workspaceWarningShown = false;
756
+ let hasWorkspaces = false;
757
+ let pyLockProperties = [];
758
+ // Keep track of any workspace components to be added to the parent component
759
+ const workspaceComponentMap = {};
760
+ const workspaceDependencySourceMap = {};
761
+ const workspacePyProjMap = {};
762
+ const workspaceRefPyProjMap = {};
763
+ const pkgParentMap = {};
764
+ if (!lockData) {
765
+ return { pkgList, dependenciesList };
766
+ }
767
+ if (!pyProjectFile && lockFile) {
768
+ // See if there is a pyproject.toml in the same directory
769
+ pyProjectFile = join(dirname(lockFile), "pyproject.toml");
770
+ }
771
+ if (pyProjectFile && safeExistsSync(pyProjectFile)) {
772
+ if (DEBUG_MODE) {
773
+ console.log(
774
+ `Parsing ${pyProjectFile} for dependencies and groups information.`,
775
+ );
776
+ }
777
+ const pyProjMap = parsePyProjectTomlFile(pyProjectFile);
778
+ directDepsKeys = pyProjMap.directDepsKeys || {};
779
+ groupDepsKeys = pyProjMap.groupDepsKeys || {};
780
+ dependencySourceMap = pyProjMap.dependencySourceMap || {};
781
+ parentComponent = pyProjMap.parentComponent;
782
+ workspacePaths = pyProjMap.workspacePaths;
783
+ if (workspacePaths?.length) {
784
+ if (!hasWorkspaces) {
785
+ hasWorkspaces = true;
786
+ }
787
+ // Parent component is going to have children
788
+ parentComponent.components = [];
789
+ for (const awpath of workspacePaths) {
790
+ const wpyprojfiles = getAllFiles(dirname(lockFile), awpath);
791
+ if (!wpyprojfiles?.length) {
792
+ if (!workspaceWarningShown) {
793
+ console.log(
794
+ `Unable to collect pyproject.toml files for the workspace pattern ${awpath}. Ensure cdxgen is run from the root directory containing the application source code.`,
795
+ );
796
+ console.log(
797
+ "The dependency tree in the generated SBOM will be flattened and therefore incorrect.",
798
+ );
799
+ workspaceWarningShown = true;
800
+ }
801
+ continue;
802
+ }
803
+ for (const awpyproj of wpyprojfiles) {
804
+ if (DEBUG_MODE) {
805
+ console.log(
806
+ `Parsing workspace ${awpyproj} to improve the dependency tree.`,
807
+ );
808
+ }
809
+ // Nested workspace is not supported
810
+ const wcompMap = parsePyProjectTomlFile(awpyproj);
811
+ if (wcompMap?.parentComponent) {
812
+ wcompMap.parentComponent.properties =
813
+ wcompMap.parentComponent.properties || [];
814
+ wcompMap.parentComponent.properties.push({
815
+ name: "internal:is_workspace",
816
+ value: "true",
817
+ });
818
+ wcompMap.parentComponent.properties.push({
819
+ name: "internal:SrcFile",
820
+ value: awpyproj,
821
+ });
822
+ wcompMap.parentComponent.properties.push({
823
+ name: "internal:virtual_path",
824
+ value: relative(dirname(lockFile), dirname(awpyproj)),
825
+ });
826
+ workspaceComponentMap[wcompMap.parentComponent.name] =
827
+ wcompMap.parentComponent;
828
+ workspacePyProjMap[wcompMap.parentComponent.name] = awpyproj;
829
+ if (wcompMap.parentComponent["bom-ref"]) {
830
+ workspaceRefPyProjMap[wcompMap.parentComponent["bom-ref"]] =
831
+ awpyproj;
832
+ }
833
+ // uv.lock auto normalizes names containing underscores
834
+ if (wcompMap.parentComponent.name.includes("_")) {
835
+ workspaceComponentMap[
836
+ wcompMap.parentComponent.name.replaceAll("_", "-")
837
+ ] = wcompMap.parentComponent;
838
+ workspacePyProjMap[
839
+ wcompMap.parentComponent.name.replaceAll("_", "-")
840
+ ] = awpyproj;
841
+ }
842
+ }
843
+ const wparentComponentRef = wcompMap.parentComponent["bom-ref"];
844
+ if (wcompMap?.dependencySourceMap) {
845
+ Object.assign(
846
+ workspaceDependencySourceMap,
847
+ wcompMap.dependencySourceMap,
848
+ );
849
+ }
850
+ // Track the parents of workspace direct dependencies
851
+ if (wcompMap?.directDepsKeys) {
852
+ for (const wdd of Object.keys(wcompMap?.directDepsKeys)) {
853
+ if (!pkgParentMap[wdd]) {
854
+ pkgParentMap[wdd] = [];
855
+ }
856
+ pkgParentMap[wdd].push(wparentComponentRef);
857
+ }
858
+ }
859
+ }
860
+ }
861
+ }
862
+ }
863
+ let lockTomlObj;
864
+ try {
865
+ lockTomlObj = toml.parse(lockData);
866
+ } catch (err) {
867
+ if (lockFile) {
868
+ console.log(`Error while parsing the lock file ${lockFile}.`, err);
869
+ } else {
870
+ console.log("Error while parsing the lock data as toml", err);
871
+ }
872
+ }
873
+ // Check for workspaces
874
+ if (lockTomlObj?.manifest?.members) {
875
+ const workspaceMembers = lockTomlObj.manifest.members;
876
+ if (workspaceMembers && !hasWorkspaces) {
877
+ hasWorkspaces = true;
878
+ }
879
+ for (const amember of workspaceMembers) {
880
+ if (amember === parentComponent.name) {
881
+ continue;
882
+ }
883
+ if (workspaceComponentMap[amember]) {
884
+ parentComponent.components.push(workspaceComponentMap[amember]);
885
+ } else {
886
+ if (!workspaceWarningShown) {
887
+ console.log(
888
+ `Unable to identify the metadata for the workspace ${amember}. Check if the path specified in ${workspacePyProjMap[amember] || pyProjectFile} is valid.`,
889
+ );
890
+ }
891
+ }
892
+ }
893
+ }
894
+ const pyLockMode = isPyLockObject(lockTomlObj);
895
+ if (pyLockMode) {
896
+ pyLockProperties = collectPyLockTopLevelProperties(lockTomlObj);
897
+ if (parentComponent) {
898
+ parentComponent.properties = parentComponent.properties || [];
899
+ parentComponent.properties =
900
+ parentComponent.properties.concat(pyLockProperties);
901
+ }
902
+ }
903
+ const packageEntries = getPyLockPackages(lockTomlObj);
904
+ for (const apkg of packageEntries) {
905
+ // This avoids validation errors with uv.lock
906
+ if (parentComponent?.name && parentComponent.name === apkg.name) {
907
+ continue;
908
+ }
909
+ const pkg = {
910
+ name: apkg.name,
911
+ version: apkg.version,
912
+ description: apkg.description || "",
913
+ properties: [],
914
+ };
915
+ if (pyProjectFile || workspacePyProjMap[apkg.name]) {
916
+ pkg.properties.push({
917
+ name: "internal:SrcFile",
918
+ value: workspacePyProjMap[apkg.name] || pyProjectFile,
919
+ });
920
+ }
921
+ const manifestSource =
922
+ dependencySourceMap[normalizePythonDependencyKey(apkg.name)] ||
923
+ workspaceDependencySourceMap[normalizePythonDependencyKey(apkg.name)] ||
924
+ collectPythonManifestSource(apkg);
925
+ applyManifestSourceProperties(pkg, "cdx:pypi", manifestSource);
926
+ if (apkg.optional) {
927
+ pkg.scope = "optional";
928
+ }
929
+ // poetry/pdm/uv use "python-versions", while pylock (PEP 751) uses "requires-python".
930
+ // Prefer the existing lock-family field when both are present.
931
+ const requiresPython = apkg["python-versions"] || apkg["requires-python"];
932
+ if (requiresPython) {
933
+ pkg.properties.push({
934
+ name: "cdx:pypi:requiresPython",
935
+ value: requiresPython,
936
+ });
937
+ }
938
+ if (apkg.index && !isDefaultPypiRegistry(apkg.index)) {
939
+ pkg.properties.push({
940
+ name: "cdx:pypi:registry",
941
+ value: normalizePyLockRegistry(apkg.index),
942
+ });
943
+ }
944
+ if (apkg?.source) {
945
+ if (
946
+ apkg.source.registry &&
947
+ !apkg?.source?.registry?.startsWith("https://pypi.org/")
948
+ ) {
949
+ pkg.properties.push({
950
+ name: "cdx:pypi:registry",
951
+ value: normalizePyLockRegistry(apkg.source.registry),
952
+ });
953
+ }
954
+ if (apkg?.source?.virtual) {
955
+ pkg.properties.push({
956
+ name: "internal:virtual_path",
957
+ value: workspacePyProjMap[apkg.name] || apkg.source.virtual,
958
+ });
959
+ }
960
+ if (apkg?.source?.editable) {
961
+ pkg.properties.push({
962
+ name: "internal:virtual_path",
963
+ value: apkg.source.editable,
964
+ });
965
+ }
966
+ }
967
+ mergeExternalReferences(pkg, collectPythonLockDistributionReferences(apkg));
968
+ if (pyLockMode) {
969
+ pkg.properties = pkg.properties.concat(
970
+ collectPyLockPackageProperties(apkg),
971
+ );
972
+ }
973
+ // Is this component a module?
974
+ if (workspaceComponentMap[pkg.name]) {
975
+ pkg.properties.push({
976
+ name: "internal:is_workspace",
977
+ value: "true",
978
+ });
979
+ pkg.type = "application";
980
+ }
981
+ const purlString = build({
982
+ type: "pypi",
983
+ namespace: "" || null,
984
+ name: pkg.name,
985
+ version: pkg.version || null,
986
+ });
987
+ pkg.purl = purlString;
988
+ pkg["bom-ref"] = decodeURIComponent(purlString);
989
+ if (parentComponent && pkg["bom-ref"] === parentComponent["bom-ref"]) {
990
+ continue;
991
+ }
992
+ pkg.evidence = {
993
+ identity: {
994
+ field: "purl",
995
+ confidence: 1,
996
+ methods: [
997
+ {
998
+ technique: "manifest-analysis",
999
+ confidence: 1,
1000
+ value: lockFile,
1001
+ },
1002
+ ],
1003
+ },
1004
+ };
1005
+ if (groupDepsKeys?.[pkg.name]) {
1006
+ pkg.scope = "optional";
1007
+ pkg.properties = pkg.properties.concat(
1008
+ groupDepsKeys[pkg.name].map((g) => {
1009
+ return { name: "cdx:pyproject:group", value: g };
1010
+ }),
1011
+ );
1012
+ }
1013
+ // Track the workspace purls that had an explicit dependency on this package
1014
+ if (pkgParentMap[pkg.name]) {
1015
+ for (const workspaceRef of pkgParentMap[pkg.name]) {
1016
+ pkg.properties.push({
1017
+ name: "internal:workspaceRef",
1018
+ value: workspaceRef,
1019
+ });
1020
+ if (workspaceRefPyProjMap[workspaceRef]) {
1021
+ pkg.properties.push({
1022
+ name: "internal:workspaceSrcFile",
1023
+ value: workspaceRefPyProjMap[workspaceRef],
1024
+ });
1025
+ }
1026
+ }
1027
+ }
1028
+ const metadataFileEntries = collectPythonLockMetadataFileEntries(
1029
+ lockTomlObj,
1030
+ pkg,
1031
+ );
1032
+ mergeExternalReferences(
1033
+ pkg,
1034
+ collectPythonLockMetadataDistributionReferences(metadataFileEntries),
1035
+ );
1036
+ if (metadataFileEntries.length) {
1037
+ pkg.components = [];
1038
+ for (const afileObj of metadataFileEntries) {
1039
+ const fileName = derivePythonLockMetadataFileName(afileObj);
1040
+ // Skip entries we cannot name - nameless type:file components are
1041
+ // invalid per the CycloneDX schema and would fail validation.
1042
+ if (!fileName) {
1043
+ continue;
1044
+ }
1045
+ const hashParts = afileObj?.hash?.split(":");
1046
+ let hashes;
1047
+ if (hashParts?.length === 2) {
1048
+ const alg = hashParts[0].replace("sha", "SHA-");
1049
+ hashes = [{ alg, content: hashParts[1] }];
1050
+ }
1051
+ pkg.components.push({
1052
+ type: "file",
1053
+ name: fileName,
1054
+ hashes,
1055
+ evidence: {
1056
+ identity: {
1057
+ field: "name",
1058
+ confidence: 1,
1059
+ methods: [
1060
+ {
1061
+ technique: "manifest-analysis",
1062
+ confidence: 1,
1063
+ value: lockFile,
1064
+ },
1065
+ ],
1066
+ },
1067
+ },
1068
+ properties: [{ name: "internal:SrcFile", value: lockFile }],
1069
+ });
1070
+ }
1071
+ // All entries may have been skipped (e.g. none had a derivable name).
1072
+ if (!pkg.components.length) {
1073
+ delete pkg.components;
1074
+ }
1075
+ }
1076
+ if (pyLockMode) {
1077
+ const pylockFileComponents = collectPyLockFileComponents(apkg, lockFile);
1078
+ if (pylockFileComponents.length) {
1079
+ pkg.components = (pkg.components || []).concat(pylockFileComponents);
1080
+ }
1081
+ }
1082
+ const normalizedPkgName = normalizePythonDependencyKey(pkg.name);
1083
+ if (
1084
+ directDepsKeys[normalizedPkgName] ||
1085
+ (hasWorkspaces && !Object.keys(workspaceComponentMap).length)
1086
+ ) {
1087
+ rootList.push(pkg);
1088
+ }
1089
+ // This would help the lookup
1090
+ existingPkgMap[pkg.name.toLowerCase()] = pkg["bom-ref"];
1091
+ pkgBomRefMap[pkg["bom-ref"]] = pkg;
1092
+ // Do not repeat workspace components again under components
1093
+ // This will reduce false positives, when a downstream tool attempts to analyze all components
1094
+ if (pkg.type !== "application") {
1095
+ pkgList.push(pkg);
1096
+ }
1097
+ if (!depsMap[pkg["bom-ref"]]) {
1098
+ depsMap[pkg["bom-ref"]] = new Set();
1099
+ }
1100
+ // Track the workspace tree
1101
+ if (pkgParentMap[pkg.name]) {
1102
+ for (const pkgParentRef of pkgParentMap[pkg.name]) {
1103
+ if (!depsMap[pkgParentRef]) {
1104
+ depsMap[pkgParentRef] = new Set();
1105
+ }
1106
+ depsMap[pkgParentRef].add(pkg["bom-ref"]);
1107
+ }
1108
+ }
1109
+ let optionalDependencies = [];
1110
+ let devDependencies = [];
1111
+ const pylockRelationshipDeps = pyLockMode
1112
+ ? collectPyLockDependencyRelationships(apkg)
1113
+ : [];
1114
+ if (apkg["dev-dependencies"]) {
1115
+ for (const agroup of Object.keys(apkg["dev-dependencies"])) {
1116
+ devDependencies = devDependencies.concat(
1117
+ apkg["dev-dependencies"][agroup],
1118
+ );
1119
+ }
1120
+ }
1121
+ if (apkg["optional-dependencies"]) {
1122
+ for (const agroup of Object.keys(apkg["optional-dependencies"])) {
1123
+ optionalDependencies = optionalDependencies.concat(
1124
+ apkg["optional-dependencies"][agroup],
1125
+ );
1126
+ }
1127
+ }
1128
+ if (
1129
+ apkg.dependencies ||
1130
+ pylockRelationshipDeps.length ||
1131
+ devDependencies.length ||
1132
+ optionalDependencies.length
1133
+ ) {
1134
+ if (Array.isArray(apkg.dependencies)) {
1135
+ // pdm.lock files
1136
+ let allDeps = apkg.dependencies;
1137
+ allDeps = allDeps.concat(devDependencies);
1138
+ allDeps = allDeps.concat(optionalDependencies);
1139
+ for (const apkgDep of allDeps) {
1140
+ // Example: "msgpack>=0.5.2"
1141
+ const nameStr =
1142
+ apkgDep.name || apkgDep.split(/(==|<=|~=|>=)/)[0].split(" ")[0];
1143
+ // Python package names are normalized/case-insensitive; support both forms for lookup.
1144
+ const nameLower = nameStr.toLowerCase();
1145
+ const depPkgRef =
1146
+ existingPkgMap[nameLower] || existingPkgMap[nameStr];
1147
+ depsMap[pkg["bom-ref"]].add(depPkgRef || nameStr);
1148
+ // Propagate the workspace properties to the child components
1149
+ if (depPkgRef && pkgBomRefMap[depPkgRef]) {
1150
+ const dependentPkg = pkgBomRefMap[depPkgRef];
1151
+ dependentPkg.properties = dependentPkg.properties || [];
1152
+ const addedValue = {};
1153
+ // Is the parent a workspace
1154
+ if (workspaceComponentMap[pkg.name]) {
1155
+ dependentPkg.properties.push({
1156
+ name: "internal:workspaceRef",
1157
+ value: pkg["bom-ref"],
1158
+ });
1159
+ dependentPkg.properties.push({
1160
+ name: "internal:workspaceSrcFile",
1161
+ value: workspaceRefPyProjMap[pkg["bom-ref"]],
1162
+ });
1163
+ addedValue[pkg["bom-ref"]] = true;
1164
+ }
1165
+ for (const pprop of pkg.properties) {
1166
+ if (
1167
+ pprop.name.startsWith("internal:workspace") &&
1168
+ !addedValue[pprop.value]
1169
+ ) {
1170
+ dependentPkg.properties.push(pprop);
1171
+ addedValue[pprop.value] = true;
1172
+ }
1173
+ }
1174
+ }
1175
+ }
1176
+ for (const relationship of pylockRelationshipDeps) {
1177
+ const depPkgRef =
1178
+ existingPkgMap[relationship.name.toLowerCase()] ||
1179
+ existingPkgMap[relationship.name];
1180
+ if (depPkgRef) {
1181
+ depsMap[pkg["bom-ref"]].add(depPkgRef);
1182
+ }
1183
+ if (relationship.scope === "optional-extra") {
1184
+ pkg.scope = pkg.scope || "optional";
1185
+ pkg.properties.push({
1186
+ name: "cdx:pyproject:extra",
1187
+ value: relationship.name,
1188
+ });
1189
+ }
1190
+ if (relationship.scope === "dependency-group") {
1191
+ pkg.properties.push({
1192
+ name: "cdx:pyproject:dependencyGroupMember",
1193
+ value: relationship.name,
1194
+ });
1195
+ }
1196
+ }
1197
+ } else if (apkg.dependencies && Object.keys(apkg.dependencies).length) {
1198
+ for (const apkgDep of Object.keys(apkg.dependencies)) {
1199
+ depsMap[pkg["bom-ref"]].add(existingPkgMap[apkgDep] || apkgDep);
1200
+ }
1201
+ for (const relationship of pylockRelationshipDeps) {
1202
+ const depPkgRef =
1203
+ existingPkgMap[relationship.name.toLowerCase()] ||
1204
+ existingPkgMap[relationship.name];
1205
+ if (depPkgRef) {
1206
+ depsMap[pkg["bom-ref"]].add(depPkgRef);
1207
+ }
1208
+ }
1209
+ } else {
1210
+ for (const relationship of pylockRelationshipDeps) {
1211
+ const depPkgRef =
1212
+ existingPkgMap[relationship.name.toLowerCase()] ||
1213
+ existingPkgMap[relationship.name];
1214
+ if (depPkgRef) {
1215
+ depsMap[pkg["bom-ref"]].add(depPkgRef);
1216
+ }
1217
+ }
1218
+ }
1219
+ }
1220
+ }
1221
+ for (const key of Object.keys(depsMap)) {
1222
+ const dependsOnList = new Set();
1223
+ const parentPkg = pkgBomRefMap[key];
1224
+ for (const adep of Array.from(depsMap[key])) {
1225
+ let depRef;
1226
+ if (adep.startsWith("pkg:")) {
1227
+ depRef = adep;
1228
+ } else if (existingPkgMap[adep]) {
1229
+ depRef = existingPkgMap[adep];
1230
+ } else if (existingPkgMap[adep.toLowerCase()]) {
1231
+ depRef = existingPkgMap[adep.toLowerCase()];
1232
+ } else if (existingPkgMap[`py${adep}`]) {
1233
+ depRef = existingPkgMap[`py${adep}`];
1234
+ } else if (existingPkgMap[adep.replace(/-/g, "_")]) {
1235
+ depRef = existingPkgMap[adep.replace(/-/g, "_")];
1236
+ }
1237
+ if (depRef) {
1238
+ dependsOnList.add(depRef);
1239
+ // We need to propagate the workspace properties from the parent
1240
+ const dependentPkg = pkgBomRefMap[depRef];
1241
+ dependentPkg.properties = dependentPkg.properties || [];
1242
+ const addedValue = {};
1243
+ for (const p of dependentPkg.properties) {
1244
+ if (p.name.startsWith("internal:workspace")) {
1245
+ addedValue[p.value] = true;
1246
+ }
1247
+ }
1248
+ if (parentPkg?.properties?.length) {
1249
+ for (const pprop of parentPkg.properties) {
1250
+ if (
1251
+ pprop.name.startsWith("internal:workspace") &&
1252
+ !addedValue[pprop.value]
1253
+ ) {
1254
+ dependentPkg.properties.push(pprop);
1255
+ addedValue[pprop.value] = true;
1256
+ } else if (pprop.name === "internal:is_workspace") {
1257
+ dependentPkg.properties.push({
1258
+ name: "internal:workspaceRef",
1259
+ value: parentPkg["bom-ref"],
1260
+ });
1261
+ dependentPkg.properties.push({
1262
+ name: "internal:workspaceSrcFile",
1263
+ value: workspaceRefPyProjMap[parentPkg["bom-ref"]],
1264
+ });
1265
+ addedValue[parentPkg["bom-ref"]] = true;
1266
+ addedValue[workspaceRefPyProjMap[parentPkg["bom-ref"]]] = true;
1267
+ const childDeps = depsMap[dependentPkg["bom-ref"]];
1268
+ for (const childRef of childDeps) {
1269
+ if (!childRef.startsWith("pkg:")) {
1270
+ continue;
1271
+ }
1272
+ const childPkg = pkgBomRefMap[childRef];
1273
+ if (childPkg) {
1274
+ childPkg.properties = childPkg.properties || [];
1275
+ childPkg.properties.push({
1276
+ name: "internal:workspaceRef",
1277
+ value: parentPkg["bom-ref"],
1278
+ });
1279
+ childPkg.properties.push({
1280
+ name: "internal:workspaceSrcFile",
1281
+ value: workspaceRefPyProjMap[parentPkg["bom-ref"]],
1282
+ });
1283
+ }
1284
+ }
1285
+ }
1286
+ }
1287
+ }
1288
+ }
1289
+ }
1290
+ dependenciesList.push({
1291
+ ref: key,
1292
+ dependsOn: [...dependsOnList].sort(),
1293
+ });
1294
+ }
1295
+ pkgList = await getPyMetadata(pkgList, false);
1296
+ return {
1297
+ parentComponent,
1298
+ pkgList,
1299
+ rootList,
1300
+ dependenciesList,
1301
+ pyLockProperties,
1302
+ workspaceWarningShown,
1303
+ };
1304
+ }
1305
+
1306
+ /**
1307
+ * Method to parse requirements.txt file. This must be replaced with atom parsedeps.
1308
+ *
1309
+ * @param {String} reqFile Requirements.txt file
1310
+ * @param {Boolean} fetchDepsInfo Fetch dependencies info from pypi
1311
+ *
1312
+ * @returns {Promise[Array<Object>]} List of direct dependencies from the requirements file
1313
+ */
1314
+ export async function parseReqFile(reqFile, fetchDepsInfo = false) {
1315
+ return await parseReqData(reqFile, null, fetchDepsInfo);
1316
+ }
1317
+
1318
+ const LICENSE_ID_COMMENTS_PATTERN =
1319
+ /^(Apache-2\.0|MIT|ISC|GPL-|LGPL-|BSD-[23]-Clause)/i;
1320
+
1321
+ function parseLicenseComment(comment) {
1322
+ if (!comment) {
1323
+ return undefined;
1324
+ }
1325
+ const licenses = comment
1326
+ .split("/")
1327
+ .map((value) => {
1328
+ const licenseId = value.trim();
1329
+ if (!licenseId.match(LICENSE_ID_COMMENTS_PATTERN)) {
1330
+ return undefined;
1331
+ }
1332
+ return { license: { id: licenseId } };
1333
+ })
1334
+ .filter((value) => value !== undefined);
1335
+ return licenses.length ? licenses : undefined;
1336
+ }
1337
+
1338
+ /**
1339
+ * Method to parse requirements.txt file. Must only be used internally.
1340
+ *
1341
+ * @param {String} reqFile Requirements.txt file
1342
+ * @param {Object} reqData Requirements.txt data for internal invocations from setup.py file etc.
1343
+ * @param {Boolean} fetchDepsInfo Fetch dependencies info from pypi
1344
+ * @returns {Promise<Array<Object>>} List of direct dependencies from the requirements file
1345
+ */
1346
+ async function parseReqData(reqFile, reqData = null, fetchDepsInfo = false) {
1347
+ const pkgList = [];
1348
+ let compScope;
1349
+ if (!reqFile && !reqData) {
1350
+ console.warn(
1351
+ "Either the requirements file or the data needs to be provided for parsing.",
1352
+ );
1353
+ return pkgList;
1354
+ }
1355
+ reqData = reqData || readFileSync(reqFile, { encoding: "utf-8" });
1356
+ const evidence = reqFile
1357
+ ? {
1358
+ identity: {
1359
+ field: "purl",
1360
+ confidence: 0.5,
1361
+ methods: [
1362
+ {
1363
+ technique: "manifest-analysis",
1364
+ confidence: 0.5,
1365
+ value: reqFile,
1366
+ },
1367
+ ],
1368
+ },
1369
+ }
1370
+ : undefined;
1371
+ const normalizedData = reqData.replace(/\r/g, "").replace(/\\\n/g, " ");
1372
+ const lines = normalizedData.split("\n");
1373
+ for (const line of lines) {
1374
+ let l = line.trim();
1375
+ let editableRequirement = false;
1376
+ if (l.includes("# Basic requirements")) {
1377
+ compScope = "required";
1378
+ } else if (l.includes("added by pip freeze")) {
1379
+ compScope = undefined;
1380
+ }
1381
+ if (l.startsWith("-e ") || l.startsWith("--editable ")) {
1382
+ editableRequirement = true;
1383
+ l = l.replace(/^--editable\s+|^-e\s+/, "").trim();
1384
+ }
1385
+ if (l.startsWith("Skipping line") || l.startsWith("(add")) {
1386
+ continue;
1387
+ }
1388
+ if (!l || l.startsWith("#") || l.startsWith("-")) {
1389
+ continue;
1390
+ }
1391
+ let comment = null;
1392
+ const commentMatch = l.match(/\s+#(.*)$/);
1393
+ if (commentMatch) {
1394
+ comment = commentMatch[1].trim();
1395
+ l = l.substring(0, commentMatch.index).trim();
1396
+ }
1397
+ const properties = reqFile
1398
+ ? [
1399
+ {
1400
+ name: "internal:SrcFile",
1401
+ value: reqFile,
1402
+ },
1403
+ ]
1404
+ : [];
1405
+ const hashes = [];
1406
+ const hashRegex = /--hash=([a-zA-Z0-9\-]+):([a-fA-F0-9]+)/g;
1407
+ let hashMatch;
1408
+ while ((hashMatch = hashRegex.exec(l)) !== null) {
1409
+ let alg = hashMatch[1].toUpperCase();
1410
+ if (alg === "SHA256") alg = "SHA-256";
1411
+ else if (alg === "SHA384") alg = "SHA-384";
1412
+ else if (alg === "SHA512") alg = "SHA-512";
1413
+ else if (alg === "SHA1") alg = "SHA-1";
1414
+ hashes.push({
1415
+ alg: alg,
1416
+ content: hashMatch[2],
1417
+ });
1418
+ }
1419
+ // Strip the hash flags and any residual backslashes
1420
+ l = l
1421
+ .replace(/--hash=[a-zA-Z0-9\-]+:[a-fA-F0-9]+/g, "")
1422
+ .replace(/\\/g, "")
1423
+ .trim();
1424
+ // Handle markers
1425
+ let markers = null;
1426
+ let structuredMarkers = null;
1427
+ if (l.includes(";")) {
1428
+ const parts = l.split(";");
1429
+ l = parts[0].trim();
1430
+ markers = parts.slice(1).join(";").trim();
1431
+ structuredMarkers = parseReqEnvMarkers(markers);
1432
+ }
1433
+ const requirementManifestSource = parsePythonRequirementManifestSource(l);
1434
+ if (requirementManifestSource?.name) {
1435
+ const apkg = {
1436
+ name: requirementManifestSource.name,
1437
+ version: null,
1438
+ scope: compScope,
1439
+ evidence,
1440
+ };
1441
+ if (hashes.length > 0) {
1442
+ apkg.hashes = hashes;
1443
+ }
1444
+ const licenses = parseLicenseComment(comment);
1445
+ if (licenses) {
1446
+ apkg.licenses = licenses;
1447
+ }
1448
+ applyManifestSourceProperties(
1449
+ apkg,
1450
+ "cdx:pypi",
1451
+ requirementManifestSource,
1452
+ );
1453
+ if (editableRequirement) {
1454
+ addComponentProperty(apkg, "cdx:pypi:editable", "true");
1455
+ }
1456
+ if (markers) {
1457
+ addComponentProperty(apkg, "cdx:pip:markers", markers);
1458
+ if (structuredMarkers?.length > 0) {
1459
+ addComponentProperty(
1460
+ apkg,
1461
+ "cdx:pip:structuredMarkers",
1462
+ JSON.stringify(structuredMarkers),
1463
+ );
1464
+ }
1465
+ }
1466
+ if (reqFile) {
1467
+ addComponentProperty(apkg, "internal:SrcFile", reqFile);
1468
+ }
1469
+ pkgList.push(apkg);
1470
+ continue;
1471
+ }
1472
+
1473
+ // Handle extras (e.g., package[extra1,extra2])
1474
+ let extras = null;
1475
+ const extrasMatch = l.match(/^([a-zA-Z0-9_\-.]+)(\[([^\]]+)])?(.*)$/);
1476
+ if (extrasMatch) {
1477
+ const [, packageName, , extrasStr, versionSpecifiers] = extrasMatch;
1478
+ const name = packageName;
1479
+ if (extrasStr) {
1480
+ extras = extrasStr.split(",").map((e) => e.trim());
1481
+ l = `${name}${versionSpecifiers}`; // Reconstruct without extras for version parsing
1482
+ }
1483
+ if (PYTHON_STD_MODULES.includes(name)) {
1484
+ continue;
1485
+ }
1486
+ const versionMatch = versionSpecifiers.match(
1487
+ /(==|!=|<=|>=|<|>|~=)([0-9.a-zA-Z_*\-+]*)/,
1488
+ );
1489
+ let version = null;
1490
+ if (versionMatch) {
1491
+ version = versionMatch[2].replaceAll("*", "0") || null;
1492
+ if (version === "0") {
1493
+ version = null;
1494
+ }
1495
+ }
1496
+ const apkg = {
1497
+ name,
1498
+ version,
1499
+ scope: compScope,
1500
+ evidence,
1501
+ };
1502
+ if (hashes.length > 0) {
1503
+ apkg.hashes = hashes;
1504
+ }
1505
+ const licenses = parseLicenseComment(comment);
1506
+ if (licenses) {
1507
+ apkg.licenses = licenses;
1508
+ }
1509
+ if (extras && extras.length > 0) {
1510
+ properties.push({
1511
+ name: "cdx:pypi:extras",
1512
+ value: extras.join(","),
1513
+ });
1514
+ }
1515
+ if (versionSpecifiers && !versionSpecifiers.startsWith("==")) {
1516
+ properties.push({
1517
+ name: "cdx:pypi:versionSpecifiers",
1518
+ value: versionSpecifiers.trim(),
1519
+ });
1520
+ }
1521
+ if (markers) {
1522
+ properties.push({
1523
+ name: "cdx:pip:markers",
1524
+ value: markers,
1525
+ });
1526
+ if (structuredMarkers && structuredMarkers.length > 0) {
1527
+ properties.push({
1528
+ name: "cdx:pip:structuredMarkers",
1529
+ value: JSON.stringify(structuredMarkers),
1530
+ });
1531
+ }
1532
+ }
1533
+ if (editableRequirement) {
1534
+ properties.push({
1535
+ name: "cdx:pypi:editable",
1536
+ value: "true",
1537
+ });
1538
+ }
1539
+ if (properties.length) {
1540
+ apkg.properties = properties;
1541
+ }
1542
+ pkgList.push(apkg);
1543
+ } else {
1544
+ const match = l.match(/^([a-zA-Z0-9_\-.]+)(.*)$/);
1545
+ if (!match) {
1546
+ continue;
1547
+ }
1548
+ const [, name, versionSpecifiers] = match;
1549
+ if (PYTHON_STD_MODULES.includes(name)) {
1550
+ continue;
1551
+ }
1552
+ const versionMatch = versionSpecifiers.match(
1553
+ /(==|!=|<=|>=|<|>|~=)([0-9.a-zA-Z_*\-+]*)/,
1554
+ );
1555
+ let version = null;
1556
+ if (versionMatch) {
1557
+ version = versionMatch[2].replaceAll("*", "0") || null;
1558
+ if (version === "0") version = null;
1559
+ }
1560
+ const apkg = {
1561
+ name,
1562
+ version,
1563
+ scope: compScope,
1564
+ evidence,
1565
+ };
1566
+ const licenses = parseLicenseComment(comment);
1567
+ if (licenses) {
1568
+ apkg.licenses = licenses;
1569
+ }
1570
+ if (versionSpecifiers && !versionSpecifiers.startsWith("==")) {
1571
+ properties.push({
1572
+ name: "cdx:pypi:versionSpecifiers",
1573
+ value: versionSpecifiers.trim(),
1574
+ });
1575
+ }
1576
+ if (markers) {
1577
+ properties.push({
1578
+ name: "cdx:pip:markers",
1579
+ value: markers,
1580
+ });
1581
+ if (structuredMarkers && structuredMarkers.length > 0) {
1582
+ properties.push({
1583
+ name: "cdx:pip:structuredMarkers",
1584
+ value: JSON.stringify(structuredMarkers),
1585
+ });
1586
+ }
1587
+ }
1588
+ if (editableRequirement) {
1589
+ properties.push({
1590
+ name: "cdx:pypi:editable",
1591
+ value: "true",
1592
+ });
1593
+ }
1594
+ if (properties.length) {
1595
+ apkg.properties = properties;
1596
+ }
1597
+ pkgList.push(apkg);
1598
+ }
1599
+ }
1600
+ return await getPyMetadata(pkgList, fetchDepsInfo);
1601
+ }
1602
+
1603
+ /**
1604
+ * Parse environment markers into structured format
1605
+ *
1606
+ * @param {String} markersStr Raw markers string
1607
+ * @returns {Array<Object>} Structured markers array
1608
+ */
1609
+ export function parseReqEnvMarkers(markersStr) {
1610
+ if (!markersStr) return [];
1611
+
1612
+ const markers = [];
1613
+ const tokens = markersStr
1614
+ .replace(/\s+/g, " ")
1615
+ .trim()
1616
+ .split(/\s+(and|or)\s+/gi)
1617
+ .filter((token) => token.trim());
1618
+ for (const token of tokens) {
1619
+ if (token.toLowerCase() === "and" || token.toLowerCase() === "or") {
1620
+ markers.push({
1621
+ operator: token.toLowerCase(),
1622
+ });
1623
+ } else {
1624
+ const match = token.match(
1625
+ /([a-zA-Z_]+)\s*(==|!=|<=|>=|<|>)\s*["']?([^"']*)["']?/,
1626
+ );
1627
+ if (match) {
1628
+ markers.push({
1629
+ variable: match[1],
1630
+ operator: match[2],
1631
+ value: match[3],
1632
+ });
1633
+ } else {
1634
+ // Add as raw token if parsing fails
1635
+ markers.push({
1636
+ raw: token,
1637
+ });
1638
+ }
1639
+ }
1640
+ }
1641
+ return markers;
1642
+ }
1643
+
1644
+ /**
1645
+ * Method to parse setup.py data
1646
+ *
1647
+ * @param {Object} setupPyData Contents of setup.py
1648
+ */
1649
+ export async function parseSetupPyFile(setupPyData) {
1650
+ let lines = [];
1651
+ let requires_found = false;
1652
+ let should_break = false;
1653
+ setupPyData.split("\n").forEach((l) => {
1654
+ l = l.trim();
1655
+ if (l.includes("install_requires")) {
1656
+ l = l.replace("install_requires=[", "");
1657
+ requires_found = true;
1658
+ }
1659
+ if (l.length && requires_found && !should_break) {
1660
+ if (l.includes("]")) {
1661
+ should_break = true;
1662
+ l = l.replaceAll("],", "").replaceAll("]", "");
1663
+ }
1664
+ let tmpA = l.replace(/['"]/g, "").split(",");
1665
+ tmpA = tmpA.filter((v) => v.length);
1666
+ lines = lines.concat(tmpA);
1667
+ }
1668
+ });
1669
+ return await parseReqData(null, lines.join("\n"), false);
1670
+ }
1671
+
1672
+ /**
1673
+ * Method to create purl using information in pixi.lock file.
1674
+ * According to pixi lock file satisfiability (https://pixi.sh/latest/features/lockfile/#lockfile-satisfiability)
1675
+ *
1676
+ *
1677
+ *
1678
+ * @param {*} packageData
1679
+ * @returns
1680
+ */
1681
+ function createPurlTemplate(packageData) {
1682
+ // conda defines build/channel/subdir/type as its qualifiers, and the pixi
1683
+ // field is already called subdir, so it maps straight across. pixi records
1684
+ // the build separately while conda versions carry it as a `version-build`
1685
+ // suffix.
1686
+ const version = packageData["build"]
1687
+ ? `${packageData["version"]}-${packageData["build"]}`
1688
+ : packageData["version"];
1689
+ return tryBuildPurl({
1690
+ type: packageData["kind"],
1691
+ name: packageData["name"],
1692
+ version,
1693
+ qualifiers: packageData["subdir"]
1694
+ ? { subdir: packageData["subdir"] }
1695
+ : undefined,
1696
+ });
1697
+ }
1698
+
1699
+ /**
1700
+ * Identifier for a pixi package, used as its `bom-ref` and by every dependency
1701
+ * that references it. Derived from the purl so the graph and the components
1702
+ * agree, with a fallback for a package whose purl cannot be built.
1703
+ *
1704
+ * @param {object} packageData Package entry from a pixi.lock file
1705
+ * @returns {string} bom-ref
1706
+ */
1707
+ function createPixiBomRef(packageData) {
1708
+ const purl = createPurlTemplate(packageData);
1709
+ if (purl) {
1710
+ return decodeURIComponent(purl);
1711
+ }
1712
+ return `library:${packageData["name"]}:${packageData["version"] || ""}`;
1713
+ }
1714
+
1715
+ /**
1716
+ * Method to parse pixi.lock data
1717
+ *
1718
+ * @param {String} pixiLockFileName pixi.lock file name
1719
+ * @param {String} path File path
1720
+ */
1721
+ export function parsePixiLockFile(pixiLockFileName, path) {
1722
+ const pixiFileData = readFileSync(pixiLockFileName, { encoding: "utf-8" });
1723
+ const pixiLockData = _load(pixiFileData);
1724
+ const evidenceBasePath = path ?? dirname(pixiLockFileName);
1725
+
1726
+ // this function returns
1727
+ let pkgList;
1728
+ const formulationList = [];
1729
+ const rootList = [];
1730
+ let dependenciesList;
1731
+ // we do not set false because we have assumed that pixi lock is accurate
1732
+ const frozen = true;
1733
+
1734
+ /**
1735
+ * pixiMapper used with a map on pixi packages list.
1736
+ * the pixi list contains the following information e.g.
1737
+ * {kind: conda
1738
+ * name: alsa-lib
1739
+ * version: 1.2.11
1740
+ * build: h31becfc_1
1741
+ * build_number: 1
1742
+ * subdir: linux-aarch64
1743
+ * url: https://conda.anaconda.org/conda-forge/linux-aarch64/alsa-lib-1.2.11-h31becfc_1.conda
1744
+ * sha256: d062bc712dd307714dfdb0f7da095a510c138c5db76321494a516ac127f9e5cf
1745
+ * md5: 76bf292a85a0556cef4f500420cabe6c
1746
+ * depends:
1747
+ * - libgcc-ng >=12
1748
+ * license: LGPL-2.1-or-later
1749
+ * license_family: GPL
1750
+ * size: 584152
1751
+ * timestamp: 1709396718705
1752
+ * }
1753
+ * We create the purl using the following logic:
1754
+ * "purl": "pkg:{kind}/{name}@{version}-{build}?os={os}"
1755
+ * type would be "library" and evidence would be
1756
+ * {
1757
+ * "identity": {
1758
+ * "field": "purl",
1759
+ * "confidence": 1,
1760
+ * "methods": [
1761
+ * {
1762
+ * "technique": "instrumentation",
1763
+ * "confidence": 1,
1764
+ * "value": "pixi.lock"
1765
+ * }
1766
+ * ]
1767
+ * }
1768
+ * }
1769
+ *
1770
+ */
1771
+ function pixiMapper(packageData) {
1772
+ // return pkgList
1773
+ /** E.g. of what a pkgList element looks like
1774
+ * {
1775
+ * name: "conda-content-trust",
1776
+ * version: "latest",
1777
+ * purl: "pkg:pypi/conda-content-trust@latest",
1778
+ * type: "library",
1779
+ * "bom-ref": "pkg:pypi/conda-content-trust@latest",
1780
+ * scope: "excluded",
1781
+ * evidence: {
1782
+ * identity: {
1783
+ * field: "purl",
1784
+ * confidence: 1,
1785
+ * methods: [
1786
+ * {
1787
+ * technique: "instrumentation",
1788
+ * confidence: 1,
1789
+ * value: "/home/greatsage/miniconda3",
1790
+ * },
1791
+ * ],
1792
+ * },
1793
+ * },
1794
+ * properties: [
1795
+ * {
1796
+ * name: "internal:SrcFile",
1797
+ * value: "/home/greatsage/projects/supplyChain/trials/pythonprojs/fastapi/requirements.txt",
1798
+ * },
1799
+ * ],
1800
+ * }
1801
+ *
1802
+ */
1803
+ const purlTemplate = createPurlTemplate(packageData);
1804
+ return {
1805
+ name: packageData["name"],
1806
+ version: packageData["version"],
1807
+ ...(purlTemplate ? { purl: purlTemplate } : {}),
1808
+ type: "library",
1809
+ "bom-ref": createPixiBomRef(packageData),
1810
+ // "licenses": [
1811
+ // [{
1812
+ // "id": packageData["license"]
1813
+ // }]
1814
+ // ],
1815
+ supplier: {
1816
+ name: packageData["build"],
1817
+ url: packageData["url"],
1818
+ },
1819
+ // "hashes": [
1820
+ // {"md5": packageData["md5"]},
1821
+ // {"sha256": packageData["sha256"]}
1822
+ // ],
1823
+ evidence: {
1824
+ identity: {
1825
+ field: "purl",
1826
+ confidence: 1,
1827
+ methods: [
1828
+ {
1829
+ technique: "instrumentation",
1830
+ confidence: 1,
1831
+ // "value": `${path}/.pixi/envs/default`
1832
+ },
1833
+ ],
1834
+ },
1835
+ },
1836
+ properties: [
1837
+ { name: "cdx:pixi:operating_system", value: packageData["subdir"] },
1838
+ {
1839
+ name: "cdx:pixi:build_number",
1840
+ value: `${packageData["build_number"]}`,
1841
+ },
1842
+ { name: "cdx:pixi:build", value: `${packageData["build"]}` },
1843
+ ],
1844
+ };
1845
+ }
1846
+
1847
+ function mapAddEvidenceValue(p) {
1848
+ // TODO: get pixi environment variable (PR #1343)
1849
+ p.evidence.identity.methods[0].value = `${evidenceBasePath}/.pixi/envs/default`;
1850
+ return p;
1851
+ }
1852
+
1853
+ // create the pkgList
1854
+ pkgList = pixiLockData["packages"].map(pixiMapper);
1855
+ pkgList = pkgList.map(mapAddEvidenceValue);
1856
+
1857
+ // create dependencies
1858
+ const dictionary_packages = pixiLockData["packages"].reduce(
1859
+ (accumulator, currentObject) => {
1860
+ accumulator[currentObject["name"]] = currentObject;
1861
+ return accumulator;
1862
+ },
1863
+ {},
1864
+ );
1865
+
1866
+ dependenciesList = [];
1867
+ for (const package_iter of pixiLockData["packages"]) {
1868
+ const depends = package_iter["depends"];
1869
+ if (!depends) {
1870
+ continue;
1871
+ }
1872
+
1873
+ const purltemplate = createPixiBomRef(package_iter);
1874
+ const subdir = package_iter["subdir"];
1875
+ const dependsOn = new Set();
1876
+ for (const depends_package of depends) {
1877
+ const depends_package_name = depends_package.split(" ");
1878
+ const depends_package_information =
1879
+ dictionary_packages[depends_package_name[0] + subdir];
1880
+ if (!depends_package_information) {
1881
+ continue;
1882
+ }
1883
+ dependsOn.add(createPixiBomRef(depends_package_information));
1884
+ }
1885
+
1886
+ dependenciesList.push({
1887
+ ref: purltemplate,
1888
+ dependsOn: [...dependsOn].sort(),
1889
+ });
1890
+ }
1891
+
1892
+ return {
1893
+ pkgList,
1894
+ formulationList,
1895
+ rootList,
1896
+ dependenciesList,
1897
+ frozen,
1898
+ };
1899
+ }
1900
+
1901
+ /**
1902
+ * Method to parse pixi.toml file
1903
+ *
1904
+ * @param {String} pixiToml
1905
+ */
1906
+ export function parsePixiTomlFile(pixiToml) {
1907
+ const pixiTomlFile = readFileSync(pixiToml, { encoding: "utf-8" });
1908
+ let tomlData;
1909
+ try {
1910
+ tomlData = toml.parse(pixiTomlFile);
1911
+ } catch (err) {
1912
+ console.log(`Error while parsing the pixi file ${pixiToml}.`, err);
1913
+ return {};
1914
+ }
1915
+ const pkg = {};
1916
+ if (!tomlData) {
1917
+ return pkg;
1918
+ }
1919
+ const projectData = tomlData.workspace || tomlData.project || {};
1920
+ pkg.description = projectData.description;
1921
+ pkg.name = projectData.name;
1922
+ pkg.version = projectData.version;
1923
+ // pkg.authors = tomlData['project']['authors'];
1924
+ pkg.homepage = projectData.homepage;
1925
+ pkg.repository = projectData.repository;
1926
+ return pkg;
1927
+ }
1928
+
1929
+ /**
1930
+ * Method to run cli command `pixi install`
1931
+ *
1932
+ *
1933
+ */
1934
+ export function generatePixiLockFile(_path) {
1935
+ const result = safeSpawnSync("pixi", ["install"]);
1936
+
1937
+ if (result.status !== 0) {
1938
+ // Handle errors
1939
+ if (result.error && result.error.code === "ENOENT") {
1940
+ console.error(
1941
+ "Error: pixi command not found. Make sure pixi.js is installed globally.",
1942
+ );
1943
+ } else {
1944
+ console.error(
1945
+ `Error executing pixi install: ${result.error || result.stderr.toString()}`,
1946
+ );
1947
+ }
1948
+ process.exit(1);
1949
+ } else {
1950
+ console.log("Dependencies installed successfully.");
1951
+ }
1952
+ }
1953
+
1954
+ /**
1955
+ * Parse a Mojo `mojoproject.toml` manifest.
1956
+ *
1957
+ * Mojo projects are pixi-managed, so conda and PyPI dependencies pulled through
1958
+ * pixi.lock already keep their correct registered types via the pixi path.
1959
+ * Only Mojo's *own* packages — declared in `mojoproject.toml` — need special
1960
+ * handling: `mojo` is not a registered purl type, so each is emitted as
1961
+ * `pkg:generic/...` with a `cdx:purl:proposedType=mojo` property.
1962
+ *
1963
+ * The manifest is TOML. The `[project]` table carries the project's name and
1964
+ * version; `[dependencies]` maps dependency names to version specifiers. A
1965
+ * declared version range (e.g. `==0.1.0`, `>=0.2`) is normalised to its
1966
+ * concrete version when one is present, otherwise the version is omitted.
1967
+ *
1968
+ * @param {string} mojoProjectFile Path to `mojoproject.toml`
1969
+ * @returns {{ pkgList: object[], parentComponent: object }}
1970
+ */
1971
+ export function parseMojoProject(mojoProjectFile) {
1972
+ let manifest;
1973
+ try {
1974
+ manifest = toml.parse(readFileSync(mojoProjectFile, "utf-8"));
1975
+ } catch (error) {
1976
+ console.warn(`Failed to parse ${mojoProjectFile}: ${error.message}`);
1977
+ return { pkgList: [], parentComponent: {} };
1978
+ }
1979
+
1980
+ const parentComponent = {};
1981
+ const project = manifest.project;
1982
+ if (project && typeof project === "object") {
1983
+ if (project.name) {
1984
+ parentComponent.name = `${project.name}`;
1985
+ parentComponent.type = "application";
1986
+ if (project.version) {
1987
+ parentComponent.version = `${project.version}`;
1988
+ }
1989
+ parentComponent.description =
1990
+ typeof project.description === "string"
1991
+ ? project.description
1992
+ : `Mojo project: ${project.name}`;
1993
+ parentComponent.properties = [
1994
+ { name: "internal:SrcFile", value: mojoProjectFile },
1995
+ ];
1996
+ }
1997
+ }
1998
+
1999
+ const pkgList = [];
2000
+ const deps = manifest.dependencies;
2001
+ if (deps && typeof deps === "object") {
2002
+ for (const [name, specRaw] of Object.entries(deps)) {
2003
+ const spec =
2004
+ typeof specRaw === "string"
2005
+ ? specRaw
2006
+ : specRaw && typeof specRaw === "object"
2007
+ ? `${specRaw.version || ""}`
2008
+ : "";
2009
+ const version = normaliseMojoVersion(spec);
2010
+ pkgList.push(mojoPackage(name, version, mojoProjectFile));
2011
+ }
2012
+ }
2013
+
2014
+ return { pkgList, parentComponent };
2015
+ }
2016
+
2017
+ /**
2018
+ * Build a component record for a Mojo dependency. Mojo has no registered purl
2019
+ * type, so the package is identified as generic with a proposedType marker.
2020
+ *
2021
+ * @param {string} name Dependency name
2022
+ * @param {string|undefined} version Concrete version, if one was declared
2023
+ * @param {string} srcFile Source manifest path for evidence
2024
+ * @returns {object} Package record
2025
+ */
2026
+ function mojoPackage(name, version, srcFile) {
2027
+ const purl = tryBuildPurl({
2028
+ type: "generic",
2029
+ name,
2030
+ version: version || undefined,
2031
+ });
2032
+ const pkg = {
2033
+ name,
2034
+ ...(version ? { version } : {}),
2035
+ type: "library",
2036
+ scope: "required",
2037
+ properties: [
2038
+ { name: "internal:SrcFile", value: srcFile },
2039
+ { name: "cdx:purl:proposedType", value: "mojo" },
2040
+ { name: "cdx:mojo:dependency", value: "direct" },
2041
+ ],
2042
+ };
2043
+ if (purl) {
2044
+ pkg.purl = purl;
2045
+ pkg["bom-ref"] = decodeURIComponent(purl);
2046
+ } else {
2047
+ pkg["bom-ref"] = `library:${name}:${version || ""}`;
2048
+ }
2049
+ return pkg;
2050
+ }
2051
+
2052
+ /**
2053
+ * Normalise a Mojo/Python-style version specifier to a concrete version.
2054
+ *
2055
+ * Specifiers like `==0.1.0`, `>=0.2,<1`, or `~=1.2` are reduced to the first
2056
+ * concrete version token; bare version strings pass through. An unresolvable
2057
+ * range yields undefined so the purl omits the version rather than encoding a
2058
+ * meaningless operator.
2059
+ *
2060
+ * @param {string} spec Version specifier
2061
+ * @returns {string|undefined}
2062
+ */
2063
+ function normaliseMojoVersion(spec) {
2064
+ if (!spec || typeof spec !== "string") return undefined;
2065
+ const trimmed = spec.trim();
2066
+ if (!trimmed) return undefined;
2067
+ // Strip common comparison operators and take the first concrete version.
2068
+ const match = trimmed.match(/(\d+(?:\.\d+)*(?:[+-][A-Za-z0-9.]+)?)/);
2069
+ return match ? match[1] : undefined;
2070
+ }