@intentius/chant-lexicon-terraform 0.124.52 → 0.124.54

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 (336) hide show
  1. package/README.md +7 -6
  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/commands.d.ts.map +1 -1
  27. package/dist/commands.js +4 -3
  28. package/dist/components/capability-plugin.d.ts +65 -3
  29. package/dist/components/capability-plugin.d.ts.map +1 -1
  30. package/dist/components/capability-plugin.js +197 -13
  31. package/dist/components/compose-group.d.ts +145 -0
  32. package/dist/components/compose-group.d.ts.map +1 -0
  33. package/dist/components/compose-group.js +407 -0
  34. package/dist/components/placeholder-preview.d.ts +78 -0
  35. package/dist/components/placeholder-preview.d.ts.map +1 -0
  36. package/dist/components/placeholder-preview.js +254 -0
  37. package/dist/compose/apply-events.d.ts +46 -0
  38. package/dist/compose/apply-events.d.ts.map +1 -0
  39. package/dist/compose/apply-events.js +77 -0
  40. package/dist/compose/estate.d.ts +194 -0
  41. package/dist/compose/estate.d.ts.map +1 -0
  42. package/dist/compose/estate.js +363 -0
  43. package/dist/compose/hcl.d.ts +99 -0
  44. package/dist/compose/hcl.d.ts.map +1 -0
  45. package/dist/compose/hcl.js +302 -0
  46. package/dist/compose/module-address.d.ts +24 -0
  47. package/dist/compose/module-address.d.ts.map +1 -0
  48. package/dist/compose/module-address.js +43 -0
  49. package/dist/compose/root.d.ts +127 -0
  50. package/dist/compose/root.d.ts.map +1 -0
  51. package/dist/compose/root.js +586 -0
  52. package/dist/compose/run.d.ts +183 -0
  53. package/dist/compose/run.d.ts.map +1 -0
  54. package/dist/compose/run.js +447 -0
  55. package/dist/compose/slice.d.ts +102 -0
  56. package/dist/compose/slice.d.ts.map +1 -0
  57. package/dist/compose/slice.js +249 -0
  58. package/dist/compose/state-address.d.ts +28 -0
  59. package/dist/compose/state-address.d.ts.map +1 -0
  60. package/dist/compose/state-address.js +154 -0
  61. package/dist/compose/state-merge.d.ts +52 -0
  62. package/dist/compose/state-merge.d.ts.map +1 -0
  63. package/dist/compose/state-merge.js +135 -0
  64. package/dist/compose.d.ts +179 -0
  65. package/dist/compose.d.ts.map +1 -0
  66. package/dist/compose.js +482 -0
  67. package/dist/composites/terraform-apply-op.d.ts.map +1 -1
  68. package/dist/composites/terraform-apply-op.js +7 -3
  69. package/dist/config.d.ts +59 -13
  70. package/dist/config.d.ts.map +1 -1
  71. package/dist/config.js +43 -9
  72. package/dist/describe-resources.d.ts +74 -12
  73. package/dist/describe-resources.d.ts.map +1 -1
  74. package/dist/describe-resources.js +374 -66
  75. package/dist/drift-read.d.ts +33 -0
  76. package/dist/drift-read.d.ts.map +1 -0
  77. package/dist/drift-read.js +243 -0
  78. package/dist/drift-record.d.ts +147 -0
  79. package/dist/drift-record.d.ts.map +1 -0
  80. package/dist/drift-record.js +383 -0
  81. package/dist/hcl/edges.d.ts.map +1 -1
  82. package/dist/hcl/edges.js +24 -1
  83. package/dist/hcl/files.d.ts +61 -0
  84. package/dist/hcl/files.d.ts.map +1 -0
  85. package/dist/hcl/files.js +221 -0
  86. package/dist/hcl/instances.d.ts +82 -0
  87. package/dist/hcl/instances.d.ts.map +1 -0
  88. package/dist/hcl/instances.js +390 -0
  89. package/dist/hcl/parse.d.ts +81 -9
  90. package/dist/hcl/parse.d.ts.map +1 -1
  91. package/dist/hcl/parse.js +114 -16
  92. package/dist/hcl/roots.d.ts.map +1 -1
  93. package/dist/hcl/roots.js +5 -0
  94. package/dist/hcl/suppressions.d.ts.map +1 -1
  95. package/dist/hcl/suppressions.js +8 -2
  96. package/dist/index.d.ts +11 -2
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +21 -2
  99. package/dist/integrity.json +3 -3
  100. package/dist/live-plan-reasons.d.ts +21 -0
  101. package/dist/live-plan-reasons.d.ts.map +1 -0
  102. package/dist/live-plan-reasons.js +47 -0
  103. package/dist/lsp/option-keys.d.ts.map +1 -1
  104. package/dist/lsp/option-keys.js +2 -0
  105. package/dist/manifest.json +1 -1
  106. package/dist/op/activities/index.d.ts +6 -2
  107. package/dist/op/activities/index.d.ts.map +1 -1
  108. package/dist/op/activities/index.js +5 -1
  109. package/dist/op/activities/live-detect.d.ts +4 -3
  110. package/dist/op/activities/live-detect.d.ts.map +1 -1
  111. package/dist/op/activities/live-detect.js +57 -32
  112. package/dist/op/activities/pin-rollout.d.ts +2 -0
  113. package/dist/op/activities/pin-rollout.d.ts.map +1 -1
  114. package/dist/op/activities/pin-rollout.js +1 -0
  115. package/dist/op/activities/terraform.d.ts +153 -5
  116. package/dist/op/activities/terraform.d.ts.map +1 -1
  117. package/dist/op/activities/terraform.js +205 -20
  118. package/dist/op/activity-contracts.d.ts +27 -0
  119. package/dist/op/activity-contracts.d.ts.map +1 -1
  120. package/dist/op/activity-contracts.js +19 -1
  121. package/dist/op/builders.d.ts +7 -1
  122. package/dist/op/builders.d.ts.map +1 -1
  123. package/dist/op/builders.js +9 -0
  124. package/dist/pin/edit.d.ts.map +1 -1
  125. package/dist/pin/edit.js +35 -0
  126. package/dist/pin/rollout.d.ts +2 -0
  127. package/dist/pin/rollout.d.ts.map +1 -1
  128. package/dist/pin/rollout.js +14 -11
  129. package/dist/plan-shape.d.ts +30 -0
  130. package/dist/plan-shape.d.ts.map +1 -0
  131. package/dist/plan-shape.js +125 -0
  132. package/dist/plugin.d.ts.map +1 -1
  133. package/dist/plugin.js +32 -18
  134. package/dist/report.d.ts +15 -6
  135. package/dist/report.d.ts.map +1 -1
  136. package/dist/report.js +28 -55
  137. package/dist/skills/chant-terraform.md +1 -1
  138. package/dist/state/azure-blob.d.ts +68 -0
  139. package/dist/state/azure-blob.d.ts.map +1 -0
  140. package/dist/state/azure-blob.js +201 -0
  141. package/dist/state/backend.d.ts +158 -0
  142. package/dist/state/backend.d.ts.map +1 -0
  143. package/dist/state/backend.js +406 -0
  144. package/dist/state/exec.d.ts +39 -0
  145. package/dist/state/exec.d.ts.map +1 -0
  146. package/dist/state/exec.js +80 -0
  147. package/dist/state/gcs.d.ts +62 -0
  148. package/dist/state/gcs.d.ts.map +1 -0
  149. package/dist/state/gcs.js +224 -0
  150. package/dist/state/index.d.ts +15 -0
  151. package/dist/state/index.d.ts.map +1 -0
  152. package/dist/state/index.js +14 -0
  153. package/dist/state/locks.d.ts +105 -0
  154. package/dist/state/locks.d.ts.map +1 -0
  155. package/dist/state/locks.js +130 -0
  156. package/dist/state/object-store.d.ts +37 -0
  157. package/dist/state/object-store.d.ts.map +1 -0
  158. package/dist/state/object-store.js +20 -0
  159. package/dist/state/root-states.d.ts +131 -0
  160. package/dist/state/root-states.d.ts.map +1 -0
  161. package/dist/state/root-states.js +241 -0
  162. package/dist/state/s3.d.ts +68 -0
  163. package/dist/state/s3.d.ts.map +1 -0
  164. package/dist/state/s3.js +170 -0
  165. package/dist/state/store.d.ts +51 -0
  166. package/dist/state/store.d.ts.map +1 -0
  167. package/dist/state/store.js +185 -0
  168. package/dist/terragrunt/affected.d.ts.map +1 -1
  169. package/dist/terragrunt/affected.js +2 -1
  170. package/package.json +7 -3
  171. package/src/__fixtures__/ACCEPTANCE.md +69 -7
  172. package/src/__fixtures__/compose/apply-failed-in-app.jsonl +12 -0
  173. package/src/__fixtures__/compose/state-app.json +66 -0
  174. package/src/__fixtures__/compose/state-edge.json +40 -0
  175. package/src/__fixtures__/compose/state-net.json +58 -0
  176. package/src/__fixtures__/compose/three-app.plan.json +184 -0
  177. package/src/__fixtures__/compose/three-composed.plan.json +509 -0
  178. package/src/__fixtures__/compose/three-edge.plan.json +144 -0
  179. package/src/__fixtures__/compose/three-net.plan.json +174 -0
  180. package/src/__fixtures__/compose/unknown-composed.plan.json +228 -0
  181. package/src/__fixtures__/compose/working-after-apply.json +145 -0
  182. package/src/__fixtures__/config-blocks/app/main.tf +61 -0
  183. package/src/__fixtures__/config-blocks/app/modules/network/main.tf +4 -0
  184. package/src/__fixtures__/config-blocks/app-json/main.tf.json +39 -0
  185. package/src/__fixtures__/config-files/shadow/main.tf +3 -0
  186. package/src/__fixtures__/config-files/shadow/main.tofu +3 -0
  187. package/src/__fixtures__/config-files/shadow/other.tf +3 -0
  188. package/src/__fixtures__/config-files/tf/main.tf +11 -0
  189. package/src/__fixtures__/config-files/tf-json/main.tf.json +18 -0
  190. package/src/__fixtures__/config-files/tofu/main.tofu +11 -0
  191. package/src/__fixtures__/config-files/tofu-json/main.tofu.json +18 -0
  192. package/src/__fixtures__/config-files/tofu-only/main.tofu +3 -0
  193. package/src/__fixtures__/drift-record/README.md +11 -0
  194. package/src/__fixtures__/drift-record/live-plan-sections.json +27 -0
  195. package/src/__fixtures__/instance-forms/app/main.tf +110 -0
  196. package/src/__fixtures__/instance-forms/app/modules/svc/main.tf +3 -0
  197. package/src/__fixtures__/instance-vars/app/main.tf +52 -0
  198. package/src/__fixtures__/instance-vars/app/modules/app/main.tf +12 -0
  199. package/src/__fixtures__/instance-vars/app/modules/edge/main.tf +3 -0
  200. package/src/__fixtures__/instance-vars/app/terraform.tfvars +1 -0
  201. package/src/__fixtures__/live-module-keyed/live-graph.json +259 -0
  202. package/src/__fixtures__/live-module-keyed/live-plan.json +87 -0
  203. package/src/__fixtures__/live-module-keyed/root/estate.chdf.hcl +1 -0
  204. package/src/__fixtures__/live-module-keyed/root/main.tf +21 -0
  205. package/src/__fixtures__/live-module-keyed/root/modules/app/main.tf +17 -0
  206. package/src/__fixtures__/live-module-keyed/root/modules/edge/main.tf +7 -0
  207. package/src/__fixtures__/live-module-keyed/root/versions.tf +30 -0
  208. package/src/__fixtures__/live-module-keyed/show-state.json +146 -0
  209. package/src/__fixtures__/pr-loop/README.md +50 -0
  210. package/src/__fixtures__/pr-loop/chant.config.json +13 -0
  211. package/src/__fixtures__/pr-loop/estate.component.ts +10 -0
  212. package/src/__fixtures__/pr-loop/roots/a/main.tf +11 -0
  213. package/src/__fixtures__/pr-loop/roots/app/main.tf +19 -0
  214. package/src/__fixtures__/pr-loop/roots/b/main.tf +7 -0
  215. package/src/__fixtures__/pr-loop/roots/dns/main.tf +3 -0
  216. package/src/__fixtures__/pr-loop/roots/net/main.tf +7 -0
  217. package/src/__fixtures__/report/applied.show.json +51 -0
  218. package/src/__fixtures__/report/generate.ts +63 -0
  219. package/src/__fixtures__/report/plan.show.json +200 -0
  220. package/src/__fixtures__/report/tf-apply/change-set.json +170 -0
  221. package/src/__fixtures__/report/tf-apply/report.json +338 -0
  222. package/src/__fixtures__/report/tf-plan/change-set.json +170 -0
  223. package/src/__fixtures__/report/tf-plan/report.json +320 -0
  224. package/src/__fixtures__/three-cloud-azure.graph.json +290 -0
  225. package/src/applied-state.ts +52 -0
  226. package/src/backend-config.test.ts +105 -0
  227. package/src/backend-config.ts +133 -0
  228. package/src/behaviour/kinds.ts +4 -0
  229. package/src/behaviour/predict.ts +5 -2
  230. package/src/behaviour/reference-catalog.plugin.test.ts +65 -0
  231. package/src/behaviour/reference-catalog.ts +16 -5
  232. package/src/behaviour/request.ts +3 -2
  233. package/src/change-set-instances.test.ts +98 -0
  234. package/src/changed-roots.ts +14 -16
  235. package/src/commands.ts +4 -3
  236. package/src/components/capability-plugin.test.ts +172 -5
  237. package/src/components/capability-plugin.ts +212 -11
  238. package/src/components/change-set-graph.e2e.test.ts +11 -5
  239. package/src/components/compose-group.test.ts +486 -0
  240. package/src/components/compose-group.ts +489 -0
  241. package/src/components/demo-composed-roots.e2e.test.ts +440 -0
  242. package/src/components/member-outputs.test.ts +76 -0
  243. package/src/components/placeholder-preview.test.ts +147 -0
  244. package/src/components/placeholder-preview.ts +257 -0
  245. package/src/components/pr-loop-compose.tofu.e2e.test.ts +363 -0
  246. package/src/components/pr-loop.tofu.test.ts +112 -56
  247. package/src/compose/apply-events.test.ts +62 -0
  248. package/src/compose/apply-events.ts +100 -0
  249. package/src/compose/estate.choudoufu.e2e.test.ts +112 -0
  250. package/src/compose/estate.test.ts +421 -0
  251. package/src/compose/estate.ts +443 -0
  252. package/src/compose/hcl.ts +311 -0
  253. package/src/compose/module-address.ts +49 -0
  254. package/src/compose/root.test.ts +416 -0
  255. package/src/compose/root.ts +592 -0
  256. package/src/compose/run.test.ts +440 -0
  257. package/src/compose/run.tofu.test.ts +176 -0
  258. package/src/compose/run.ts +527 -0
  259. package/src/compose/slice.test.ts +184 -0
  260. package/src/compose/slice.ts +290 -0
  261. package/src/compose/state-address.ts +157 -0
  262. package/src/compose/state-merge.test.ts +131 -0
  263. package/src/compose/state-merge.ts +148 -0
  264. package/src/compose.test.ts +248 -0
  265. package/src/compose.ts +627 -0
  266. package/src/composites/terraform-apply-op.test.ts +9 -0
  267. package/src/composites/terraform-apply-op.ts +7 -3
  268. package/src/config-file-listers.test.ts +265 -0
  269. package/src/config.ts +44 -9
  270. package/src/describe-resources.engine-facts.test.ts +412 -0
  271. package/src/describe-resources.live-module-keyed.test.ts +290 -0
  272. package/src/describe-resources.ts +416 -70
  273. package/src/drift-read.ts +284 -0
  274. package/src/drift-record.test.ts +223 -0
  275. package/src/drift-record.ts +455 -0
  276. package/src/hcl/config-blocks.test.ts +174 -0
  277. package/src/hcl/edges.ts +21 -1
  278. package/src/hcl/files.ts +234 -0
  279. package/src/hcl/instance-forms.test.ts +94 -0
  280. package/src/hcl/instances.test.ts +137 -0
  281. package/src/hcl/instances.ts +422 -0
  282. package/src/hcl/parse.test.ts +139 -1
  283. package/src/hcl/parse.ts +149 -16
  284. package/src/hcl/roots.ts +6 -0
  285. package/src/hcl/suppressions.ts +8 -2
  286. package/src/index.ts +76 -0
  287. package/src/live-plan-reasons.ts +54 -0
  288. package/src/lsp/completions.test.ts +1 -1
  289. package/src/lsp/option-keys.ts +2 -0
  290. package/src/op/activities/choudoufu-plan-set-op.test.ts +111 -0
  291. package/src/op/activities/index.ts +9 -0
  292. package/src/op/activities/live-detect.ts +55 -26
  293. package/src/op/activities/pin-rollout.ts +3 -0
  294. package/src/op/activities/registry.test.ts +2 -1
  295. package/src/op/activities/terraform.test.ts +55 -0
  296. package/src/op/activities/terraform.ts +266 -22
  297. package/src/op/activity-contracts.test.ts +1 -0
  298. package/src/op/activity-contracts.ts +24 -1
  299. package/src/op/builders.ts +14 -0
  300. package/src/pin/bundle.test.ts +2 -0
  301. package/src/pin/edit.ts +30 -0
  302. package/src/pin/rollout.ts +16 -11
  303. package/src/plan-shape.test.ts +148 -0
  304. package/src/plan-shape.ts +128 -0
  305. package/src/plugin.ts +33 -19
  306. package/src/report.test.ts +82 -1
  307. package/src/report.ts +31 -54
  308. package/src/signal-only-root.test.ts +72 -0
  309. package/src/skills/chant-terraform.md +1 -1
  310. package/src/state/azure-blob.ts +223 -0
  311. package/src/state/backend-verdict.test.ts +187 -0
  312. package/src/state/backend.test.ts +127 -0
  313. package/src/state/backend.ts +488 -0
  314. package/src/state/exec.ts +111 -0
  315. package/src/state/gcs.ts +254 -0
  316. package/src/state/index.ts +15 -0
  317. package/src/state/locks.test.ts +84 -0
  318. package/src/state/locks.ts +201 -0
  319. package/src/state/object-store.ts +35 -0
  320. package/src/state/root-states-floci.e2e.test.ts +66 -0
  321. package/src/state/root-states.test.ts +462 -0
  322. package/src/state/root-states.ts +309 -0
  323. package/src/state/s3.ts +193 -0
  324. package/src/state/store.ts +225 -0
  325. package/src/terragrunt/affected.ts +2 -1
  326. package/src/workspace-kinds.test.ts +4 -17
  327. package/workspace-kinds.json +1 -24
  328. package/dist/workspace-member.d.ts +0 -30
  329. package/dist/workspace-member.d.ts.map +0 -1
  330. package/dist/workspace-member.js +0 -91
  331. package/schemas/pulumi.schema.json +0 -34
  332. package/src/testdata/pulumi-member/Pulumi.yaml +0 -2
  333. package/src/testdata/pulumi-member/stack-export.json +0 -53
  334. package/src/testdata/pulumi-unexported/Pulumi.yaml +0 -2
  335. package/src/workspace-member.test.ts +0 -89
  336. package/src/workspace-member.ts +0 -126
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Azure Blob Storage for an azurerm backend's state, over its REST API with
3
+ * `fetch` and `node:crypto`: a blob's properties and metadata, its text, a
4
+ * write (under a lease when one holds it), a snapshot, a delete, and the
5
+ * blob lease the backend locks a state with.
6
+ *
7
+ * Requests are signed with Shared Key for an account key, carry a SAS as it
8
+ * is, or carry a storage token the job's OIDC identity is traded for at Entra
9
+ * ID (a client assertion, the way the azurerm backend does it).
10
+ *
11
+ * Lifted from terragucci's `report/azure-blob.ts` (c493e0e), without SAS
12
+ * links, version reads and version listing.
13
+ */
14
+ import { createHmac } from "node:crypto";
15
+ import { readFileSync } from "node:fs";
16
+ import { defaultFetch, encodePath, StoreError, xmlText } from "./object-store.js";
17
+ /** The REST version every request names. */
18
+ export const AZURE_VERSION = "2021-08-06";
19
+ /** Entra ID's public cloud. */
20
+ export const AZURE_AUTHORITY = "https://login.microsoftonline.com";
21
+ const STORAGE_SCOPE = "https://storage.azure.com/.default";
22
+ const hmac64 = (key, s) => createHmac("sha256", Buffer.from(key, "base64")).update(s, "utf8").digest("base64");
23
+ /** The headers whose values Shared Key signs by position, in order. */
24
+ const SIGNED = ["content-encoding", "content-language", "content-length", "content-md5", "content-type", "date", "if-modified-since", "if-match", "if-none-match", "if-unmodified-since", "range"];
25
+ /** The Shared Key Authorization header for a request. */
26
+ export function sharedKey(account, accountKey, method, rawUrl, headers) {
27
+ const url = new URL(rawUrl);
28
+ const h = Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]));
29
+ const fixed = SIGNED.map((n) => (n === "content-length" && h[n] === "0" ? "" : (h[n] ?? "")));
30
+ const ms = Object.keys(h).filter((n) => n.startsWith("x-ms-")).sort().map((n) => `${n}:${h[n].trim()}\n`).join("");
31
+ const params = new Map();
32
+ for (const [k, v] of url.searchParams)
33
+ params.set(k.toLowerCase(), [...(params.get(k.toLowerCase()) ?? []), v]);
34
+ const query = [...params.keys()].sort().map((k) => `\n${k}:${params.get(k).sort().join(",")}`).join("");
35
+ const toSign = [method, ...fixed].join("\n") + "\n" + ms + `/${account}${url.pathname}` + query;
36
+ return `SharedKey ${account}:${hmac64(accountKey, toSign)}`;
37
+ }
38
+ /** Entra ID's error, or the start of the body. */
39
+ const why = (text) => {
40
+ try {
41
+ const j = JSON.parse(text);
42
+ if (j.error)
43
+ return [j.error, j.error_description?.split("\r\n")[0]].filter(Boolean).join(": ");
44
+ }
45
+ catch {
46
+ // Not JSON: Blob Storage answers in XML.
47
+ }
48
+ return [xmlText(text, "Code"), xmlText(text, "Message")?.split("\n")[0]].filter(Boolean).join(": ") || text.slice(0, 300);
49
+ };
50
+ export class AzureBlobClient {
51
+ constructor(target, fetchFn = defaultFetch, readToken = (f) => readFileSync(f, "utf-8")) {
52
+ this.target = target;
53
+ this.fetchFn = fetchFn;
54
+ this.readToken = readToken;
55
+ }
56
+ where(key) {
57
+ return `az://${this.target.account}/${this.target.container}/${key}`;
58
+ }
59
+ blobUrl(key, query = "") {
60
+ const t = this.target;
61
+ const q = [query, "sas" in t ? t.sas.replace(/^\?/, "") : ""].filter(Boolean).join("&");
62
+ return `${t.endpoint}/${t.container}/${encodePath(key)}${q ? `?${q}` : ""}`;
63
+ }
64
+ /** The storage token for the OIDC identity: once per client, again a minute before it expires. */
65
+ async bearer(o) {
66
+ const fetchToken = async () => {
67
+ let assertion;
68
+ try {
69
+ assertion = this.readToken(o.tokenFile).trim();
70
+ }
71
+ catch (e) {
72
+ throw new StoreError(`cannot read the OIDC token in ${o.tokenFile}: ${e.message}`);
73
+ }
74
+ if (!assertion)
75
+ throw new StoreError(`the OIDC token file ${o.tokenFile} is empty`);
76
+ const body = new URLSearchParams({
77
+ client_id: o.clientId,
78
+ scope: STORAGE_SCOPE,
79
+ grant_type: "client_credentials",
80
+ client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
81
+ client_assertion: assertion,
82
+ }).toString();
83
+ const res = await this.fetchFn(`${o.authority}/${o.tenantId}/oauth2/v2.0/token`, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body });
84
+ const text = await res.text();
85
+ if (!res.ok)
86
+ throw new StoreError(`Entra ID refused the OIDC token for client ${o.clientId}: ${res.status} ${why(text)}`);
87
+ let j = {};
88
+ try {
89
+ j = JSON.parse(text);
90
+ }
91
+ catch {
92
+ // Reported below as no token.
93
+ }
94
+ if (!j.access_token)
95
+ throw new StoreError(`Entra ID answered client ${o.clientId} without a token`);
96
+ return { token: j.access_token, expires: Date.now() + Number(j.expires_in ?? 3600) * 1000 };
97
+ };
98
+ const again = () => (this.token = fetchToken().catch((e) => {
99
+ this.token = undefined;
100
+ throw e;
101
+ }));
102
+ let held = await (this.token ?? again());
103
+ if (held.expires - Date.now() < 60000)
104
+ held = await again();
105
+ return held.token;
106
+ }
107
+ /** The headers for one request, signed or with the bearer token. */
108
+ async headers(method, url, extra) {
109
+ const h = { "x-ms-date": new Date().toUTCString(), "x-ms-version": AZURE_VERSION, ...extra };
110
+ const t = this.target;
111
+ if ("accountKey" in t)
112
+ return { ...h, authorization: sharedKey(t.account, t.accountKey, method, url, h) };
113
+ if ("sas" in t)
114
+ return h;
115
+ return { ...h, authorization: `Bearer ${await this.bearer(t.oidc)}` };
116
+ }
117
+ async get(key) {
118
+ const url = this.blobUrl(key);
119
+ const res = await this.fetchFn(url, { method: "GET", headers: await this.headers("GET", url, {}) });
120
+ if (res.status === 404)
121
+ return undefined;
122
+ if (!res.ok)
123
+ throw new StoreError(`GET ${this.where(key)}: ${res.status} ${why(await res.text())}`);
124
+ return res.text();
125
+ }
126
+ /** A blob's properties and metadata, from a HEAD. */
127
+ async head(key) {
128
+ const url = this.blobUrl(key);
129
+ const res = await this.fetchFn(url, { method: "HEAD", headers: await this.headers("HEAD", url, {}) });
130
+ if (res.status === 404)
131
+ return { exists: false, metadata: {} };
132
+ if (!res.ok)
133
+ throw new StoreError(`HEAD ${this.where(key)}: ${res.status}`);
134
+ const get = (n) => res.headers?.get(n) ?? undefined;
135
+ const metadata = {};
136
+ const all = res.headers;
137
+ all?.forEach?.((v, k) => {
138
+ if (k.toLowerCase().startsWith("x-ms-meta-"))
139
+ metadata[k.toLowerCase().slice("x-ms-meta-".length)] = v;
140
+ });
141
+ const etag = get("etag");
142
+ const leaseState = get("x-ms-lease-state");
143
+ return { exists: true, ...(etag ? { etag } : {}), ...(leaseState ? { leaseState } : {}), metadata };
144
+ }
145
+ /** Take a snapshot of a blob: its id, the time Azure gives it. */
146
+ async snapshot(key) {
147
+ const url = this.blobUrl(key, "comp=snapshot");
148
+ const res = await this.fetchFn(url, { method: "PUT", headers: await this.headers("PUT", url, { "content-length": "0" }) });
149
+ if (!res.ok)
150
+ throw new StoreError(`snapshot of ${this.where(key)}: ${res.status} ${why(await res.text())}`);
151
+ const id = res.headers?.get("x-ms-snapshot");
152
+ if (!id)
153
+ throw new StoreError(`snapshot of ${this.where(key)}: Azure answered without x-ms-snapshot`);
154
+ return id;
155
+ }
156
+ /** Write a block blob with metadata, under a lease when one holds it; with `ifNoneMatch`, only when there is none (false when one was there). */
157
+ async putBlob(key, body, contentType, options = {}) {
158
+ const url = this.blobUrl(key);
159
+ const meta = Object.fromEntries(Object.entries(options.metadata ?? {}).map(([k, v]) => [`x-ms-meta-${k}`, v]));
160
+ const extra = {
161
+ "x-ms-blob-type": "BlockBlob",
162
+ "content-type": contentType,
163
+ "content-length": String(Buffer.byteLength(body)),
164
+ ...meta,
165
+ ...(options.leaseId ? { "x-ms-lease-id": options.leaseId } : {}),
166
+ ...(options.ifNoneMatch ? { "if-none-match": "*" } : {}),
167
+ };
168
+ const res = await this.fetchFn(url, { method: "PUT", headers: await this.headers("PUT", url, extra), body });
169
+ if (options.ifNoneMatch && (res.status === 409 || res.status === 412))
170
+ return false;
171
+ if (!res.ok)
172
+ throw new StoreError(`PUT ${this.where(key)}: ${res.status} ${why(await res.text())}`);
173
+ return true;
174
+ }
175
+ /** Delete a blob. One that is not there is deleted already. */
176
+ async remove(key) {
177
+ const url = this.blobUrl(key);
178
+ const res = await this.fetchFn(url, { method: "DELETE", headers: await this.headers("DELETE", url, {}) });
179
+ if (!res.ok && res.status !== 404)
180
+ throw new StoreError(`DELETE ${this.where(key)}: ${res.status} ${why(await res.text())}`);
181
+ }
182
+ /** A blob lease: acquire one that never expires with the id given (false when one holds it), or release it. */
183
+ async lease(key, action, id) {
184
+ const url = this.blobUrl(key, "comp=lease");
185
+ const extra = { "x-ms-lease-action": action, "content-length": "0", ...(action === "acquire" ? { "x-ms-lease-duration": "-1", "x-ms-proposed-lease-id": id } : { "x-ms-lease-id": id }) };
186
+ const res = await this.fetchFn(url, { method: "PUT", headers: await this.headers("PUT", url, extra) });
187
+ if (action === "acquire" && res.status === 409)
188
+ return false;
189
+ if (!res.ok)
190
+ throw new StoreError(`${action} the lease of ${this.where(key)}: ${res.status} ${why(await res.text())}`);
191
+ return true;
192
+ }
193
+ /** Set a blob's metadata, all of it, under its lease when one holds it. */
194
+ async setMetadata(key, metadata, leaseId) {
195
+ const url = this.blobUrl(key, "comp=metadata");
196
+ const extra = { "content-length": "0", ...Object.fromEntries(Object.entries(metadata).map(([k, v]) => [`x-ms-meta-${k}`, v])), ...(leaseId ? { "x-ms-lease-id": leaseId } : {}) };
197
+ const res = await this.fetchFn(url, { method: "PUT", headers: await this.headers("PUT", url, extra) });
198
+ if (!res.ok)
199
+ throw new StoreError(`set the metadata of ${this.where(key)}: ${res.status} ${why(await res.text())}`);
200
+ }
201
+ }
@@ -0,0 +1,158 @@
1
+ import { type AzureOidc } from "./azure-blob.js";
2
+ import { type GcsTarget } from "./gcs.js";
3
+ import { type S3Target } from "./s3.js";
4
+ /** The backend `init` recorded: its type and configuration. */
5
+ export interface InitialisedBackend {
6
+ type: string;
7
+ config: Record<string, unknown>;
8
+ }
9
+ /** A state in an S3 bucket. */
10
+ export interface S3State {
11
+ backend: "s3";
12
+ bucket: string;
13
+ key: string;
14
+ region: string;
15
+ endpoint?: string;
16
+ /** `use_lockfile = true`: the backend locks with `<key>.tflock` beside the state. */
17
+ lockfile: boolean;
18
+ target: S3Target;
19
+ }
20
+ /** A state in a GCS bucket: `<prefix>/<workspace>.tfstate`, locked by `<prefix>/<workspace>.tflock`. */
21
+ export interface GcsState {
22
+ backend: "gcs";
23
+ bucket: string;
24
+ key: string;
25
+ lock: string;
26
+ target: GcsTarget;
27
+ }
28
+ /** How a request to Azure Blob Storage is authorized: an account key, a SAS, or the job's OIDC identity. */
29
+ export type AzureAuth = {
30
+ accountKey: string;
31
+ } | {
32
+ sas: string;
33
+ } | {
34
+ oidc: AzureOidc;
35
+ };
36
+ /** A state blob in an Azure storage container, locked by a lease on it. */
37
+ export interface AzureState {
38
+ backend: "azurerm";
39
+ account: string;
40
+ container: string;
41
+ key: string;
42
+ /** The backend snapshots the blob before each write (`snapshot = true`). */
43
+ snapshot: boolean;
44
+ /** The account's blob endpoint. */
45
+ endpoint: string;
46
+ auth: AzureAuth;
47
+ }
48
+ /** A local state file, its path relative to the root (or absolute). */
49
+ export interface LocalState {
50
+ backend: "local";
51
+ path: string;
52
+ }
53
+ /** Why chant does not lock or write a root's state. */
54
+ export type StateRefusalKind = "cloud" | "no-lockfile" | "backend" | "config" | "credentials" | "disagree";
55
+ export interface StateRefusal {
56
+ backend: string;
57
+ refused: StateRefusalKind;
58
+ reason: string;
59
+ }
60
+ /** Where a root's state lives, or why chant does not lock it. */
61
+ export type StateObject = S3State | GcsState | AzureState | LocalState | StateRefusal;
62
+ /** A state in a bucket or a container. */
63
+ export type StoredState = S3State | GcsState | AzureState;
64
+ /** A state chant locks and writes. */
65
+ export type LockableState = StoredState | LocalState;
66
+ export declare const isRefused: (o: StateObject) => o is StateRefusal;
67
+ /** Whether the state is in a bucket or a container: s3, gcs or azurerm. */
68
+ export declare const isStored: (o: StateObject) => o is StoredState;
69
+ /** The backend types whose state chant locks and writes itself, s3 only with `use_lockfile = true` (#4437). The one list (chant#4478). */
70
+ export declare const LOCKABLE_BACKENDS: readonly string[];
71
+ /** What a refusal says chant locks, spelled from {@link LOCKABLE_BACKENDS}. */
72
+ export declare const LOCKS: string;
73
+ /** The root's data dir: `TF_DATA_DIR` (relative to the root, as the binary run with `-chdir` reads it), else `.terraform`. */
74
+ export declare function dataDir(dir: string, env?: NodeJS.ProcessEnv): string;
75
+ /** The backend `init` recorded for the root, or undefined when it has not been initialised with one. */
76
+ export declare function initialisedBackend(dir: string, env?: NodeJS.ProcessEnv): InitialisedBackend | undefined;
77
+ /** The workspace the binary runs in: `TF_WORKSPACE`, else the one `workspace select` recorded, else `default`. */
78
+ export declare function workspaceOf(dir: string, env?: NodeJS.ProcessEnv): string;
79
+ /** The S3 key of a workspace's state, as the S3 backend names it: the key in `default`, else `<workspace_key_prefix>/<workspace>/<key>`. */
80
+ export declare function s3StateKey(key: string, workspace: string, prefix?: string): string;
81
+ /**
82
+ * Whether the root's code has a `cloud` block, over the configuration files
83
+ * `binary` reads: `.tf` and `.tf.json`, plus `.tofu` and `.tofu.json` for a
84
+ * tofu or choudoufu root, from the lexicon's one lister (chant#4457).
85
+ */
86
+ export declare function hasCloudBlock(dir: string, binary?: string): boolean;
87
+ /** Where a root's backend is read from, before `init` runs. */
88
+ export interface DeclaredBackendInput {
89
+ /** `terraform.roots.<name>.backendConfig`: the `-backend-config` pairs chant's own init passes, last. */
90
+ backendConfig?: Readonly<Record<string, string>>;
91
+ /** `terraform.roots.<name>.backendConfigFiles`: the backend-config files chant's own init passes before the pairs (chant#4459), relative to the root. */
92
+ backendConfigFiles?: readonly string[];
93
+ /** The job's environment: its `TF_CLI_ARGS` and `TF_CLI_ARGS_init` may carry `-backend-config` flags. */
94
+ env?: NodeJS.ProcessEnv;
95
+ /** `terraform.binary`, which says which of the root's files are its code (chant#4457). */
96
+ binary?: string;
97
+ }
98
+ /** The `-backend-config` flags in `TF_CLI_ARGS` then `TF_CLI_ARGS_init`, in order: `key=value` pairs, and the paths of backend-config files. */
99
+ export declare function cliBackendConfig(env?: NodeJS.ProcessEnv): {
100
+ pairs: Record<string, string>;
101
+ files: string[];
102
+ ordered: Array<{
103
+ file: string;
104
+ } | {
105
+ key: string;
106
+ value: string;
107
+ }>;
108
+ };
109
+ /**
110
+ * The backend the root's code declares, with the `-backend-config` flags of
111
+ * `TF_CLI_ARGS`, `TF_CLI_ARGS_init` and then `backendConfig` over it, in the
112
+ * order init applies them: what `init` would record, as far as chant can read
113
+ * it before init runs. A `cloud` block is `{ type: "cloud" }`. Undefined when
114
+ * the code declares neither, which init records as no backend (local).
115
+ */
116
+ export declare function declaredBackend(dir: string, input?: DeclaredBackendInput): InitialisedBackend | undefined;
117
+ /** A root's backend as both sources give it, and the one the verdict reads. */
118
+ export interface BackendReading {
119
+ /** From the root's code and the `-backend-config` flags, before init. */
120
+ declared?: InitialisedBackend;
121
+ /** What `init` recorded. */
122
+ recorded?: InitialisedBackend;
123
+ /** The recorded backend when there is one, else the declared one, else local. */
124
+ backend: InitialisedBackend;
125
+ /** Why the two disagree, naming both, when both exist and they do. */
126
+ disagreement?: string;
127
+ }
128
+ /** Where a root's backend is read from: {@link DeclaredBackendInput}, plus what `init` recorded, which the root's data dir holds unless given. */
129
+ export interface ReadBackendInput extends DeclaredBackendInput {
130
+ /** What `init` recorded; `null` for none. Read from the root's data dir when absent. */
131
+ recorded?: InitialisedBackend | null;
132
+ }
133
+ /**
134
+ * A root's backend from its code and flags and from what `init` recorded,
135
+ * compared (chant#4478). They disagree when both exist and name another type,
136
+ * or when a key both give a plain value has two values; a key only one side
137
+ * gives (a default init filled in, a value from a backend-config file chant
138
+ * did not read) is no disagreement. Code that declares no backend leaves the
139
+ * record to stand.
140
+ */
141
+ export declare function readBackend(dir: string, input?: ReadBackendInput): BackendReading;
142
+ /**
143
+ * Whether chant can lock the root's state, from one {@link BackendReading}:
144
+ * undefined when it can, else the refusal and why. The one verdict the
145
+ * composition's `backend` fallback (#4438) and the state refusals (#4437)
146
+ * both give (chant#4478).
147
+ */
148
+ export declare function lockRefusal(reading: BackendReading): StateRefusal | undefined;
149
+ /**
150
+ * Where the root's state is, or why chant does not lock it, from
151
+ * {@link readBackend}: what `init` recorded (`backend` stands in for it),
152
+ * compared with the root's code, `backendConfigFiles` and `backendConfig`. A root neither declares
153
+ * nor records a backend for reads as a local one.
154
+ */
155
+ export declare function stateObject(dir: string, env?: NodeJS.ProcessEnv, backend?: InitialisedBackend | undefined, binary?: string, flags?: Pick<DeclaredBackendInput, "backendConfig" | "backendConfigFiles">): StateObject;
156
+ /** `s3://<bucket>/<key>`, `gs://<bucket>/<key>`, `az://<account>/<container>/<key>`, or the local file's path; undefined for a refusal. */
157
+ export declare function stateLocation(o: StateObject): string | undefined;
158
+ //# sourceMappingURL=backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/state/backend.ts"],"names":[],"mappings":"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"}