@cdxgen/cdxgen 13.3.0 → 13.5.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 (372) hide show
  1. package/README.md +12 -9
  2. package/bin/cdxgen-secure.js +15 -0
  3. package/bin/cdxgen.js +115 -31
  4. package/bin/evinse.js +23 -1
  5. package/bin/hbom.js +15 -7
  6. package/bin/repl.js +115 -0
  7. package/bin/sign.js +45 -15
  8. package/bin/tracebom.js +5 -1
  9. package/bin/validate.js +84 -18
  10. package/bin/verify.js +155 -86
  11. package/data/cbomosdb-queries.json +13 -1
  12. package/data/component-tags.json +8 -0
  13. package/data/helpers/init.gradle +46 -21
  14. package/data/queries-darwin.json +25 -1
  15. package/data/queries-win.json +19 -1
  16. package/data/queries.json +41 -0
  17. package/data/remediations.json +344 -1
  18. package/data/rules/cbom-security.yaml +235 -4
  19. package/data/rules/dependency-sources.yaml +67 -0
  20. package/data/rules/go-binaries.yaml +46 -0
  21. package/data/rules/golem-go.yaml +80 -0
  22. package/data/rules/hbom-compliance.yaml +40 -22
  23. package/data/rules/hbom-performance.yaml +7 -1
  24. package/data/rules/host-topology.yaml +1 -1
  25. package/data/rules/obom-runtime.yaml +31 -2
  26. package/data/rules/php-runtime.yaml +143 -0
  27. package/data/rules/scala-evidence.yaml +115 -0
  28. package/lib/audit/index.js +52 -6
  29. package/lib/cli/bomAssembly.js +28 -3
  30. package/lib/cli/cliOptions.js +110 -3
  31. package/lib/cli/index.js +186 -58
  32. package/lib/cli/jsBom.js +50 -29
  33. package/lib/cli/jvmBom.js +779 -146
  34. package/lib/cli/managedBom.js +1021 -261
  35. package/lib/cli/nativeBom.js +364 -58
  36. package/lib/core/activity.js +12 -0
  37. package/lib/core/env.js +47 -17
  38. package/lib/core/fs.js +31 -21
  39. package/lib/core/httpClient.js +233 -69
  40. package/lib/core/pluginRun.js +184 -0
  41. package/lib/core/processTree.js +100 -0
  42. package/lib/core/projectConfig.js +1 -0
  43. package/lib/core/projectTooling.js +97 -0
  44. package/lib/core/propertySanitizer.js +72 -0
  45. package/lib/core/runState.js +39 -0
  46. package/lib/core/toml.js +72 -0
  47. package/lib/ecosystems/asarutils.js +4 -2
  48. package/lib/ecosystems/bunutils.js +5 -7
  49. package/lib/ecosystems/cargoCache.js +231 -8
  50. package/lib/ecosystems/cmakeResolver.js +10 -21
  51. package/lib/ecosystems/cppBuildContext.js +631 -0
  52. package/lib/ecosystems/cppEvidence.js +337 -22
  53. package/lib/ecosystems/cppIncludeResolver.js +294 -0
  54. package/lib/ecosystems/denoutils.js +93 -66
  55. package/lib/ecosystems/ecosystems.js +1967 -788
  56. package/lib/ecosystems/golem.js +578 -18
  57. package/lib/ecosystems/gradleutils.js +340 -46
  58. package/lib/ecosystems/jsEvidence.js +85 -24
  59. package/lib/ecosystems/kosi.js +21 -4
  60. package/lib/ecosystems/npmutils.js +64 -0
  61. package/lib/ecosystems/parsers-dotnet.js +668 -153
  62. package/lib/ecosystems/parsers-elm.js +46 -28
  63. package/lib/ecosystems/parsers-gleam.js +3 -4
  64. package/lib/ecosystems/parsers-go.js +1283 -297
  65. package/lib/ecosystems/parsers-js.js +92 -26
  66. package/lib/ecosystems/parsers-julia.js +2 -3
  67. package/lib/ecosystems/parsers-jvm.js +463 -29
  68. package/lib/ecosystems/parsers-misc.js +405 -93
  69. package/lib/ecosystems/parsers-python.js +152 -20
  70. package/lib/ecosystems/parsers-rust.js +4 -4
  71. package/lib/ecosystems/parsers-terraform.js +1573 -19
  72. package/lib/ecosystems/pythonutils.js +102 -6
  73. package/lib/ecosystems/remote/huggingface.js +3 -0
  74. package/lib/ecosystems/rubyutils.js +73 -20
  75. package/lib/ecosystems/rusi.js +32 -9
  76. package/lib/ecosystems/sbtutils.js +243 -187
  77. package/lib/ecosystems/scalacliutils.js +343 -0
  78. package/lib/ecosystems/scalasem.js +2620 -0
  79. package/lib/ecosystems/terraformRegistry.js +288 -0
  80. package/lib/ecosystems/utils.js +2 -0
  81. package/lib/ecosystems/vendoredCode.js +156 -0
  82. package/lib/evinser/evinser.js +695 -78
  83. package/lib/evinser/swiftsem.js +68 -5
  84. package/lib/helpers/agenticToolutils.js +2 -2
  85. package/lib/helpers/bomSigner.js +576 -128
  86. package/lib/inventory/agentSkillSpec.js +17 -0
  87. package/lib/inventory/aiCollector.js +4 -1
  88. package/lib/inventory/analyzer.js +110 -127
  89. package/lib/inventory/apkInstalledDb.js +243 -0
  90. package/lib/inventory/atomUtils.js +204 -48
  91. package/lib/inventory/auditCategories.js +10 -3
  92. package/lib/inventory/buildToolRateLimit.js +144 -0
  93. package/lib/inventory/cacheCommands.js +2 -1
  94. package/lib/inventory/cacheDir.js +52 -9
  95. package/lib/inventory/certificates.js +2371 -0
  96. package/lib/inventory/cmakeBuildDirs.js +254 -0
  97. package/lib/inventory/communityAiConfigParser.js +4 -9
  98. package/lib/inventory/deps.js +507 -128
  99. package/lib/inventory/display.js +200 -3
  100. package/lib/inventory/dosai.js +747 -101
  101. package/lib/inventory/dosaiParsers.js +310 -15
  102. package/lib/inventory/dynamic.js +96 -8
  103. package/lib/inventory/envcontext.js +168 -5
  104. package/lib/inventory/evidenceUtils.js +590 -132
  105. package/lib/inventory/fetchBatch.js +574 -38
  106. package/lib/inventory/fetchDiskCache.js +597 -0
  107. package/lib/inventory/forgeEnricher.js +14 -5
  108. package/lib/inventory/formulationParsers.js +3 -2
  109. package/lib/inventory/goBuildInfo.js +140 -0
  110. package/lib/inventory/hbom.js +67 -7
  111. package/lib/inventory/hbomAnalysis.js +16 -0
  112. package/lib/inventory/hostTopology.js +21 -0
  113. package/lib/inventory/jvmLocalRepos.js +917 -0
  114. package/lib/inventory/mcpConfigParser.js +2 -3
  115. package/lib/inventory/osPackagePurl.js +244 -0
  116. package/lib/inventory/osPackageResolver.js +89 -87
  117. package/lib/inventory/osinfo.js +79 -31
  118. package/lib/inventory/osqueryTransform.js +114 -5
  119. package/lib/inventory/parentSelection.js +146 -0
  120. package/lib/inventory/phpBuildInfo.js +487 -0
  121. package/lib/inventory/phpHostProbe.js +641 -0
  122. package/lib/inventory/rootfsCerts.js +426 -0
  123. package/lib/inventory/rustFormulationParser.js +3 -4
  124. package/lib/inventory/scalaCoords.js +153 -0
  125. package/lib/inventory/source.js +215 -11
  126. package/lib/inventory/spdx.js +245 -0
  127. package/lib/inventory/traceRunner.js +93 -8
  128. package/lib/inventory/tracedCrypto.js +423 -0
  129. package/lib/managers/binary.js +529 -183
  130. package/lib/managers/docker.js +199 -44
  131. package/lib/managers/oci.js +24 -2
  132. package/lib/parsers/cmakeCache.js +69 -0
  133. package/lib/parsers/cmakeLists.js +16 -2
  134. package/lib/parsers/cmakePresets.js +400 -0
  135. package/lib/parsers/compileCommands.js +557 -0
  136. package/lib/parsers/email.js +277 -0
  137. package/lib/parsers/largeJson.js +34 -2
  138. package/lib/parsers/strictJson.js +322 -0
  139. package/lib/parsers/terraformConfig.js +1073 -0
  140. package/lib/parsers/terraformSource.js +652 -0
  141. package/lib/server/server.js +209 -1
  142. package/lib/stages/postgen/annotator.js +17 -1
  143. package/lib/stages/postgen/introspection/markers.js +1 -1
  144. package/lib/stages/postgen/introspection/reflect.js +4 -1
  145. package/lib/stages/postgen/postgen.js +20 -6
  146. package/lib/stages/postgen/ruleEngine.js +58 -1
  147. package/lib/stages/postgen/specVersionCompat.js +62 -0
  148. package/lib/stages/pregen/pregen.js +117 -5
  149. package/lib/validator/bomValidator.js +26 -5
  150. package/lib/validator/generated/runtime.mjs +13 -0
  151. package/lib/validator/generated/validate-1.6.mjs +26 -7
  152. package/lib/validator/generated/validate-1.7.mjs +31 -12
  153. package/lib/validator/generated/validate-2.0.mjs +30 -11
  154. package/lib/validator/index.js +25 -10
  155. package/lib/validator/reporters/json.js +1 -0
  156. package/package.json +23 -23
  157. package/types/bin/cdxgen-secure.d.ts +3 -0
  158. package/types/bin/cdxgen-secure.d.ts.map +1 -0
  159. package/types/bin/repl.d.ts.map +1 -1
  160. package/types/lib/audit/index.d.ts.map +1 -1
  161. package/types/lib/cli/bomAssembly.d.ts +9 -2
  162. package/types/lib/cli/bomAssembly.d.ts.map +1 -1
  163. package/types/lib/cli/cliOptions.d.ts +43 -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.map +1 -1
  167. package/types/lib/cli/jvmBom.d.ts +44 -1
  168. package/types/lib/cli/jvmBom.d.ts.map +1 -1
  169. package/types/lib/cli/managedBom.d.ts +7 -4
  170. package/types/lib/cli/managedBom.d.ts.map +1 -1
  171. package/types/lib/cli/nativeBom.d.ts +3 -1
  172. package/types/lib/cli/nativeBom.d.ts.map +1 -1
  173. package/types/lib/core/activity.d.ts.map +1 -1
  174. package/types/lib/core/env.d.ts +27 -2
  175. package/types/lib/core/env.d.ts.map +1 -1
  176. package/types/lib/core/fs.d.ts.map +1 -1
  177. package/types/lib/core/httpClient.d.ts +13 -8
  178. package/types/lib/core/httpClient.d.ts.map +1 -1
  179. package/types/lib/core/pluginRun.d.ts +97 -0
  180. package/types/lib/core/pluginRun.d.ts.map +1 -0
  181. package/types/lib/core/processTree.d.ts +36 -0
  182. package/types/lib/core/processTree.d.ts.map +1 -0
  183. package/types/lib/core/projectConfig.d.ts.map +1 -1
  184. package/types/lib/core/projectTooling.d.ts +41 -0
  185. package/types/lib/core/projectTooling.d.ts.map +1 -0
  186. package/types/lib/core/propertySanitizer.d.ts +26 -0
  187. package/types/lib/core/propertySanitizer.d.ts.map +1 -1
  188. package/types/lib/core/runState.d.ts +29 -0
  189. package/types/lib/core/runState.d.ts.map +1 -0
  190. package/types/lib/core/toml.d.ts +20 -0
  191. package/types/lib/core/toml.d.ts.map +1 -0
  192. package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
  193. package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
  194. package/types/lib/ecosystems/cargoCache.d.ts +12 -0
  195. package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
  196. package/types/lib/ecosystems/cmakeResolver.d.ts +5 -3
  197. package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
  198. package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
  199. package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
  200. package/types/lib/ecosystems/cppEvidence.d.ts +19 -3
  201. package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
  202. package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
  203. package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
  204. package/types/lib/ecosystems/denoutils.d.ts +9 -3
  205. package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
  206. package/types/lib/ecosystems/ecosystems.d.ts +62 -13
  207. package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
  208. package/types/lib/ecosystems/golem.d.ts +81 -1
  209. package/types/lib/ecosystems/golem.d.ts.map +1 -1
  210. package/types/lib/ecosystems/gradleutils.d.ts +59 -7
  211. package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
  212. package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
  213. package/types/lib/ecosystems/kosi.d.ts.map +1 -1
  214. package/types/lib/ecosystems/npmutils.d.ts +15 -0
  215. package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
  216. package/types/lib/ecosystems/parsers-dotnet.d.ts +155 -5
  217. package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
  218. package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
  219. package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
  220. package/types/lib/ecosystems/parsers-go.d.ts +119 -5
  221. package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
  222. package/types/lib/ecosystems/parsers-js.d.ts +6 -1
  223. package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
  224. package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
  225. package/types/lib/ecosystems/parsers-jvm.d.ts +74 -3
  226. package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
  227. package/types/lib/ecosystems/parsers-misc.d.ts +21 -59
  228. package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
  229. package/types/lib/ecosystems/parsers-python.d.ts +57 -6
  230. package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
  231. package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
  232. package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
  233. package/types/lib/ecosystems/pythonutils.d.ts +26 -1
  234. package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
  235. package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
  236. package/types/lib/ecosystems/rubyutils.d.ts +21 -1
  237. package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
  238. package/types/lib/ecosystems/rusi.d.ts.map +1 -1
  239. package/types/lib/ecosystems/sbtutils.d.ts +88 -2
  240. package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
  241. package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
  242. package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
  243. package/types/lib/ecosystems/scalasem.d.ts +311 -0
  244. package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
  245. package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
  246. package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
  247. package/types/lib/ecosystems/utils.d.ts +2 -2
  248. package/types/lib/ecosystems/utils.d.ts.map +1 -1
  249. package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
  250. package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
  251. package/types/lib/evinser/evinser.d.ts +100 -8
  252. package/types/lib/evinser/evinser.d.ts.map +1 -1
  253. package/types/lib/evinser/swiftsem.d.ts +10 -0
  254. package/types/lib/evinser/swiftsem.d.ts.map +1 -1
  255. package/types/lib/helpers/bomSigner.d.ts +80 -4
  256. package/types/lib/helpers/bomSigner.d.ts.map +1 -1
  257. package/types/lib/inventory/agentSkillSpec.d.ts +13 -0
  258. package/types/lib/inventory/agentSkillSpec.d.ts.map +1 -0
  259. package/types/lib/inventory/aiCollector.d.ts.map +1 -1
  260. package/types/lib/inventory/analyzer.d.ts.map +1 -1
  261. package/types/lib/inventory/apkInstalledDb.d.ts +42 -0
  262. package/types/lib/inventory/apkInstalledDb.d.ts.map +1 -0
  263. package/types/lib/inventory/atomUtils.d.ts +96 -10
  264. package/types/lib/inventory/atomUtils.d.ts.map +1 -1
  265. package/types/lib/inventory/auditCategories.d.ts +3 -0
  266. package/types/lib/inventory/auditCategories.d.ts.map +1 -1
  267. package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
  268. package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
  269. package/types/lib/inventory/cacheCommands.d.ts +2 -1
  270. package/types/lib/inventory/cacheCommands.d.ts.map +1 -1
  271. package/types/lib/inventory/cacheDir.d.ts +12 -4
  272. package/types/lib/inventory/cacheDir.d.ts.map +1 -1
  273. package/types/lib/inventory/certificates.d.ts +205 -0
  274. package/types/lib/inventory/certificates.d.ts.map +1 -0
  275. package/types/lib/inventory/cmakeBuildDirs.d.ts +58 -0
  276. package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
  277. package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
  278. package/types/lib/inventory/deps.d.ts +61 -2
  279. package/types/lib/inventory/deps.d.ts.map +1 -1
  280. package/types/lib/inventory/display.d.ts +18 -0
  281. package/types/lib/inventory/display.d.ts.map +1 -1
  282. package/types/lib/inventory/dosai.d.ts +202 -14
  283. package/types/lib/inventory/dosai.d.ts.map +1 -1
  284. package/types/lib/inventory/dosaiParsers.d.ts +53 -7
  285. package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
  286. package/types/lib/inventory/dynamic.d.ts +16 -1
  287. package/types/lib/inventory/dynamic.d.ts.map +1 -1
  288. package/types/lib/inventory/envcontext.d.ts +40 -2
  289. package/types/lib/inventory/envcontext.d.ts.map +1 -1
  290. package/types/lib/inventory/evidenceUtils.d.ts +48 -14
  291. package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
  292. package/types/lib/inventory/fetchBatch.d.ts +83 -14
  293. package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
  294. package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
  295. package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
  296. package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
  297. package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
  298. package/types/lib/inventory/goBuildInfo.d.ts +10 -0
  299. package/types/lib/inventory/goBuildInfo.d.ts.map +1 -0
  300. package/types/lib/inventory/hbom.d.ts.map +1 -1
  301. package/types/lib/inventory/hbomAnalysis.d.ts +10 -0
  302. package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -1
  303. package/types/lib/inventory/hostTopology.d.ts.map +1 -1
  304. package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
  305. package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
  306. package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
  307. package/types/lib/inventory/osPackagePurl.d.ts +99 -0
  308. package/types/lib/inventory/osPackagePurl.d.ts.map +1 -0
  309. package/types/lib/inventory/osPackageResolver.d.ts +6 -2
  310. package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
  311. package/types/lib/inventory/osinfo.d.ts +31 -6
  312. package/types/lib/inventory/osinfo.d.ts.map +1 -1
  313. package/types/lib/inventory/osqueryTransform.d.ts +51 -0
  314. package/types/lib/inventory/osqueryTransform.d.ts.map +1 -1
  315. package/types/lib/inventory/parentSelection.d.ts +34 -0
  316. package/types/lib/inventory/parentSelection.d.ts.map +1 -0
  317. package/types/lib/inventory/phpBuildInfo.d.ts +142 -0
  318. package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -0
  319. package/types/lib/inventory/phpHostProbe.d.ts +35 -0
  320. package/types/lib/inventory/phpHostProbe.d.ts.map +1 -0
  321. package/types/lib/inventory/rootfsCerts.d.ts +27 -0
  322. package/types/lib/inventory/rootfsCerts.d.ts.map +1 -0
  323. package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -1
  324. package/types/lib/inventory/scalaCoords.d.ts +80 -0
  325. package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
  326. package/types/lib/inventory/source.d.ts +28 -0
  327. package/types/lib/inventory/source.d.ts.map +1 -1
  328. package/types/lib/inventory/spdx.d.ts +24 -0
  329. package/types/lib/inventory/spdx.d.ts.map +1 -1
  330. package/types/lib/inventory/traceRunner.d.ts +16 -1
  331. package/types/lib/inventory/traceRunner.d.ts.map +1 -1
  332. package/types/lib/inventory/tracedCrypto.d.ts +64 -0
  333. package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
  334. package/types/lib/managers/binary.d.ts +10 -0
  335. package/types/lib/managers/binary.d.ts.map +1 -1
  336. package/types/lib/managers/docker.d.ts +12 -0
  337. package/types/lib/managers/docker.d.ts.map +1 -1
  338. package/types/lib/managers/oci.d.ts +3 -1
  339. package/types/lib/managers/oci.d.ts.map +1 -1
  340. package/types/lib/parsers/cmakeCache.d.ts +16 -0
  341. package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
  342. package/types/lib/parsers/cmakeLists.d.ts +2 -1
  343. package/types/lib/parsers/cmakeLists.d.ts.map +1 -1
  344. package/types/lib/parsers/cmakePresets.d.ts +78 -0
  345. package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
  346. package/types/lib/parsers/compileCommands.d.ts +115 -0
  347. package/types/lib/parsers/compileCommands.d.ts.map +1 -0
  348. package/types/lib/parsers/email.d.ts +19 -0
  349. package/types/lib/parsers/email.d.ts.map +1 -0
  350. package/types/lib/parsers/largeJson.d.ts +13 -0
  351. package/types/lib/parsers/largeJson.d.ts.map +1 -1
  352. package/types/lib/parsers/strictJson.d.ts +46 -0
  353. package/types/lib/parsers/strictJson.d.ts.map +1 -0
  354. package/types/lib/parsers/terraformConfig.d.ts +70 -0
  355. package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
  356. package/types/lib/parsers/terraformSource.d.ts +66 -0
  357. package/types/lib/parsers/terraformSource.d.ts.map +1 -0
  358. package/types/lib/server/server.d.ts +8 -0
  359. package/types/lib/server/server.d.ts.map +1 -1
  360. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  361. package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -1
  362. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  363. package/types/lib/stages/postgen/ruleEngine.d.ts +7 -4
  364. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  365. package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
  366. package/types/lib/stages/pregen/pregen.d.ts +14 -1
  367. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  368. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  369. package/types/lib/validator/index.d.ts +8 -0
  370. package/types/lib/validator/index.d.ts.map +1 -1
  371. package/types/lib/validator/reporters/json.d.ts.map +1 -1
  372. package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
@@ -0,0 +1,652 @@
1
+ /**
2
+ * Pure parser for Terraform / OpenTofu module and provider source addresses.
3
+ *
4
+ * A module `source` argument can be a local path, a registry shorthand, a git
5
+ * URL (forced with `git::` or detected from a github.com/gitlab.com/bitbucket.org
6
+ * host or an scp-style `git@host:path` string), a mercurial URL, or an archive
7
+ * URL over http/s3/gcs. The grammar is go-getter's: an optional `<getter>::`
8
+ * prefix, a base address, an optional `//subdirectory` suffix that starts after
9
+ * the `://` of a URL when one is present, and go-getter query parameters such
10
+ * as `ref`, `rev`, `checksum` and `archive`.
11
+ *
12
+ * Source strings are untrusted and can carry credentials (URL passwords, the
13
+ * git `sshkey` parameter, S3 keys), so this module never returns the raw input.
14
+ * The `url` field is rebuilt from parsed, sanitized pieces — userinfo, query
15
+ * and fragment removed — and `displaySource` is assembled from those pieces
16
+ * only. `credentialInSource` flags that a secret-shaped parameter was present
17
+ * without repeating it.
18
+ *
19
+ * Layer 1: no filesystem, no network, no purl construction. Callers turn the
20
+ * returned plain data into components and purls.
21
+ */
22
+
23
+ export const TERRAFORM_REGISTRY_HOST = "registry.terraform.io";
24
+ export const OPENTOFU_REGISTRY_HOST = "registry.opentofu.org";
25
+
26
+ /** Getters that may be forced with a `name::` prefix. */
27
+ const FORCED_GETTERS = new Set([
28
+ "git",
29
+ "hg",
30
+ "s3",
31
+ "gcs",
32
+ "http",
33
+ "https",
34
+ "file",
35
+ ]);
36
+
37
+ /** go-getter query parameters that carry credentials (checked case-blind). */
38
+ const CREDENTIAL_QUERY_KEYS = new Set([
39
+ "sshkey",
40
+ "aws_access_key_id",
41
+ "aws_access_key_secret",
42
+ "aws_access_token",
43
+ "token",
44
+ "access_token",
45
+ "private_token",
46
+ "password",
47
+ "secret",
48
+ "sig",
49
+ "signature",
50
+ "x-amz-signature",
51
+ "x-goog-signature",
52
+ ]);
53
+
54
+ /** Registry namespace and name: alphanumeric edges, `-`/`_` inside, 1–64 chars. */
55
+ const REGISTRY_PART = /^[0-9A-Za-z](?:[0-9A-Za-z_-]{0,62}[0-9A-Za-z])?$/;
56
+ /** Registry target system: lower-case only. */
57
+ const REGISTRY_SYSTEM = /^[0-9a-z]{1,64}$/;
58
+ /** Archive filename suffixes go-getter unpacks without `?archive=`. */
59
+ const ARCHIVE_EXTENSIONS = [
60
+ ".zip",
61
+ ".tar",
62
+ ".tar.gz",
63
+ ".tgz",
64
+ ".tar.bz2",
65
+ ".tbz2",
66
+ ".tar.xz",
67
+ ".txz",
68
+ ];
69
+ /** `?checksum=` algorithms and the hex length each digest must have. */
70
+ const CHECKSUM_ALGORITHMS = {
71
+ md5: { alg: "MD5", length: 32 },
72
+ sha1: { alg: "SHA-1", length: 40 },
73
+ sha256: { alg: "SHA-256", length: 64 },
74
+ sha512: { alg: "SHA-512", length: 128 },
75
+ };
76
+ const HEX_DIGEST = /^[0-9a-f]+$/i;
77
+ /** A bare or `=`-prefixed single semver-ish clause. */
78
+ const EXACT_VERSION =
79
+ /^v?[0-9]+(?:\.[0-9]+){0,2}(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
80
+ /** A version-shaped git ref; the suffix must start with `-` or `+`. */
81
+ const VCS_TAG = /^v?[0-9]+(?:\.[0-9]+)*(?:[-+][0-9A-Za-z.-]+)?$/;
82
+ /** Windows drive roots such as `C:\` or `C:/`. */
83
+ const DRIVE_ROOT = /^[A-Za-z]:[\\/]/;
84
+ const GIT_HOSTS = new Set(["github.com", "gitlab.com", "bitbucket.org"]);
85
+
86
+ /**
87
+ * Parse a module `source` argument into a classified descriptor.
88
+ *
89
+ * @param {string} source Module source string as written in the configuration
90
+ * @param {Object} [options]
91
+ * @param {string} [options.defaultRegistryHost] Host for 3-segment registry
92
+ * shorthand (`registry.terraform.io` unless the caller knows better)
93
+ * @returns {null|Object} `null` for non-strings, otherwise a descriptor whose
94
+ * `kind` is `local`, `registry`, `git`, `hg`, `http`, `s3`, `gcs`, `file` or
95
+ * `unknown`
96
+ */
97
+ export function parseModuleSource(source, { defaultRegistryHost } = {}) {
98
+ const defaultHost = defaultRegistryHost || TERRAFORM_REGISTRY_HOST;
99
+ if (typeof source !== "string") {
100
+ return null;
101
+ }
102
+ const text = source.trim();
103
+ if (!text) {
104
+ return { kind: "unknown", credentialInSource: false };
105
+ }
106
+
107
+ // Local sources stay inside the calling package and are never components.
108
+ if (
109
+ text === "." ||
110
+ text === ".." ||
111
+ text.startsWith("./") ||
112
+ text.startsWith("../") ||
113
+ text.startsWith(".\\") ||
114
+ text.startsWith("..\\")
115
+ ) {
116
+ return {
117
+ kind: "local",
118
+ path: text,
119
+ credentialInSource: false,
120
+ displaySource: text,
121
+ };
122
+ }
123
+
124
+ // Absolute paths (and drive roots) are file sources; callers never emit them.
125
+ if (text.startsWith("/") || text.startsWith("\\") || DRIVE_ROOT.test(text)) {
126
+ return { kind: "file", credentialInSource: false };
127
+ }
128
+
129
+ // Forced getter prefix.
130
+ let getter;
131
+ let rest = text;
132
+ const dd = text.indexOf("::");
133
+ if (dd >= 0) {
134
+ const prefix = text.slice(0, dd).toLowerCase();
135
+ if (!FORCED_GETTERS.has(prefix)) {
136
+ return { kind: "unknown", credentialInSource: false };
137
+ }
138
+ getter = prefix;
139
+ rest = text.slice(dd + 2);
140
+ }
141
+
142
+ // Split the `//subdirectory` marker and the query string off the base, the
143
+ // way go-getter's SourceDirSubdir does. The marker is only searched for
144
+ // before the first `?` — a query value may itself contain `//` (a URL, or
145
+ // a base64 token) and must never become a subdirectory, because the
146
+ // subdirectory is published while the query is not. The search also starts
147
+ // after `://`, so a URL's scheme slashes do not count. A query found on the
148
+ // subdirectory belongs to the base URL.
149
+ const firstQuery = rest.indexOf("?");
150
+ const stop = firstQuery >= 0 ? firstQuery : rest.length;
151
+ const schemeAt = rest.slice(0, stop).indexOf("://");
152
+ const searchFrom = schemeAt >= 0 ? schemeAt + 3 : 0;
153
+ const marker = rest.slice(0, stop).indexOf("//", searchFrom);
154
+ let base = rest;
155
+ let rawSubdir;
156
+ if (marker >= 0) {
157
+ const tail = rest.slice(marker + 2);
158
+ const queryAt = tail.indexOf("?");
159
+ if (queryAt >= 0) {
160
+ rawSubdir = tail.slice(0, queryAt);
161
+ base = rest.slice(0, marker) + tail.slice(queryAt);
162
+ } else {
163
+ rawSubdir = tail;
164
+ base = rest.slice(0, marker);
165
+ }
166
+ }
167
+ const queryAt = base.indexOf("?");
168
+ const address = queryAt >= 0 ? base.slice(0, queryAt) : base;
169
+ const queryString = queryAt >= 0 ? base.slice(queryAt + 1) : "";
170
+
171
+ // Query parameters: keep the identity-relevant ones, flag the secret-shaped
172
+ // ones without ever copying their values.
173
+ const params = new URLSearchParams(queryString);
174
+ const refParam = params.get("ref");
175
+ const revParam = params.get("rev");
176
+ const checksumParam = params.get("checksum");
177
+ const archiveParam = params.has("archive");
178
+ let credentialInSource = false;
179
+ for (const key of params.keys()) {
180
+ if (CREDENTIAL_QUERY_KEYS.has(key.toLowerCase())) {
181
+ credentialInSource = true;
182
+ break;
183
+ }
184
+ }
185
+
186
+ // Normalize the subdirectory: forward slashes, no outer slashes. A `..`
187
+ // segment escapes the package, so the source is unusable.
188
+ let subdir;
189
+ if (rawSubdir !== undefined) {
190
+ const segments = rawSubdir.replace(/\\/g, "/").split("/").filter(Boolean);
191
+ if (segments.includes("..")) {
192
+ return { kind: "unknown", credentialInSource };
193
+ }
194
+ if (segments.length) {
195
+ subdir = segments.join("/");
196
+ }
197
+ }
198
+
199
+ const result = {
200
+ kind: "unknown",
201
+ credentialInSource,
202
+ ...(subdir ? { subdir } : {}),
203
+ };
204
+
205
+ if (getter) {
206
+ fillForcedGetter(result, getter, address);
207
+ } else {
208
+ fillDetectedSource(result, address, defaultHost);
209
+ }
210
+ if (result.kind === "unknown") {
211
+ return result;
212
+ }
213
+ if (result.kind === "hg") {
214
+ result.ref = revParam ?? refParam ?? result.ref;
215
+ } else if (result.kind === "git") {
216
+ result.ref = refParam ?? result.ref;
217
+ }
218
+ if (checksumParam && !result.checksum) {
219
+ const checksum = parseChecksumParam(checksumParam);
220
+ if (checksum) {
221
+ result.checksum = checksum;
222
+ }
223
+ }
224
+ if (archiveParam && !result.archive) {
225
+ result.archive = true;
226
+ }
227
+ if (!result.archive && result.url) {
228
+ const lower = result.url.toLowerCase();
229
+ if (ARCHIVE_EXTENSIONS.some((ext) => lower.endsWith(ext))) {
230
+ result.archive = true;
231
+ }
232
+ }
233
+ result.displaySource = buildDisplaySource(result);
234
+ return result;
235
+ }
236
+
237
+ /**
238
+ * Classify an address that had no `<getter>::` prefix.
239
+ *
240
+ * @param {Object} result Descriptor under construction, mutated
241
+ * @param {string} address Base address without subdirectory or query
242
+ * @param {string} defaultHost Registry host for 3-segment shorthand
243
+ */
244
+ function fillDetectedSource(result, address, defaultHost) {
245
+ const segments = address.split("/");
246
+ const host = (segments[0] || "").toLowerCase();
247
+ if (GIT_HOSTS.has(host) && segments.length >= 3 && segments[1]) {
248
+ // go-getter turns `github.com/o/r/x/y` into the repo plus `//x/y`.
249
+ const repo = segments[2].replace(/\.git$/i, "");
250
+ result.kind = "git";
251
+ result.url = sanitizeUrl(
252
+ `https://${segments[0]}/${segments[1]}/${repo}.git`,
253
+ );
254
+ const extra = segments.slice(3).filter(Boolean).join("/");
255
+ if (extra) {
256
+ result.subdir = result.subdir ? `${result.subdir}/${extra}` : extra;
257
+ }
258
+ return;
259
+ }
260
+ if (address.startsWith("git@")) {
261
+ const scp = parseScpSource(address);
262
+ if (scp) {
263
+ result.kind = "git";
264
+ result.url = scp.url;
265
+ result.credentialInSource = result.credentialInSource || scp.hasPassword;
266
+ return;
267
+ }
268
+ }
269
+ if (address.startsWith("http://") || address.startsWith("https://")) {
270
+ const parsed = parseWebUrl(address);
271
+ if (parsed) {
272
+ result.kind = parsed.kind;
273
+ result.url = parsed.url;
274
+ result.credentialInSource =
275
+ result.credentialInSource || parsed.hasPassword;
276
+ return;
277
+ }
278
+ return;
279
+ }
280
+ const registry = matchRegistryAddress(address, defaultHost);
281
+ if (registry) {
282
+ result.kind = "registry";
283
+ Object.assign(result, registry);
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Interpret the base address of a `<getter>::` source.
289
+ *
290
+ * @param {Object} result Descriptor under construction, mutated
291
+ * @param {string} getter Forced getter name
292
+ * @param {string} address Base address without subdirectory or query
293
+ */
294
+ function fillForcedGetter(result, getter, address) {
295
+ if (getter === "file") {
296
+ result.kind = "file";
297
+ return;
298
+ }
299
+ if (getter === "git") {
300
+ if (address.startsWith("file://")) {
301
+ result.kind = "file";
302
+ return;
303
+ }
304
+ if (isWebOrGitScheme(address)) {
305
+ result.kind = "git";
306
+ result.url = sanitizeUrl(address);
307
+ result.credentialInSource =
308
+ result.credentialInSource || urlHasPassword(address);
309
+ return;
310
+ }
311
+ const scp = parseScpSource(address);
312
+ if (scp) {
313
+ result.kind = "git";
314
+ result.url = scp.url;
315
+ result.credentialInSource = result.credentialInSource || scp.hasPassword;
316
+ }
317
+ return;
318
+ }
319
+ if (getter === "hg") {
320
+ if (isWebOrGitScheme(address)) {
321
+ result.kind = "hg";
322
+ result.url = sanitizeUrl(address);
323
+ result.credentialInSource =
324
+ result.credentialInSource || urlHasPassword(address);
325
+ }
326
+ return;
327
+ }
328
+ if (getter === "s3" || getter === "gcs" || getter === "http") {
329
+ if (address.startsWith("http://") || address.startsWith("https://")) {
330
+ result.kind = getter === "s3" || getter === "gcs" ? getter : "http";
331
+ result.url = sanitizeUrl(address);
332
+ result.credentialInSource =
333
+ result.credentialInSource || urlHasPassword(address);
334
+ }
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Parse an `http(s)` address, mapping S3 and GCS hosts to their kinds.
340
+ *
341
+ * @param {string} address Base address
342
+ * @returns {null|{kind: string, url: string|undefined, hasPassword: boolean}}
343
+ */
344
+ function parseWebUrl(address) {
345
+ let parsed;
346
+ try {
347
+ parsed = new URL(address);
348
+ } catch {
349
+ return null;
350
+ }
351
+ const host = parsed.hostname.toLowerCase();
352
+ let kind = "http";
353
+ if (host.endsWith(".amazonaws.com")) {
354
+ kind = "s3";
355
+ } else if (
356
+ host === "www.googleapis.com" &&
357
+ parsed.pathname.startsWith("/storage/")
358
+ ) {
359
+ kind = "gcs";
360
+ }
361
+ return {
362
+ kind,
363
+ url: sanitizeUrl(address),
364
+ hasPassword: urlHasPassword(address),
365
+ };
366
+ }
367
+
368
+ /**
369
+ * Whether a URL's userinfo carries a credential: a password, or a username
370
+ * that hides one behind a percent-encoded colon (`user%3Atoken@host`), which
371
+ * git and go-getter decode back into `user:token`. A bare username is not a
372
+ * secret and is dropped silently.
373
+ *
374
+ * @param {string} address Absolute URL
375
+ * @returns {boolean}
376
+ */
377
+ function urlHasPassword(address) {
378
+ try {
379
+ const parsed = new URL(address);
380
+ return (
381
+ parsed.password !== "" || parsed.username.toLowerCase().includes("%3a")
382
+ );
383
+ } catch {
384
+ return false;
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Whether the address is an http, https, ssh or git URL.
390
+ *
391
+ * @param {string} address Base address
392
+ * @returns {boolean}
393
+ */
394
+ function isWebOrGitScheme(address) {
395
+ return (
396
+ address.startsWith("https://") ||
397
+ address.startsWith("http://") ||
398
+ address.startsWith("ssh://") ||
399
+ address.startsWith("git://")
400
+ );
401
+ }
402
+
403
+ /**
404
+ * Convert an scp-style `user[:password]@host:path` string to an ssh URL.
405
+ *
406
+ * @param {string} address Base address
407
+ * @returns {null|{url: string, hasPassword: boolean}}
408
+ */
409
+ function parseScpSource(address) {
410
+ const at = address.lastIndexOf("@");
411
+ if (at < 0) {
412
+ return null;
413
+ }
414
+ const userInfo = address.slice(0, at);
415
+ const hostPart = address.slice(at + 1);
416
+ const colon = hostPart.indexOf(":");
417
+ if (colon < 0) {
418
+ return null;
419
+ }
420
+ const host = hostPart.slice(0, colon);
421
+ const path = hostPart.slice(colon + 1);
422
+ if (!host || !path || host.includes("/")) {
423
+ return null;
424
+ }
425
+ return {
426
+ url: sanitizeUrl(`ssh://${host}/${path}`),
427
+ hasPassword:
428
+ userInfo.includes(":") || userInfo.toLowerCase().includes("%3a"),
429
+ };
430
+ }
431
+
432
+ /**
433
+ * Strip userinfo, query and fragment from a URL.
434
+ *
435
+ * The conversion of scp forms to `ssh://` happens before this runs, because a
436
+ * generic URL sanitizer keeps userinfo when it cannot parse an authority.
437
+ *
438
+ * @param {string} address Absolute URL
439
+ * @returns {string|undefined} Sanitized URL
440
+ */
441
+ function sanitizeUrl(address) {
442
+ try {
443
+ const parsed = new URL(address);
444
+ parsed.username = "";
445
+ parsed.password = "";
446
+ parsed.search = "";
447
+ parsed.hash = "";
448
+ return parsed.toString();
449
+ } catch {
450
+ return undefined;
451
+ }
452
+ }
453
+
454
+ /**
455
+ * Match a registry module address: `[host/]namespace/name/system`.
456
+ *
457
+ * @param {string} address Base address
458
+ * @param {string} defaultHost Host for the 3-segment form
459
+ * @returns {null|{host: string, namespace: string, name: string, system: string, address: string}}
460
+ */
461
+ function matchRegistryAddress(address, defaultHost) {
462
+ const segments = address.split("/");
463
+ if (segments.length !== 3 && segments.length !== 4) {
464
+ return null;
465
+ }
466
+ let host = null;
467
+ const hasHost = segments.length === 4;
468
+ if (hasHost) {
469
+ let rawHost = segments[0];
470
+ let port = "";
471
+ const colon = rawHost.indexOf(":");
472
+ if (colon >= 0) {
473
+ port = rawHost.slice(colon + 1);
474
+ if (!/^[0-9]{1,5}$/.test(port)) {
475
+ return null;
476
+ }
477
+ rawHost = rawHost.slice(0, colon);
478
+ }
479
+ host = rawHost.toLowerCase();
480
+ if (!host.includes(".") && host !== "localhost") {
481
+ return null;
482
+ }
483
+ // The port is part of the registry's identity: two registries on one
484
+ // host are different sources.
485
+ if (port) {
486
+ host = `${host}:${port}`;
487
+ }
488
+ } else if (segments.some((segment) => segment.includes(":"))) {
489
+ return null;
490
+ }
491
+ const ns = segments[hasHost ? 1 : 0];
492
+ const name = segments[hasHost ? 2 : 1];
493
+ const system = segments[hasHost ? 3 : 2];
494
+ if (
495
+ !REGISTRY_PART.test(ns) ||
496
+ !REGISTRY_PART.test(name) ||
497
+ !REGISTRY_SYSTEM.test(system)
498
+ ) {
499
+ return null;
500
+ }
501
+ const fullHost = (host || defaultHost).toLowerCase();
502
+ const lowerNs = ns.toLowerCase();
503
+ const lowerName = name.toLowerCase();
504
+ const lowerSystem = system.toLowerCase();
505
+ return {
506
+ host: fullHost,
507
+ namespace: lowerNs,
508
+ name: lowerName,
509
+ system: lowerSystem,
510
+ address: `${fullHost}/${lowerNs}/${lowerName}/${lowerSystem}`,
511
+ };
512
+ }
513
+
514
+ /**
515
+ * Parse a `?checksum=<alg>:<hex>` parameter.
516
+ *
517
+ * @param {string} value Raw parameter value
518
+ * @returns {null|{alg: string, content: string}} Digest descriptor
519
+ */
520
+ function parseChecksumParam(value) {
521
+ const colon = value.indexOf(":");
522
+ if (colon < 0) {
523
+ return null;
524
+ }
525
+ const spec = CHECKSUM_ALGORITHMS[value.slice(0, colon).toLowerCase()];
526
+ const hex = value.slice(colon + 1);
527
+ if (!spec || hex.length !== spec.length || !HEX_DIGEST.test(hex)) {
528
+ return null;
529
+ }
530
+ return { alg: spec.alg, content: hex.toLowerCase() };
531
+ }
532
+
533
+ /**
534
+ * Build the sanitized display form Terraform itself uses in `modules.json`.
535
+ *
536
+ * @param {Object} result Classified descriptor
537
+ * @returns {string|undefined} Display source
538
+ */
539
+ function buildDisplaySource(result) {
540
+ let base;
541
+ if (result.kind === "registry") {
542
+ base = result.address;
543
+ } else if (["git", "hg", "s3", "gcs"].includes(result.kind) && result.url) {
544
+ base = `${result.kind}::${result.url}`;
545
+ } else if (result.kind === "http" && result.url) {
546
+ base = result.url;
547
+ } else {
548
+ return undefined;
549
+ }
550
+ return result.subdir ? `${base}//${result.subdir}` : base;
551
+ }
552
+
553
+ /**
554
+ * Parse a `required_providers` source string into a provider address.
555
+ *
556
+ * @param {string} source Provider source such as `hashicorp/aws` or
557
+ * `registry.terraform.io/hashicorp/aws`
558
+ * @param {Object} [options]
559
+ * @param {string} [options.defaultRegistryHost] Host for 2-segment shorthand
560
+ * @returns {null|Object} `{ host, namespace, type, address }` lower-cased,
561
+ * `{ builtin: true }` for `terraform.io/builtin/*`, or `null`
562
+ */
563
+ export function parseProviderSource(source, { defaultRegistryHost } = {}) {
564
+ const defaultHost = defaultRegistryHost || TERRAFORM_REGISTRY_HOST;
565
+ if (typeof source !== "string") {
566
+ return null;
567
+ }
568
+ const text = source.trim();
569
+ if (!text || text.includes("::")) {
570
+ return null;
571
+ }
572
+ if (text.toLowerCase().startsWith("terraform.io/builtin/")) {
573
+ return { builtin: true };
574
+ }
575
+ const segments = text.split("/");
576
+ let host;
577
+ let namespace;
578
+ let type;
579
+ if (segments.length === 2) {
580
+ host = defaultHost;
581
+ namespace = segments[0];
582
+ type = segments[1];
583
+ } else if (segments.length === 3) {
584
+ host = segments[0].toLowerCase();
585
+ if (!host.includes(".") && host !== "localhost") {
586
+ return null;
587
+ }
588
+ namespace = segments[1];
589
+ type = segments[2];
590
+ } else {
591
+ return null;
592
+ }
593
+ if (!REGISTRY_PART.test(namespace) || !REGISTRY_PART.test(type)) {
594
+ return null;
595
+ }
596
+ const fullHost = host.toLowerCase();
597
+ const lowerNs = namespace.toLowerCase();
598
+ const lowerType = type.toLowerCase();
599
+ return {
600
+ host: fullHost,
601
+ namespace: lowerNs,
602
+ type: lowerType,
603
+ address: `${fullHost}/${lowerNs}/${lowerType}`,
604
+ };
605
+ }
606
+
607
+ /**
608
+ * Classify a module `version` constraint by how tightly it pins.
609
+ *
610
+ * @param {string} constraint Constraint string from the configuration
611
+ * @returns {Object} `{ pinning: "exact", version }`, `{ pinning: "range" }` or
612
+ * `{ pinning: "none" }`
613
+ */
614
+ export function classifyVersionConstraint(constraint) {
615
+ if (typeof constraint !== "string" || !constraint.trim()) {
616
+ return { pinning: "none" };
617
+ }
618
+ const clauses = constraint.split(",").map((clause) => clause.trim());
619
+ if (clauses.length !== 1) {
620
+ return { pinning: "range" };
621
+ }
622
+ let clause = clauses[0];
623
+ if (clause.startsWith("=")) {
624
+ clause = clause.slice(1).trim();
625
+ }
626
+ if (clause && EXACT_VERSION.test(clause)) {
627
+ return { pinning: "exact", version: clause };
628
+ }
629
+ return { pinning: "range" };
630
+ }
631
+
632
+ /**
633
+ * Classify a git/hg ref by how immutably it identifies a commit.
634
+ *
635
+ * @param {string} ref Ref value from `?ref=` or `?rev=`
636
+ * @returns {"sha"|"tag"|"branch"|"none"}
637
+ */
638
+ export function classifyVcsRef(ref) {
639
+ if (typeof ref !== "string" || !ref) {
640
+ return "none";
641
+ }
642
+ if (ref.length > 255) {
643
+ return "branch";
644
+ }
645
+ if (/^[0-9a-f]{40}$/i.test(ref) || /^[0-9a-f]{64}$/i.test(ref)) {
646
+ return "sha";
647
+ }
648
+ if (VCS_TAG.test(ref)) {
649
+ return "tag";
650
+ }
651
+ return "branch";
652
+ }