@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,87 @@
1
+ {
2
+ "estate": "module-keyed-estate",
3
+ "choudoufu_version": "",
4
+ "upstream_version": "1.13.0",
5
+ "bound": [
6
+ {
7
+ "addr": "module.app[0].aws_cloudwatch_log_group.logs",
8
+ "type": "aws_cloudwatch_log_group",
9
+ "identity": "/module-keyed-estate/app-0",
10
+ "identity_values": {
11
+ "name": "/module-keyed-estate/app-0"
12
+ },
13
+ "source": "derived"
14
+ },
15
+ {
16
+ "addr": "module.app[0].aws_eip.pool[0]",
17
+ "type": "aws_eip",
18
+ "identity": "eipalloc-0a41c7d2e9b3f5061",
19
+ "source": "marker"
20
+ },
21
+ {
22
+ "addr": "module.app[0].aws_eip.pool[1]",
23
+ "type": "aws_eip",
24
+ "identity": "eipalloc-0b52d8e3fac4061f2",
25
+ "source": "marker"
26
+ },
27
+ {
28
+ "addr": "module.app[1].aws_eip.pool[0]",
29
+ "type": "aws_eip",
30
+ "identity": "eipalloc-0c63e9f40bd5172a3",
31
+ "source": "marker"
32
+ },
33
+ {
34
+ "addr": "module.app[1].aws_eip.pool[1]",
35
+ "type": "aws_eip",
36
+ "identity": "eipalloc-0d74fa051ce6283b4",
37
+ "source": "marker"
38
+ }
39
+ ],
40
+ "omissions": [
41
+ {
42
+ "addr": "module.app[1].aws_cloudwatch_log_group.logs",
43
+ "reason": "ABSENT",
44
+ "detail": "The provider reports no aws_cloudwatch_log_group exists with identity \"/module-keyed-estate/app-1\", so this resource has not been created yet. The plan will propose creating it."
45
+ },
46
+ {
47
+ "addr": "module.edge[\"east\"].aws_cloudwatch_log_group.front",
48
+ "reason": "UNOWNED",
49
+ "detail": "A live aws_cloudwatch_log_group already exists with identity \"/module-keyed-estate/edge-east\" and carries no tofu-estate marker, so this estate does not own it and the plan proposes creating the resource this configuration declares - which, for a type whose name must be unique, the cloud will refuse while the unowned one holds it. Adopt it by writing tofu-estate=\"module-keyed-estate\" and tofu-address=\"module.edge:east.aws_cloudwatch_log_group.front\" onto it, then re-run; or set policy { declared_untagged = \"adopt\" } in the live block to have this run adopt it for you; or point this resource at a name nobody is using."
50
+ },
51
+ {
52
+ "addr": "module.edge[\"west\"].aws_cloudwatch_log_group.front",
53
+ "reason": "UNOWNED",
54
+ "detail": "A live aws_cloudwatch_log_group already exists with identity \"/module-keyed-estate/edge-west\" and carries tofu-estate=\"other-estate\", so it belongs to another estate and nothing in this plan reads, changes or destroys it. Taking it over is something you do deliberately: `live-mv -from-estate=other-estate` rewrites the marker to this estate one address at a time, and `live-import -approve` stamps this estate's markers over the resources a state file lists. Or point this resource at a name nobody is using. See live/MARKERS.md, \"Ownership semantics\"."
55
+ }
56
+ ],
57
+ "unowned": [
58
+ {
59
+ "addr": "module.edge[\"east\"].aws_cloudwatch_log_group.front",
60
+ "type": "aws_cloudwatch_log_group",
61
+ "identity": "/module-keyed-estate/edge-east",
62
+ "adopt_tofu_estate": "module-keyed-estate",
63
+ "adopt_tofu_address": "module.edge:east.aws_cloudwatch_log_group.front"
64
+ },
65
+ {
66
+ "addr": "module.edge[\"west\"].aws_cloudwatch_log_group.front",
67
+ "type": "aws_cloudwatch_log_group",
68
+ "identity": "/module-keyed-estate/edge-west",
69
+ "tofu_estate": "other-estate"
70
+ }
71
+ ],
72
+ "foreign": null,
73
+ "adoptable": [],
74
+ "swept": [],
75
+ "diagnostics": [
76
+ {
77
+ "severity": "warning",
78
+ "summary": "Live resource outside this estate",
79
+ "detail": "A live aws_cloudwatch_log_group already exists with identity \"/module-keyed-estate/edge-east\" and carries no tofu-estate marker, so this estate does not own it and the plan proposes creating the resource this configuration declares - which, for a type whose name must be unique, the cloud will refuse while the unowned one holds it. Adopt it by writing tofu-estate=\"module-keyed-estate\" and tofu-address=\"module.edge:east.aws_cloudwatch_log_group.front\" onto it, then re-run; or set policy { declared_untagged = \"adopt\" } in the live block to have this run adopt it for you; or point this resource at a name nobody is using."
80
+ },
81
+ {
82
+ "severity": "warning",
83
+ "summary": "Live resource outside this estate",
84
+ "detail": "A live aws_cloudwatch_log_group already exists with identity \"/module-keyed-estate/edge-west\" and carries tofu-estate=\"other-estate\", so it belongs to another estate and nothing in this plan reads, changes or destroys it. Taking it over is something you do deliberately: `live-mv -from-estate=other-estate` rewrites the marker to this estate one address at a time, and `live-import -approve` stamps this estate's markers over the resources a state file lists. Or point this resource at a name nobody is using. See live/MARKERS.md, \"Ownership semantics\"."
85
+ }
86
+ ]
87
+ }
@@ -0,0 +1 @@
1
+ estate = "module-keyed-estate"
@@ -0,0 +1,21 @@
1
+ # Two expanded module calls, one per expansion form, so every address the
2
+ # live-plan and state documents beside this directory carry is module-keyed
3
+ # (chant #4513): `module.app[0].aws_eip.pool[1]`, `module.edge["east"]...`.
4
+ #
5
+ # The instance key reaches the child only through a variable, which is the
6
+ # form choudoufu's identity resolver reads for a module call's count and
7
+ # for_each (internal/live/identity/moduleforeachvar_test.go,
8
+ # TestModuleCallCountVar and TestModuleCallForEachVar, testdata
9
+ # module-count-var/ and module-foreach-var/).
10
+
11
+ module "app" {
12
+ source = "./modules/app"
13
+ count = 2
14
+ index = count.index
15
+ }
16
+
17
+ module "edge" {
18
+ source = "./modules/edge"
19
+ for_each = toset(["east", "west"])
20
+ zone = each.key
21
+ }
@@ -0,0 +1,17 @@
1
+ variable "index" {
2
+ type = number
3
+ }
4
+
5
+ # Expanded itself too, so its instances carry a key and a scope:
6
+ # `module.app[1].aws_eip.pool[0]`. EC2 assigns the allocation id, so
7
+ # choudoufu binds these by marker.
8
+ resource "aws_eip" "pool" {
9
+ count = 2
10
+ domain = "vpc"
11
+ }
12
+
13
+ # Not expanded itself: its instances carry a scope and no key. The name is
14
+ # the identity, so choudoufu derives it from the configuration.
15
+ resource "aws_cloudwatch_log_group" "logs" {
16
+ name = "/module-keyed-estate/app-${var.index}"
17
+ }
@@ -0,0 +1,7 @@
1
+ variable "zone" {
2
+ type = string
3
+ }
4
+
5
+ resource "aws_cloudwatch_log_group" "front" {
6
+ name = "/module-keyed-estate/edge-${var.zone}"
7
+ }
@@ -0,0 +1,30 @@
1
+ # Provider wiring, copied from ../../live-estate/versions.tf (itself derived
2
+ # from choudoufu's live/e2e/estate-block/versions.tf). The estate name is in
3
+ # the estate.chdf.hcl sidecar beside this file, as in live-estate/.
4
+ #
5
+ # Same environment-variable wiring as choudoufu's own fixture
6
+ # (AWS_ENDPOINT_URL, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION);
7
+ # the provider block carries only the flags with no env-var form.
8
+
9
+ terraform {
10
+ required_version = ">= 1.5.0"
11
+
12
+ required_providers {
13
+ aws = {
14
+ source = "hashicorp/aws"
15
+ version = "= 6.58.0"
16
+ }
17
+ }
18
+ }
19
+
20
+ provider "aws" {
21
+ skip_credentials_validation = true
22
+ skip_metadata_api_check = true
23
+
24
+ # skip_requesting_account_id deliberately absent — same rationale as the
25
+ # main estate's versions.tf (live/e2e/estate/versions.tf): letting the
26
+ # provider resolve the account keeps tag-filtered discovery honest about
27
+ # what real AWS would do.
28
+
29
+ s3_use_path_style = true
30
+ }
@@ -0,0 +1,146 @@
1
+ {
2
+ "format_version": "1.0",
3
+ "terraform_version": "1.13.0",
4
+ "values": {
5
+ "root_module": {
6
+ "child_modules": [
7
+ {
8
+ "resources": [
9
+ {
10
+ "address": "module.app[0].aws_cloudwatch_log_group.logs",
11
+ "mode": "managed",
12
+ "type": "aws_cloudwatch_log_group",
13
+ "name": "logs",
14
+ "provider_name": "registry.opentofu.org/hashicorp/aws",
15
+ "schema_version": 0,
16
+ "values": {
17
+ "arn": "arn:aws:logs:us-east-1:000000000000:log-group:/module-keyed-estate/app-0",
18
+ "id": "/module-keyed-estate/app-0",
19
+ "name": "/module-keyed-estate/app-0"
20
+ },
21
+ "sensitive_values": {}
22
+ },
23
+ {
24
+ "address": "module.app[0].aws_eip.pool[0]",
25
+ "mode": "managed",
26
+ "type": "aws_eip",
27
+ "name": "pool",
28
+ "index": 0,
29
+ "provider_name": "registry.opentofu.org/hashicorp/aws",
30
+ "schema_version": 0,
31
+ "values": {
32
+ "allocation_id": "eipalloc-0a41c7d2e9b3f5061",
33
+ "domain": "vpc",
34
+ "id": "eipalloc-0a41c7d2e9b3f5061"
35
+ },
36
+ "sensitive_values": {}
37
+ },
38
+ {
39
+ "address": "module.app[0].aws_eip.pool[1]",
40
+ "mode": "managed",
41
+ "type": "aws_eip",
42
+ "name": "pool",
43
+ "index": 1,
44
+ "provider_name": "registry.opentofu.org/hashicorp/aws",
45
+ "schema_version": 0,
46
+ "values": {
47
+ "allocation_id": "eipalloc-0b52d8e3fac4061f2",
48
+ "domain": "vpc",
49
+ "id": "eipalloc-0b52d8e3fac4061f2"
50
+ },
51
+ "sensitive_values": {}
52
+ }
53
+ ],
54
+ "address": "module.app[0]"
55
+ },
56
+ {
57
+ "resources": [
58
+ {
59
+ "address": "module.app[1].aws_cloudwatch_log_group.logs",
60
+ "mode": "managed",
61
+ "type": "aws_cloudwatch_log_group",
62
+ "name": "logs",
63
+ "provider_name": "registry.opentofu.org/hashicorp/aws",
64
+ "schema_version": 0,
65
+ "values": {
66
+ "arn": "arn:aws:logs:us-east-1:000000000000:log-group:/module-keyed-estate/app-1",
67
+ "id": "/module-keyed-estate/app-1",
68
+ "name": "/module-keyed-estate/app-1"
69
+ },
70
+ "sensitive_values": {}
71
+ },
72
+ {
73
+ "address": "module.app[1].aws_eip.pool[0]",
74
+ "mode": "managed",
75
+ "type": "aws_eip",
76
+ "name": "pool",
77
+ "index": 0,
78
+ "provider_name": "registry.opentofu.org/hashicorp/aws",
79
+ "schema_version": 0,
80
+ "values": {
81
+ "allocation_id": "eipalloc-0c63e9f40bd5172a3",
82
+ "domain": "vpc",
83
+ "id": "eipalloc-0c63e9f40bd5172a3"
84
+ },
85
+ "sensitive_values": {}
86
+ },
87
+ {
88
+ "address": "module.app[1].aws_eip.pool[1]",
89
+ "mode": "managed",
90
+ "type": "aws_eip",
91
+ "name": "pool",
92
+ "index": 1,
93
+ "provider_name": "registry.opentofu.org/hashicorp/aws",
94
+ "schema_version": 0,
95
+ "values": {
96
+ "allocation_id": "eipalloc-0d74fa051ce6283b4",
97
+ "domain": "vpc",
98
+ "id": "eipalloc-0d74fa051ce6283b4"
99
+ },
100
+ "sensitive_values": {}
101
+ }
102
+ ],
103
+ "address": "module.app[1]"
104
+ },
105
+ {
106
+ "resources": [
107
+ {
108
+ "address": "module.edge[\"east\"].aws_cloudwatch_log_group.front",
109
+ "mode": "managed",
110
+ "type": "aws_cloudwatch_log_group",
111
+ "name": "front",
112
+ "provider_name": "registry.opentofu.org/hashicorp/aws",
113
+ "schema_version": 0,
114
+ "values": {
115
+ "arn": "arn:aws:logs:us-east-1:000000000000:log-group:/module-keyed-estate/edge-east",
116
+ "id": "/module-keyed-estate/edge-east",
117
+ "name": "/module-keyed-estate/edge-east"
118
+ },
119
+ "sensitive_values": {}
120
+ }
121
+ ],
122
+ "address": "module.edge[\"east\"]"
123
+ },
124
+ {
125
+ "resources": [
126
+ {
127
+ "address": "module.edge[\"west\"].aws_cloudwatch_log_group.front",
128
+ "mode": "managed",
129
+ "type": "aws_cloudwatch_log_group",
130
+ "name": "front",
131
+ "provider_name": "registry.opentofu.org/hashicorp/aws",
132
+ "schema_version": 0,
133
+ "values": {
134
+ "arn": "arn:aws:logs:us-east-1:000000000000:log-group:/module-keyed-estate/edge-west",
135
+ "id": "/module-keyed-estate/edge-west",
136
+ "name": "/module-keyed-estate/edge-west"
137
+ },
138
+ "sensitive_values": {}
139
+ }
140
+ ],
141
+ "address": "module.edge[\"west\"]"
142
+ }
143
+ ]
144
+ }
145
+ }
146
+ }
@@ -0,0 +1,50 @@
1
+ # pr-loop: five roots through the pull-request loop
2
+
3
+ The workspace `../../components/pr-loop.tofu.test.ts` runs through
4
+ `chant components pr-plan` and `chant components pr-apply` over real `tofu`
5
+ (or `terraform`). Every root uses `terraform_data` with local state, so
6
+ nothing downloads a provider or reaches a cloud.
7
+
8
+ The estate is net -> a, b and a -> app, with dns on its own. a and b read
9
+ net's `cidr`, and app reads a's `id`, through `stackOutput()` in
10
+ `estate.component.ts`. a's `id` is `terraform_data.subnet.output`, which is
11
+ known only after a applies, so on a pull request that changes a, app sits
12
+ outside any group with an unknown upstream read and is previewed with a
13
+ placeholder for `var.subnet` (chant#4463).
14
+
15
+ What happens on merge depends on the value a applies with:
16
+
17
+ - A pull request that changes a's subnet suffix from `a-v1` to `a-v2`: app's
18
+ real plan, made once a applied, is the update the preview showed with
19
+ `a.id` filled in. The first approval covers it and both roots apply in one
20
+ run. This is the single-approval path.
21
+ - A pull request that changes it to `a-wide`: app's `wide` resource has
22
+ `count = local.wide`, and `local.wide` reads `var.subnet` through a local,
23
+ which the preview does not follow. The stand-in does not end in `-wide`, so
24
+ the preview plans no `terraform_data.wide`. The real id does, so the real
25
+ plan also creates `terraform_data.wide[0]`. That exceeds the preview, so
26
+ app's round 2 is not covered and waits on its own `pr-apply-round-2` gate
27
+ (chant#4487).
28
+
29
+ `chant.config.json` names `tofu`; the test writes its own with whichever
30
+ binary is on PATH.
31
+
32
+ ## The recorded pull-request run for chant#4463
33
+
34
+ chant#4463's maintainer run uses this fixture, on the `a-v2` path. In a scratch
35
+ directory:
36
+
37
+ 1. Copy this directory, `git init -b main`, add a `.gitignore` with
38
+ `node_modules`, `.terraform`, `.terraform.lock.hcl`, `*.tfstate*`,
39
+ `chant.tfplan` and `.chant`, and commit.
40
+ 2. Apply the base once: write `all.json` as `{"changed":["net","dns"]}` and run
41
+ `chant components fan-out --from-affected all.json`.
42
+ 3. On a branch, change `a-v1` to `a-v2` in `roots/a/main.tf`, commit, and run
43
+ `chant components pr-plan --base main --pr <n> --forge github` on the pull
44
+ request. The note's app row says `previewed with placeholders for var.subnet`.
45
+ 4. Approve the digest the note names, merge, and run
46
+ `chant components pr-apply --base <main before the merge> --forge github --require-review`.
47
+ Both roots apply in one run, and the note says app's round was covered by
48
+ the first approval with `a.id` filled in.
49
+
50
+ Record the note and the apply's output on chant#4463.
@@ -0,0 +1,13 @@
1
+ {
2
+ "lexicons": ["terraform"],
3
+ "terraform": {
4
+ "binary": "tofu",
5
+ "roots": {
6
+ "net": { "dir": "roots/net" },
7
+ "a": { "dir": "roots/a" },
8
+ "b": { "dir": "roots/b" },
9
+ "app": { "dir": "roots/app" },
10
+ "dns": { "dir": "roots/dns" }
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ import { phase, stackOutput, type Component } from "@intentius/chant/components";
2
+
3
+ const apply = (root: string, vars?: Record<string, unknown>) =>
4
+ [phase("Apply", [{ kind: "terraform-apply", root, noRollback: "test roots with local state", vars: vars ?? {} }])];
5
+
6
+ export const net: Component = { name: "net", dependsOn: [], deploy: apply("net") };
7
+ export const a: Component = { name: "a", dependsOn: ["net"], deploy: apply("a", { cidr: stackOutput("net", "cidr") }) };
8
+ export const b: Component = { name: "b", dependsOn: ["net"], deploy: apply("b", { cidr: stackOutput("net", "cidr") }) };
9
+ export const app: Component = { name: "app", dependsOn: ["a"], deploy: apply("app", { subnet: stackOutput("a", "id") }) };
10
+ export const dns: Component = { name: "dns", dependsOn: [], deploy: apply("dns") };
@@ -0,0 +1,11 @@
1
+ variable "cidr" {
2
+ type = string
3
+ }
4
+
5
+ resource "terraform_data" "subnet" {
6
+ input = "${var.cidr}/a-v1"
7
+ }
8
+
9
+ output "id" {
10
+ value = terraform_data.subnet.output
11
+ }
@@ -0,0 +1,19 @@
1
+ variable "subnet" {
2
+ type = string
3
+ }
4
+
5
+ locals {
6
+ # A second resource only on a subnet whose id ends in -wide. The count
7
+ # reads var.subnet through a local, which the placeholder preview does not
8
+ # follow (chant#4463), so the preview plans no wide instance. See README.md.
9
+ wide = endswith(var.subnet, "-wide") ? 1 : 0
10
+ }
11
+
12
+ resource "terraform_data" "app" {
13
+ input = "app on ${var.subnet}"
14
+ }
15
+
16
+ resource "terraform_data" "wide" {
17
+ count = local.wide
18
+ input = "wide on ${var.subnet}"
19
+ }
@@ -0,0 +1,7 @@
1
+ variable "cidr" {
2
+ type = string
3
+ }
4
+
5
+ resource "terraform_data" "subnet" {
6
+ input = "${var.cidr}/b-v1"
7
+ }
@@ -0,0 +1,3 @@
1
+ resource "terraform_data" "zone" {
2
+ input = "example.test"
3
+ }
@@ -0,0 +1,7 @@
1
+ resource "terraform_data" "vpc" {
2
+ input = "10.0.0.0/16"
3
+ }
4
+
5
+ output "cidr" {
6
+ value = terraform_data.vpc.output
7
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "format_version": "1.2",
3
+ "resource_changes": [],
4
+ "prior_state": {
5
+ "values": {
6
+ "root_module": {
7
+ "child_modules": [
8
+ {
9
+ "address": "module.network",
10
+ "resources": [
11
+ {
12
+ "address": "module.network.aws_subnet.new",
13
+ "values": {
14
+ "id": "subnet-0a1b",
15
+ "arn": "arn:aws:ec2:us-east-1:000000000000:subnet/subnet-0a1b"
16
+ },
17
+ "sensitive_values": {}
18
+ }
19
+ ]
20
+ },
21
+ {
22
+ "address": "module.app",
23
+ "resources": [
24
+ {
25
+ "address": "module.app.aws_security_group.sg",
26
+ "values": {
27
+ "id": "sg-0c2d",
28
+ "vpc_id": "vpc-0e3f"
29
+ },
30
+ "sensitive_values": {}
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ "address": "module.edge",
36
+ "resources": [
37
+ {
38
+ "address": "module.edge.aws_route_table.rt",
39
+ "values": {
40
+ "id": "rtb-0f4a",
41
+ "vpc_id": "vpc-0e3f"
42
+ },
43
+ "sensitive_values": {}
44
+ }
45
+ ]
46
+ }
47
+ ]
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Regenerate the `chant terraform report` fixture behold renders (#4439):
3
+ *
4
+ * npx tsx lexicons/terraform/src/__fixtures__/report/generate.ts
5
+ *
6
+ * It reads `plan.show.json` (a three-estate composed plan: network, app and
7
+ * edge, with app reading network and edge reading app) and `applied.show.json`
8
+ * (the plan made after the apply), runs `terraformReport` for both stages, and
9
+ * writes `<stage>/report.json` and `<stage>/change-set.json` beside them.
10
+ * `report.test.ts` runs `generateReportFixture` and compares it with the
11
+ * files, so a change to the writer shows as a diff here.
12
+ */
13
+
14
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
15
+ import { dirname, join } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+ import { terraformReport, writeReport, type ReportStage, type ReportStore } from "../../report";
18
+
19
+ const here = dirname(fileURLToPath(import.meta.url));
20
+
21
+ export const FIXTURE_RUN = { project: "forgejo:3000/admin/demo-terragrunt", commit: "4439c0ffee", job_url: "http://forgejo:3000/admin/demo-terragrunt/actions/runs/1", pull_request: "1" };
22
+ export const FIXTURE_ESTATES = { network: "demo-network", app: "demo-app", edge: "demo-edge" };
23
+ const FINISHED: Record<ReportStage, string> = { "tf-plan": "2026-10-25T10:00:00Z", "tf-apply": "2026-10-25T10:05:00Z" };
24
+
25
+ const readJson = (name: string): unknown => JSON.parse(readFileSync(join(here, name), "utf8"));
26
+
27
+ /** The fixture's output files by path under this directory: `<stage>/report.json` and `<stage>/change-set.json`. */
28
+ export async function generateReportFixture(): Promise<Record<string, string>> {
29
+ const plan = readJson("plan.show.json");
30
+ const applied = readJson("applied.show.json");
31
+ const files: Record<string, string> = {};
32
+ const store: ReportStore = {
33
+ async read() {
34
+ return undefined;
35
+ },
36
+ async put(key, body) {
37
+ const m = /\/(tf-plan|tf-apply)\/(report|change-set)\.json$/.exec(key);
38
+ if (m) files[`${m[1]}/${m[2]}.json`] = body;
39
+ },
40
+ };
41
+ for (const stage of ["tf-plan", "tf-apply"] as const) {
42
+ await writeReport(store, terraformReport({
43
+ stage,
44
+ plan,
45
+ ...(stage === "tf-apply" ? { applied } : {}),
46
+ run: FIXTURE_RUN,
47
+ binary: "choudoufu",
48
+ rootDir: "estates",
49
+ estates: FIXTURE_ESTATES,
50
+ finished: FINISHED[stage],
51
+ }));
52
+ }
53
+ return files;
54
+ }
55
+
56
+ if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
57
+ const files = await generateReportFixture();
58
+ for (const [name, body] of Object.entries(files)) {
59
+ mkdirSync(dirname(join(here, name)), { recursive: true });
60
+ writeFileSync(join(here, name), body);
61
+ }
62
+ console.log(`wrote ${Object.keys(files).join(", ")}`);
63
+ }