@cdxgen/cdxgen 13.5.0 → 13.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/README.md +17 -10
  2. package/bin/audit.js +7 -4
  3. package/bin/cdxgen.js +260 -37
  4. package/bin/convert.js +146 -22
  5. package/bin/evinse.js +28 -3
  6. package/bin/repl.js +47 -3
  7. package/bin/sign.js +211 -34
  8. package/bin/tracebom.js +18 -6
  9. package/bin/validate.js +24 -3
  10. package/bin/verify.js +113 -5
  11. package/data/behavior-taxonomy.schema.json +1491 -0
  12. package/data/cyclonedx-2.0-bundled.schema.json +18606 -5528
  13. package/data/cyclonedx-2.0-cryptography-defs.schema.json +857 -0
  14. package/data/license-aliases.json +24 -2
  15. package/data/pqc-migration.json +239 -0
  16. package/data/remediations.json +176 -0
  17. package/data/rules/ai-bom.yaml +1 -1
  18. package/data/rules/brotli-decoder.yaml +107 -0
  19. package/data/rules/cbom-security.yaml +4 -3
  20. package/data/rules/package-integrity.yaml +28 -0
  21. package/data/rules/vscode-extensions.yaml +75 -0
  22. package/data/spdx-license-list.json +121 -7
  23. package/data/spdx-licenses.json +69 -0
  24. package/data/spdx.schema.json +845 -2
  25. package/lib/audit/index.js +25 -3
  26. package/lib/cli/bomAssembly.js +172 -4
  27. package/lib/cli/cliOptions.js +121 -17
  28. package/lib/cli/index.js +720 -902
  29. package/lib/cli/jsBom.js +156 -64
  30. package/lib/cli/jvmBom.js +602 -86
  31. package/lib/cli/managedBom.js +161 -19
  32. package/lib/cli/nativeBom.js +52 -5
  33. package/lib/core/boundedFile.js +344 -0
  34. package/lib/core/brotliProbe.js +182 -0
  35. package/lib/core/env.js +34 -0
  36. package/lib/core/fs.js +138 -3
  37. package/lib/core/globPatterns.js +218 -0
  38. package/lib/core/httpClient.js +98 -1
  39. package/lib/core/lockPaths.js +38 -0
  40. package/lib/core/paths.js +24 -1
  41. package/lib/core/processTree.js +100 -8
  42. package/lib/core/projectConfig.js +332 -25
  43. package/lib/core/toolRegistry.js +184 -0
  44. package/lib/ecosystems/cppEvidence.js +263 -106
  45. package/lib/ecosystems/cppIncludeResolver.js +16 -5
  46. package/lib/ecosystems/denoutils.js +2 -2
  47. package/lib/ecosystems/ecosystems.js +25 -10
  48. package/lib/ecosystems/gemHostProbe.js +301 -0
  49. package/lib/ecosystems/golem.js +3 -8
  50. package/lib/ecosystems/gradleutils.js +1909 -229
  51. package/lib/ecosystems/jsEvidence.js +90 -38
  52. package/lib/ecosystems/kosi.js +3 -5
  53. package/lib/ecosystems/npmVersionResolution.js +376 -0
  54. package/lib/ecosystems/parsers-bazel.js +107 -6
  55. package/lib/ecosystems/parsers-js.js +505 -22
  56. package/lib/ecosystems/parsers-misc.js +209 -20
  57. package/lib/ecosystems/parsers-python.js +178 -30
  58. package/lib/ecosystems/parsers-rust.js +117 -15
  59. package/lib/ecosystems/pythonutils.js +128 -2
  60. package/lib/ecosystems/remote/huggingface.js +22 -0
  61. package/lib/ecosystems/rubyutils.js +538 -31
  62. package/lib/ecosystems/rusi.js +2 -4
  63. package/lib/ecosystems/scalacliutils.js +2 -0
  64. package/lib/ecosystems/scalasem.js +798 -152
  65. package/lib/ecosystems/vendoredCode.js +237 -3
  66. package/lib/ecosystems/venvProbe.js +360 -0
  67. package/lib/evinser/evinser.js +536 -71
  68. package/lib/evinser/scalasem.js +5 -1
  69. package/lib/helpers/agenticToolutils.js +525 -94
  70. package/lib/helpers/bomSigner.js +43 -9
  71. package/lib/helpers/jssSigner.js +1276 -0
  72. package/lib/helpers/vsixutils.js +1574 -315
  73. package/lib/inventory/agentBlueprint.js +193 -0
  74. package/lib/inventory/agentToolNames.js +145 -0
  75. package/lib/inventory/aiCollector.js +153 -7
  76. package/lib/inventory/aiInventory.js +44 -8
  77. package/lib/inventory/aiProviders.js +324 -0
  78. package/lib/inventory/atomUtils.js +77 -0
  79. package/lib/inventory/bomUtils.js +8 -1
  80. package/lib/inventory/brotliDecoder.js +142 -0
  81. package/lib/inventory/buildToolRateLimit.js +1 -1
  82. package/lib/inventory/cbomutils.js +56 -7
  83. package/lib/inventory/ciParsers/githubActionsLock.js +821 -0
  84. package/lib/inventory/citations.js +31 -2
  85. package/lib/inventory/communityAiConfigParser.js +978 -80
  86. package/lib/inventory/cyclonedx20.js +152 -0
  87. package/lib/inventory/cyclonedx20Common.js +286 -0
  88. package/lib/inventory/cyclonedx20Derived.js +159 -0
  89. package/lib/inventory/cyclonedx20Parties.js +552 -0
  90. package/lib/inventory/cyclonedx20Read.js +768 -0
  91. package/lib/inventory/cyclonedx20ReadCommon.js +374 -0
  92. package/lib/inventory/cyclonedx20ReadComponents.js +692 -0
  93. package/lib/inventory/cyclonedx20ReadContext.js +380 -0
  94. package/lib/inventory/cyclonedx20ReadEvidence.js +466 -0
  95. package/lib/inventory/cyclonedx20ReadSections.js +599 -0
  96. package/lib/inventory/cyclonedx20Render.js +766 -0
  97. package/lib/inventory/cyclonedx20RenderComponents.js +716 -0
  98. package/lib/inventory/cyclonedx20RenderDefinitions.js +405 -0
  99. package/lib/inventory/cyclonedx20RenderEvidence.js +726 -0
  100. package/lib/inventory/cyclonedx20RenderHardware.js +203 -0
  101. package/lib/inventory/cyclonedx20RenderPatents.js +174 -0
  102. package/lib/inventory/cyclonedx20RenderRefIds.js +314 -0
  103. package/lib/inventory/cyclonedx20RenderSections.js +499 -0
  104. package/lib/inventory/cyclonedx20Tables.js +594 -0
  105. package/lib/inventory/deps.js +141 -13
  106. package/lib/inventory/dosai.js +375 -6
  107. package/lib/inventory/dosaiParsers.js +3 -6
  108. package/lib/inventory/dotnetRuntime.js +367 -0
  109. package/lib/inventory/ecosystemFormulationParsers.js +979 -0
  110. package/lib/inventory/envcontext.js +436 -48
  111. package/lib/inventory/evidenceUtils.js +13 -1
  112. package/lib/inventory/fetchBatch.js +1 -1
  113. package/lib/inventory/formulationParsers.js +124 -14
  114. package/lib/inventory/gtfobins.js +13 -0
  115. package/lib/inventory/hbom.js +45 -6
  116. package/lib/inventory/hbomLoader.js +166 -0
  117. package/lib/inventory/hostRuntimeProbe.js +686 -0
  118. package/lib/inventory/jvmLocalRepos.js +9 -2
  119. package/lib/inventory/jvmToolEnv.js +29 -0
  120. package/lib/inventory/licenseEnhancer.js +12 -0
  121. package/lib/inventory/mavenCentralMirror.js +534 -0
  122. package/lib/inventory/mcpConfigParser.js +5 -0
  123. package/lib/inventory/nodeBuildInfo.js +218 -0
  124. package/lib/inventory/nodeHostProbe.js +202 -0
  125. package/lib/inventory/occurrenceKey.js +90 -0
  126. package/lib/inventory/osPackageResolver.js +182 -0
  127. package/lib/inventory/phpBuildInfo.js +10 -59
  128. package/lib/inventory/phpHostProbe.js +32 -488
  129. package/lib/inventory/pqcMigration.js +426 -0
  130. package/lib/inventory/rubyBuildInfo.js +972 -0
  131. package/lib/inventory/rubyHostProbe.js +218 -0
  132. package/lib/inventory/rustFormulationParser.js +21 -10
  133. package/lib/inventory/scalaCoords.js +4 -3
  134. package/lib/inventory/scalaDedupe.js +440 -0
  135. package/lib/inventory/source.js +114 -8
  136. package/lib/managers/binary.js +337 -3
  137. package/lib/managers/docker.js +79 -0
  138. package/lib/parsers/huggingfaceManifest.js +9 -1
  139. package/lib/parsers/huggingfaceUtils.js +18 -0
  140. package/lib/parsers/kiroPermissions.js +166 -0
  141. package/lib/parsers/largeJson.js +28 -11
  142. package/lib/parsers/vscodeExtensionId.js +183 -0
  143. package/lib/server/server.js +48 -35
  144. package/lib/stages/postgen/postgen.js +41 -1
  145. package/lib/stages/postgen/ruleEngine.js +13 -5
  146. package/lib/stages/postgen/specVersionCompat.js +76 -0
  147. package/lib/stages/pregen/envAudit.js +1 -0
  148. package/lib/stages/pregen/pregen.js +114 -57
  149. package/lib/validator/bomValidator.js +14 -2
  150. package/lib/validator/complianceEngine.js +30 -3
  151. package/lib/validator/complianceRules.js +1416 -4
  152. package/lib/validator/generated/validate-1.6.mjs +1 -1
  153. package/lib/validator/generated/validate-1.7.mjs +1 -1
  154. package/lib/validator/generated/validate-2.0.mjs +57554 -13851
  155. package/lib/validator/index.js +49 -8
  156. package/lib/validator/reporters/json.js +6 -0
  157. package/package.json +11 -10
  158. package/types/bin/repl.d.ts.map +1 -1
  159. package/types/lib/audit/index.d.ts +6 -2
  160. package/types/lib/audit/index.d.ts.map +1 -1
  161. package/types/lib/cli/bomAssembly.d.ts +29 -1
  162. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  163. package/types/lib/cli/cliOptions.d.ts +6 -0
  164. package/types/lib/cli/cliOptions.d.ts.map +1 -1
  165. package/types/lib/cli/index.d.ts.map +1 -1
  166. package/types/lib/cli/jsBom.d.ts +3 -18
  167. package/types/lib/cli/jsBom.d.ts.map +1 -1
  168. package/types/lib/cli/jvmBom.d.ts +15 -0
  169. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  170. package/types/lib/cli/managedBom.d.ts.map +1 -1
  171. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  172. package/types/lib/core/boundedFile.d.ts +100 -0
  173. package/types/lib/core/boundedFile.d.ts.map +1 -0
  174. package/types/lib/core/brotliProbe.d.ts +37 -0
  175. package/types/lib/core/brotliProbe.d.ts.map +1 -0
  176. package/types/lib/core/env.d.ts +14 -0
  177. package/types/lib/core/env.d.ts.map +1 -1
  178. package/types/lib/core/fs.d.ts +4 -0
  179. package/types/lib/core/fs.d.ts.map +1 -1
  180. package/types/lib/core/globPatterns.d.ts +70 -0
  181. package/types/lib/core/globPatterns.d.ts.map +1 -0
  182. package/types/lib/core/httpClient.d.ts +24 -0
  183. package/types/lib/core/httpClient.d.ts.map +1 -1
  184. package/types/lib/core/lockPaths.d.ts +19 -0
  185. package/types/lib/core/lockPaths.d.ts.map +1 -0
  186. package/types/lib/core/paths.d.ts +9 -0
  187. package/types/lib/core/paths.d.ts.map +1 -1
  188. package/types/lib/core/processTree.d.ts +17 -4
  189. package/types/lib/core/processTree.d.ts.map +1 -1
  190. package/types/lib/core/projectConfig.d.ts +47 -8
  191. package/types/lib/core/projectConfig.d.ts.map +1 -1
  192. package/types/lib/core/toolRegistry.d.ts +36 -0
  193. package/types/lib/core/toolRegistry.d.ts.map +1 -0
  194. package/types/lib/ecosystems/cppEvidence.d.ts +40 -13
  195. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  196. package/types/lib/ecosystems/cppIncludeResolver.d.ts +2 -1
  197. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -1
  198. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  199. package/types/lib/ecosystems/gemHostProbe.d.ts +28 -0
  200. package/types/lib/ecosystems/gemHostProbe.d.ts.map +1 -0
  201. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  202. package/types/lib/ecosystems/gradleutils.d.ts +294 -20
  203. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  204. package/types/lib/ecosystems/jsEvidence.d.ts +14 -1
  205. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  206. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  207. package/types/lib/ecosystems/npmVersionResolution.d.ts +119 -0
  208. package/types/lib/ecosystems/npmVersionResolution.d.ts.map +1 -0
  209. package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -1
  210. package/types/lib/ecosystems/parsers-js.d.ts +17 -20
  211. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  212. package/types/lib/ecosystems/parsers-misc.d.ts +19 -0
  213. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  214. package/types/lib/ecosystems/parsers-python.d.ts +10 -0
  215. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  216. package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
  217. package/types/lib/ecosystems/pythonutils.d.ts +19 -1
  218. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  219. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  220. package/types/lib/ecosystems/rubyutils.d.ts +144 -12
  221. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  222. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  223. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -1
  224. package/types/lib/ecosystems/scalasem.d.ts +58 -16
  225. package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
  226. package/types/lib/ecosystems/vendoredCode.d.ts +26 -0
  227. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -1
  228. package/types/lib/ecosystems/venvProbe.d.ts +40 -0
  229. package/types/lib/ecosystems/venvProbe.d.ts.map +1 -0
  230. package/types/lib/evinser/evinser.d.ts +120 -13
  231. package/types/lib/evinser/evinser.d.ts.map +1 -1
  232. package/types/lib/evinser/scalasem.d.ts.map +1 -1
  233. package/types/lib/helpers/agenticToolutils.d.ts +53 -19
  234. package/types/lib/helpers/agenticToolutils.d.ts.map +1 -1
  235. package/types/lib/helpers/bomSigner.d.ts +20 -3
  236. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  237. package/types/lib/helpers/jssSigner.d.ts +288 -0
  238. package/types/lib/helpers/jssSigner.d.ts.map +1 -0
  239. package/types/lib/helpers/vsixutils.d.ts +303 -19
  240. package/types/lib/helpers/vsixutils.d.ts.map +1 -1
  241. package/types/lib/inventory/agentBlueprint.d.ts +70 -0
  242. package/types/lib/inventory/agentBlueprint.d.ts.map +1 -0
  243. package/types/lib/inventory/agentToolNames.d.ts +51 -0
  244. package/types/lib/inventory/agentToolNames.d.ts.map +1 -0
  245. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  246. package/types/lib/inventory/aiInventory.d.ts.map +1 -1
  247. package/types/lib/inventory/aiProviders.d.ts +85 -0
  248. package/types/lib/inventory/aiProviders.d.ts.map +1 -0
  249. package/types/lib/inventory/atomUtils.d.ts +19 -0
  250. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  251. package/types/lib/inventory/bomUtils.d.ts.map +1 -1
  252. package/types/lib/inventory/brotliDecoder.d.ts +58 -0
  253. package/types/lib/inventory/brotliDecoder.d.ts.map +1 -0
  254. package/types/lib/inventory/cbomutils.d.ts +17 -0
  255. package/types/lib/inventory/cbomutils.d.ts.map +1 -1
  256. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts +101 -0
  257. package/types/lib/inventory/ciParsers/githubActionsLock.d.ts.map +1 -0
  258. package/types/lib/inventory/citations.d.ts +5 -0
  259. package/types/lib/inventory/citations.d.ts.map +1 -1
  260. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  261. package/types/lib/inventory/cyclonedx20.d.ts +99 -0
  262. package/types/lib/inventory/cyclonedx20.d.ts.map +1 -0
  263. package/types/lib/inventory/cyclonedx20Common.d.ts +102 -0
  264. package/types/lib/inventory/cyclonedx20Common.d.ts.map +1 -0
  265. package/types/lib/inventory/cyclonedx20Derived.d.ts +74 -0
  266. package/types/lib/inventory/cyclonedx20Derived.d.ts.map +1 -0
  267. package/types/lib/inventory/cyclonedx20Parties.d.ts +91 -0
  268. package/types/lib/inventory/cyclonedx20Parties.d.ts.map +1 -0
  269. package/types/lib/inventory/cyclonedx20Read.d.ts +51 -0
  270. package/types/lib/inventory/cyclonedx20Read.d.ts.map +1 -0
  271. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts +69 -0
  272. package/types/lib/inventory/cyclonedx20ReadCommon.d.ts.map +1 -0
  273. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts +77 -0
  274. package/types/lib/inventory/cyclonedx20ReadComponents.d.ts.map +1 -0
  275. package/types/lib/inventory/cyclonedx20ReadContext.d.ts +118 -0
  276. package/types/lib/inventory/cyclonedx20ReadContext.d.ts.map +1 -0
  277. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts +40 -0
  278. package/types/lib/inventory/cyclonedx20ReadEvidence.d.ts.map +1 -0
  279. package/types/lib/inventory/cyclonedx20ReadSections.d.ts +45 -0
  280. package/types/lib/inventory/cyclonedx20ReadSections.d.ts.map +1 -0
  281. package/types/lib/inventory/cyclonedx20Render.d.ts +53 -0
  282. package/types/lib/inventory/cyclonedx20Render.d.ts.map +1 -0
  283. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts +73 -0
  284. package/types/lib/inventory/cyclonedx20RenderComponents.d.ts.map +1 -0
  285. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts +29 -0
  286. package/types/lib/inventory/cyclonedx20RenderDefinitions.d.ts.map +1 -0
  287. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts +110 -0
  288. package/types/lib/inventory/cyclonedx20RenderEvidence.d.ts.map +1 -0
  289. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts +42 -0
  290. package/types/lib/inventory/cyclonedx20RenderHardware.d.ts.map +1 -0
  291. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts +26 -0
  292. package/types/lib/inventory/cyclonedx20RenderPatents.d.ts.map +1 -0
  293. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts +55 -0
  294. package/types/lib/inventory/cyclonedx20RenderRefIds.d.ts.map +1 -0
  295. package/types/lib/inventory/cyclonedx20RenderSections.d.ts +45 -0
  296. package/types/lib/inventory/cyclonedx20RenderSections.d.ts.map +1 -0
  297. package/types/lib/inventory/cyclonedx20Tables.d.ts +134 -0
  298. package/types/lib/inventory/cyclonedx20Tables.d.ts.map +1 -0
  299. package/types/lib/inventory/deps.d.ts +35 -2
  300. package/types/lib/inventory/deps.d.ts.map +1 -1
  301. package/types/lib/inventory/dosai.d.ts +36 -1
  302. package/types/lib/inventory/dosai.d.ts.map +1 -1
  303. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  304. package/types/lib/inventory/dotnetRuntime.d.ts +91 -0
  305. package/types/lib/inventory/dotnetRuntime.d.ts.map +1 -0
  306. package/types/lib/inventory/ecosystemFormulationParsers.d.ts +73 -0
  307. package/types/lib/inventory/ecosystemFormulationParsers.d.ts.map +1 -0
  308. package/types/lib/inventory/envcontext.d.ts +74 -12
  309. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  310. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  311. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  312. package/types/lib/inventory/gtfobins.d.ts.map +1 -1
  313. package/types/lib/inventory/hbom.d.ts +11 -0
  314. package/types/lib/inventory/hbom.d.ts.map +1 -1
  315. package/types/lib/inventory/hbomLoader.d.ts +54 -0
  316. package/types/lib/inventory/hbomLoader.d.ts.map +1 -1
  317. package/types/lib/inventory/hostRuntimeProbe.d.ts +44 -0
  318. package/types/lib/inventory/hostRuntimeProbe.d.ts.map +1 -0
  319. package/types/lib/inventory/jvmLocalRepos.d.ts +5 -1
  320. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -1
  321. package/types/lib/inventory/jvmToolEnv.d.ts +12 -0
  322. package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
  323. package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -1
  324. package/types/lib/inventory/mavenCentralMirror.d.ts +170 -0
  325. package/types/lib/inventory/mavenCentralMirror.d.ts.map +1 -0
  326. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  327. package/types/lib/inventory/nodeBuildInfo.d.ts +95 -0
  328. package/types/lib/inventory/nodeBuildInfo.d.ts.map +1 -0
  329. package/types/lib/inventory/nodeHostProbe.d.ts +15 -0
  330. package/types/lib/inventory/nodeHostProbe.d.ts.map +1 -0
  331. package/types/lib/inventory/occurrenceKey.d.ts +52 -0
  332. package/types/lib/inventory/occurrenceKey.d.ts.map +1 -0
  333. package/types/lib/inventory/osPackageResolver.d.ts +38 -0
  334. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
  335. package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -1
  336. package/types/lib/inventory/phpHostProbe.d.ts.map +1 -1
  337. package/types/lib/inventory/pqcMigration.d.ts +84 -0
  338. package/types/lib/inventory/pqcMigration.d.ts.map +1 -0
  339. package/types/lib/inventory/rubyBuildInfo.d.ts +271 -0
  340. package/types/lib/inventory/rubyBuildInfo.d.ts.map +1 -0
  341. package/types/lib/inventory/rubyHostProbe.d.ts +47 -0
  342. package/types/lib/inventory/rubyHostProbe.d.ts.map +1 -0
  343. package/types/lib/inventory/rustFormulationParser.d.ts +7 -2
  344. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  345. package/types/lib/inventory/scalaCoords.d.ts.map +1 -1
  346. package/types/lib/inventory/scalaDedupe.d.ts +43 -0
  347. package/types/lib/inventory/scalaDedupe.d.ts.map +1 -0
  348. package/types/lib/inventory/source.d.ts +25 -0
  349. package/types/lib/inventory/source.d.ts.map +1 -1
  350. package/types/lib/managers/binary.d.ts.map +1 -1
  351. package/types/lib/managers/docker.d.ts +12 -0
  352. package/types/lib/managers/docker.d.ts.map +1 -1
  353. package/types/lib/parsers/huggingfaceManifest.d.ts +10 -1
  354. package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -1
  355. package/types/lib/parsers/huggingfaceUtils.d.ts +12 -0
  356. package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
  357. package/types/lib/parsers/kiroPermissions.d.ts +62 -0
  358. package/types/lib/parsers/kiroPermissions.d.ts.map +1 -0
  359. package/types/lib/parsers/largeJson.d.ts +4 -3
  360. package/types/lib/parsers/largeJson.d.ts.map +1 -1
  361. package/types/lib/parsers/vscodeExtensionId.d.ts +48 -0
  362. package/types/lib/parsers/vscodeExtensionId.d.ts.map +1 -0
  363. package/types/lib/server/server.d.ts.map +1 -1
  364. package/types/lib/stages/postgen/postgen.d.ts +7 -0
  365. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  366. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  367. package/types/lib/stages/postgen/specVersionCompat.d.ts +25 -0
  368. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  369. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  370. package/types/lib/stages/pregen/pregen.d.ts +12 -8
  371. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  372. package/types/lib/validator/bomValidator.d.ts +5 -1
  373. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  374. package/types/lib/validator/complianceEngine.d.ts +4 -4
  375. package/types/lib/validator/complianceEngine.d.ts.map +1 -1
  376. package/types/lib/validator/complianceRules.d.ts +14 -2
  377. package/types/lib/validator/complianceRules.d.ts.map +1 -1
  378. package/types/lib/validator/index.d.ts +10 -0
  379. package/types/lib/validator/index.d.ts.map +1 -1
  380. package/types/lib/validator/reporters/json.d.ts.map +1 -1
@@ -0,0 +1,218 @@
1
+ // Bounded Node.js build-version reader for unpackaged `node` binaries.
2
+ //
3
+ // The Node.js the Docker Official images, the release tarballs, nvm, fnm and
4
+ // volta install is not owned by any package manager, so a BOM sees it only as
5
+ // a file. Its version decides whether the runtime is affected by advisories
6
+ // such as CVE-2026-111497 (fixed in 22.23.4, 24.22.1 and 26.12.1).
7
+ //
8
+ // Two markers are compiled into the binary:
9
+ // - the release URLs, `https://nodejs.org/download/<channel>/v<version>/`,
10
+ // which a build configured with release URLs (every nodejs.org build)
11
+ // carries for process.release.sourceUrl and headersUrl
12
+ // https://github.com/nodejs/node/blob/v24.22.0/src/node_metadata.cc#L191-L197
13
+ // - `node.js/v<version>`, NUL-terminated, the inspector's /json/version
14
+ // Browser string, which every build with the inspector carries; it is the
15
+ // fallback for a build without release URLs.
16
+ // https://github.com/nodejs/node/blob/v24.22.0/src/inspector_socket_server.cc#L117
17
+ //
18
+ // process.versions.brotli is not a usable signal: Node.js backports the
19
+ // decoder fix without changing it (24.22.1 still reports 1.2.0). The decoder
20
+ // state is read separately, by brotliDecoder.js.
21
+
22
+ import { basename } from "node:path";
23
+
24
+ import { scanFileMarkers } from "../core/boundedFile.js";
25
+ import { applyPurl, tryBuildPurl } from "./purl.js";
26
+
27
+ const RELEASE_URL_MARKER = Buffer.from("https://nodejs.org/download/");
28
+ const USER_AGENT_MARKER = Buffer.from("node.js/v");
29
+ const MAX_VERSION_LENGTH = 64;
30
+ const VERSION_RE = /^(\d+\.\d+\.\d+)(?:-([0-9A-Za-z][0-9A-Za-z.]*))?$/;
31
+ const CHANNELS = new Set(["release", "rc", "nightly", "test", "v8-canary"]);
32
+
33
+ /**
34
+ * The most node-named files one scan opens in search of a build version.
35
+ *
36
+ * @type {number}
37
+ */
38
+ export const MAX_NODE_PROBES = 64;
39
+
40
+ /**
41
+ * Whether a file name is one the Node.js runtime is installed under.
42
+ *
43
+ * @param {string} fileName basename or path of the candidate
44
+ * @returns {boolean} true for `node`, `nodejs` and `node.exe`
45
+ */
46
+ export function isNodeBinaryName(fileName) {
47
+ if (typeof fileName !== "string" || !fileName) {
48
+ return false;
49
+ }
50
+ const name = basename(fileName.replaceAll("\\", "/"));
51
+ return name === "node" || name === "nodejs" || name === "node.exe";
52
+ }
53
+
54
+ /**
55
+ * Parse a Node.js version in the grammar the release tooling produces:
56
+ * `24.22.1`, `25.0.0-rc.1`, `26.0.0-nightly20260301abcdef`.
57
+ *
58
+ * @param {string} text candidate version, without the leading `v`
59
+ * @returns {string|undefined} the version, or undefined
60
+ */
61
+ export function parseNodeVersion(text) {
62
+ if (typeof text !== "string" || !text || text.length > MAX_VERSION_LENGTH) {
63
+ return undefined;
64
+ }
65
+ return VERSION_RE.test(text) ? text : undefined;
66
+ }
67
+
68
+ function versionFromReleaseUrl(after) {
69
+ // <channel>/v<version>/...
70
+ const text = after.toString("latin1");
71
+ const slash = text.indexOf("/");
72
+ if (slash <= 0) {
73
+ return undefined;
74
+ }
75
+ const channel = text.slice(0, slash);
76
+ if (!CHANNELS.has(channel) || text[slash + 1] !== "v") {
77
+ return undefined;
78
+ }
79
+ const end = text.indexOf("/", slash + 2);
80
+ if (end === -1) {
81
+ return undefined;
82
+ }
83
+ const version = parseNodeVersion(text.slice(slash + 2, end));
84
+ return version ? { version, channel } : undefined;
85
+ }
86
+
87
+ function versionFromUserAgent(after) {
88
+ const end = after.indexOf(0);
89
+ if (end <= 0) {
90
+ return undefined;
91
+ }
92
+ return parseNodeVersion(after.toString("latin1", 0, end));
93
+ }
94
+
95
+ /**
96
+ * Read the Node.js version a `node` binary was built as.
97
+ *
98
+ * @param {string} absPath absolute path of the binary
99
+ * @param {string|undefined} rootDir extracted root, when the file came from one
100
+ * @returns {{version: string, source: string, channel?: string}|undefined}
101
+ * source is `release-url` or `binary`
102
+ */
103
+ export function readNodeBuildVersion(absPath, rootDir) {
104
+ const scan = scanFileMarkers(
105
+ absPath,
106
+ rootDir,
107
+ [RELEASE_URL_MARKER, USER_AGENT_MARKER],
108
+ { contextBytes: MAX_VERSION_LENGTH + 32, maxHits: 8 },
109
+ );
110
+ if (!scan || scan.skipped) {
111
+ return undefined;
112
+ }
113
+ const [releaseHits, userAgentHits] = scan.hits;
114
+ const fromBinary = userAgentHits
115
+ .map((hit) => versionFromUserAgent(hit.after))
116
+ .find(Boolean);
117
+ for (const hit of releaseHits) {
118
+ const release = versionFromReleaseUrl(hit.after);
119
+ // The headers URL names the release a binary was published as. A binary
120
+ // whose own version string disagrees is not that release, so the URL is
121
+ // used only when the two agree or the version string is missing.
122
+ if (release && (!fromBinary || fromBinary === release.version)) {
123
+ return {
124
+ version: release.version,
125
+ source: "release-url",
126
+ channel: release.channel,
127
+ };
128
+ }
129
+ }
130
+ return fromBinary ? { version: fromBinary, source: "binary" } : undefined;
131
+ }
132
+
133
+ /**
134
+ * The CPE that lets a downstream scanner match a Node.js version. NVD names the
135
+ * product node.js and keeps a pre-release in the update field.
136
+ *
137
+ * @param {string} version Node.js version
138
+ * @returns {string} CPE 2.3 string
139
+ */
140
+ export function nodeCpe(version) {
141
+ const match = VERSION_RE.exec(version || "");
142
+ if (!match) {
143
+ return `cpe:2.3:a:nodejs:node.js:${version}:*:*:*:*:*:*:*`;
144
+ }
145
+ const update = match[2] ? match[2].replaceAll(".", "").toLowerCase() : "*";
146
+ return `cpe:2.3:a:nodejs:node.js:${match[1]}:${update}:*:*:*:*:*:*`;
147
+ }
148
+
149
+ /**
150
+ * A Node.js runtime is one `platform` component per distinct version, like the
151
+ * PHP and Go stdlib components. Its identity is `pkg:generic/node`: it is only
152
+ * used where no package manager owns the runtime.
153
+ *
154
+ * @param {string} version Node.js version
155
+ * @returns {Object} component with `purl`, `bom-ref` and `cpe`
156
+ */
157
+ export function createNodeRuntimeComponent(version) {
158
+ return applyPurl(
159
+ { type: "platform", name: "node", version, cpe: nodeCpe(version) },
160
+ tryBuildPurl({ type: "generic", name: "node", version }),
161
+ );
162
+ }
163
+
164
+ /**
165
+ * The properties a node file component carries once its build is known.
166
+ *
167
+ * @param {{version: string, source: string, channel?: string}} build result of readNodeBuildVersion
168
+ * @returns {{name: string, value: string}[]} properties to append
169
+ */
170
+ export function nodeBuildProperties(build) {
171
+ const properties = [
172
+ { name: "cdx:node:buildVersion", value: build.version },
173
+ { name: "cdx:node:buildVersionSource", value: build.source },
174
+ ];
175
+ if (build.channel) {
176
+ properties.push({ name: "cdx:node:releaseChannel", value: build.channel });
177
+ }
178
+ return properties;
179
+ }
180
+
181
+ /**
182
+ * Start collecting the runtime components and edges of one scan.
183
+ *
184
+ * @returns {{runtimeComponents: Object[], dependencies: Object[], runtimeRefs: Set<string>}}
185
+ */
186
+ export function createNodeRuntimeInventory() {
187
+ return { runtimeComponents: [], dependencies: [], runtimeRefs: new Set() };
188
+ }
189
+
190
+ /**
191
+ * Tag a node file component with its build facts and link it to the runtime
192
+ * component of its version, creating that component on first use. Mutates the
193
+ * component in place.
194
+ *
195
+ * @param {{runtimeComponents: Object[], dependencies: Object[], runtimeRefs: Set<string>}} inventory
196
+ * accumulator from createNodeRuntimeInventory
197
+ * @param {Object} component file component, with a `properties` array
198
+ * @param {{version: string, source: string, channel?: string}} build result of readNodeBuildVersion
199
+ */
200
+ export function attachNodeBuild(inventory, component, build) {
201
+ component.properties.push(...nodeBuildProperties(build));
202
+ const runtime = createNodeRuntimeComponent(build.version);
203
+ const runtimeRef = runtime["bom-ref"];
204
+ if (!runtimeRef) {
205
+ return;
206
+ }
207
+ if (!inventory.runtimeRefs.has(runtimeRef)) {
208
+ inventory.runtimeRefs.add(runtimeRef);
209
+ inventory.runtimeComponents.push(runtime);
210
+ inventory.dependencies.push({ ref: runtimeRef, dependsOn: [] });
211
+ }
212
+ if (component["bom-ref"]) {
213
+ inventory.dependencies.push({
214
+ ref: component["bom-ref"],
215
+ dependsOn: [runtimeRef],
216
+ });
217
+ }
218
+ }
@@ -0,0 +1,202 @@
1
+ // Bounded, read-only probe for the Node.js no package manager owns on a live
2
+ // host, for `-t os` / obom. The release tarballs, the nodejs.org installer and
3
+ // the version managers (nvm, fnm, volta, asdf, mise, n) put Node.js where no
4
+ // package database records it, so an OBOM sees neither the runtime nor the
5
+ // Brotli decoder compiled into it.
6
+ //
7
+ // Candidates come from fixed directories and from each version manager's
8
+ // tree under the home directories, one wildcard level at a time, never from a
9
+ // walk of the file system. The ownership rules, caps and degradations are the
10
+ // shared host-runtime probe's.
11
+
12
+ import { join } from "node:path";
13
+
14
+ import {
15
+ isDryRun,
16
+ readEnvironmentVariable,
17
+ recordActivity,
18
+ } from "../core/activity.js";
19
+ import { recordDegradation } from "../core/buildLedger.js";
20
+ import {
21
+ attachBrotliDecoder,
22
+ createBrotliInventory,
23
+ finishBrotliInventory,
24
+ readBrotliDecoder,
25
+ } from "./brotliDecoder.js";
26
+ import {
27
+ isDirectory,
28
+ listDirectory,
29
+ probeHostRuntime,
30
+ } from "./hostRuntimeProbe.js";
31
+ import {
32
+ attachNodeBuild,
33
+ createNodeRuntimeInventory,
34
+ isNodeBinaryName,
35
+ MAX_NODE_PROBES,
36
+ readNodeBuildVersion,
37
+ } from "./nodeBuildInfo.js";
38
+
39
+ // The most directories one wildcard pattern may expand to.
40
+ const MAX_EXPANDED_DIRECTORIES = 256;
41
+
42
+ // Relative to the root.
43
+ const POSIX_DIRECTORIES = {
44
+ linux: ["usr/local/bin", "opt/*/bin", "usr/local/n/versions/node/*/bin"],
45
+ darwin: ["usr/local/bin", "opt/homebrew/bin", "opt/*/bin"],
46
+ };
47
+
48
+ // Relative to a home directory.
49
+ const VERSION_MANAGER_DIRECTORIES = [
50
+ ".nvm/versions/node/*/bin",
51
+ ".local/share/fnm/node-versions/*/installation/bin",
52
+ ".fnm/node-versions/*/installation/bin",
53
+ "Library/Application Support/fnm/node-versions/*/installation/bin",
54
+ ".volta/tools/image/node/*/bin",
55
+ ".asdf/installs/nodejs/*/bin",
56
+ ".local/share/mise/installs/node/*/bin",
57
+ ];
58
+
59
+ const HOME_PARENTS = {
60
+ linux: ["home"],
61
+ darwin: ["Users"],
62
+ };
63
+
64
+ /**
65
+ * Expand a relative directory pattern whose `*` segments match one directory
66
+ * name each.
67
+ *
68
+ * @param {string} base absolute directory the pattern hangs off
69
+ * @param {string} pattern `/`-separated relative pattern
70
+ * @returns {string[]} existing directories, at most MAX_EXPANDED_DIRECTORIES
71
+ */
72
+ function expandDirectories(base, pattern) {
73
+ let current = [base];
74
+ for (const segment of pattern.split("/")) {
75
+ const next = [];
76
+ for (const directory of current) {
77
+ if (segment !== "*") {
78
+ next.push(join(directory, segment));
79
+ continue;
80
+ }
81
+ for (const name of listDirectory(directory)) {
82
+ const child = join(directory, name);
83
+ if (isDirectory(child)) {
84
+ next.push(child);
85
+ }
86
+ if (next.length >= MAX_EXPANDED_DIRECTORIES) {
87
+ break;
88
+ }
89
+ }
90
+ }
91
+ current = next.slice(0, MAX_EXPANDED_DIRECTORIES);
92
+ }
93
+ return current.filter(isDirectory);
94
+ }
95
+
96
+ function homeDirectories(context) {
97
+ const { rootPath, platform } = context;
98
+ const homes = [];
99
+ if (platform === "linux") {
100
+ homes.push(join(rootPath, "root"));
101
+ }
102
+ for (const parent of HOME_PARENTS[platform] || []) {
103
+ for (const name of listDirectory(join(rootPath, parent))) {
104
+ const home = join(rootPath, parent, name);
105
+ if (isDirectory(home)) {
106
+ homes.push(home);
107
+ }
108
+ }
109
+ }
110
+ return homes.slice(0, MAX_EXPANDED_DIRECTORIES);
111
+ }
112
+
113
+ // Where the Node.js MSI installs, by itself or for Chocolatey's nodejs.install.
114
+ function windowsInstallDirectory(context) {
115
+ const programFiles =
116
+ context.readEnv("ProgramFiles") || join(context.rootPath, "Program Files");
117
+ return join(programFiles, "nodejs");
118
+ }
119
+
120
+ function candidateDirectories(context) {
121
+ const { rootPath, platform } = context;
122
+ const directories = [];
123
+ if (platform === "win32") {
124
+ directories.push({ directory: windowsInstallDirectory(context) });
125
+ const appData = context.readEnv("APPDATA");
126
+ if (appData) {
127
+ for (const directory of expandDirectories(appData, "nvm/*")) {
128
+ directories.push({ directory });
129
+ }
130
+ }
131
+ return directories;
132
+ }
133
+ for (const pattern of POSIX_DIRECTORIES[platform] || []) {
134
+ for (const directory of expandDirectories(rootPath, pattern)) {
135
+ directories.push({ directory });
136
+ }
137
+ }
138
+ for (const home of homeDirectories(context)) {
139
+ for (const pattern of VERSION_MANAGER_DIRECTORIES) {
140
+ for (const directory of expandDirectories(home, pattern)) {
141
+ directories.push({ directory });
142
+ }
143
+ }
144
+ }
145
+ return directories;
146
+ }
147
+
148
+ function readBuild(context, candidate) {
149
+ const node = readNodeBuildVersion(candidate.real, context.realRoot);
150
+ if (!node) {
151
+ return undefined;
152
+ }
153
+ return { node, brotli: readBrotliDecoder(candidate.real, context.realRoot) };
154
+ }
155
+
156
+ /**
157
+ * Look for Node.js no package manager owns on the host. Components come back
158
+ * only for the files nothing owns: a `file` component for each `node` binary
159
+ * with the cdx:node and cdx:brotli properties, one `platform` component per
160
+ * Node.js version with its CPE, and the brotli component when a binary embeds
161
+ * a decoder.
162
+ *
163
+ * @param {Object} [options] probe options, as probeHostPhp takes them
164
+ * @returns {{components: Object[], dependencies: Object[]}}
165
+ */
166
+ export function probeHostNode(options = {}) {
167
+ return probeHostRuntime(options, {
168
+ label: "Node.js",
169
+ ecosystem: "npm",
170
+ capability: "node-host-probe",
171
+ remediationId: "npm.host-probe.package-db-unreadable",
172
+ maxProbes: MAX_NODE_PROBES,
173
+ chocolateyPackages: ["nodejs", "nodejs-lts", "nodejs.install"],
174
+ chocolateyDirectories: (context) => [windowsInstallDirectory(context)],
175
+ directories: candidateDirectories,
176
+ classify: (name) => (isNodeBinaryName(name) ? "node" : undefined),
177
+ readBuild,
178
+ createInventory: () => ({
179
+ node: createNodeRuntimeInventory(),
180
+ brotli: createBrotliInventory(),
181
+ }),
182
+ attach: (inventory, component, build) => {
183
+ attachNodeBuild(inventory.node, component, build.node);
184
+ if (build.brotli) {
185
+ attachBrotliDecoder(inventory.brotli, component, build.brotli);
186
+ }
187
+ },
188
+ finish: (inventory) => {
189
+ const brotli = finishBrotliInventory(inventory.brotli);
190
+ return {
191
+ components: [...inventory.node.runtimeComponents, ...brotli.components],
192
+ dependencies: [...inventory.node.dependencies, ...brotli.dependencies],
193
+ };
194
+ },
195
+ hooks: {
196
+ isDryRun,
197
+ readEnvironmentVariable,
198
+ recordActivity,
199
+ recordDegradation,
200
+ },
201
+ });
202
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The key of a place in a purl's occurrence set (`purlLocationMap`).
3
+ *
4
+ * Every location that enters an occurrence set is keyed by this function,
5
+ * whatever evidence source added it: the seeding from the input BOM
6
+ * (`initFromSbom`), the atom `usages` and `callsites` slices, the golem, rusi,
7
+ * kosi, dosai and scalasem reports, the C include attribution and the Swift
8
+ * semantics slices. Backslashes become `/`, so a place spelled with `\` in the
9
+ * input BOM (Windows cdxgen output) and `/` in a slice is one occurrence, not
10
+ * two (issue 4726). The path is otherwise left as spelled: no resolving, no
11
+ * case folding, no stripping of a leading `./`.
12
+ *
13
+ * A place a line already names is keyed `file#line`; a place a callsites
14
+ * record names down to its column (counted from 0, as atom writes it) is keyed
15
+ * `file:line:offset`, so two use
16
+ * sites on one line are two occurrences. An occurrence with only `location`
17
+ * and `line` names the line as a whole: it is the same place as any use site
18
+ * that line carries, and it is kept as an occurrence of its own only while no
19
+ * `file:line:offset` key of that line exists (the writer drops the line-only
20
+ * key then, see `dropSubsumedOccurrenceKeys`). That rule is what keeps a
21
+ * re-run of evinse over its own output at the same occurrences: the first run
22
+ * writes the `file:line:offset` keys, and the second run seeds and re-adds
23
+ * exactly those.
24
+ *
25
+ * @param {string} location File path or other location text
26
+ * @param {number} [line] Line number; not a positive number means the location names no line
27
+ * @param {number} [offset] Column within the line, counted from 0 as atom writes it; a value that is not an integer of 0 or more (atom writes -1 for an unknown column) means the place is the line
28
+ * @returns {string|undefined} Key in the `file:line:offset`, `file#line` or plain `file` shape; undefined when the location is empty
29
+ */
30
+ export function occurrenceLocationKey(location, line, offset) {
31
+ const normalized = `${location ?? ""}`.trim().replaceAll("\\", "/");
32
+ if (!normalized) {
33
+ return undefined;
34
+ }
35
+ if (!(line > 0)) {
36
+ return normalized;
37
+ }
38
+ return Number.isInteger(offset) && offset >= 0
39
+ ? `${normalized}:${line}:${offset}`
40
+ : `${normalized}#${line}`;
41
+ }
42
+
43
+ /**
44
+ * Drop the occurrence keys a use-site key subsumes.
45
+ *
46
+ * A `file:line:offset` key names a use site on a line; the line-only
47
+ * `file#line` key of the same line names no place of its own any more, so it
48
+ * is removed rather than counted beside the use sites (issue 4726: an
49
+ * occurrence seeded from an input BOM with only `location` and `line` is the
50
+ * same place as a callsites occurrence at that line).
51
+ *
52
+ * @param {string[]} keys Occurrence-set keys
53
+ * @returns {string[]} The keys without the subsumed line-only entries
54
+ */
55
+ export function dropSubsumedOccurrenceKeys(keys) {
56
+ const linesWithOffset = new Set();
57
+ for (const key of keys) {
58
+ const withOffset = /^(.*):(\d+):(\d+)$/.exec(key);
59
+ if (withOffset) {
60
+ linesWithOffset.add(`${withOffset[1]}#${withOffset[2]}`);
61
+ }
62
+ }
63
+ if (!linesWithOffset.size) {
64
+ return keys;
65
+ }
66
+ return keys.filter((key) => {
67
+ const lineOnly = /^(.*)#(\d+)$/.exec(key);
68
+ return !(lineOnly && linesWithOffset.has(`${lineOnly[1]}#${lineOnly[2]}`));
69
+ });
70
+ }
71
+
72
+ /**
73
+ * The location part of an occurrence-set key: `src/a.js` for `src/a.js#3`,
74
+ * `src/a.js:3:14` and `src/a.js` alike.
75
+ *
76
+ * @param {string} key Key made by `occurrenceLocationKey`
77
+ * @returns {string} The location the key names
78
+ */
79
+ export function occurrenceKeyLocation(key) {
80
+ const text = `${key ?? ""}`;
81
+ const withOffset = /^(.*):(\d+):(\d+)$/.exec(text);
82
+ if (withOffset) {
83
+ return withOffset[1];
84
+ }
85
+ const hash = text.lastIndexOf("#");
86
+ if (hash > 0 && /^\d+$/.test(text.slice(hash + 1))) {
87
+ return text.slice(0, hash);
88
+ }
89
+ return text;
90
+ }
@@ -493,3 +493,185 @@ function collectAllLdConfs(basePath, ldConf, allLdConfDirs, libPaths) {
493
493
  }
494
494
  }
495
495
  }
496
+
497
+ // Native modules that language package managers install outside the library
498
+ // directories the loader searches: CPython and PyPy extension modules, PHP
499
+ // extensions, Ruby gem extensions, Node.js addons, and the native half of a
500
+ // .NET runtime. A Brotli decoder compiled into one of them is invisible unless
501
+ // the file is read.
502
+ const NATIVE_EXTENSION_GLOBS = [
503
+ "**/site-packages/**/*.{so,pyd}",
504
+ "**/dist-packages/**/*.so",
505
+ "**/lib/php/**/*.so",
506
+ "**/lib/php*/modules/*.so",
507
+ "**/php*/ext/php_*.dll",
508
+ "**/gems/*/lib/**/*.{so,bundle}",
509
+ "**/gems/*/extensions/**/*.{so,bundle}",
510
+ "**/bundle/extensions/**/*.{so,bundle}",
511
+ "**/node_modules/**/*.node",
512
+ "**/dotnet/shared/*/*/*.so",
513
+ "**/.dotnet/shared/*/*/*.so",
514
+ // Of a Windows runtime's many DLLs, only this one is native and holds the
515
+ // decoder.
516
+ "**/dotnet/shared/*/*/System.IO.Compression.Native.dll",
517
+ ];
518
+ const NATIVE_EXTENSION_IGNORES = ["proc/**", "sys/**", "dev/**"];
519
+
520
+ /**
521
+ * The most native extension candidates one scan returns.
522
+ *
523
+ * @type {number}
524
+ */
525
+ export const MAX_NATIVE_EXTENSIONS = 4096;
526
+
527
+ /**
528
+ * Collect native extension modules under a root file system that the library
529
+ * collector does not see, leaving out paths a package database owns and paths
530
+ * already collected. Symlinks are not followed, so a link pointing out of the
531
+ * root is never listed.
532
+ *
533
+ * @param {string} basePath extracted root file system
534
+ * @param {string[]} [excludePaths] root-relative paths to leave out
535
+ * @returns {string[]} root-relative paths, sorted, capped at MAX_NATIVE_EXTENSIONS
536
+ */
537
+ export function collectNativeExtensions(basePath, excludePaths = []) {
538
+ if (!basePath) {
539
+ return [];
540
+ }
541
+ const excluded = new Set(
542
+ (excludePaths || []).map((f) => f.replace(/^\/+/, "").replace(/\\/g, "/")),
543
+ );
544
+ let files = [];
545
+ try {
546
+ files = globSync(NATIVE_EXTENSION_GLOBS, {
547
+ cwd: basePath,
548
+ absolute: false,
549
+ nodir: true,
550
+ dot: true,
551
+ follow: false,
552
+ ignore: NATIVE_EXTENSION_IGNORES,
553
+ });
554
+ } catch (_err) {
555
+ return [];
556
+ }
557
+ const result = new Set();
558
+ for (const file of files) {
559
+ const normalized = file.replace(/\\/g, "/").replace(/^\/+/, "");
560
+ if (!excluded.has(normalized)) {
561
+ result.add(normalized);
562
+ }
563
+ }
564
+ return Array.from(result).sort().slice(0, MAX_NATIVE_EXTENSIONS);
565
+ }
566
+
567
+ const OS_PACKAGE_PURL_PREFIXES = [
568
+ "pkg:deb/",
569
+ "pkg:apk/",
570
+ "pkg:rpm/",
571
+ "pkg:alpm/",
572
+ "pkg:qpkg/",
573
+ "pkg:generic/",
574
+ ];
575
+
576
+ /**
577
+ * Whether a source file is the installation record of a language package,
578
+ * the file a package manager writes when it installs the package: dist-info
579
+ * or egg-info metadata, an installed gemspec, a package.json inside
580
+ * node_modules, or a jar. A lock file or manifest only names packages, so an
581
+ * OS package owning one says nothing about who installed them.
582
+ *
583
+ * @param {string} filePath root-relative path with forward slashes
584
+ * @returns {boolean}
585
+ */
586
+ function isInstallRecord(filePath) {
587
+ const parts = filePath.split("/");
588
+ const name = parts.at(-1) || "";
589
+ const parent = parts.at(-2) || "";
590
+ if (parent.endsWith(".dist-info") || parent.endsWith(".egg-info")) {
591
+ return true;
592
+ }
593
+ if (name.endsWith(".egg-info") || name.endsWith(".jar")) {
594
+ return true;
595
+ }
596
+ if (name.endsWith(".gemspec") && parts.includes("specifications")) {
597
+ return true;
598
+ }
599
+ return name === "package.json" && parts.includes("node_modules");
600
+ }
601
+
602
+ /**
603
+ * Mark language packages that an OS package installed. Alpine's py3-brotli
604
+ * ships a Brotli-1.1.0.dist-info that a Python scan reports as
605
+ * pkg:pypi/brotli@1.1.0, but a distro fixes it by backporting under the same
606
+ * upstream version, so a PyPI advisory range keeps matching after the fix. The
607
+ * `cdx:os:installedBy` property names the OS package that owns the
608
+ * installation record, so a consumer can judge the component by that package
609
+ * instead.
610
+ *
611
+ * A component is marked only when every installation record it was read from
612
+ * belongs to an OS package: a copy that pip put in a virtual environment
613
+ * beside the distro's is not the distro's to fix. Run it after duplicates
614
+ * merge, so that a merged component carries all of its records.
615
+ *
616
+ * @param {Object[]} components BOM components, mutated in place
617
+ * @param {Map<string, string>|undefined} ownerByPath root-relative file path to
618
+ * owning OS package bom-ref
619
+ * @param {string} [rootDir] extracted root, stripped from absolute source paths
620
+ * @returns {number} how many components were marked
621
+ */
622
+ export function markOsInstalledLanguagePackages(
623
+ components,
624
+ ownerByPath,
625
+ rootDir,
626
+ ) {
627
+ if (!ownerByPath?.size || !Array.isArray(components)) {
628
+ return 0;
629
+ }
630
+ const rootPrefix = rootDir
631
+ ? rootDir.replaceAll("\\", "/").replace(/\/+$/, "")
632
+ : undefined;
633
+ let marked = 0;
634
+ for (const component of components) {
635
+ const purl = component?.purl;
636
+ if (
637
+ typeof purl !== "string" ||
638
+ !purl.startsWith("pkg:") ||
639
+ OS_PACKAGE_PURL_PREFIXES.some((prefix) => purl.startsWith(prefix)) ||
640
+ !Array.isArray(component.properties) ||
641
+ component.properties.some((prop) => prop.name === "cdx:os:installedBy")
642
+ ) {
643
+ continue;
644
+ }
645
+ const owners = new Set();
646
+ let records = 0;
647
+ let unowned = 0;
648
+ for (const prop of component.properties) {
649
+ if (prop.name !== "internal:SrcFile" || typeof prop.value !== "string") {
650
+ continue;
651
+ }
652
+ let filePath = prop.value.replaceAll("\\", "/");
653
+ if (rootPrefix && filePath.startsWith(`${rootPrefix}/`)) {
654
+ filePath = filePath.slice(rootPrefix.length);
655
+ }
656
+ filePath = filePath.replace(/^\/+/, "");
657
+ if (!isInstallRecord(filePath)) {
658
+ continue;
659
+ }
660
+ records += 1;
661
+ const owner = ownerByPath.get(filePath);
662
+ if (owner) {
663
+ owners.add(owner);
664
+ } else {
665
+ unowned += 1;
666
+ }
667
+ }
668
+ if (!records || unowned) {
669
+ continue;
670
+ }
671
+ for (const owner of Array.from(owners).sort()) {
672
+ component.properties.push({ name: "cdx:os:installedBy", value: owner });
673
+ }
674
+ marked += 1;
675
+ }
676
+ return marked;
677
+ }