@intentius/chant-lexicon-terraform 0.124.52 → 0.124.55

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 (641) hide show
  1. package/README.md +14 -10
  2. package/dist/__fixtures__/pr-loop/estate.component.d.ts +7 -0
  3. package/dist/__fixtures__/pr-loop/estate.component.d.ts.map +1 -0
  4. package/dist/__fixtures__/pr-loop/estate.component.js +7 -0
  5. package/dist/__fixtures__/report/generate.d.ts +26 -0
  6. package/dist/__fixtures__/report/generate.d.ts.map +1 -0
  7. package/dist/__fixtures__/report/generate.js +58 -0
  8. package/dist/applied-state.d.ts +27 -0
  9. package/dist/applied-state.d.ts.map +1 -0
  10. package/dist/applied-state.js +44 -0
  11. package/dist/backend-config.d.ts +53 -0
  12. package/dist/backend-config.d.ts.map +1 -0
  13. package/dist/backend-config.js +136 -0
  14. package/dist/behaviour/kinds.d.ts.map +1 -1
  15. package/dist/behaviour/kinds.js +4 -0
  16. package/dist/behaviour/predict.d.ts.map +1 -1
  17. package/dist/behaviour/predict.js +6 -2
  18. package/dist/behaviour/reference-catalog.d.ts +16 -5
  19. package/dist/behaviour/reference-catalog.d.ts.map +1 -1
  20. package/dist/behaviour/reference-catalog.js +16 -5
  21. package/dist/behaviour/request.d.ts.map +1 -1
  22. package/dist/behaviour/request.js +3 -2
  23. package/dist/changed-roots.d.ts +6 -4
  24. package/dist/changed-roots.d.ts.map +1 -1
  25. package/dist/changed-roots.js +14 -18
  26. package/dist/ci-setup.d.ts +11 -0
  27. package/dist/ci-setup.d.ts.map +1 -0
  28. package/dist/ci-setup.js +41 -0
  29. package/dist/commands.d.ts.map +1 -1
  30. package/dist/commands.js +4 -3
  31. package/dist/components/capability-plugin.d.ts +105 -9
  32. package/dist/components/capability-plugin.d.ts.map +1 -1
  33. package/dist/components/capability-plugin.js +357 -36
  34. package/dist/components/compose-group.d.ts +145 -0
  35. package/dist/components/compose-group.d.ts.map +1 -0
  36. package/dist/components/compose-group.js +407 -0
  37. package/dist/components/placeholder-preview.d.ts +78 -0
  38. package/dist/components/placeholder-preview.d.ts.map +1 -0
  39. package/dist/components/placeholder-preview.js +254 -0
  40. package/dist/components/release-inputs.d.ts +29 -0
  41. package/dist/components/release-inputs.d.ts.map +1 -0
  42. package/dist/components/release-inputs.js +57 -0
  43. package/dist/components/trace-facts.d.ts +16 -0
  44. package/dist/components/trace-facts.d.ts.map +1 -0
  45. package/dist/components/trace-facts.js +19 -0
  46. package/dist/compose/apply-events.d.ts +46 -0
  47. package/dist/compose/apply-events.d.ts.map +1 -0
  48. package/dist/compose/apply-events.js +77 -0
  49. package/dist/compose/estate.d.ts +194 -0
  50. package/dist/compose/estate.d.ts.map +1 -0
  51. package/dist/compose/estate.js +363 -0
  52. package/dist/compose/hcl.d.ts +99 -0
  53. package/dist/compose/hcl.d.ts.map +1 -0
  54. package/dist/compose/hcl.js +302 -0
  55. package/dist/compose/module-address.d.ts +24 -0
  56. package/dist/compose/module-address.d.ts.map +1 -0
  57. package/dist/compose/module-address.js +43 -0
  58. package/dist/compose/root.d.ts +127 -0
  59. package/dist/compose/root.d.ts.map +1 -0
  60. package/dist/compose/root.js +586 -0
  61. package/dist/compose/run.d.ts +183 -0
  62. package/dist/compose/run.d.ts.map +1 -0
  63. package/dist/compose/run.js +447 -0
  64. package/dist/compose/slice.d.ts +102 -0
  65. package/dist/compose/slice.d.ts.map +1 -0
  66. package/dist/compose/slice.js +249 -0
  67. package/dist/compose/state-address.d.ts +28 -0
  68. package/dist/compose/state-address.d.ts.map +1 -0
  69. package/dist/compose/state-address.js +154 -0
  70. package/dist/compose/state-merge.d.ts +52 -0
  71. package/dist/compose/state-merge.d.ts.map +1 -0
  72. package/dist/compose/state-merge.js +135 -0
  73. package/dist/compose.d.ts +179 -0
  74. package/dist/compose.d.ts.map +1 -0
  75. package/dist/compose.js +482 -0
  76. package/dist/composites/terraform-apply-op.d.ts.map +1 -1
  77. package/dist/composites/terraform-apply-op.js +7 -3
  78. package/dist/cone.d.ts +53 -0
  79. package/dist/cone.d.ts.map +1 -0
  80. package/dist/cone.js +119 -0
  81. package/dist/config.d.ts +59 -13
  82. package/dist/config.d.ts.map +1 -1
  83. package/dist/config.js +43 -9
  84. package/dist/cost-hold.d.ts +27 -0
  85. package/dist/cost-hold.d.ts.map +1 -0
  86. package/dist/cost-hold.js +21 -0
  87. package/dist/describe-resources.d.ts +74 -12
  88. package/dist/describe-resources.d.ts.map +1 -1
  89. package/dist/describe-resources.js +374 -66
  90. package/dist/drift-read.d.ts +33 -0
  91. package/dist/drift-read.d.ts.map +1 -0
  92. package/dist/drift-read.js +243 -0
  93. package/dist/drift-record.d.ts +147 -0
  94. package/dist/drift-record.d.ts.map +1 -0
  95. package/dist/drift-record.js +383 -0
  96. package/dist/drift-rows.d.ts +61 -0
  97. package/dist/drift-rows.d.ts.map +1 -0
  98. package/dist/drift-rows.js +108 -0
  99. package/dist/exit-codes.d.ts +55 -0
  100. package/dist/exit-codes.d.ts.map +1 -0
  101. package/dist/exit-codes.js +48 -0
  102. package/dist/hcl/edges.d.ts.map +1 -1
  103. package/dist/hcl/edges.js +24 -1
  104. package/dist/hcl/files.d.ts +61 -0
  105. package/dist/hcl/files.d.ts.map +1 -0
  106. package/dist/hcl/files.js +221 -0
  107. package/dist/hcl/instances.d.ts +82 -0
  108. package/dist/hcl/instances.d.ts.map +1 -0
  109. package/dist/hcl/instances.js +390 -0
  110. package/dist/hcl/parse.d.ts +81 -9
  111. package/dist/hcl/parse.d.ts.map +1 -1
  112. package/dist/hcl/parse.js +114 -16
  113. package/dist/hcl/roots.d.ts.map +1 -1
  114. package/dist/hcl/roots.js +5 -0
  115. package/dist/hcl/suppressions.d.ts.map +1 -1
  116. package/dist/hcl/suppressions.js +8 -2
  117. package/dist/index.d.ts +13 -2
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/index.js +24 -2
  120. package/dist/integrity.json +8 -5
  121. package/dist/lint/audit-catalog.d.ts.map +1 -1
  122. package/dist/lint/audit-catalog.js +27 -3
  123. package/dist/lint/audit-lineage.d.ts +14 -2
  124. package/dist/lint/audit-lineage.d.ts.map +1 -1
  125. package/dist/lint/post-synth/index.d.ts.map +1 -1
  126. package/dist/lint/post-synth/index.js +4 -0
  127. package/dist/lint/post-synth/record-store.d.ts +54 -0
  128. package/dist/lint/post-synth/record-store.d.ts.map +1 -0
  129. package/dist/lint/post-synth/record-store.js +104 -0
  130. package/dist/lint/post-synth/tf001.d.ts +2 -2
  131. package/dist/lint/post-synth/tf001.js +2 -2
  132. package/dist/lint/post-synth/tf024.d.ts +35 -11
  133. package/dist/lint/post-synth/tf024.d.ts.map +1 -1
  134. package/dist/lint/post-synth/tf024.js +92 -20
  135. package/dist/lint/post-synth/tf046.d.ts +64 -0
  136. package/dist/lint/post-synth/tf046.d.ts.map +1 -0
  137. package/dist/lint/post-synth/tf046.js +175 -0
  138. package/dist/lint/post-synth/tf047.d.ts +36 -0
  139. package/dist/lint/post-synth/tf047.d.ts.map +1 -0
  140. package/dist/lint/post-synth/tf047.js +94 -0
  141. package/dist/live-plan-reasons.d.ts +21 -0
  142. package/dist/live-plan-reasons.d.ts.map +1 -0
  143. package/dist/live-plan-reasons.js +47 -0
  144. package/dist/lock-rows.d.ts +36 -0
  145. package/dist/lock-rows.d.ts.map +1 -0
  146. package/dist/lock-rows.js +60 -0
  147. package/dist/lock-timeout.d.ts +22 -0
  148. package/dist/lock-timeout.d.ts.map +1 -0
  149. package/dist/lock-timeout.js +32 -0
  150. package/dist/lsp/option-keys.d.ts.map +1 -1
  151. package/dist/lsp/option-keys.js +2 -0
  152. package/dist/manifest.json +1 -1
  153. package/dist/module-catalog/index.d.ts +69 -0
  154. package/dist/module-catalog/index.d.ts.map +1 -0
  155. package/dist/module-catalog/index.js +110 -0
  156. package/dist/module-catalog/refresh-cli.d.ts +4 -0
  157. package/dist/module-catalog/refresh-cli.d.ts.map +1 -0
  158. package/dist/module-catalog/refresh-cli.js +64 -0
  159. package/dist/module-catalog/static-tier.d.ts +6 -0
  160. package/dist/module-catalog/static-tier.d.ts.map +1 -0
  161. package/dist/module-catalog/static-tier.js +1650 -0
  162. package/dist/module-catalog/types.d.ts +65 -0
  163. package/dist/module-catalog/types.d.ts.map +1 -0
  164. package/dist/module-catalog/types.js +33 -0
  165. package/dist/okf/index.md +3 -1
  166. package/dist/okf/rules/TF024.md +2 -2
  167. package/dist/okf/rules/TF046.md +11 -0
  168. package/dist/okf/rules/TF047.md +11 -0
  169. package/dist/op/activities/index.d.ts +6 -2
  170. package/dist/op/activities/index.d.ts.map +1 -1
  171. package/dist/op/activities/index.js +5 -1
  172. package/dist/op/activities/live-detect.d.ts +4 -3
  173. package/dist/op/activities/live-detect.d.ts.map +1 -1
  174. package/dist/op/activities/live-detect.js +57 -32
  175. package/dist/op/activities/pin-rollout.d.ts +2 -0
  176. package/dist/op/activities/pin-rollout.d.ts.map +1 -1
  177. package/dist/op/activities/pin-rollout.js +1 -0
  178. package/dist/op/activities/terraform.d.ts +182 -5
  179. package/dist/op/activities/terraform.d.ts.map +1 -1
  180. package/dist/op/activities/terraform.js +224 -24
  181. package/dist/op/activity-contracts.d.ts +27 -0
  182. package/dist/op/activity-contracts.d.ts.map +1 -1
  183. package/dist/op/activity-contracts.js +19 -1
  184. package/dist/op/builders.d.ts +7 -1
  185. package/dist/op/builders.d.ts.map +1 -1
  186. package/dist/op/builders.js +9 -0
  187. package/dist/pin/consumers.d.ts +35 -0
  188. package/dist/pin/consumers.d.ts.map +1 -0
  189. package/dist/pin/consumers.js +70 -0
  190. package/dist/pin/edit.d.ts.map +1 -1
  191. package/dist/pin/edit.js +35 -0
  192. package/dist/pin/rollout.d.ts +2 -0
  193. package/dist/pin/rollout.d.ts.map +1 -1
  194. package/dist/pin/rollout.js +14 -11
  195. package/dist/plan-shape.d.ts +30 -0
  196. package/dist/plan-shape.d.ts.map +1 -0
  197. package/dist/plan-shape.js +125 -0
  198. package/dist/plugin.d.ts.map +1 -1
  199. package/dist/plugin.js +37 -18
  200. package/dist/registry/address.d.ts +63 -0
  201. package/dist/registry/address.d.ts.map +1 -0
  202. package/dist/registry/address.js +65 -0
  203. package/dist/registry/catalog-read.d.ts +14 -0
  204. package/dist/registry/catalog-read.d.ts.map +1 -0
  205. package/dist/registry/catalog-read.js +58 -0
  206. package/dist/registry/deprecated.d.ts +37 -0
  207. package/dist/registry/deprecated.d.ts.map +1 -0
  208. package/dist/registry/deprecated.js +43 -0
  209. package/dist/registry/docs.d.ts +96 -0
  210. package/dist/registry/docs.d.ts.map +1 -0
  211. package/dist/registry/docs.js +210 -0
  212. package/dist/registry/edge/edge.d.ts +46 -0
  213. package/dist/registry/edge/edge.d.ts.map +1 -0
  214. package/dist/registry/edge/edge.js +194 -0
  215. package/dist/registry/edge/index.d.ts +11 -0
  216. package/dist/registry/edge/index.d.ts.map +1 -0
  217. package/dist/registry/edge/index.js +10 -0
  218. package/dist/registry/edge/lambda-edge.d.ts +76 -0
  219. package/dist/registry/edge/lambda-edge.d.ts.map +1 -0
  220. package/dist/registry/edge/lambda-edge.js +95 -0
  221. package/dist/registry/edge/sigv4-web.d.ts +33 -0
  222. package/dist/registry/edge/sigv4-web.d.ts.map +1 -0
  223. package/dist/registry/edge/sigv4-web.js +56 -0
  224. package/dist/registry/edge/token-source.d.ts +73 -0
  225. package/dist/registry/edge/token-source.d.ts.map +1 -0
  226. package/dist/registry/edge/token-source.js +115 -0
  227. package/dist/registry/edge/worker.d.ts +45 -0
  228. package/dist/registry/edge/worker.d.ts.map +1 -0
  229. package/dist/registry/edge/worker.js +26 -0
  230. package/dist/registry/handler.d.ts +25 -0
  231. package/dist/registry/handler.d.ts.map +1 -0
  232. package/dist/registry/handler.js +75 -0
  233. package/dist/registry/headers-file.d.ts +21 -0
  234. package/dist/registry/headers-file.d.ts.map +1 -0
  235. package/dist/registry/headers-file.js +57 -0
  236. package/dist/registry/index.d.ts +31 -0
  237. package/dist/registry/index.d.ts.map +1 -0
  238. package/dist/registry/index.js +30 -0
  239. package/dist/registry/mirror-paths.d.ts +9 -0
  240. package/dist/registry/mirror-paths.d.ts.map +1 -0
  241. package/dist/registry/mirror-paths.js +8 -0
  242. package/dist/registry/mirror.d.ts +130 -0
  243. package/dist/registry/mirror.d.ts.map +1 -0
  244. package/dist/registry/mirror.js +319 -0
  245. package/dist/registry/proxies.d.ts +73 -0
  246. package/dist/registry/proxies.d.ts.map +1 -0
  247. package/dist/registry/proxies.js +111 -0
  248. package/dist/registry/reader.d.ts +57 -0
  249. package/dist/registry/reader.d.ts.map +1 -0
  250. package/dist/registry/reader.js +198 -0
  251. package/dist/registry/semver.d.ts +16 -0
  252. package/dist/registry/semver.d.ts.map +1 -0
  253. package/dist/registry/semver.js +24 -0
  254. package/dist/registry/serve.d.ts +24 -0
  255. package/dist/registry/serve.d.ts.map +1 -0
  256. package/dist/registry/serve.js +64 -0
  257. package/dist/registry/source-forms.d.ts +79 -0
  258. package/dist/registry/source-forms.d.ts.map +1 -0
  259. package/dist/registry/source-forms.js +202 -0
  260. package/dist/registry/targets/artifactory.d.ts +28 -0
  261. package/dist/registry/targets/artifactory.d.ts.map +1 -0
  262. package/dist/registry/targets/artifactory.js +206 -0
  263. package/dist/registry/targets/fake-artifactory.d.ts +30 -0
  264. package/dist/registry/targets/fake-artifactory.d.ts.map +1 -0
  265. package/dist/registry/targets/fake-artifactory.js +142 -0
  266. package/dist/registry/targets/fake-gitlab.d.ts +39 -0
  267. package/dist/registry/targets/fake-gitlab.d.ts.map +1 -0
  268. package/dist/registry/targets/fake-gitlab.js +136 -0
  269. package/dist/registry/targets/fake-hcp.d.ts +50 -0
  270. package/dist/registry/targets/fake-hcp.d.ts.map +1 -0
  271. package/dist/registry/targets/fake-hcp.js +202 -0
  272. package/dist/registry/targets/fake-http.d.ts +31 -0
  273. package/dist/registry/targets/fake-http.d.ts.map +1 -0
  274. package/dist/registry/targets/fake-http.js +87 -0
  275. package/dist/registry/targets/fake-nexus.d.ts +27 -0
  276. package/dist/registry/targets/fake-nexus.d.ts.map +1 -0
  277. package/dist/registry/targets/fake-nexus.js +137 -0
  278. package/dist/registry/targets/gitlab.d.ts +53 -0
  279. package/dist/registry/targets/gitlab.d.ts.map +1 -0
  280. package/dist/registry/targets/gitlab.js +187 -0
  281. package/dist/registry/targets/hcp.d.ts +29 -0
  282. package/dist/registry/targets/hcp.d.ts.map +1 -0
  283. package/dist/registry/targets/hcp.js +310 -0
  284. package/dist/registry/targets/hosted.d.ts +62 -0
  285. package/dist/registry/targets/hosted.d.ts.map +1 -0
  286. package/dist/registry/targets/hosted.js +74 -0
  287. package/dist/registry/targets/index.d.ts +18 -0
  288. package/dist/registry/targets/index.d.ts.map +1 -0
  289. package/dist/registry/targets/index.js +17 -0
  290. package/dist/registry/targets/module-target.d.ts +68 -0
  291. package/dist/registry/targets/module-target.d.ts.map +1 -0
  292. package/dist/registry/targets/module-target.js +63 -0
  293. package/dist/registry/targets/nexus.d.ts +43 -0
  294. package/dist/registry/targets/nexus.d.ts.map +1 -0
  295. package/dist/registry/targets/nexus.js +250 -0
  296. package/dist/registry/targets/zip.d.ts +55 -0
  297. package/dist/registry/targets/zip.d.ts.map +1 -0
  298. package/dist/registry/targets/zip.js +278 -0
  299. package/dist/registry/writer.d.ts +101 -0
  300. package/dist/registry/writer.d.ts.map +1 -0
  301. package/dist/registry/writer.js +109 -0
  302. package/dist/report.d.ts +15 -6
  303. package/dist/report.d.ts.map +1 -1
  304. package/dist/report.js +28 -55
  305. package/dist/rules/record-store.ts +122 -0
  306. package/dist/rules/tf001.ts +2 -2
  307. package/dist/rules/tf024.ts +105 -22
  308. package/dist/rules/tf046.ts +204 -0
  309. package/dist/rules/tf047.ts +114 -0
  310. package/dist/skills/chant-terraform.md +1 -1
  311. package/dist/state/azure-blob.d.ts +9 -0
  312. package/dist/state/azure-blob.d.ts.map +1 -0
  313. package/dist/state/azure-blob.js +8 -0
  314. package/dist/state/backend.d.ts +158 -0
  315. package/dist/state/backend.d.ts.map +1 -0
  316. package/dist/state/backend.js +406 -0
  317. package/dist/state/exec.d.ts +39 -0
  318. package/dist/state/exec.d.ts.map +1 -0
  319. package/dist/state/exec.js +80 -0
  320. package/dist/state/gcs.d.ts +8 -0
  321. package/dist/state/gcs.d.ts.map +1 -0
  322. package/dist/state/gcs.js +7 -0
  323. package/dist/state/index.d.ts +15 -0
  324. package/dist/state/index.d.ts.map +1 -0
  325. package/dist/state/index.js +14 -0
  326. package/dist/state/locks.d.ts +105 -0
  327. package/dist/state/locks.d.ts.map +1 -0
  328. package/dist/state/locks.js +130 -0
  329. package/dist/state/object-store.d.ts +8 -0
  330. package/dist/state/object-store.d.ts.map +1 -0
  331. package/dist/state/object-store.js +7 -0
  332. package/dist/state/root-states.d.ts +131 -0
  333. package/dist/state/root-states.d.ts.map +1 -0
  334. package/dist/state/root-states.js +241 -0
  335. package/dist/state/s3.d.ts +21 -0
  336. package/dist/state/s3.d.ts.map +1 -0
  337. package/dist/state/s3.js +19 -0
  338. package/dist/state/store.d.ts +51 -0
  339. package/dist/state/store.d.ts.map +1 -0
  340. package/dist/state/store.js +185 -0
  341. package/dist/state-ops.d.ts +255 -0
  342. package/dist/state-ops.d.ts.map +1 -0
  343. package/dist/state-ops.js +305 -0
  344. package/dist/state-reads.d.ts +57 -0
  345. package/dist/state-reads.d.ts.map +1 -0
  346. package/dist/state-reads.js +104 -0
  347. package/dist/terragrunt/affected.d.ts.map +1 -1
  348. package/dist/terragrunt/affected.js +2 -1
  349. package/dist/used-sources.d.ts +54 -0
  350. package/dist/used-sources.d.ts.map +1 -0
  351. package/dist/used-sources.js +157 -0
  352. package/package.json +24 -4
  353. package/src/__fixtures__/ACCEPTANCE.md +69 -7
  354. package/src/__fixtures__/compose/apply-failed-in-app.jsonl +12 -0
  355. package/src/__fixtures__/compose/state-app.json +66 -0
  356. package/src/__fixtures__/compose/state-edge.json +40 -0
  357. package/src/__fixtures__/compose/state-net.json +58 -0
  358. package/src/__fixtures__/compose/three-app.plan.json +184 -0
  359. package/src/__fixtures__/compose/three-composed.plan.json +509 -0
  360. package/src/__fixtures__/compose/three-edge.plan.json +144 -0
  361. package/src/__fixtures__/compose/three-net.plan.json +174 -0
  362. package/src/__fixtures__/compose/unknown-composed.plan.json +228 -0
  363. package/src/__fixtures__/compose/working-after-apply.json +145 -0
  364. package/src/__fixtures__/config-blocks/app/main.tf +61 -0
  365. package/src/__fixtures__/config-blocks/app/modules/network/main.tf +4 -0
  366. package/src/__fixtures__/config-blocks/app-json/main.tf.json +39 -0
  367. package/src/__fixtures__/config-files/shadow/main.tf +3 -0
  368. package/src/__fixtures__/config-files/shadow/main.tofu +3 -0
  369. package/src/__fixtures__/config-files/shadow/other.tf +3 -0
  370. package/src/__fixtures__/config-files/tf/main.tf +11 -0
  371. package/src/__fixtures__/config-files/tf-json/main.tf.json +18 -0
  372. package/src/__fixtures__/config-files/tofu/main.tofu +11 -0
  373. package/src/__fixtures__/config-files/tofu-json/main.tofu.json +18 -0
  374. package/src/__fixtures__/config-files/tofu-only/main.tofu +3 -0
  375. package/src/__fixtures__/drift-record/README.md +16 -0
  376. package/src/__fixtures__/drift-record/live-plan-sections.json +27 -0
  377. package/src/__fixtures__/drift-rows/live-root-plan.json +70 -0
  378. package/src/__fixtures__/drift-rows/refresh-plan.json +61 -0
  379. package/src/__fixtures__/instance-forms/app/main.tf +110 -0
  380. package/src/__fixtures__/instance-forms/app/modules/svc/main.tf +3 -0
  381. package/src/__fixtures__/instance-vars/app/main.tf +52 -0
  382. package/src/__fixtures__/instance-vars/app/modules/app/main.tf +12 -0
  383. package/src/__fixtures__/instance-vars/app/modules/edge/main.tf +3 -0
  384. package/src/__fixtures__/instance-vars/app/terraform.tfvars +1 -0
  385. package/src/__fixtures__/live-module-keyed/live-graph.json +259 -0
  386. package/src/__fixtures__/live-module-keyed/live-plan.json +87 -0
  387. package/src/__fixtures__/live-module-keyed/root/estate.chdf.hcl +1 -0
  388. package/src/__fixtures__/live-module-keyed/root/main.tf +21 -0
  389. package/src/__fixtures__/live-module-keyed/root/modules/app/main.tf +17 -0
  390. package/src/__fixtures__/live-module-keyed/root/modules/edge/main.tf +7 -0
  391. package/src/__fixtures__/live-module-keyed/root/versions.tf +30 -0
  392. package/src/__fixtures__/live-module-keyed/show-state.json +146 -0
  393. package/src/__fixtures__/pr-loop/README.md +50 -0
  394. package/src/__fixtures__/pr-loop/chant.config.json +13 -0
  395. package/src/__fixtures__/pr-loop/estate.component.ts +10 -0
  396. package/src/__fixtures__/pr-loop/roots/a/main.tf +11 -0
  397. package/src/__fixtures__/pr-loop/roots/app/main.tf +19 -0
  398. package/src/__fixtures__/pr-loop/roots/b/main.tf +7 -0
  399. package/src/__fixtures__/pr-loop/roots/dns/main.tf +3 -0
  400. package/src/__fixtures__/pr-loop/roots/net/main.tf +7 -0
  401. package/src/__fixtures__/report/applied.show.json +51 -0
  402. package/src/__fixtures__/report/generate.ts +63 -0
  403. package/src/__fixtures__/report/plan.show.json +200 -0
  404. package/src/__fixtures__/report/tf-apply/change-set.json +170 -0
  405. package/src/__fixtures__/report/tf-apply/report.json +338 -0
  406. package/src/__fixtures__/report/tf-plan/change-set.json +170 -0
  407. package/src/__fixtures__/report/tf-plan/report.json +320 -0
  408. package/src/__fixtures__/three-cloud-azure.graph.json +290 -0
  409. package/src/__fixtures__/used-sources/root/extra.tofu +1 -0
  410. package/src/__fixtures__/used-sources/root/main.tf +31 -0
  411. package/src/__fixtures__/used-sources/root/modules/net/main.tf +14 -0
  412. package/src/__fixtures__/used-sources/root/modules/net/versions.tf.json +7 -0
  413. package/src/__fixtures__/used-sources/unit/terragrunt.hcl +3 -0
  414. package/src/applied-state.ts +52 -0
  415. package/src/backend-config.test.ts +105 -0
  416. package/src/backend-config.ts +133 -0
  417. package/src/behaviour/kinds.ts +4 -0
  418. package/src/behaviour/predict.ts +5 -2
  419. package/src/behaviour/reference-catalog.plugin.test.ts +65 -0
  420. package/src/behaviour/reference-catalog.ts +16 -5
  421. package/src/behaviour/request.ts +3 -2
  422. package/src/change-set-instances.test.ts +98 -0
  423. package/src/changed-roots.ts +14 -16
  424. package/src/ci-setup.ts +42 -0
  425. package/src/commands.ts +4 -3
  426. package/src/components/capability-plugin.test.ts +198 -19
  427. package/src/components/capability-plugin.ts +383 -35
  428. package/src/components/change-set-graph.e2e.test.ts +11 -5
  429. package/src/components/compose-group.test.ts +486 -0
  430. package/src/components/compose-group.ts +489 -0
  431. package/src/components/demo-composed-roots.e2e.test.ts +440 -0
  432. package/src/components/member-outputs.test.ts +76 -0
  433. package/src/components/placeholder-preview.test.ts +147 -0
  434. package/src/components/placeholder-preview.ts +257 -0
  435. package/src/components/pr-loop-compose.tofu.e2e.test.ts +363 -0
  436. package/src/components/pr-loop.tofu.test.ts +113 -57
  437. package/src/components/release-inputs.ts +69 -0
  438. package/src/components/trace-facts.test.ts +21 -0
  439. package/src/components/trace-facts.ts +27 -0
  440. package/src/compose/apply-events.test.ts +62 -0
  441. package/src/compose/apply-events.ts +100 -0
  442. package/src/compose/estate.choudoufu.e2e.test.ts +112 -0
  443. package/src/compose/estate.test.ts +421 -0
  444. package/src/compose/estate.ts +443 -0
  445. package/src/compose/hcl.ts +311 -0
  446. package/src/compose/module-address.ts +49 -0
  447. package/src/compose/root.test.ts +416 -0
  448. package/src/compose/root.ts +592 -0
  449. package/src/compose/run.test.ts +440 -0
  450. package/src/compose/run.tofu.test.ts +176 -0
  451. package/src/compose/run.ts +527 -0
  452. package/src/compose/slice.test.ts +184 -0
  453. package/src/compose/slice.ts +290 -0
  454. package/src/compose/state-address.ts +157 -0
  455. package/src/compose/state-merge.test.ts +131 -0
  456. package/src/compose/state-merge.ts +148 -0
  457. package/src/compose.test.ts +248 -0
  458. package/src/compose.ts +627 -0
  459. package/src/composites/terraform-apply-op.test.ts +9 -0
  460. package/src/composites/terraform-apply-op.ts +7 -3
  461. package/src/cone.ts +138 -0
  462. package/src/config-file-listers.test.ts +265 -0
  463. package/src/config.ts +44 -9
  464. package/src/cost-hold.ts +29 -0
  465. package/src/describe-resources.engine-facts.test.ts +411 -0
  466. package/src/describe-resources.live-module-keyed.test.ts +290 -0
  467. package/src/describe-resources.ts +416 -70
  468. package/src/drift-read.ts +284 -0
  469. package/src/drift-record.test.ts +223 -0
  470. package/src/drift-record.ts +455 -0
  471. package/src/drift-rows.test.ts +135 -0
  472. package/src/drift-rows.ts +137 -0
  473. package/src/exit-codes.test.ts +23 -0
  474. package/src/exit-codes.ts +59 -0
  475. package/src/hcl/config-blocks.test.ts +174 -0
  476. package/src/hcl/edges.ts +21 -1
  477. package/src/hcl/files.ts +234 -0
  478. package/src/hcl/instance-forms.test.ts +94 -0
  479. package/src/hcl/instances.test.ts +137 -0
  480. package/src/hcl/instances.ts +422 -0
  481. package/src/hcl/parse.test.ts +139 -1
  482. package/src/hcl/parse.ts +149 -16
  483. package/src/hcl/roots.ts +6 -0
  484. package/src/hcl/suppressions.ts +8 -2
  485. package/src/index.ts +79 -0
  486. package/src/lint/audit-catalog.ts +29 -3
  487. package/src/lint/audit-lineage.ts +14 -2
  488. package/src/lint/post-synth/fixtures/TF024/live-with-record-store/main.tf +18 -0
  489. package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/estate.chdf.hcl +1 -0
  490. package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/main.tf +10 -0
  491. package/src/lint/post-synth/fixtures/TF046/azurerm-no-resource-group/main.tf +15 -0
  492. package/src/lint/post-synth/fixtures/TF046/backend-config-only/main.tf +14 -0
  493. package/src/lint/post-synth/fixtures/TF046/derived-s3/backend.tf +7 -0
  494. package/src/lint/post-synth/fixtures/TF046/derived-s3/main.tf +9 -0
  495. package/src/lint/post-synth/fixtures/TF046/explicit-local/main.tf +16 -0
  496. package/src/lint/post-synth/fixtures/TF046/explicit-s3-beside-local-backend/main.tf +15 -0
  497. package/src/lint/post-synth/fixtures/TF046/implied-local/main.tf +9 -0
  498. package/src/lint/post-synth/fixtures/TF046/sidecar-implied/estate.chdf.hcl +1 -0
  499. package/src/lint/post-synth/fixtures/TF046/sidecar-implied/main.tf +5 -0
  500. package/src/lint/post-synth/fixtures/TF047/clear/main.tf +12 -0
  501. package/src/lint/post-synth/fixtures/TF047/refused/main.tf +12 -0
  502. package/src/lint/post-synth/fixtures/TF047/unknown-module/main.tf +12 -0
  503. package/src/lint/post-synth/fixtures/TF047/unknown-version/main.tf +12 -0
  504. package/src/lint/post-synth/index.ts +4 -0
  505. package/src/lint/post-synth/record-store.ts +122 -0
  506. package/src/lint/post-synth/tf001.ts +2 -2
  507. package/src/lint/post-synth/tf024.test.ts +26 -5
  508. package/src/lint/post-synth/tf024.ts +105 -22
  509. package/src/lint/post-synth/tf046.test.ts +137 -0
  510. package/src/lint/post-synth/tf046.ts +204 -0
  511. package/src/lint/post-synth/tf047.test.ts +56 -0
  512. package/src/lint/post-synth/tf047.ts +114 -0
  513. package/src/live-plan-reasons.ts +54 -0
  514. package/src/lock-rows.test.ts +70 -0
  515. package/src/lock-rows.ts +82 -0
  516. package/src/lock-timeout.ts +34 -0
  517. package/src/lsp/completions.test.ts +1 -1
  518. package/src/lsp/option-keys.ts +2 -0
  519. package/src/module-catalog/index.test.ts +93 -0
  520. package/src/module-catalog/index.ts +159 -0
  521. package/src/module-catalog/refresh-cli.ts +68 -0
  522. package/src/module-catalog/static-tier.ts +1659 -0
  523. package/src/module-catalog/types.ts +88 -0
  524. package/src/op/activities/choudoufu-plan-set-op.test.ts +111 -0
  525. package/src/op/activities/index.ts +9 -0
  526. package/src/op/activities/live-detect.ts +55 -26
  527. package/src/op/activities/pin-rollout.ts +3 -0
  528. package/src/op/activities/registry.test.ts +2 -1
  529. package/src/op/activities/terraform.test.ts +55 -0
  530. package/src/op/activities/terraform.ts +312 -27
  531. package/src/op/activity-contracts.test.ts +1 -0
  532. package/src/op/activity-contracts.ts +24 -1
  533. package/src/op/builders.ts +14 -0
  534. package/src/op-wave-step.test.ts +109 -0
  535. package/src/pin/__fixtures__/consumers/live/dev/main.tf +4 -0
  536. package/src/pin/__fixtures__/consumers/live/prod/main.tf +21 -0
  537. package/src/pin/__fixtures__/consumers/units/vpc/terragrunt.hcl +7 -0
  538. package/src/pin/bundle.test.ts +2 -0
  539. package/src/pin/consumers.test.ts +57 -0
  540. package/src/pin/consumers.ts +95 -0
  541. package/src/pin/edit.ts +30 -0
  542. package/src/pin/rollout.ts +16 -11
  543. package/src/plan-shape.test.ts +148 -0
  544. package/src/plan-shape.ts +128 -0
  545. package/src/plugin.ts +39 -19
  546. package/src/registry/__fixtures__/docs/documented/.terraform-docs.yml +3 -0
  547. package/src/registry/__fixtures__/docs/documented/README.md +1 -0
  548. package/src/registry/__fixtures__/docs/documented/main.tf +8 -0
  549. package/src/registry/__fixtures__/docs/json/main.tf.json +14 -0
  550. package/src/registry/__fixtures__/docs/vpc/README.md +3 -0
  551. package/src/registry/__fixtures__/docs/vpc/examples/complete/main.tf +5 -0
  552. package/src/registry/__fixtures__/docs/vpc/examples/simple/README.md +1 -0
  553. package/src/registry/__fixtures__/docs/vpc/examples/simple/main.tf +4 -0
  554. package/src/registry/__fixtures__/docs/vpc/main.tf +14 -0
  555. package/src/registry/__fixtures__/docs/vpc/outputs.tf +9 -0
  556. package/src/registry/__fixtures__/docs/vpc/variables.tf +16 -0
  557. package/src/registry/__fixtures__/proxied-root/main.tf +12 -0
  558. package/src/registry/address.ts +100 -0
  559. package/src/registry/catalog-read.ts +56 -0
  560. package/src/registry/deprecated.test.ts +139 -0
  561. package/src/registry/deprecated.ts +76 -0
  562. package/src/registry/docs.test.ts +140 -0
  563. package/src/registry/docs.ts +299 -0
  564. package/src/registry/edge/bundle.test.ts +50 -0
  565. package/src/registry/edge/edge.test.ts +176 -0
  566. package/src/registry/edge/edge.ts +211 -0
  567. package/src/registry/edge/index.ts +10 -0
  568. package/src/registry/edge/lambda-edge.ts +127 -0
  569. package/src/registry/edge/sigv4-web.ts +79 -0
  570. package/src/registry/edge/token-source.test.ts +258 -0
  571. package/src/registry/edge/token-source.ts +169 -0
  572. package/src/registry/edge/worker.ts +61 -0
  573. package/src/registry/handler.ts +89 -0
  574. package/src/registry/headers-file.ts +61 -0
  575. package/src/registry/index.ts +31 -0
  576. package/src/registry/mirror-paths.ts +10 -0
  577. package/src/registry/mirror.test.ts +198 -0
  578. package/src/registry/mirror.ts +395 -0
  579. package/src/registry/proxies.test.ts +153 -0
  580. package/src/registry/proxies.ts +132 -0
  581. package/src/registry/reader.ts +225 -0
  582. package/src/registry/registry.test.ts +262 -0
  583. package/src/registry/semver.ts +34 -0
  584. package/src/registry/serve.ts +82 -0
  585. package/src/registry/source-forms.test.ts +87 -0
  586. package/src/registry/source-forms.ts +216 -0
  587. package/src/registry/targets/artifactory.test.ts +248 -0
  588. package/src/registry/targets/artifactory.ts +257 -0
  589. package/src/registry/targets/fake-artifactory.ts +158 -0
  590. package/src/registry/targets/fake-gitlab.ts +161 -0
  591. package/src/registry/targets/fake-hcp.ts +233 -0
  592. package/src/registry/targets/fake-http.ts +97 -0
  593. package/src/registry/targets/fake-nexus.ts +152 -0
  594. package/src/registry/targets/gitlab.test.ts +208 -0
  595. package/src/registry/targets/gitlab.ts +223 -0
  596. package/src/registry/targets/hcp.test.ts +230 -0
  597. package/src/registry/targets/hcp.ts +360 -0
  598. package/src/registry/targets/hosted.ts +117 -0
  599. package/src/registry/targets/index.ts +17 -0
  600. package/src/registry/targets/module-target.ts +131 -0
  601. package/src/registry/targets/nexus.test.ts +220 -0
  602. package/src/registry/targets/nexus.ts +314 -0
  603. package/src/registry/targets/zip.test.ts +65 -0
  604. package/src/registry/targets/zip.ts +287 -0
  605. package/src/registry/writer.ts +155 -0
  606. package/src/report.test.ts +82 -1
  607. package/src/report.ts +31 -54
  608. package/src/signal-only-root.test.ts +72 -0
  609. package/src/skills/chant-terraform.md +1 -1
  610. package/src/state/azure-blob.ts +8 -0
  611. package/src/state/backend-verdict.test.ts +187 -0
  612. package/src/state/backend.test.ts +127 -0
  613. package/src/state/backend.ts +488 -0
  614. package/src/state/exec.ts +111 -0
  615. package/src/state/gcs.ts +7 -0
  616. package/src/state/index.ts +15 -0
  617. package/src/state/locks.test.ts +84 -0
  618. package/src/state/locks.ts +201 -0
  619. package/src/state/object-store.ts +7 -0
  620. package/src/state/root-states-floci.e2e.test.ts +66 -0
  621. package/src/state/root-states.test.ts +462 -0
  622. package/src/state/root-states.ts +309 -0
  623. package/src/state/s3.ts +21 -0
  624. package/src/state/store.ts +225 -0
  625. package/src/state-ops.test.ts +182 -0
  626. package/src/state-ops.ts +462 -0
  627. package/src/state-reads.ts +116 -0
  628. package/src/terragrunt/affected.ts +2 -1
  629. package/src/used-sources.test.ts +75 -0
  630. package/src/used-sources.ts +204 -0
  631. package/src/workspace-kinds.test.ts +4 -17
  632. package/workspace-kinds.json +1 -24
  633. package/dist/workspace-member.d.ts +0 -30
  634. package/dist/workspace-member.d.ts.map +0 -1
  635. package/dist/workspace-member.js +0 -91
  636. package/schemas/pulumi.schema.json +0 -34
  637. package/src/testdata/pulumi-member/Pulumi.yaml +0 -2
  638. package/src/testdata/pulumi-member/stack-export.json +0 -53
  639. package/src/testdata/pulumi-unexported/Pulumi.yaml +0 -2
  640. package/src/workspace-member.test.ts +0 -89
  641. package/src/workspace-member.ts +0 -126
@@ -0,0 +1,233 @@
1
+ /**
2
+ * An in-memory stand-in for HCP Terraform's private module registry
3
+ * (chant#4604), for the HCP module target's tests. It is a fetch function:
4
+ * nothing listens on a port and nothing leaves the process, and no HCP
5
+ * account or call is involved.
6
+ *
7
+ * It answers the calls the API docs give
8
+ * (developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/modules):
9
+ *
10
+ * GET /api/v2/organizations/:org/registry-modules/private/:org/:name/:provider attributes.version-statuses
11
+ * POST /api/v2/organizations/:org/registry-modules 201, 422 when it exists
12
+ * POST /api/v2/organizations/:org/registry-modules/private/:org/:name/:provider/versions 201 with links.upload, 422 when it exists
13
+ * PUT https://archivist.terraform.io/v1/object/<id> the gzip tarball
14
+ *
15
+ * and the registry protocol Terraform installs through:
16
+ *
17
+ * GET /.well-known/terraform.json {"modules.v1": "/api/registry/v1/modules/"}
18
+ * GET /api/registry/v1/modules/:org/:name/:provider/:version/download 204, X-Terraform-Get
19
+ * GET https://archivist.terraform.io/v1/object/<id> the tarball
20
+ *
21
+ * A token the fake does not know gets 401. A known token without Manage
22
+ * modules, or any token when the organization has no entitlement, gets 404
23
+ * from the registry calls, as HCP answers. A version is `pending` once
24
+ * created, and turns `ok` after its tarball is uploaded and the module has
25
+ * been read `parseAfterReads` more times. `throttle(n)` answers the next n
26
+ * requests with 429. Every request is kept, headers and body included.
27
+ */
28
+ import { gunzipSync } from "node:zlib";
29
+
30
+ export interface FakeHcpRequest {
31
+ method: string;
32
+ url: string;
33
+ /** Header names lower-cased. */
34
+ headers: Record<string, string>;
35
+ body?: Uint8Array;
36
+ }
37
+
38
+ export interface FakeHcpOptions {
39
+ /** Default app.terraform.io. */
40
+ host?: string;
41
+ organization: string;
42
+ /** Tokens the fake knows, and whether each one's team has Manage modules. */
43
+ tokens: Record<string, { manageModules: boolean }>;
44
+ /** Whether the organization has the private registry. Default true. */
45
+ entitled?: boolean;
46
+ /** Module reads after an upload before the version is `ok`. Default 0; Infinity keeps it pending. */
47
+ parseAfterReads?: number;
48
+ }
49
+
50
+ interface FakeVersion {
51
+ status: string;
52
+ commitSha: string | null;
53
+ archive?: Uint8Array;
54
+ object: string;
55
+ readsLeft: number;
56
+ }
57
+
58
+ export type FakeHcpFetch = (url: string, init?: { method?: string; headers?: unknown; body?: unknown }) => Promise<Response>;
59
+
60
+ export interface FakeHcp {
61
+ fetch: FakeHcpFetch;
62
+ requests: FakeHcpRequest[];
63
+ /** Modules by `<name>/<provider>`, each with its versions. */
64
+ modules: Map<string, Map<string, FakeVersion>>;
65
+ /** Put a module, and a version with its archive, in directly. Status `ok` unless given. */
66
+ seed(name: string, provider: string, version?: { version: string; archive: Uint8Array; status?: string }): void;
67
+ /** Answer the next `n` requests with 429, carrying `Retry-After` when it is given. */
68
+ throttle(n: number, retryAfter?: string): void;
69
+ }
70
+
71
+ export const ARCHIVIST = "archivist.terraform.io";
72
+
73
+ function headersOf(h: unknown): Record<string, string> {
74
+ const out: Record<string, string> = {};
75
+ if (!h) return out;
76
+ if (typeof (h as Headers).forEach === "function" && typeof (h as Headers).get === "function") {
77
+ (h as Headers).forEach((v, k) => (out[k.toLowerCase()] = v));
78
+ return out;
79
+ }
80
+ for (const [k, v] of Object.entries(h as Record<string, string>)) out[k.toLowerCase()] = String(v);
81
+ return out;
82
+ }
83
+
84
+ function bodyOf(b: unknown): Uint8Array | undefined {
85
+ if (b === undefined || b === null) return undefined;
86
+ if (typeof b === "string") return new TextEncoder().encode(b);
87
+ if (b instanceof Uint8Array) return b;
88
+ if (b instanceof ArrayBuffer) return new Uint8Array(b);
89
+ throw new Error("the fake takes a string or bytes as a body");
90
+ }
91
+
92
+ const doc = (status: number, body: unknown) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/vnd.api+json" } });
93
+ const errors = (status: number, title: string) => doc(status, { errors: [{ status: String(status), title }] });
94
+
95
+ export function createFakeHcp(o: FakeHcpOptions): FakeHcp {
96
+ const host = o.host ?? "app.terraform.io";
97
+ const org = o.organization;
98
+ const requests: FakeHcpRequest[] = [];
99
+ const modules = new Map<string, Map<string, FakeVersion>>();
100
+ const objects = new Map<string, { module: string; version: string }>();
101
+ let throttled = 0;
102
+ let throttleAfter: string | undefined;
103
+ let next = 0;
104
+
105
+ const newVersion = (module: string, version: string, status: string, commitSha: string | null, archive?: Uint8Array): FakeVersion => {
106
+ const object = `obj${++next}`;
107
+ objects.set(object, { module, version });
108
+ return { status, commitSha, object, readsLeft: o.parseAfterReads ?? 0, ...(archive ? { archive } : {}) };
109
+ };
110
+ const seed: FakeHcp["seed"] = (name, provider, version) => {
111
+ const key = `${name}/${provider}`;
112
+ const vs = modules.get(key) ?? new Map<string, FakeVersion>();
113
+ modules.set(key, vs);
114
+ if (version) vs.set(version.version, newVersion(key, version.version, version.status ?? "ok", null, version.archive));
115
+ };
116
+
117
+ const moduleDoc = (name: string, provider: string, vs: Map<string, FakeVersion>) =>
118
+ doc(200, {
119
+ data: {
120
+ id: `mod-${name}-${provider}`,
121
+ type: "registry-modules",
122
+ attributes: {
123
+ name,
124
+ provider,
125
+ namespace: org,
126
+ "registry-name": "private",
127
+ status: vs.size ? "setup_complete" : "pending",
128
+ "version-statuses": [...vs.entries()].map(([version, v]) => ({ version, status: v.status })),
129
+ },
130
+ },
131
+ });
132
+
133
+ const fetch: FakeHcpFetch = async (url, init = {}) => {
134
+ const method = (init.method ?? "GET").toUpperCase();
135
+ const headers = headersOf(init.headers);
136
+ const body = bodyOf(init.body);
137
+ requests.push({ method, url, headers, ...(body ? { body } : {}) });
138
+ if (throttled > 0) {
139
+ throttled--;
140
+ return new Response(JSON.stringify({ errors: [{ status: "429", title: "Too Many Requests" }] }), { status: 429, headers: throttleAfter !== undefined ? { "retry-after": throttleAfter } : {} });
141
+ }
142
+ const u = new URL(url);
143
+
144
+ if (u.host === ARCHIVIST) {
145
+ const id = /^\/v1\/object\/([^/]+)$/.exec(u.pathname)?.[1];
146
+ const ref = id ? objects.get(id) : undefined;
147
+ if (!ref) return errors(404, "not found");
148
+ const v = modules.get(ref.module)!.get(ref.version)!;
149
+ if (method === "PUT") {
150
+ if (headers["content-type"] !== "application/octet-stream") return errors(400, "content type");
151
+ if (!body) return errors(400, "no body");
152
+ try {
153
+ gunzipSync(body);
154
+ } catch {
155
+ v.status = "reg_ingress_failed";
156
+ return new Response(null, { status: 200 });
157
+ }
158
+ v.archive = body;
159
+ if (v.readsLeft <= 0) v.status = "ok";
160
+ return new Response(null, { status: 200 });
161
+ }
162
+ if (method === "GET") return v.archive ? new Response(new Uint8Array(v.archive), { status: 200 }) : errors(404, "not found");
163
+ return errors(405, "method");
164
+ }
165
+ if (u.host !== host) throw new TypeError(`fetch failed: the fake answers only ${host} and ${ARCHIVIST}, not ${u.host}`);
166
+
167
+ if (method === "GET" && u.pathname === "/.well-known/terraform.json") return new Response(JSON.stringify({ "modules.v1": "/api/registry/v1/modules/" }), { status: 200 });
168
+
169
+ const bearer = /^Bearer (.+)$/i.exec(headers.authorization ?? "")?.[1];
170
+ if (!bearer || !o.tokens[bearer]) return errors(401, "unauthorized");
171
+ const allowed = o.tokens[bearer]!.manageModules && o.entitled !== false;
172
+
173
+ const proto = /^\/api\/registry\/v1\/modules\/([^/]+)\/([^/]+)\/([^/]+)\/([^/]+)\/download$/.exec(u.pathname);
174
+ if (proto && method === "GET") {
175
+ if (proto[1] !== org || o.entitled === false) return errors(404, "not found");
176
+ const v = modules.get(`${proto[2]}/${proto[3]}`)?.get(proto[4]!);
177
+ if (!v || v.status !== "ok") return errors(404, "not found");
178
+ return new Response(null, { status: 204, headers: { "X-Terraform-Get": `https://${ARCHIVIST}/v1/object/${v.object}` } });
179
+ }
180
+
181
+ const base = `/api/v2/organizations/${org}/registry-modules`;
182
+ if (!u.pathname.startsWith(base)) return errors(404, "not found");
183
+ if (!allowed) return errors(404, "not found");
184
+
185
+ if (method === "POST" && u.pathname === base) {
186
+ const d = JSON.parse(new TextDecoder().decode(body ?? new Uint8Array())) as { data?: { type?: string; attributes?: Record<string, unknown> } };
187
+ const a = d.data?.attributes ?? {};
188
+ if (d.data?.type !== "registry-modules" || typeof a.name !== "string" || typeof a.provider !== "string" || a["registry-name"] !== "private") return errors(422, "malformed");
189
+ const key = `${a.name}/${a.provider}`;
190
+ if (modules.has(key)) return errors(422, "Name has already been taken");
191
+ modules.set(key, new Map());
192
+ return doc(201, { data: { type: "registry-modules", attributes: { name: a.name, provider: a.provider } } });
193
+ }
194
+
195
+ const m = /^\/private\/([^/]+)\/([^/]+)\/([^/]+)(\/versions)?$/.exec(u.pathname.slice(base.length));
196
+ if (!m || m[1] !== org) return errors(404, "not found");
197
+ const key = `${m[2]}/${m[3]}`;
198
+ const vs = modules.get(key);
199
+ if (!vs) return errors(404, "not found");
200
+
201
+ if (!m[4] && method === "GET") {
202
+ for (const v of vs.values()) {
203
+ if (v.status === "pending" && v.archive) {
204
+ if (v.readsLeft <= 0) v.status = "ok";
205
+ else v.readsLeft--;
206
+ }
207
+ }
208
+ return moduleDoc(m[2]!, m[3]!, vs);
209
+ }
210
+ if (m[4] && method === "POST") {
211
+ const d = JSON.parse(new TextDecoder().decode(body ?? new Uint8Array())) as { data?: { type?: string; attributes?: { version?: unknown; "commit-sha"?: unknown } } };
212
+ const version = d.data?.attributes?.version;
213
+ if (d.data?.type !== "registry-module-versions" || typeof version !== "string") return errors(422, "malformed");
214
+ if (vs.has(version)) return errors(422, "Version has already been taken");
215
+ const sha = d.data.attributes?.["commit-sha"];
216
+ const v = newVersion(key, version, "pending", typeof sha === "string" ? sha : null);
217
+ vs.set(version, v);
218
+ return doc(201, { data: { type: "registry-module-versions", attributes: { version, status: "pending", source: "tfe-api", "commit-sha": v.commitSha }, links: { upload: `https://${ARCHIVIST}/v1/object/${v.object}` } } });
219
+ }
220
+ return errors(405, "method");
221
+ };
222
+
223
+ return {
224
+ fetch,
225
+ requests,
226
+ modules,
227
+ seed,
228
+ throttle(n, retryAfter) {
229
+ throttled = n;
230
+ throttleAfter = retryAfter;
231
+ },
232
+ };
233
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Pieces the in-memory host fakes share (chant#4605): reading a request's
3
+ * headers and body as a fetch caller passes them, JSON answers, basic and
4
+ * bearer header parsing, and a module tarball builder, so a test (in chant
5
+ * or in terragucci#1302) can make a real attested archive to publish.
6
+ */
7
+ import { gzipSync } from "node:zlib";
8
+
9
+ /** One request a fake was sent. */
10
+ export interface FakeRequest {
11
+ method: string;
12
+ url: string;
13
+ /** Header names lower-cased. */
14
+ headers: Record<string, string>;
15
+ body?: Uint8Array;
16
+ }
17
+
18
+ /** The fetch a fake answers: both the target's `fetch` and the reader's `registryFetch`. */
19
+ export type FakeFetch = (url: string, init?: { method?: string; headers?: unknown; body?: unknown }) => Promise<Response>;
20
+
21
+ export function headersOf(h: unknown): Record<string, string> {
22
+ const out: Record<string, string> = {};
23
+ if (!h) return out;
24
+ if (typeof (h as Headers).forEach === "function" && typeof (h as Headers).get === "function") {
25
+ (h as Headers).forEach((v, k) => (out[k.toLowerCase()] = v));
26
+ return out;
27
+ }
28
+ for (const [k, v] of Object.entries(h as Record<string, string>)) out[k.toLowerCase()] = String(v);
29
+ return out;
30
+ }
31
+
32
+ export function bodyOf(b: unknown): Uint8Array | undefined {
33
+ if (b === undefined || b === null) return undefined;
34
+ if (typeof b === "string") return new TextEncoder().encode(b);
35
+ if (b instanceof Uint8Array) return b;
36
+ if (b instanceof ArrayBuffer) return new Uint8Array(b);
37
+ throw new Error("the fake takes a string or bytes as a body");
38
+ }
39
+
40
+ export const jsonAnswer = (status: number, doc: unknown): Response => new Response(JSON.stringify(doc), { status, headers: { "content-type": "application/json" } });
41
+
42
+ /** The user and password of a `Basic` header, or undefined. */
43
+ export function basicOf(authorization: string | undefined): { user: string; password: string } | undefined {
44
+ const m = /^Basic (.+)$/i.exec(authorization ?? "");
45
+ if (!m) return undefined;
46
+ const text = Buffer.from(m[1]!, "base64").toString("utf-8");
47
+ const at = text.indexOf(":");
48
+ return at < 0 ? undefined : { user: text.slice(0, at), password: text.slice(at + 1) };
49
+ }
50
+
51
+ /** The token of a `Bearer` header, or undefined. */
52
+ export const bearerOf = (authorization: string | undefined): string | undefined => /^Bearer (.+)$/i.exec(authorization ?? "")?.[1];
53
+
54
+ /** A ustar header block for one entry. */
55
+ function tarHeader(path: string, size: number, type: "0" | "5", mode: number, mtime: number): Buffer {
56
+ const h = Buffer.alloc(512);
57
+ const put = (text: string, at: number, len: number) => h.write(text.slice(0, len), at, len, "utf-8");
58
+ const oct = (n: number, len: number) => n.toString(8).padStart(len - 1, "0") + "\0";
59
+ put(path, 0, 100);
60
+ put(oct(mode, 8), 100, 8);
61
+ put(oct(0, 8), 108, 8);
62
+ put(oct(0, 8), 116, 8);
63
+ put(oct(size, 12), 124, 12);
64
+ put(oct(mtime, 12), 136, 12);
65
+ h.fill(0x20, 148, 156);
66
+ h.write(type, 156, 1, "latin1");
67
+ put("ustar\0", 257, 6);
68
+ put("00", 263, 2);
69
+ let sum = 0;
70
+ for (const b of h) sum += b;
71
+ put(sum.toString(8).padStart(6, "0") + "\0 ", 148, 8);
72
+ return h;
73
+ }
74
+
75
+ /**
76
+ * A module tarball as the bucket registry serves one: a gzip of a ustar
77
+ * archive with the given files at its root (paths under 100 bytes), each
78
+ * directory written before its files.
79
+ */
80
+ export function moduleTarball(files: Record<string, string | Uint8Array>, mtime = 1_700_000_000): Buffer {
81
+ const blocks: Buffer[] = [];
82
+ const dirs = new Set<string>();
83
+ for (const path of Object.keys(files).sort()) {
84
+ const parts = path.split("/");
85
+ for (let i = 1; i < parts.length; i++) {
86
+ const dir = parts.slice(0, i).join("/");
87
+ if (dirs.has(dir)) continue;
88
+ dirs.add(dir);
89
+ blocks.push(tarHeader(`${dir}/`, 0, "5", 0o755, mtime));
90
+ }
91
+ const raw = files[path]!;
92
+ const data = typeof raw === "string" ? Buffer.from(raw, "utf-8") : Buffer.from(raw);
93
+ blocks.push(tarHeader(path, data.length, "0", 0o644, mtime), data, Buffer.alloc((512 - (data.length % 512)) % 512));
94
+ }
95
+ blocks.push(Buffer.alloc(1024));
96
+ return gzipSync(Buffer.concat(blocks));
97
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * An in-memory stand-in for a Sonatype Nexus Repository hosted Terraform
3
+ * repository (chant#4605), for the Nexus module target's tests here and in
4
+ * terragucci#1302. It is a fetch function: nothing listens on a port and
5
+ * nothing leaves the process.
6
+ *
7
+ * It answers the calls terragucci#1299's research found in Sonatype's docs,
8
+ * under `/repository/<repo>/`:
9
+ *
10
+ * PUT v1/modules/<ns>/<name>/<system>/<version>/<file> basic credentials, the archive as the body
11
+ * GET v1/modules/<ns>/<name>/<system>/<version>/<file>
12
+ * GET v1/modules/<ns>/<name>/<system>/versions
13
+ * GET v1/modules/<ns>/<name>/<system>/<version>/download 204, X-Terraform-Get
14
+ * GET v1/api/token the 3.95 bearer token, for basic credentials
15
+ *
16
+ * There is no `/.well-known/terraform.json`: a Nexus repository is reached
17
+ * through a CLI `host` block. Without credentials every call gets 401.
18
+ * `bearer: false` drops the token call (Nexus before 3.95), and reads then
19
+ * take basic credentials only. A body that is not a zip or a gzip holding a
20
+ * `.tf` file gets 400, and an upload over a version already held gets 400,
21
+ * as a deployment policy that disallows redeploy does, unless `redeploy` is
22
+ * set. `cacheNotFound` keeps a new version's versions list answering 404 for
23
+ * that many reads, as Nexus before 3.95 kept a "not found" in its cache.
24
+ * Every request is kept, headers and body included.
25
+ */
26
+ import { gunzipSync } from "node:zlib";
27
+ import { readZip } from "./zip";
28
+ import { basicOf, bearerOf, bodyOf, headersOf, jsonAnswer, type FakeFetch, type FakeRequest } from "./fake-http";
29
+
30
+ export interface FakeNexusOptions {
31
+ /** The host, such as `nexus.example.com`. */
32
+ host: string;
33
+ /** The hosted Terraform repositories' names. */
34
+ repos: string[];
35
+ /** Users (or user token name codes) and their passwords (or pass codes). */
36
+ users: Record<string, string>;
37
+ /** Whether the 3.95 token call is there. Default true. */
38
+ bearer?: boolean;
39
+ /** Whether an upload over a held version is taken. Default false: 400. */
40
+ redeploy?: boolean;
41
+ /** How many versions reads a new version answers 404 for. Default 0. */
42
+ cacheNotFound?: number;
43
+ }
44
+
45
+ export interface FakeNexus {
46
+ fetch: FakeFetch;
47
+ requests: FakeRequest[];
48
+ /** Uploaded assets, keyed `<repo>/<ns>/<name>/<system>/<version>/<file>`. */
49
+ assets: Map<string, Uint8Array>;
50
+ /** Bearer tokens the token call issued. */
51
+ issued: Set<string>;
52
+ /** Put an asset in directly, as an upload by hand would. */
53
+ seed(repo: string, ns: string, name: string, system: string, version: string, file: string, bytes: Uint8Array): void;
54
+ }
55
+
56
+ const holdsTf = (body: Uint8Array): boolean => {
57
+ if (body[0] === 0x50 && body[1] === 0x4b) return readZip(body).entries.some((e) => !e.dir && e.path.endsWith(".tf"));
58
+ if (body[0] === 0x1f && body[1] === 0x8b) return gunzipSync(body).includes(Buffer.from(".tf"));
59
+ return false;
60
+ };
61
+
62
+ export function createFakeNexus(o: FakeNexusOptions): FakeNexus {
63
+ const requests: FakeRequest[] = [];
64
+ const assets = new Map<string, Uint8Array>();
65
+ const issued = new Set<string>();
66
+ const cached = new Map<string, number>();
67
+
68
+ const userOf = (headers: Record<string, string>): string | undefined => {
69
+ const b = basicOf(headers.authorization);
70
+ return b && o.users[b.user] === b.password ? b.user : undefined;
71
+ };
72
+ const mayRead = (headers: Record<string, string>): boolean => {
73
+ if (userOf(headers)) return true;
74
+ const bearer = bearerOf(headers.authorization);
75
+ return o.bearer !== false && bearer !== undefined && issued.has(bearer);
76
+ };
77
+ const versionOf = (key: string) => key.split("/").slice(0, 5).join("/");
78
+
79
+ const seed: FakeNexus["seed"] = (repo, ns, name, system, version, file, bytes) => void assets.set(`${repo}/${ns}/${name}/${system}/${version}/${file}`, bytes);
80
+
81
+ const fetch: FakeFetch = async (url, init = {}) => {
82
+ const method = (init.method ?? "GET").toUpperCase();
83
+ const headers = headersOf(init.headers);
84
+ const body = bodyOf(init.body);
85
+ requests.push({ method, url, headers, ...(body ? { body } : {}) });
86
+ const u = new URL(url);
87
+ if (u.host !== o.host) throw new TypeError(`fetch failed: the fake answers only ${o.host}, not ${u.host}`);
88
+ const m = /^\/repository\/([^/]+)\/(.*)$/.exec(u.pathname);
89
+ if (!m || !o.repos.includes(decodeURIComponent(m[1]!))) return jsonAnswer(404, { message: "Not Found" });
90
+ const repo = decodeURIComponent(m[1]!);
91
+ const rest = m[2]!.split("/").map(decodeURIComponent);
92
+
93
+ if (rest.join("/") === "v1/api/token") {
94
+ if (method !== "GET" || o.bearer === false) return jsonAnswer(404, { message: "Not Found" });
95
+ const user = userOf(headers);
96
+ if (!user) return jsonAnswer(401, { message: "Unauthorized" });
97
+ const token = `TerraformBearerToken.fake-${user}-${issued.size + 1}`;
98
+ issued.add(token);
99
+ return jsonAnswer(200, { token });
100
+ }
101
+ if (rest[0] !== "v1" || rest[1] !== "modules") return jsonAnswer(404, { message: "Not Found" });
102
+ const [ns, name, system] = rest.slice(2, 5);
103
+ const prefix = `${repo}/${ns}/${name}/${system}/`;
104
+ const tail = rest.slice(5);
105
+
106
+ if (method === "PUT") {
107
+ if (tail.length !== 2) return jsonAnswer(404, { message: "Not Found" });
108
+ if (!userOf(headers)) return jsonAnswer(401, { message: "Unauthorized" });
109
+ if (!body || body.length === 0) return jsonAnswer(400, { message: "empty body" });
110
+ let ok = false;
111
+ try {
112
+ ok = holdsTf(body);
113
+ } catch {
114
+ ok = false;
115
+ }
116
+ if (!ok) return jsonAnswer(400, { message: "the archive must be a .zip, .tar.gz or .tgz holding .tf files" });
117
+ const k = `${prefix}${tail[0]}/${tail[1]}`;
118
+ const held = [...assets.keys()].some((a) => versionOf(a) === versionOf(k));
119
+ if (held && !o.redeploy) return jsonAnswer(400, { message: "Repository does not allow updating assets" });
120
+ assets.set(k, body);
121
+ if (o.cacheNotFound) cached.set(`${prefix}`, o.cacheNotFound);
122
+ return new Response(null, { status: 201 });
123
+ }
124
+ if (method !== "GET") return jsonAnswer(405, { message: "Method Not Allowed" });
125
+ if (!mayRead(headers)) return jsonAnswer(401, { message: "Unauthorized" });
126
+
127
+ if (tail.length === 1 && tail[0] === "versions") {
128
+ const left = cached.get(prefix) ?? 0;
129
+ if (left > 0) {
130
+ cached.set(prefix, left - 1);
131
+ return jsonAnswer(404, { message: "Not Found" });
132
+ }
133
+ const versions = [...new Set([...assets.keys()].filter((k) => k.startsWith(prefix)).map((k) => k.slice(prefix.length).split("/")[0]!))];
134
+ if (versions.length === 0) return jsonAnswer(404, { message: "Not Found" });
135
+ return jsonAnswer(200, { modules: [{ versions: versions.map((version) => ({ version })) }] });
136
+ }
137
+ if (tail.length === 2 && tail[1] === "download") {
138
+ const asset = [...assets.keys()].find((k) => k.startsWith(`${prefix}${tail[0]}/`));
139
+ if (!asset) return jsonAnswer(404, { message: "Not Found" });
140
+ const file = asset.slice(`${prefix}${tail[0]}/`.length);
141
+ return new Response(null, { status: 204, headers: { "X-Terraform-Get": `${u.origin}/repository/${repo}/v1/modules/${ns}/${name}/${system}/${tail[0]}/${file}` } });
142
+ }
143
+ if (tail.length === 2) {
144
+ const stored = assets.get(`${prefix}${tail[0]}/${tail[1]}`);
145
+ if (!stored) return jsonAnswer(404, { message: "Not Found" });
146
+ return new Response(new Uint8Array(stored), { status: 200, headers: { "content-type": "application/octet-stream" } });
147
+ }
148
+ return jsonAnswer(404, { message: "Not Found" });
149
+ };
150
+
151
+ return { fetch, requests, assets, issued, seed };
152
+ }