@intentius/chant-lexicon-terraform 0.124.54 → 0.124.56

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 (351) hide show
  1. package/README.md +7 -4
  2. package/dist/ci-setup.d.ts +11 -0
  3. package/dist/ci-setup.d.ts.map +1 -0
  4. package/dist/ci-setup.js +41 -0
  5. package/dist/components/capability-plugin.d.ts +40 -6
  6. package/dist/components/capability-plugin.d.ts.map +1 -1
  7. package/dist/components/capability-plugin.js +174 -30
  8. package/dist/components/compose-group.d.ts +1 -1
  9. package/dist/components/compose-group.d.ts.map +1 -1
  10. package/dist/components/compose-group.js +1 -1
  11. package/dist/components/release-inputs.d.ts +29 -0
  12. package/dist/components/release-inputs.d.ts.map +1 -0
  13. package/dist/components/release-inputs.js +57 -0
  14. package/dist/components/trace-facts.d.ts +16 -0
  15. package/dist/components/trace-facts.d.ts.map +1 -0
  16. package/dist/components/trace-facts.js +19 -0
  17. package/dist/cone.d.ts +53 -0
  18. package/dist/cone.d.ts.map +1 -0
  19. package/dist/cone.js +119 -0
  20. package/dist/cost-hold.d.ts +27 -0
  21. package/dist/cost-hold.d.ts.map +1 -0
  22. package/dist/cost-hold.js +21 -0
  23. package/dist/drift-rows.d.ts +61 -0
  24. package/dist/drift-rows.d.ts.map +1 -0
  25. package/dist/drift-rows.js +108 -0
  26. package/dist/exit-codes.d.ts +55 -0
  27. package/dist/exit-codes.d.ts.map +1 -0
  28. package/dist/exit-codes.js +48 -0
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +3 -0
  32. package/dist/integrity.json +7 -4
  33. package/dist/lint/audit-catalog.d.ts.map +1 -1
  34. package/dist/lint/audit-catalog.js +27 -3
  35. package/dist/lint/audit-lineage.d.ts +14 -2
  36. package/dist/lint/audit-lineage.d.ts.map +1 -1
  37. package/dist/lint/post-synth/index.d.ts.map +1 -1
  38. package/dist/lint/post-synth/index.js +4 -0
  39. package/dist/lint/post-synth/record-store.d.ts +54 -0
  40. package/dist/lint/post-synth/record-store.d.ts.map +1 -0
  41. package/dist/lint/post-synth/record-store.js +104 -0
  42. package/dist/lint/post-synth/tf001.d.ts +2 -2
  43. package/dist/lint/post-synth/tf001.js +2 -2
  44. package/dist/lint/post-synth/tf024.d.ts +35 -11
  45. package/dist/lint/post-synth/tf024.d.ts.map +1 -1
  46. package/dist/lint/post-synth/tf024.js +92 -20
  47. package/dist/lint/post-synth/tf046.d.ts +64 -0
  48. package/dist/lint/post-synth/tf046.d.ts.map +1 -0
  49. package/dist/lint/post-synth/tf046.js +175 -0
  50. package/dist/lint/post-synth/tf047.d.ts +36 -0
  51. package/dist/lint/post-synth/tf047.d.ts.map +1 -0
  52. package/dist/lint/post-synth/tf047.js +94 -0
  53. package/dist/lock-rows.d.ts +36 -0
  54. package/dist/lock-rows.d.ts.map +1 -0
  55. package/dist/lock-rows.js +60 -0
  56. package/dist/lock-timeout.d.ts +22 -0
  57. package/dist/lock-timeout.d.ts.map +1 -0
  58. package/dist/lock-timeout.js +32 -0
  59. package/dist/manifest.json +1 -1
  60. package/dist/module-catalog/index.d.ts +69 -0
  61. package/dist/module-catalog/index.d.ts.map +1 -0
  62. package/dist/module-catalog/index.js +110 -0
  63. package/dist/module-catalog/refresh-cli.d.ts +4 -0
  64. package/dist/module-catalog/refresh-cli.d.ts.map +1 -0
  65. package/dist/module-catalog/refresh-cli.js +64 -0
  66. package/dist/module-catalog/static-tier.d.ts +6 -0
  67. package/dist/module-catalog/static-tier.d.ts.map +1 -0
  68. package/dist/module-catalog/static-tier.js +1650 -0
  69. package/dist/module-catalog/types.d.ts +65 -0
  70. package/dist/module-catalog/types.d.ts.map +1 -0
  71. package/dist/module-catalog/types.js +33 -0
  72. package/dist/okf/index.md +3 -1
  73. package/dist/okf/rules/TF024.md +2 -2
  74. package/dist/okf/rules/TF046.md +11 -0
  75. package/dist/okf/rules/TF047.md +11 -0
  76. package/dist/op/activities/terraform.d.ts +29 -0
  77. package/dist/op/activities/terraform.d.ts.map +1 -1
  78. package/dist/op/activities/terraform.js +19 -4
  79. package/dist/pin/consumers.d.ts +35 -0
  80. package/dist/pin/consumers.d.ts.map +1 -0
  81. package/dist/pin/consumers.js +70 -0
  82. package/dist/plugin.d.ts.map +1 -1
  83. package/dist/plugin.js +5 -0
  84. package/dist/registry/address.d.ts +63 -0
  85. package/dist/registry/address.d.ts.map +1 -0
  86. package/dist/registry/address.js +65 -0
  87. package/dist/registry/catalog-read.d.ts +14 -0
  88. package/dist/registry/catalog-read.d.ts.map +1 -0
  89. package/dist/registry/catalog-read.js +58 -0
  90. package/dist/registry/deprecated.d.ts +37 -0
  91. package/dist/registry/deprecated.d.ts.map +1 -0
  92. package/dist/registry/deprecated.js +43 -0
  93. package/dist/registry/docs.d.ts +96 -0
  94. package/dist/registry/docs.d.ts.map +1 -0
  95. package/dist/registry/docs.js +210 -0
  96. package/dist/registry/edge/edge.d.ts +46 -0
  97. package/dist/registry/edge/edge.d.ts.map +1 -0
  98. package/dist/registry/edge/edge.js +194 -0
  99. package/dist/registry/edge/index.d.ts +11 -0
  100. package/dist/registry/edge/index.d.ts.map +1 -0
  101. package/dist/registry/edge/index.js +10 -0
  102. package/dist/registry/edge/lambda-edge.d.ts +76 -0
  103. package/dist/registry/edge/lambda-edge.d.ts.map +1 -0
  104. package/dist/registry/edge/lambda-edge.js +95 -0
  105. package/dist/registry/edge/sigv4-web.d.ts +33 -0
  106. package/dist/registry/edge/sigv4-web.d.ts.map +1 -0
  107. package/dist/registry/edge/sigv4-web.js +56 -0
  108. package/dist/registry/edge/token-source.d.ts +73 -0
  109. package/dist/registry/edge/token-source.d.ts.map +1 -0
  110. package/dist/registry/edge/token-source.js +115 -0
  111. package/dist/registry/edge/worker.d.ts +45 -0
  112. package/dist/registry/edge/worker.d.ts.map +1 -0
  113. package/dist/registry/edge/worker.js +26 -0
  114. package/dist/registry/handler.d.ts +25 -0
  115. package/dist/registry/handler.d.ts.map +1 -0
  116. package/dist/registry/handler.js +75 -0
  117. package/dist/registry/headers-file.d.ts +21 -0
  118. package/dist/registry/headers-file.d.ts.map +1 -0
  119. package/dist/registry/headers-file.js +57 -0
  120. package/dist/registry/index.d.ts +31 -0
  121. package/dist/registry/index.d.ts.map +1 -0
  122. package/dist/registry/index.js +30 -0
  123. package/dist/registry/mirror-paths.d.ts +9 -0
  124. package/dist/registry/mirror-paths.d.ts.map +1 -0
  125. package/dist/registry/mirror-paths.js +8 -0
  126. package/dist/registry/mirror.d.ts +130 -0
  127. package/dist/registry/mirror.d.ts.map +1 -0
  128. package/dist/registry/mirror.js +319 -0
  129. package/dist/registry/proxies.d.ts +73 -0
  130. package/dist/registry/proxies.d.ts.map +1 -0
  131. package/dist/registry/proxies.js +111 -0
  132. package/dist/registry/reader.d.ts +57 -0
  133. package/dist/registry/reader.d.ts.map +1 -0
  134. package/dist/registry/reader.js +198 -0
  135. package/dist/registry/semver.d.ts +16 -0
  136. package/dist/registry/semver.d.ts.map +1 -0
  137. package/dist/registry/semver.js +24 -0
  138. package/dist/registry/serve.d.ts +24 -0
  139. package/dist/registry/serve.d.ts.map +1 -0
  140. package/dist/registry/serve.js +64 -0
  141. package/dist/registry/source-forms.d.ts +79 -0
  142. package/dist/registry/source-forms.d.ts.map +1 -0
  143. package/dist/registry/source-forms.js +202 -0
  144. package/dist/registry/targets/artifactory.d.ts +28 -0
  145. package/dist/registry/targets/artifactory.d.ts.map +1 -0
  146. package/dist/registry/targets/artifactory.js +206 -0
  147. package/dist/registry/targets/fake-artifactory.d.ts +30 -0
  148. package/dist/registry/targets/fake-artifactory.d.ts.map +1 -0
  149. package/dist/registry/targets/fake-artifactory.js +142 -0
  150. package/dist/registry/targets/fake-gitlab.d.ts +39 -0
  151. package/dist/registry/targets/fake-gitlab.d.ts.map +1 -0
  152. package/dist/registry/targets/fake-gitlab.js +136 -0
  153. package/dist/registry/targets/fake-hcp.d.ts +50 -0
  154. package/dist/registry/targets/fake-hcp.d.ts.map +1 -0
  155. package/dist/registry/targets/fake-hcp.js +202 -0
  156. package/dist/registry/targets/fake-http.d.ts +31 -0
  157. package/dist/registry/targets/fake-http.d.ts.map +1 -0
  158. package/dist/registry/targets/fake-http.js +87 -0
  159. package/dist/registry/targets/fake-nexus.d.ts +27 -0
  160. package/dist/registry/targets/fake-nexus.d.ts.map +1 -0
  161. package/dist/registry/targets/fake-nexus.js +137 -0
  162. package/dist/registry/targets/gitlab.d.ts +53 -0
  163. package/dist/registry/targets/gitlab.d.ts.map +1 -0
  164. package/dist/registry/targets/gitlab.js +187 -0
  165. package/dist/registry/targets/hcp.d.ts +29 -0
  166. package/dist/registry/targets/hcp.d.ts.map +1 -0
  167. package/dist/registry/targets/hcp.js +310 -0
  168. package/dist/registry/targets/hosted.d.ts +62 -0
  169. package/dist/registry/targets/hosted.d.ts.map +1 -0
  170. package/dist/registry/targets/hosted.js +74 -0
  171. package/dist/registry/targets/index.d.ts +18 -0
  172. package/dist/registry/targets/index.d.ts.map +1 -0
  173. package/dist/registry/targets/index.js +17 -0
  174. package/dist/registry/targets/module-target.d.ts +68 -0
  175. package/dist/registry/targets/module-target.d.ts.map +1 -0
  176. package/dist/registry/targets/module-target.js +63 -0
  177. package/dist/registry/targets/nexus.d.ts +43 -0
  178. package/dist/registry/targets/nexus.d.ts.map +1 -0
  179. package/dist/registry/targets/nexus.js +250 -0
  180. package/dist/registry/targets/zip.d.ts +55 -0
  181. package/dist/registry/targets/zip.d.ts.map +1 -0
  182. package/dist/registry/targets/zip.js +278 -0
  183. package/dist/registry/writer.d.ts +101 -0
  184. package/dist/registry/writer.d.ts.map +1 -0
  185. package/dist/registry/writer.js +109 -0
  186. package/dist/rules/record-store.ts +122 -0
  187. package/dist/rules/tf001.ts +2 -2
  188. package/dist/rules/tf024.ts +105 -22
  189. package/dist/rules/tf046.ts +204 -0
  190. package/dist/rules/tf047.ts +114 -0
  191. package/dist/state/azure-blob.d.ts +8 -67
  192. package/dist/state/azure-blob.d.ts.map +1 -1
  193. package/dist/state/azure-blob.js +6 -199
  194. package/dist/state/gcs.d.ts +7 -61
  195. package/dist/state/gcs.d.ts.map +1 -1
  196. package/dist/state/gcs.js +5 -222
  197. package/dist/state/object-store.d.ts +4 -33
  198. package/dist/state/object-store.d.ts.map +1 -1
  199. package/dist/state/object-store.js +4 -17
  200. package/dist/state/s3.d.ts +11 -58
  201. package/dist/state/s3.d.ts.map +1 -1
  202. package/dist/state/s3.js +10 -161
  203. package/dist/state/store.js +2 -2
  204. package/dist/state-ops.d.ts +255 -0
  205. package/dist/state-ops.d.ts.map +1 -0
  206. package/dist/state-ops.js +305 -0
  207. package/dist/state-reads.d.ts +57 -0
  208. package/dist/state-reads.d.ts.map +1 -0
  209. package/dist/state-reads.js +104 -0
  210. package/dist/used-sources.d.ts +54 -0
  211. package/dist/used-sources.d.ts.map +1 -0
  212. package/dist/used-sources.js +157 -0
  213. package/package.json +19 -3
  214. package/src/__fixtures__/drift-record/README.md +5 -0
  215. package/src/__fixtures__/drift-rows/live-root-plan.json +70 -0
  216. package/src/__fixtures__/drift-rows/refresh-plan.json +61 -0
  217. package/src/__fixtures__/used-sources/root/extra.tofu +1 -0
  218. package/src/__fixtures__/used-sources/root/main.tf +31 -0
  219. package/src/__fixtures__/used-sources/root/modules/net/main.tf +14 -0
  220. package/src/__fixtures__/used-sources/root/modules/net/versions.tf.json +7 -0
  221. package/src/__fixtures__/used-sources/unit/terragrunt.hcl +3 -0
  222. package/src/ci-setup.ts +42 -0
  223. package/src/components/capability-plugin.test.ts +26 -14
  224. package/src/components/capability-plugin.ts +185 -31
  225. package/src/components/compose-group.ts +1 -1
  226. package/src/components/pr-loop-compose.tofu.e2e.test.ts +1 -1
  227. package/src/components/pr-loop.tofu.test.ts +1 -1
  228. package/src/components/release-inputs.ts +69 -0
  229. package/src/components/trace-facts.test.ts +21 -0
  230. package/src/components/trace-facts.ts +27 -0
  231. package/src/cone.ts +138 -0
  232. package/src/cost-hold.ts +29 -0
  233. package/src/describe-resources.engine-facts.test.ts +2 -3
  234. package/src/drift-rows.test.ts +135 -0
  235. package/src/drift-rows.ts +137 -0
  236. package/src/exit-codes.test.ts +23 -0
  237. package/src/exit-codes.ts +59 -0
  238. package/src/index.ts +3 -0
  239. package/src/lint/audit-catalog.ts +29 -3
  240. package/src/lint/audit-lineage.ts +14 -2
  241. package/src/lint/post-synth/fixtures/TF024/live-with-record-store/main.tf +18 -0
  242. package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/estate.chdf.hcl +1 -0
  243. package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/main.tf +10 -0
  244. package/src/lint/post-synth/fixtures/TF046/azurerm-no-resource-group/main.tf +15 -0
  245. package/src/lint/post-synth/fixtures/TF046/backend-config-only/main.tf +14 -0
  246. package/src/lint/post-synth/fixtures/TF046/derived-s3/backend.tf +7 -0
  247. package/src/lint/post-synth/fixtures/TF046/derived-s3/main.tf +9 -0
  248. package/src/lint/post-synth/fixtures/TF046/explicit-local/main.tf +16 -0
  249. package/src/lint/post-synth/fixtures/TF046/explicit-s3-beside-local-backend/main.tf +15 -0
  250. package/src/lint/post-synth/fixtures/TF046/implied-local/main.tf +9 -0
  251. package/src/lint/post-synth/fixtures/TF046/sidecar-implied/estate.chdf.hcl +1 -0
  252. package/src/lint/post-synth/fixtures/TF046/sidecar-implied/main.tf +5 -0
  253. package/src/lint/post-synth/fixtures/TF047/clear/main.tf +12 -0
  254. package/src/lint/post-synth/fixtures/TF047/refused/main.tf +12 -0
  255. package/src/lint/post-synth/fixtures/TF047/unknown-module/main.tf +12 -0
  256. package/src/lint/post-synth/fixtures/TF047/unknown-version/main.tf +12 -0
  257. package/src/lint/post-synth/index.ts +4 -0
  258. package/src/lint/post-synth/record-store.ts +122 -0
  259. package/src/lint/post-synth/tf001.ts +2 -2
  260. package/src/lint/post-synth/tf024.test.ts +26 -5
  261. package/src/lint/post-synth/tf024.ts +105 -22
  262. package/src/lint/post-synth/tf046.test.ts +137 -0
  263. package/src/lint/post-synth/tf046.ts +204 -0
  264. package/src/lint/post-synth/tf047.test.ts +56 -0
  265. package/src/lint/post-synth/tf047.ts +114 -0
  266. package/src/lock-rows.test.ts +70 -0
  267. package/src/lock-rows.ts +82 -0
  268. package/src/lock-timeout.ts +34 -0
  269. package/src/module-catalog/index.test.ts +93 -0
  270. package/src/module-catalog/index.ts +159 -0
  271. package/src/module-catalog/refresh-cli.ts +68 -0
  272. package/src/module-catalog/static-tier.ts +1659 -0
  273. package/src/module-catalog/types.ts +88 -0
  274. package/src/op/activities/terraform.ts +46 -5
  275. package/src/op-wave-step.test.ts +109 -0
  276. package/src/pin/__fixtures__/consumers/live/dev/main.tf +4 -0
  277. package/src/pin/__fixtures__/consumers/live/prod/main.tf +21 -0
  278. package/src/pin/__fixtures__/consumers/units/vpc/terragrunt.hcl +7 -0
  279. package/src/pin/consumers.test.ts +57 -0
  280. package/src/pin/consumers.ts +95 -0
  281. package/src/plugin.ts +6 -0
  282. package/src/registry/__fixtures__/docs/documented/.terraform-docs.yml +3 -0
  283. package/src/registry/__fixtures__/docs/documented/README.md +1 -0
  284. package/src/registry/__fixtures__/docs/documented/main.tf +8 -0
  285. package/src/registry/__fixtures__/docs/json/main.tf.json +14 -0
  286. package/src/registry/__fixtures__/docs/vpc/README.md +3 -0
  287. package/src/registry/__fixtures__/docs/vpc/examples/complete/main.tf +5 -0
  288. package/src/registry/__fixtures__/docs/vpc/examples/simple/README.md +1 -0
  289. package/src/registry/__fixtures__/docs/vpc/examples/simple/main.tf +4 -0
  290. package/src/registry/__fixtures__/docs/vpc/main.tf +14 -0
  291. package/src/registry/__fixtures__/docs/vpc/outputs.tf +9 -0
  292. package/src/registry/__fixtures__/docs/vpc/variables.tf +16 -0
  293. package/src/registry/__fixtures__/proxied-root/main.tf +12 -0
  294. package/src/registry/address.ts +100 -0
  295. package/src/registry/catalog-read.ts +56 -0
  296. package/src/registry/deprecated.test.ts +139 -0
  297. package/src/registry/deprecated.ts +76 -0
  298. package/src/registry/docs.test.ts +140 -0
  299. package/src/registry/docs.ts +299 -0
  300. package/src/registry/edge/bundle.test.ts +50 -0
  301. package/src/registry/edge/edge.test.ts +176 -0
  302. package/src/registry/edge/edge.ts +211 -0
  303. package/src/registry/edge/index.ts +10 -0
  304. package/src/registry/edge/lambda-edge.ts +127 -0
  305. package/src/registry/edge/sigv4-web.ts +79 -0
  306. package/src/registry/edge/token-source.test.ts +258 -0
  307. package/src/registry/edge/token-source.ts +169 -0
  308. package/src/registry/edge/worker.ts +61 -0
  309. package/src/registry/handler.ts +89 -0
  310. package/src/registry/headers-file.ts +61 -0
  311. package/src/registry/index.ts +31 -0
  312. package/src/registry/mirror-paths.ts +10 -0
  313. package/src/registry/mirror.test.ts +198 -0
  314. package/src/registry/mirror.ts +395 -0
  315. package/src/registry/proxies.test.ts +153 -0
  316. package/src/registry/proxies.ts +132 -0
  317. package/src/registry/reader.ts +225 -0
  318. package/src/registry/registry.test.ts +262 -0
  319. package/src/registry/semver.ts +34 -0
  320. package/src/registry/serve.ts +82 -0
  321. package/src/registry/source-forms.test.ts +87 -0
  322. package/src/registry/source-forms.ts +216 -0
  323. package/src/registry/targets/artifactory.test.ts +248 -0
  324. package/src/registry/targets/artifactory.ts +257 -0
  325. package/src/registry/targets/fake-artifactory.ts +158 -0
  326. package/src/registry/targets/fake-gitlab.ts +161 -0
  327. package/src/registry/targets/fake-hcp.ts +233 -0
  328. package/src/registry/targets/fake-http.ts +97 -0
  329. package/src/registry/targets/fake-nexus.ts +152 -0
  330. package/src/registry/targets/gitlab.test.ts +208 -0
  331. package/src/registry/targets/gitlab.ts +223 -0
  332. package/src/registry/targets/hcp.test.ts +230 -0
  333. package/src/registry/targets/hcp.ts +360 -0
  334. package/src/registry/targets/hosted.ts +117 -0
  335. package/src/registry/targets/index.ts +17 -0
  336. package/src/registry/targets/module-target.ts +131 -0
  337. package/src/registry/targets/nexus.test.ts +220 -0
  338. package/src/registry/targets/nexus.ts +314 -0
  339. package/src/registry/targets/zip.test.ts +65 -0
  340. package/src/registry/targets/zip.ts +287 -0
  341. package/src/registry/writer.ts +155 -0
  342. package/src/state/azure-blob.ts +6 -221
  343. package/src/state/gcs.ts +5 -252
  344. package/src/state/object-store.ts +4 -32
  345. package/src/state/s3.ts +10 -182
  346. package/src/state/store.ts +2 -2
  347. package/src/state-ops.test.ts +182 -0
  348. package/src/state-ops.ts +462 -0
  349. package/src/state-reads.ts +116 -0
  350. package/src/used-sources.test.ts +75 -0
  351. package/src/used-sources.ts +204 -0
@@ -0,0 +1,319 @@
1
+ /**
2
+ * A provider network mirror served from the module registry's bucket
3
+ * (chant#4564), and the lock-file grouping terragucci's image recipe uses for
4
+ * its `filesystem_mirror` (moved from terragucci `image-recipe.ts:225-232`,
5
+ * 18f6431595), so both build from one implementation.
6
+ *
7
+ * The network mirror protocol is the layout `providers mirror` writes, served
8
+ * over HTTPS (https://developer.hashicorp.com/terraform/internals/provider-network-mirror-protocol):
9
+ *
10
+ * <host>/<namespace>/<type>/index.json {"versions": {"<v>": {}}}
11
+ * <host>/<namespace>/<type>/<v>.json {"archives": {"<os>_<arch>": {"url": ..., "hashes": ["h1:...", "zh:..."]}}}
12
+ * <host>/<namespace>/<type>/terraform-provider-<type>_<v>_<os>_<arch>.zip
13
+ *
14
+ * `buildMirror` writes one module per distinct lock file, each holding its
15
+ * providers at exactly the locked version beside that lock file, and runs
16
+ * `providers mirror` on each for the platforms asked for, so the lock file's
17
+ * hashes check every download. `uploadMirror` puts the result under the
18
+ * registry's prefix at `providers/`, archives first and `index.json` last, and
19
+ * merges each `index.json` with the one already in the bucket.
20
+ *
21
+ * Lock files keep the host the provider came from. A hostless source resolves
22
+ * to registry.terraform.io under Terraform and to registry.opentofu.org under
23
+ * OpenTofu and choudoufu, so by default each provider locked on one of those
24
+ * two hosts is mirrored under the other as well.
25
+ */
26
+ import { spawnSync } from "node:child_process";
27
+ import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
28
+ import { tmpdir } from "node:os";
29
+ import { join, posix, relative } from "node:path";
30
+ import { keyFor } from "./address.js";
31
+ import { PROVIDER_MIRROR_PREFIX } from "./mirror-paths.js";
32
+ export { PROVIDER_MIRROR_PREFIX, isMirrorVersionPath } from "./mirror-paths.js";
33
+ export const LOCK_FILE = ".terraform.lock.hcl";
34
+ /** The two hosts a hostless provider source resolves to. */
35
+ export const TERRAFORM_REGISTRY = "registry.terraform.io";
36
+ export const OPENTOFU_REGISTRY = "registry.opentofu.org";
37
+ /** Directories a lock file is never looked for in: caches and what init or a package manager writes. */
38
+ const SKIP = new Set([".git", ".terraform", ".terragrunt-cache", "node_modules", "cdktf.out", ".terragucci"]);
39
+ /** Every provider in a lock file, by its full address, with its version. */
40
+ export function readLock(text) {
41
+ const out = new Map();
42
+ for (const m of text.matchAll(/provider\s+"([^"]+)"\s*\{([^}]*)\}/g)) {
43
+ const v = /\bversion\s*=\s*"([^"]+)"/.exec(m[2]);
44
+ if (v)
45
+ out.set(m[1], v[1]);
46
+ }
47
+ return out;
48
+ }
49
+ /** The repo's lock files, as `/`-separated paths relative to the repo, sorted. */
50
+ export function lockFiles(repo) {
51
+ const out = [];
52
+ const walk = (dir) => {
53
+ let names;
54
+ try {
55
+ names = readdirSync(dir);
56
+ }
57
+ catch {
58
+ return;
59
+ }
60
+ for (const n of names) {
61
+ const p = join(dir, n);
62
+ if (n === LOCK_FILE) {
63
+ out.push(posix.normalize(relative(repo, p).split("\\").join("/")));
64
+ continue;
65
+ }
66
+ if (SKIP.has(n))
67
+ continue;
68
+ let dirLike = false;
69
+ try {
70
+ dirLike = statSync(p).isDirectory();
71
+ }
72
+ catch {
73
+ dirLike = false;
74
+ }
75
+ if (dirLike)
76
+ walk(p);
77
+ }
78
+ };
79
+ walk(repo);
80
+ return out.sort();
81
+ }
82
+ /** Every provider every lock file pins. */
83
+ export function lockEntries(repo, files = lockFiles(repo)) {
84
+ return files.flatMap((lock) => [...readLock(readFileSync(join(repo, lock), "utf-8"))].map(([address, version]) => ({ lock, address, version })));
85
+ }
86
+ const byKey = ([a], [b]) => (a < b ? -1 : a > b ? 1 : 0);
87
+ /** The repo's lock files grouped by what they pin; a lock file that pins nothing is left out. */
88
+ export function mirrorGroups(repo, locks = lockFiles(repo)) {
89
+ const groups = new Map();
90
+ for (const lock of locks) {
91
+ const text = readFileSync(join(repo, lock), "utf-8");
92
+ const providers = readLock(text);
93
+ if (providers.size === 0)
94
+ continue;
95
+ const key = [...providers].sort(byKey).map(([a, v]) => `${a}=${v}`).join("\n");
96
+ const g = groups.get(key);
97
+ if (g)
98
+ g.locks.push(lock);
99
+ else
100
+ groups.set(key, { locks: [lock], text, providers });
101
+ }
102
+ return [...groups.values()];
103
+ }
104
+ /** The other default host's address for a provider locked on one of them, or undefined. */
105
+ export function otherHostAddress(address) {
106
+ const [host, ...rest] = address.split("/");
107
+ if (rest.length !== 2)
108
+ return undefined;
109
+ const h = host.toLowerCase();
110
+ if (h === TERRAFORM_REGISTRY)
111
+ return [OPENTOFU_REGISTRY, ...rest].join("/");
112
+ if (h === OPENTOFU_REGISTRY)
113
+ return [TERRAFORM_REGISTRY, ...rest].join("/");
114
+ return undefined;
115
+ }
116
+ /**
117
+ * One module per group: `versions.tf` holding each provider at exactly its
118
+ * locked version, and the lock file beside it so `providers mirror` checks the
119
+ * hashes. With `bothHosts`, the other default host's address is required too;
120
+ * the lock file does not name it, so its download is checked by that
121
+ * registry's signature alone.
122
+ */
123
+ export function mirrorModules(groups, options = {}) {
124
+ const base = options.dir ?? "mirror";
125
+ const files = [];
126
+ groups.forEach((g, i) => {
127
+ const dir = `${base}/${String(i + 1).padStart(2, "0")}`;
128
+ const wanted = new Map(g.providers);
129
+ if (options.bothHosts) {
130
+ for (const [address, version] of g.providers) {
131
+ const other = otherHostAddress(address);
132
+ if (other && ![...wanted.keys()].some((a) => a.toLowerCase() === other.toLowerCase()))
133
+ wanted.set(other, version);
134
+ }
135
+ }
136
+ const required = [...wanted].sort(byKey).map(([address, version], n) => ` p${n} = { source = "${address}", version = "= ${version}" }`);
137
+ files.push({
138
+ path: `${dir}/versions.tf`,
139
+ content: [`# The providers ${g.locks.join(", ")} lock${g.locks.length === 1 ? "s" : ""}, each at exactly its locked version.`, "terraform {", " required_providers {", ...required, " }", "}", ""].join("\n"),
140
+ });
141
+ files.push({ path: `${dir}/${LOCK_FILE}`, content: g.text });
142
+ });
143
+ return files;
144
+ }
145
+ /** A platform as the binaries name it, `linux_amd64`, from that form or Docker's `linux/amd64`. */
146
+ export function binaryPlatform(platform) {
147
+ const p = platform.trim().toLowerCase().replace("/", "_");
148
+ if (!/^[a-z0-9]+_[a-z0-9]+$/.test(p))
149
+ throw new Error(`${platform}: name a platform as os_arch or os/arch, such as linux_amd64`);
150
+ return p;
151
+ }
152
+ /** The platform this process runs on, as the binaries name it. */
153
+ export function hostPlatform(platform = process.platform, arch = process.arch) {
154
+ const a = arch === "x64" ? "amd64" : arch === "ia32" ? "386" : arch;
155
+ return `${platform}_${a}`;
156
+ }
157
+ /**
158
+ * Whether a mirror directory holds the provider at the version for the
159
+ * platform, in either layout a `filesystem_mirror` reads: packed (what
160
+ * `providers mirror` writes, a zip per platform) or unpacked (a directory per
161
+ * platform).
162
+ */
163
+ export function mirrorHas(mirror, address, version, platform) {
164
+ const parts = address.split("/");
165
+ const type = parts[parts.length - 1];
166
+ const dir = join(mirror, ...parts);
167
+ return existsSync(join(dir, `terraform-provider-${type}_${version}_${platform}.zip`)) || existsSync(join(dir, version, platform));
168
+ }
169
+ const defaultRun = (bin, args, cwd) => {
170
+ const r = spawnSync(bin, args, { cwd, encoding: "utf-8", env: { ...process.env, TF_IN_AUTOMATION: "1", TF_INPUT: "0", CHECKPOINT_DISABLE: "1" } });
171
+ return { status: r.status, output: `${r.stdout ?? ""}${r.stderr ?? ""}${r.error ? r.error.message : ""}` };
172
+ };
173
+ export class MirrorBuildError extends Error {
174
+ constructor(message) {
175
+ super(message);
176
+ this.name = "MirrorBuildError";
177
+ }
178
+ }
179
+ /** The versions every `<version>.json` beside an `index.json` names, as the index lists them. */
180
+ const indexFor = (dir) => {
181
+ const versions = readdirSync(dir)
182
+ .filter((f) => f.endsWith(".json") && f !== "index.json")
183
+ .map((f) => f.slice(0, -".json".length))
184
+ .sort();
185
+ return `${JSON.stringify({ versions: Object.fromEntries(versions.map((v) => [v, {}])) }, null, 2)}\n`;
186
+ };
187
+ /** Every provider directory (`<host>/<ns>/<type>`) under a mirror. */
188
+ const providerDirs = (out) => {
189
+ const dirs = [];
190
+ const list = (d) => (existsSync(d) ? readdirSync(d).filter((n) => statSync(join(d, n)).isDirectory()) : []);
191
+ for (const host of list(out))
192
+ for (const ns of list(join(out, host)))
193
+ for (const type of list(join(out, host, ns)))
194
+ dirs.push(join(out, host, ns, type));
195
+ return dirs;
196
+ };
197
+ /**
198
+ * Runs `providers mirror` over every lock file's group into `out`, then
199
+ * rewrites each `index.json` from the version files present, so groups that
200
+ * mirror different versions of one provider all show.
201
+ */
202
+ export function buildMirror(repo, out, options = {}) {
203
+ const binary = options.binary ?? "tofu";
204
+ const platforms = [...new Set((options.platforms?.length ? options.platforms : ["linux_amd64"]).map(binaryPlatform))];
205
+ const bothHosts = options.bothHosts ?? true;
206
+ const groups = mirrorGroups(repo, options.locks ?? lockFiles(repo));
207
+ const work = options.workDir ?? mkdtempSync(join(tmpdir(), "chant-provider-mirror-"));
208
+ const run = options.run ?? defaultRun;
209
+ const modules = mirrorModules(groups, { dir: "mirror", bothHosts });
210
+ for (const f of modules) {
211
+ mkdirSync(join(work, posix.dirname(f.path)), { recursive: true });
212
+ writeFileSync(join(work, f.path), f.content);
213
+ }
214
+ mkdirSync(out, { recursive: true });
215
+ const dirs = [...new Set(modules.map((f) => posix.dirname(f.path)))];
216
+ for (const d of dirs) {
217
+ const r = run(binary, [`-chdir=${join(work, d)}`, "providers", "mirror", ...platforms.map((p) => `-platform=${p}`), out], repo);
218
+ if (r.status !== 0)
219
+ throw new MirrorBuildError(`${binary} providers mirror for ${d} failed (exit ${r.status}):\n${r.output.trim()}`);
220
+ }
221
+ for (const d of providerDirs(out))
222
+ writeFileSync(join(d, "index.json"), indexFor(d));
223
+ const providers = new Set();
224
+ for (const g of groups) {
225
+ for (const [address, version] of g.providers) {
226
+ providers.add(`${address} ${version}`);
227
+ const other = bothHosts ? otherHostAddress(address) : undefined;
228
+ if (other)
229
+ providers.add(`${other} ${version}`);
230
+ }
231
+ }
232
+ return { out, locks: groups.flatMap((g) => g.locks).sort(), providers: [...providers].sort(), platforms };
233
+ }
234
+ const contentTypeOf = (name) => (name.endsWith(".json") ? "application/json" : name.endsWith(".zip") ? "application/zip" : "application/octet-stream");
235
+ /** Every file under a directory, relative to it, `/`-separated. */
236
+ const walkFiles = (root) => {
237
+ const out = [];
238
+ const walk = (d) => {
239
+ for (const n of readdirSync(d)) {
240
+ const p = join(d, n);
241
+ if (statSync(p).isDirectory())
242
+ walk(p);
243
+ else
244
+ out.push(relative(root, p).split("\\").join("/"));
245
+ }
246
+ };
247
+ if (existsSync(root))
248
+ walk(root);
249
+ return out.sort();
250
+ };
251
+ /** The key a mirror file goes to. */
252
+ export const mirrorKey = (prefix, path) => keyFor(prefix, `${PROVIDER_MIRROR_PREFIX}/${path}`);
253
+ /** The versions an `index.json` lists. */
254
+ const indexVersions = (text) => {
255
+ if (!text)
256
+ return [];
257
+ try {
258
+ return Object.keys(JSON.parse(text).versions ?? {});
259
+ }
260
+ catch {
261
+ return [];
262
+ }
263
+ };
264
+ /**
265
+ * Uploads a built mirror: archives, then each `<version>.json`, then each
266
+ * `index.json` merged with the versions the store's copy already lists, so a
267
+ * reader never sees an index naming a version whose files are not there yet.
268
+ */
269
+ export async function uploadMirror(store, dir, options = {}) {
270
+ const files = walkFiles(dir);
271
+ const rank = (f) => (f.endsWith("/index.json") ? 2 : f.endsWith(".json") ? 1 : 0);
272
+ const ordered = [...files].sort((a, b) => rank(a) - rank(b) || (a < b ? -1 : a > b ? 1 : 0));
273
+ const put = [];
274
+ const kept = [];
275
+ for (const f of ordered) {
276
+ const key = mirrorKey(options.prefix, f);
277
+ if (rank(f) === 0 && store.has && (await store.has(key))) {
278
+ kept.push(key);
279
+ continue;
280
+ }
281
+ let body = readFileSync(join(dir, f));
282
+ if (rank(f) === 2) {
283
+ const versions = [...new Set([...indexVersions((await store.read(key)).body), ...indexVersions(body.toString("utf-8"))])].sort();
284
+ body = `${JSON.stringify({ versions: Object.fromEntries(versions.map((v) => [v, {}])) }, null, 2)}\n`;
285
+ }
286
+ await store.put(key, body, contentTypeOf(f));
287
+ put.push(key);
288
+ }
289
+ return { put, kept };
290
+ }
291
+ /** The mirror's URL under a registry's base URL, ending in `/`. */
292
+ export const mirrorUrl = (registryUrl, prefix) => `${registryUrl.replace(/\/+$/, "")}/${mirrorKey(prefix, "")}`;
293
+ /**
294
+ * The CLI config block users add: the mirrored providers come only from the
295
+ * mirror, and everything else directly from its registry. `include` keeps
296
+ * the mirror from being asked for a provider it lacks, and `exclude` keeps a
297
+ * mirrored provider from going direct.
298
+ */
299
+ export function mirrorCliConfig(url, addresses) {
300
+ // Takes addresses, or BuiltMirror.providers' `address version` lines.
301
+ const list = [...new Set(addresses.map((a) => a.trim().split(/\s+/)[0]))].sort();
302
+ const quoted = list.map((a) => ` "${a}",`);
303
+ return [
304
+ "provider_installation {",
305
+ " network_mirror {",
306
+ ` url = "${url.endsWith("/") ? url : `${url}/`}"`,
307
+ " include = [",
308
+ ...quoted,
309
+ " ]",
310
+ " }",
311
+ " direct {",
312
+ " exclude = [",
313
+ ...quoted,
314
+ " ]",
315
+ " }",
316
+ "}",
317
+ "",
318
+ ].join("\n");
319
+ }
@@ -0,0 +1,73 @@
1
+ /** The upstream a proxy stands for when an entry names none. */
2
+ export declare const DEFAULT_PROXY_UPSTREAM = "registry.terraform.io";
3
+ /** One registry proxy. */
4
+ export interface RegistryProxy {
5
+ /** The host sources through the proxy name: Artifactory's host, or the label of a Nexus host block. */
6
+ host: string;
7
+ /** Artifactory: the remote or virtual repository's key, joined to the namespace with `__`. Absent for Nexus. */
8
+ repo?: string;
9
+ /** The registry host the proxy stands for. Default registry.terraform.io. */
10
+ upstream?: string;
11
+ /**
12
+ * The modules.v1 URL a CLI host block gives the label (a Nexus proxy or
13
+ * group repository's `<url>/repository/<repo>/v1/modules/`), read in
14
+ * place of the label's service discovery.
15
+ */
16
+ modules?: string;
17
+ /** The providers.v1 URL of the same host block, when reads of providers go through it. */
18
+ providers?: string;
19
+ }
20
+ /** The `__` an Artifactory source joins its repository key and namespace with. */
21
+ export declare const ARTIFACTORY_JOINER = "__";
22
+ /** A proxy entry for an Artifactory remote or virtual Terraform repository. */
23
+ export declare const artifactoryProxy: (host: string, repo: string, upstream?: string) => RegistryProxy;
24
+ /**
25
+ * A proxy entry for a Nexus proxy or group Terraform repository at `url`.
26
+ * The label defaults to the upstream, as Sonatype's docs write the host
27
+ * block (`host "registry.terraform.io"`), so plain sources go through it.
28
+ */
29
+ export declare function nexusProxy(o: {
30
+ url: string;
31
+ repo: string;
32
+ upstream?: string;
33
+ host?: string;
34
+ }): RegistryProxy;
35
+ /** The bare labels the proxies use as hosts, so a source starting with one parses as a registry source. */
36
+ export declare const proxyLabels: (proxies?: readonly RegistryProxy[]) => string[];
37
+ /**
38
+ * The upstream registry source a module source written through a proxy
39
+ * stands for, `<upstream>/<ns>/<name>/<system>` with any `//subdir` kept and
40
+ * the query dropped, and the proxy it went through. Undefined for a source
41
+ * through none of them. A Nexus label that is the upstream itself gives the
42
+ * source back at the upstream.
43
+ */
44
+ export declare function moduleThroughProxy(source: string, proxies?: readonly RegistryProxy[]): {
45
+ proxy: RegistryProxy;
46
+ upstream: string;
47
+ } | undefined;
48
+ /**
49
+ * The upstream provider address a provider source written through a proxy
50
+ * stands for, `<upstream>/<ns>/<type>` in lower case. Undefined for a
51
+ * source through none of them.
52
+ */
53
+ export declare function providerThroughProxy(source: string, proxies?: readonly RegistryProxy[]): {
54
+ proxy: RegistryProxy;
55
+ upstream: string;
56
+ } | undefined;
57
+ /**
58
+ * Where a read of a module at `host/<ns>/<name>/<system>` goes when a proxy
59
+ * stands for `host`: the host and namespace the proxy names it by, and the
60
+ * modules.v1 URL to read in place of discovery (a Nexus host block's).
61
+ * Undefined when no proxy stands for `host`, or the module already names a
62
+ * proxy's host.
63
+ */
64
+ export declare function proxyRoute(s: {
65
+ host: string;
66
+ namespace: string;
67
+ }, proxies?: readonly RegistryProxy[]): {
68
+ proxy: RegistryProxy;
69
+ host: string;
70
+ namespace: string;
71
+ modules?: string;
72
+ } | undefined;
73
+ //# sourceMappingURL=proxies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxies.d.ts","sourceRoot":"","sources":["../../src/registry/proxies.ts"],"names":[],"mappings":"AAqBA,gEAAgE;AAChE,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAE9D,0BAA0B;AAC1B,MAAM,WAAW,aAAa;IAC5B,uGAAuG;IACvG,IAAI,EAAE,MAAM,CAAC;IACb,gHAAgH;IAChH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAEvC,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,SAAU,MAAM,QAAQ,MAAM,aAAa,MAAM,KAAG,aAAgH,CAAC;AAElM;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAK5G;AAKD,2GAA2G;AAC3G,eAAO,MAAM,WAAW,aAAa,SAAS,aAAa,EAAE,KAAQ,MAAM,EAAgC,CAAC;AAS5G;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,SAAS,aAAa,EAAO,GAAG;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAcjJ;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,SAAS,aAAa,EAAO,GAAG;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAWnJ;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EACtC,OAAO,GAAE,SAAS,aAAa,EAAO,GACrC;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAOzF"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Registry proxies (chant#4606, terragucci#1290 bundle C): an Artifactory
3
+ * remote or virtual repository, or a Nexus proxy or group repository,
4
+ * standing in front of an upstream registry, so a source written through
5
+ * one and the plain upstream source compare equal, and reads go through the
6
+ * proxy. The shapes are the ones terragucci#1299's research found:
7
+ *
8
+ * Artifactory <host>/<repo>__<ns>/<name>/<system> module, the repository key joined to the namespace by `__`
9
+ * <host>/<repo>__<ns>/<type> provider, the same joiner
10
+ * Nexus <label>/<ns>/<name>/<system> behind a CLI `host "<label>"` block whose services
11
+ * point at the proxy repository; the label is usually
12
+ * the upstream itself (`host "registry.terraform.io"`)
13
+ *
14
+ * An entry names the host sources through the proxy write, the Artifactory
15
+ * repository key when there is one, and the upstream it stands for
16
+ * (registry.terraform.io unless set). A Nexus entry carries the repository's
17
+ * modules.v1 URL, which reads use in place of the label's discovery, as the
18
+ * CLI's host block does. No Node imports, so an edge function can carry it.
19
+ */
20
+ import { parseRegistrySource } from "./address.js";
21
+ /** The upstream a proxy stands for when an entry names none. */
22
+ export const DEFAULT_PROXY_UPSTREAM = "registry.terraform.io";
23
+ /** The `__` an Artifactory source joins its repository key and namespace with. */
24
+ export const ARTIFACTORY_JOINER = "__";
25
+ /** A proxy entry for an Artifactory remote or virtual Terraform repository. */
26
+ export const artifactoryProxy = (host, repo, upstream) => ({ host: host.toLowerCase(), repo, ...(upstream ? { upstream: upstream.toLowerCase() } : {}) });
27
+ /**
28
+ * A proxy entry for a Nexus proxy or group Terraform repository at `url`.
29
+ * The label defaults to the upstream, as Sonatype's docs write the host
30
+ * block (`host "registry.terraform.io"`), so plain sources go through it.
31
+ */
32
+ export function nexusProxy(o) {
33
+ const base = o.url.replace(/\/+$/, "");
34
+ const upstream = (o.upstream ?? DEFAULT_PROXY_UPSTREAM).toLowerCase();
35
+ const repo = encodeURIComponent(o.repo);
36
+ return { host: (o.host ?? upstream).toLowerCase(), upstream, modules: `${base}/repository/${repo}/v1/modules/`, providers: `${base}/repository/${repo}/v1/providers/` };
37
+ }
38
+ const upstreamOf = (p) => (p.upstream ?? DEFAULT_PROXY_UPSTREAM).toLowerCase();
39
+ const sameHost = (a, b) => a.toLowerCase() === b.toLowerCase();
40
+ /** The bare labels the proxies use as hosts, so a source starting with one parses as a registry source. */
41
+ export const proxyLabels = (proxies = []) => proxies.map((p) => p.host);
42
+ /** A namespace through an Artifactory proxy without its `<repo>__`, or undefined when it does not carry that repository. */
43
+ function unjoin(p, namespace) {
44
+ if (!p.repo)
45
+ return namespace;
46
+ const prefix = `${p.repo}${ARTIFACTORY_JOINER}`;
47
+ return namespace.toLowerCase().startsWith(prefix.toLowerCase()) && namespace.length > prefix.length ? namespace.slice(prefix.length) : undefined;
48
+ }
49
+ /**
50
+ * The upstream registry source a module source written through a proxy
51
+ * stands for, `<upstream>/<ns>/<name>/<system>` with any `//subdir` kept and
52
+ * the query dropped, and the proxy it went through. Undefined for a source
53
+ * through none of them. A Nexus label that is the upstream itself gives the
54
+ * source back at the upstream.
55
+ */
56
+ export function moduleThroughProxy(source, proxies = []) {
57
+ if (proxies.length === 0)
58
+ return undefined;
59
+ const written = source.trim().split("?")[0];
60
+ const [base, ...sub] = written.split("//");
61
+ const s = parseRegistrySource(base, proxyLabels(proxies));
62
+ if (!s)
63
+ return undefined;
64
+ for (const p of proxies) {
65
+ if (!sameHost(p.host, s.host))
66
+ continue;
67
+ const ns = unjoin(p, s.namespace);
68
+ if (ns === undefined)
69
+ continue;
70
+ const upstream = [`${upstreamOf(p)}/${ns}/${s.name}/${s.system}`, ...sub].join("//");
71
+ return { proxy: p, upstream };
72
+ }
73
+ return undefined;
74
+ }
75
+ /**
76
+ * The upstream provider address a provider source written through a proxy
77
+ * stands for, `<upstream>/<ns>/<type>` in lower case. Undefined for a
78
+ * source through none of them.
79
+ */
80
+ export function providerThroughProxy(source, proxies = []) {
81
+ const parts = source.trim().toLowerCase().split("/");
82
+ if (parts.length !== 3)
83
+ return undefined;
84
+ const [host, namespace, type] = parts;
85
+ for (const p of proxies) {
86
+ if (!sameHost(p.host, host))
87
+ continue;
88
+ const ns = unjoin(p, namespace);
89
+ if (ns === undefined || !ns || !type)
90
+ continue;
91
+ return { proxy: p, upstream: `${upstreamOf(p)}/${ns}/${type}` };
92
+ }
93
+ return undefined;
94
+ }
95
+ /**
96
+ * Where a read of a module at `host/<ns>/<name>/<system>` goes when a proxy
97
+ * stands for `host`: the host and namespace the proxy names it by, and the
98
+ * modules.v1 URL to read in place of discovery (a Nexus host block's).
99
+ * Undefined when no proxy stands for `host`, or the module already names a
100
+ * proxy's host.
101
+ */
102
+ export function proxyRoute(s, proxies = []) {
103
+ // A source written through a proxy already reads from its host; a Nexus label is resolved by its modules URL.
104
+ const named = proxies.find((p) => sameHost(p.host, s.host));
105
+ if (named)
106
+ return named.modules ? { proxy: named, host: named.host, namespace: s.namespace, modules: named.modules } : undefined;
107
+ const p = proxies.find((q) => sameHost(upstreamOf(q), s.host));
108
+ if (!p)
109
+ return undefined;
110
+ return { proxy: p, host: p.host, namespace: p.repo ? `${p.repo}${ARTIFACTORY_JOINER}${s.namespace}` : s.namespace, ...(p.modules ? { modules: p.modules } : {}) };
111
+ }
@@ -0,0 +1,57 @@
1
+ import { type CredentialsOptions } from "@intentius/chant/terraform/credentials";
2
+ import { type RegistryProxy } from "./proxies.js";
3
+ /** The fetch the reader calls: the global fetch's shape. */
4
+ export type RegistryFetch = (url: string, init?: RequestInit) => Promise<Response>;
5
+ export declare class RegistryError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ /** How a download answer is read. */
9
+ export type DownloadReader = "terraform" | "tofu" | "either";
10
+ export interface RegistryReadOptions {
11
+ fetch?: RegistryFetch;
12
+ /** The URL scheme service discovery is fetched over. Default https, as both CLIs use. */
13
+ scheme?: "https" | "http";
14
+ /**
15
+ * The bearer token sent to the registry's host. Default: the one the CLIs
16
+ * would send (`TF_TOKEN_<host>`, then the credentials files). `false` sends none.
17
+ */
18
+ token?: string | false;
19
+ /** Where the default token lookup reads (a test passes its own env and files). */
20
+ credentials?: CredentialsOptions;
21
+ /**
22
+ * The modules.v1 URL per registry host, read in place of the host's
23
+ * `/.well-known/terraform.json`, as a CLI's `host "<name>" { services = {...} }`
24
+ * block does. A host named here is taken as a registry host even without a dot.
25
+ */
26
+ services?: Record<string, string>;
27
+ /**
28
+ * A whole `Authorization` header value sent on every request to the
29
+ * registry, in place of the bearer token, such as Nexus's basic
30
+ * credentials before its bearer form (3.95). Never printed.
31
+ */
32
+ authorization?: string;
33
+ /** Registry proxies in front of upstream hosts; a read of a module at an upstream goes through its proxy. */
34
+ proxies?: readonly RegistryProxy[];
35
+ }
36
+ /** The token a read sends to a host, by the options. */
37
+ export declare const readToken: (host: string, o: RegistryReadOptions) => string | undefined;
38
+ /** The modules.v1 base a host's service discovery names, ending in `/`. */
39
+ export declare function modulesBase(host: string, options?: RegistryFetch | RegistryReadOptions): Promise<string>;
40
+ /** Every version a registry lists for a module; none when it has no versions file. */
41
+ export declare function registryVersions(source: string, options?: RegistryFetch | RegistryReadOptions): Promise<string[]>;
42
+ export interface RegistryLocationOptions extends RegistryReadOptions {
43
+ /** Which CLI's reading to follow. Default `either`. */
44
+ reads?: DownloadReader;
45
+ }
46
+ /** The location a download answer gives, read as `reads` says, or undefined when it gives none that way. */
47
+ export declare function locationFromAnswer(res: Response, reads?: DownloadReader): Promise<string | undefined>;
48
+ /** Where a registry says one version is, resolved against the download URL when it is relative. */
49
+ export declare function registryLocation(source: string, version: string, options?: RegistryFetch | RegistryLocationOptions): Promise<string>;
50
+ /**
51
+ * The module archive a tarball location holds, uncompressed: the bytes a
52
+ * release's digest is of. The host's token goes along only when the location
53
+ * has no query string; a signed URL carries its own grant, and a bucket
54
+ * refuses a request that has both a signature and an `Authorization` header.
55
+ */
56
+ export declare function fetchTarball(location: string, options?: RegistryFetch | RegistryReadOptions): Promise<Buffer>;
57
+ //# sourceMappingURL=reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/registry/reader.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAkD,KAAK,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAEjI,OAAO,EAAmD,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAGhG,4DAA4D;AAC5D,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAInF,qBAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED,qCAAqC;AACrC,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE7D,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,yFAAyF;IACzF,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACvB,kFAAkF;IAClF,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6GAA6G;IAC7G,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACpC;AAED,wDAAwD;AACxD,eAAO,MAAM,SAAS,SAAU,MAAM,KAAK,mBAAmB,KAAG,MAAM,GAAG,SAA+F,CAAC;AAqD1K,2EAA2E;AAC3E,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB9G;AAED,sFAAsF;AACtF,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,mBAAmB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUvH;AAED,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,uDAAuD;IACvD,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,4GAA4G;AAC5G,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,GAAE,cAAyB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAcrH;AAED,mGAAmG;AACnG,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB1I;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAYnH"}