@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,51 @@
1
+ import type { LockableState } from "./backend.js";
2
+ import { type StoreFetch } from "./object-store.js";
3
+ /** The lock a state's backend holds: the ID `force-unlock` takes, and the lock info the binary (or a run) wrote. */
4
+ export interface LockHolder {
5
+ id: string;
6
+ /** The lock info as written, JSON. */
7
+ info: string;
8
+ }
9
+ /** A state where it is, for what locks it and keeps beside it. */
10
+ export interface StateStore {
11
+ readonly backend: LockableState["backend"];
12
+ /** Where the state is. */
13
+ readonly location: string;
14
+ /** Where its lock is: the lock object, or the blob whose lease is the lock. */
15
+ readonly lockLocation: string;
16
+ /** The lock the backend holds now, or undefined. */
17
+ heldLock(): Promise<LockHolder | undefined>;
18
+ /** Take the state's lock with `info`, the way the backend takes it: false when it is held. */
19
+ lock(info: string): Promise<boolean>;
20
+ /** Release the lock `lock` took, or the one `adopt` took over. */
21
+ unlock(): Promise<void>;
22
+ /**
23
+ * Write a new state under the lock, for a backend whose lock keeps the
24
+ * binary from writing (azurerm's lease); undefined for a backend the
25
+ * binary writes with `-lock=false` while the run holds the lock.
26
+ */
27
+ write?: (body: string) => Promise<void>;
28
+ /**
29
+ * The object beside the state whose key is the state's with `suffix` after
30
+ * it, in the same bucket, container or directory, under the state's own
31
+ * access controls: read (undefined when there is none), written, removed.
32
+ */
33
+ readBeside(suffix: string): Promise<string | undefined>;
34
+ writeBeside(suffix: string, body: string): Promise<void>;
35
+ removeBeside(suffix: string): Promise<void>;
36
+ /** Where the object beside the state with `suffix` is, for messages. */
37
+ besideLocation(suffix: string): string;
38
+ /**
39
+ * Take over a lock this store finds held, which an earlier run of the same
40
+ * operation left held on purpose: `unlock` then releases it. A lease
41
+ * (azurerm) is taken over by its ID, the others need nothing.
42
+ */
43
+ adopt(held: LockHolder): void;
44
+ }
45
+ /** The ID in a lock info's JSON, or "" when it names none. */
46
+ export declare function lockId(text: string): string;
47
+ /** The metadata an azurerm backend keeps a lock's info in, base64 JSON, on the leased blob. */
48
+ export declare const LOCK_METADATA = "terraformlockid";
49
+ /** The store a state is in, opened with the credentials stateObject chose. `dir` is the root a local path is relative to. */
50
+ export declare function stateStore(o: LockableState, dir: string, fetchFn?: StoreFetch): StateStore;
51
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/state/store.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAoC,aAAa,EAAW,MAAM,WAAW,CAAC;AAE1F,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAG7D,oHAAoH;AACpH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,kEAAkE;AAClE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAC3C,0BAA0B;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,oDAAoD;IACpD,QAAQ,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAC5C,8FAA8F;IAC9F,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,kEAAkE;IAClE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC;;;;OAIG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxD,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,wEAAwE;IACxE,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CAC/B;AAED,8DAA8D;AAC9D,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO3C;AAiDD,+FAA+F;AAC/F,eAAO,MAAM,aAAa,oBAAoB,CAAC;AAsF/C,6HAA6H;AAC7H,wBAAgB,UAAU,CAAC,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,UAAU,CAK1F"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * A state where it is, opened for its lock and for what a run keeps beside
3
+ * it. Each backend locks its own way:
4
+ *
5
+ * s3 the lock file `use_lockfile` takes, `<key>.tflock`, written only
6
+ * when absent
7
+ * gcs the lock object `<prefix>/<workspace>.tflock`, written only when
8
+ * absent; the ID `force-unlock` takes is its generation
9
+ * azurerm a lease on the state blob, with the lock info base64 in its
10
+ * `terraformlockid` metadata; the binary cannot write the blob
11
+ * while chant holds the lease, so the store writes it
12
+ * local a lock file `<path>.tflock` beside the state, created only when
13
+ * absent. It keeps another chant run out; the binary's own local
14
+ * lock is a file lock it takes per command, so the run writes
15
+ * with `-lock=false` while it holds this one. A bare
16
+ * `terraform apply` on the same checkout at the same time is not
17
+ * kept out. Ruled on #4481 (ruling 4, 2026-10-25): chant's own
18
+ * lock file, no Terraform lock-info file, local backends allowed.
19
+ *
20
+ * Lifted from terragucci's `backend.ts` (c493e0e): `StateStore`, `s3Store`,
21
+ * `gcsStore` and `azureStore`, plus a local store and `removeBeside`.
22
+ */
23
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
24
+ import { dirname, isAbsolute, join } from "node:path";
25
+ import { AzureBlobClient } from "./azure-blob.js";
26
+ import { GcsClient } from "./gcs.js";
27
+ import { StoreError } from "./object-store.js";
28
+ import { S3Client } from "./s3.js";
29
+ /** The ID in a lock info's JSON, or "" when it names none. */
30
+ export function lockId(text) {
31
+ try {
32
+ const v = JSON.parse(text);
33
+ return typeof v.ID === "string" ? v.ID : "";
34
+ }
35
+ catch {
36
+ return "";
37
+ }
38
+ }
39
+ const JSON_TYPE = "application/json";
40
+ /** The S3 state, locked by the lock file `use_lockfile` takes. */
41
+ function s3Store(o, fetchFn) {
42
+ const client = new S3Client(o.target, fetchFn);
43
+ const lockKey = `${o.key}.tflock`;
44
+ return {
45
+ backend: "s3",
46
+ location: `s3://${o.bucket}/${o.key}`,
47
+ lockLocation: `s3://${o.bucket}/${lockKey}`,
48
+ heldLock: async () => {
49
+ const text = await client.get(lockKey);
50
+ return text === undefined ? undefined : { id: lockId(text), info: text };
51
+ },
52
+ lock: (info) => client.putIfAbsent(lockKey, info, JSON_TYPE),
53
+ unlock: () => client.remove(lockKey),
54
+ readBeside: (suffix) => client.get(`${o.key}${suffix}`),
55
+ writeBeside: (suffix, body) => client.put(`${o.key}${suffix}`, body, JSON_TYPE),
56
+ removeBeside: (suffix) => client.remove(`${o.key}${suffix}`),
57
+ besideLocation: (suffix) => `s3://${o.bucket}/${o.key}${suffix}`,
58
+ adopt: () => { },
59
+ };
60
+ }
61
+ /** The GCS state, locked by `<prefix>/<workspace>.tflock`, whose generation is the lock's ID. */
62
+ function gcsStore(o, fetchFn) {
63
+ const client = new GcsClient(o.target, fetchFn);
64
+ return {
65
+ backend: "gcs",
66
+ location: `gs://${o.bucket}/${o.key}`,
67
+ lockLocation: `gs://${o.bucket}/${o.lock}`,
68
+ heldLock: async () => {
69
+ const head = await client.head(o.lock);
70
+ const info = head.exists ? await client.get(o.lock) : undefined;
71
+ if (!head.exists || info === undefined)
72
+ return undefined;
73
+ return { id: head.generation ?? lockId(info), info };
74
+ },
75
+ lock: (info) => client.putIfAbsent(o.lock, info, JSON_TYPE),
76
+ unlock: () => client.remove(o.lock),
77
+ readBeside: (suffix) => client.get(`${o.key}${suffix}`),
78
+ writeBeside: (suffix, body) => client.put(`${o.key}${suffix}`, body, JSON_TYPE),
79
+ removeBeside: (suffix) => client.remove(`${o.key}${suffix}`),
80
+ besideLocation: (suffix) => `gs://${o.bucket}/${o.key}${suffix}`,
81
+ adopt: () => { },
82
+ };
83
+ }
84
+ /** The metadata an azurerm backend keeps a lock's info in, base64 JSON, on the leased blob. */
85
+ export const LOCK_METADATA = "terraformlockid";
86
+ /** The azurerm state blob, locked by a lease on it with the lock info in its metadata. */
87
+ function azureStore(o, fetchFn) {
88
+ const client = new AzureBlobClient({ account: o.account, container: o.container, endpoint: o.endpoint, ...o.auth }, fetchFn);
89
+ let leaseId;
90
+ const at = `az://${o.account}/${o.container}/${o.key}`;
91
+ return {
92
+ backend: "azurerm",
93
+ location: at,
94
+ lockLocation: at,
95
+ heldLock: async () => {
96
+ const head = await client.head(o.key);
97
+ if (!head.exists || head.leaseState !== "leased")
98
+ return undefined;
99
+ const meta = head.metadata[LOCK_METADATA];
100
+ const info = meta ? Buffer.from(meta, "base64").toString("utf-8") : "";
101
+ return { id: lockId(info), info };
102
+ },
103
+ lock: async (info) => {
104
+ const id = lockId(info);
105
+ // The backend leases a blob that is there: a state with none yet gets an empty one first, as the backend makes it.
106
+ if (!(await client.head(o.key)).exists)
107
+ await client.putBlob(o.key, "", JSON_TYPE, { ifNoneMatch: true });
108
+ if (!(await client.lease(o.key, "acquire", id)))
109
+ return false;
110
+ leaseId = id;
111
+ await client.setMetadata(o.key, { [LOCK_METADATA]: Buffer.from(info).toString("base64") }, id);
112
+ return true;
113
+ },
114
+ unlock: async () => {
115
+ if (!leaseId)
116
+ return;
117
+ const id = leaseId;
118
+ await client.setMetadata(o.key, {}, id);
119
+ await client.lease(o.key, "release", id);
120
+ leaseId = undefined;
121
+ },
122
+ write: async (body) => {
123
+ if (!leaseId)
124
+ throw new StoreError(`${at} is written under its lease, and none is held`);
125
+ // As the backend writes it: a snapshot first when it takes snapshots, and the lock info kept on the blob.
126
+ if (o.snapshot && (await client.head(o.key)).exists)
127
+ await client.snapshot(o.key);
128
+ const meta = (await client.head(o.key)).metadata;
129
+ await client.putBlob(o.key, body, JSON_TYPE, { leaseId, metadata: meta });
130
+ },
131
+ readBeside: (suffix) => client.get(`${o.key}${suffix}`),
132
+ writeBeside: async (suffix, body) => void (await client.putBlob(`${o.key}${suffix}`, body, JSON_TYPE)),
133
+ removeBeside: (suffix) => client.remove(`${o.key}${suffix}`),
134
+ besideLocation: (suffix) => `${at}${suffix}`,
135
+ adopt: (held) => {
136
+ leaseId = held.id;
137
+ },
138
+ };
139
+ }
140
+ /** A local state, locked by `<path>.tflock` created only when absent. `dir` is the root the path is relative to. */
141
+ function localStore(o, dir) {
142
+ const file = isAbsolute(o.path) ? o.path : join(dir, o.path);
143
+ const lockFile = `${file}.tflock`;
144
+ const read = (f) => (existsSync(f) ? readFileSync(f, "utf-8") : undefined);
145
+ return {
146
+ backend: "local",
147
+ location: file,
148
+ lockLocation: lockFile,
149
+ heldLock: async () => {
150
+ const text = read(lockFile);
151
+ return text === undefined ? undefined : { id: lockId(text), info: text };
152
+ },
153
+ lock: async (info) => {
154
+ mkdirSync(dirname(lockFile), { recursive: true });
155
+ try {
156
+ writeFileSync(lockFile, info, { flag: "wx" });
157
+ return true;
158
+ }
159
+ catch (e) {
160
+ if (e.code === "EEXIST")
161
+ return false;
162
+ throw e;
163
+ }
164
+ },
165
+ unlock: async () => rmSync(lockFile, { force: true }),
166
+ readBeside: async (suffix) => read(`${file}${suffix}`),
167
+ writeBeside: async (suffix, body) => {
168
+ mkdirSync(dirname(file), { recursive: true });
169
+ writeFileSync(`${file}${suffix}`, body);
170
+ },
171
+ removeBeside: async (suffix) => rmSync(`${file}${suffix}`, { force: true }),
172
+ besideLocation: (suffix) => `${file}${suffix}`,
173
+ adopt: () => { },
174
+ };
175
+ }
176
+ /** The store a state is in, opened with the credentials stateObject chose. `dir` is the root a local path is relative to. */
177
+ export function stateStore(o, dir, fetchFn) {
178
+ if (o.backend === "s3")
179
+ return s3Store(o, fetchFn);
180
+ if (o.backend === "gcs")
181
+ return gcsStore(o, fetchFn);
182
+ if (o.backend === "azurerm")
183
+ return azureStore(o, fetchFn);
184
+ return localStore(o, dir);
185
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"affected.d.ts","sourceRoot":"","sources":["../../src/terragrunt/affected.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"affected.d.ts","sourceRoot":"","sources":["../../src/terragrunt/affected.ts"],"names":[],"mappings":"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"}
@@ -190,7 +190,8 @@ export function terragruntAffected(input) {
190
190
  const moduleDirs = terragruntModuleDirs(unit);
191
191
  const called = new Map();
192
192
  for (const m of moduleDirs) {
193
- for (const d of rootWatchPaths(input.dir, { dir: m }))
193
+ // Terragrunt runs tofu when it is installed, so a module's `.tofu` files count (chant#4457).
194
+ for (const d of rootWatchPaths(input.dir, { dir: m }, "tofu"))
194
195
  if (!moduleDirs.includes(d) && !called.has(d))
195
196
  called.set(d, m);
196
197
  }
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-terraform",
3
- "version": "0.124.52",
3
+ "version": "0.124.54",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src/",
7
7
  "dist/",
8
- "schemas/",
9
8
  "workspace-kinds.json"
10
9
  ],
11
10
  "exports": {
@@ -40,6 +39,11 @@
40
39
  "types": "./dist/terragrunt/index.d.ts",
41
40
  "default": "./dist/terragrunt/index.js"
42
41
  },
42
+ "./state": {
43
+ "development": "./src/state/index.ts",
44
+ "types": "./dist/state/index.d.ts",
45
+ "default": "./dist/state/index.js"
46
+ },
43
47
  "./lint/post-synth": {
44
48
  "development": "./src/lint/post-synth/index.ts",
45
49
  "types": "./dist/lint/post-synth/index.d.ts",
@@ -68,7 +72,7 @@
68
72
  "access": "public"
69
73
  },
70
74
  "peerDependencies": {
71
- "@intentius/chant": "^0.124.52",
75
+ "@intentius/chant": "^0.124.54",
72
76
  "zod": "^4.3.6"
73
77
  },
74
78
  "description": "terraform lexicon for chant, existing Terraform root modules as declarable entities",
@@ -1,14 +1,17 @@
1
1
  # What the gated acceptance suites have actually run against
2
2
 
3
- Eight `describe` blocks across five files run this lexicon against a real
3
+ Eleven `describe` blocks across eight files run this lexicon against a real
4
4
  binary rather than a fixture, and every one of them skips rather than fails
5
5
  when its dependency is absent. A skip is silent by design, so without this
6
6
  file nothing in the tree says which of them has ever passed, against what, or
7
7
  when. The evidence had been living in PR prose (`#2157` for the live apply
8
8
  pair), which no reader of the suite can see.
9
9
 
10
- One row per gated block below: what it proves, what gates it, the command,
11
- and the last binary and emulator it is known to have passed against.
10
+ Ten sections below cover the eleven blocks, one section per block except
11
+ section 6, where `plan-read.acceptance.test.ts`'s per-binary loop makes two
12
+ blocks of one body. Each section says what the block proves, what gates it,
13
+ the command, and the last binary and emulator it is known to have passed
14
+ against, or "not recorded" when no run has been written down yet.
12
15
 
13
16
  `live-estate/README.md` next door is the sibling record for the two recorded
14
17
  documents (`../live-plan.json`, `../live-ls.json`) rather than for a suite,
@@ -31,7 +34,7 @@ same recipe one tag back
31
34
  `live/smoke/docker-compose.yml` and exported as
32
35
  `CHOUDOUFU_EMULATOR_ENDPOINT=http://localhost:<mapped port>`.
33
36
 
34
- ## The four blocks
37
+ ## The eleven blocks
35
38
 
36
39
  ### 1. `TerraformApplyOp applies a real root`
37
40
 
@@ -52,7 +55,7 @@ npx vitest run lexicons/terraform/src/composites/terraform-apply-op.acceptance.t
52
55
  Last passed: 2026-09-08, `Terraform v1.15.8` on `darwin_arm64`, with
53
56
  `hashicorp/null` resolved from the public registry for the fixture's `~> 3.2`
54
57
  constraint. No emulator is involved. Re-run by chant #2241 alongside every
55
- other block in this file, so all four rows come from one run; #2168 had run it
58
+ other block this file held then, so those four rows come from one run; #2168 had run it
56
59
  on 2026-09-07 the same way.
57
60
 
58
61
  ### 2. `TerraformApplyOp applies a live root against choudoufu's emulator`
@@ -172,7 +175,7 @@ path, which is the only thing it exists to prove.
172
175
 
173
176
  ### 5. `TerraformAdoptOp reaches its gate on a checkout that has never run init`
174
177
 
175
- Same file, third block (#2302). One test: build `TerraformAdoptOp` and drive
178
+ Same file, second block (#2302). One test: build `TerraformAdoptOp` and drive
176
179
  it through `runOpLocally`, exactly as the apply Op's own acceptance suite
177
180
  does, over a project this test creates fresh and never initializes by hand —
178
181
  no `terraformInit` call anywhere in the block. The Op's own Init phase is what
@@ -215,7 +218,8 @@ With the Init phase back, the same run reaches its gate:
215
218
 
216
219
  `../plan-read.acceptance.test.ts`, one block per binary, three tests each, over
217
220
  the `plan-read/` fixture (built-in `terraform_data`, `local` backend, so no
218
- registry, no network and no credentials). The first reads the plan depth
221
+ registry, no network and no credentials). Four tests each now; the run recorded
222
+ below had three, before #4372 added the planned-create test. The first reads the plan depth
219
223
  through `describeResources` and checks the IR attributes, `sources` reading
220
224
  `"plan"`, no secret in the result, nothing new or changed in the root, and no
221
225
  `chant-terraform-plan-*` directory left in the temp dir. The second holds the
@@ -263,6 +267,64 @@ by chant #4371. Proved red the same day: with `plan-observation.ts`'s
263
267
  redaction put back to flagging each side by its own marks, the old secret
264
268
  came through as `tags.token`'s `before`.
265
269
 
270
+ ### 8. `Terragrunt units against a real terragrunt`
271
+
272
+ `terragrunt/terragrunt.acceptance.test.ts` (#3414), four tests over the
273
+ `terragrunt/five-units/` fixture (implicit stacks, `terraform_data` only,
274
+ local state under the copied fixture, so no provider download and no cloud).
275
+ It checks that `terragrunt` is 1.1 or later, that `discoverTerragruntUnits`
276
+ lists what `terragrunt find` lists less the catalog template, that each of the
277
+ three waves plans and applies exactly its own units and that the run report's
278
+ per-unit results reach the change set with no input carrying a mock, and that
279
+ a wave keeps to its units when a `.terragrunt-filters` file selects more.
280
+
281
+ Gated on `terragrunt` and `tofu` on PATH.
282
+
283
+ ```
284
+ npx vitest run lexicons/terraform/src/terragrunt/terragrunt.acceptance.test.ts
285
+ ```
286
+
287
+ Last passed: not recorded. No run of this block has been written down; the
288
+ maintainer records the first one here (maintainer run).
289
+
290
+ ### 9. `mock outputs in Terragrunt waves against a real terragrunt`
291
+
292
+ `terragrunt/mocks.acceptance.test.ts` (#3416), one test over the same
293
+ `five-units/` fixture. Wave 2 is refused until wave 1 has applied, naming each
294
+ upstream and planning nothing. A provisional plan of wave 2 made before that
295
+ reads the mocks, is marked provisional, matches Terragrunt's own mock warning,
296
+ and is refused at apply. Once wave 1 applies, wave 2 plans on the real
297
+ upstream values and applies.
298
+
299
+ Gated on `terragrunt` and `tofu` on PATH.
300
+
301
+ ```
302
+ npx vitest run lexicons/terraform/src/terragrunt/mocks.acceptance.test.ts
303
+ ```
304
+
305
+ Last passed: not recorded. No run of this block has been written down; the
306
+ maintainer records the first one here (maintainer run).
307
+
308
+ ### 10. `affected Terragrunt units against a real terragrunt`
309
+
310
+ `terragrunt/affected.acceptance.test.ts` (#3415), over a git copy of the
311
+ `terragrunt/affected/` fixture. One test checks discovery against
312
+ `recorded/affected-find.json`; then one test per case in
313
+ `__fixtures__/terragrunt/affected-cases.ts`, each made as a commit, checks that
314
+ Terragrunt's own `[HEAD~1...HEAD]` filter selects exactly the case's
315
+ `terragrunt` column (nothing, for the three supplements) and that
316
+ `findTerragruntAffected` returns the case's expected units and reasons. Nothing
317
+ is planned.
318
+
319
+ Gated on `terragrunt` and `git` on PATH. It does not need `tofu`.
320
+
321
+ ```
322
+ npx vitest run lexicons/terraform/src/terragrunt/affected.acceptance.test.ts
323
+ ```
324
+
325
+ Last passed: not recorded. No run of this block has been written down; the
326
+ maintainer records the first one here (maintainer run).
327
+
266
328
  ## Running everything that can run on a machine with no choudoufu
267
329
 
268
330
  ```
@@ -0,0 +1,12 @@
1
+ {"@level":"info","@message":"Terraform 1.10.5","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.101000Z","terraform":"1.10.5","type":"version","ui":"1.2"}
2
+ {"@level":"info","@message":"module.net.terraform_data.vpc: Plan to update","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.412000Z","change":{"resource":{"addr":"module.net.terraform_data.vpc","module":"module.net","resource":"terraform_data.vpc","implied_provider":"terraform","resource_type":"terraform_data","resource_name":"vpc","resource_key":null},"action":"update"},"type":"planned_change"}
3
+ {"@level":"info","@message":"module.app.terraform_data.service: Plan to create","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.412100Z","change":{"resource":{"addr":"module.app.terraform_data.service","module":"module.app","resource":"terraform_data.service","implied_provider":"terraform","resource_type":"terraform_data","resource_name":"service","resource_key":null},"action":"create"},"type":"planned_change"}
4
+ {"@level":"info","@message":"module.app.module.logs.terraform_data.group: Plan to create","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.412200Z","change":{"resource":{"addr":"module.app.module.logs.terraform_data.group","module":"module.app.module.logs","resource":"terraform_data.group","implied_provider":"terraform","resource_type":"terraform_data","resource_name":"group","resource_key":null},"action":"create"},"type":"planned_change"}
5
+ {"@level":"info","@message":"module.edge.terraform_data.dns: Plan to update","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.412300Z","change":{"resource":{"addr":"module.edge.terraform_data.dns","module":"module.edge","resource":"terraform_data.dns","implied_provider":"terraform","resource_type":"terraform_data","resource_name":"dns","resource_key":null},"action":"update"},"type":"planned_change"}
6
+ {"@level":"info","@message":"Plan: 2 to add, 2 to change, 0 to destroy.","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.412400Z","changes":{"add":2,"change":2,"import":0,"remove":0,"operation":"apply"},"type":"change_summary"}
7
+ {"@level":"info","@message":"module.net.terraform_data.vpc: Modifying... [id=6f2b6c1e-0c55-4f0b-9d4e-3a1c2b7d9e01]","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.520000Z","hook":{"resource":{"addr":"module.net.terraform_data.vpc","module":"module.net","resource":"terraform_data.vpc","implied_provider":"terraform","resource_type":"terraform_data","resource_name":"vpc","resource_key":null},"action":"update","id_key":"id","id_value":"6f2b6c1e-0c55-4f0b-9d4e-3a1c2b7d9e01"},"type":"apply_start"}
8
+ {"@level":"info","@message":"module.net.terraform_data.vpc: Modifications complete after 0s [id=6f2b6c1e-0c55-4f0b-9d4e-3a1c2b7d9e01]","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.530000Z","hook":{"resource":{"addr":"module.net.terraform_data.vpc","module":"module.net","resource":"terraform_data.vpc","implied_provider":"terraform","resource_type":"terraform_data","resource_name":"vpc","resource_key":null},"action":"update","id_key":"id","id_value":"6f2b6c1e-0c55-4f0b-9d4e-3a1c2b7d9e01","elapsed_seconds":0},"type":"apply_complete"}
9
+ {"@level":"info","@message":"module.app.terraform_data.service: Creating...","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.540000Z","hook":{"resource":{"addr":"module.app.terraform_data.service","module":"module.app","resource":"terraform_data.service","implied_provider":"terraform","resource_type":"terraform_data","resource_name":"service","resource_key":null},"action":"create"},"type":"apply_start"}
10
+ {"@level":"error","@message":"module.app.terraform_data.service: Creation errored after 0s","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.550000Z","hook":{"resource":{"addr":"module.app.terraform_data.service","module":"module.app","resource":"terraform_data.service","implied_provider":"terraform","resource_type":"terraform_data","resource_name":"service","resource_key":null},"action":"create","elapsed_seconds":0},"type":"apply_errored"}
11
+ {"@level":"error","@message":"Error: Invalid input","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.551000Z","diagnostic":{"severity":"error","summary":"Invalid input","detail":"The service input is not a VPC id.\nCheck the vpc_id variable.","address":"module.app.terraform_data.service","range":{"filename":"../../roots/app/main.tf","start":{"line":1,"column":1,"byte":0},"end":{"line":1,"column":36,"byte":35}}},"type":"diagnostic"}
12
+ {"@level":"error","@message":"Error: Provider produced inconsistent final plan","@module":"terraform.ui","@timestamp":"2026-10-25T12:05:00.552000Z","diagnostic":{"severity":"error","summary":"Provider produced inconsistent final plan","detail":"This is a bug in the provider."},"type":"diagnostic"}
@@ -0,0 +1,66 @@
1
+ {
2
+ "version": 4,
3
+ "terraform_version": "1.10.5",
4
+ "serial": 3,
5
+ "lineage": "8d4e2f1a-3b5c-4d6e-9f7a-1c2b3d4e5f60",
6
+ "outputs": {
7
+ "service_id": {
8
+ "value": "0b7e4a2c-93d1-4f6e-a5b8-2c1d9e3f4a77",
9
+ "type": "string"
10
+ }
11
+ },
12
+ "resources": [
13
+ {
14
+ "module": "module.logs",
15
+ "mode": "managed",
16
+ "type": "terraform_data",
17
+ "name": "group",
18
+ "provider": "provider[\"terraform.io/builtin/terraform\"]",
19
+ "instances": [
20
+ {
21
+ "schema_version": 0,
22
+ "attributes": {
23
+ "id": "a3c5e7f9-1b2d-4c6e-8a0b-3d5f7a9c1e2f",
24
+ "input": {
25
+ "value": "app-logs",
26
+ "type": "string"
27
+ },
28
+ "output": {
29
+ "value": "app-logs",
30
+ "type": "string"
31
+ },
32
+ "triggers_replace": null
33
+ },
34
+ "sensitive_attributes": [],
35
+ "identity_schema_version": 0
36
+ }
37
+ ]
38
+ },
39
+ {
40
+ "mode": "managed",
41
+ "type": "terraform_data",
42
+ "name": "service",
43
+ "provider": "provider[\"terraform.io/builtin/terraform\"]",
44
+ "instances": [
45
+ {
46
+ "schema_version": 0,
47
+ "attributes": {
48
+ "id": "0b7e4a2c-93d1-4f6e-a5b8-2c1d9e3f4a77",
49
+ "input": {
50
+ "value": "6f2b6c1e-0c55-4f0b-9d4e-3a1c2b7d9e01",
51
+ "type": "string"
52
+ },
53
+ "output": {
54
+ "value": "6f2b6c1e-0c55-4f0b-9d4e-3a1c2b7d9e01",
55
+ "type": "string"
56
+ },
57
+ "triggers_replace": null
58
+ },
59
+ "sensitive_attributes": [],
60
+ "identity_schema_version": 0
61
+ }
62
+ ]
63
+ }
64
+ ],
65
+ "check_results": null
66
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "version": 4,
3
+ "terraform_version": "1.10.5",
4
+ "serial": 12,
5
+ "lineage": "c0ffee00-1234-4abc-8def-0123456789ab",
6
+ "outputs": {
7
+ "name": {
8
+ "value": "www",
9
+ "type": "string"
10
+ }
11
+ },
12
+ "resources": [
13
+ {
14
+ "mode": "managed",
15
+ "type": "terraform_data",
16
+ "name": "dns",
17
+ "provider": "provider[\"terraform.io/builtin/terraform\"]",
18
+ "instances": [
19
+ {
20
+ "schema_version": 0,
21
+ "attributes": {
22
+ "id": "1d9a0c55-77e2-4c1b-8f3a-5b6e2d4c7a10",
23
+ "input": {
24
+ "value": "www",
25
+ "type": "string"
26
+ },
27
+ "output": {
28
+ "value": "www",
29
+ "type": "string"
30
+ },
31
+ "triggers_replace": null
32
+ },
33
+ "sensitive_attributes": [],
34
+ "identity_schema_version": 0
35
+ }
36
+ ]
37
+ }
38
+ ],
39
+ "check_results": null
40
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "version": 4,
3
+ "terraform_version": "1.10.5",
4
+ "serial": 7,
5
+ "lineage": "2b1f6c0a-6a1e-4c55-9f3d-7e0a1b2c3d4e",
6
+ "outputs": {
7
+ "vpc_id": {
8
+ "value": "6f2b6c1e-0c55-4f0b-9d4e-3a1c2b7d9e01",
9
+ "type": "string"
10
+ }
11
+ },
12
+ "resources": [
13
+ {
14
+ "mode": "managed",
15
+ "type": "terraform_data",
16
+ "name": "vpc",
17
+ "provider": "provider[\"terraform.io/builtin/terraform\"]",
18
+ "instances": [
19
+ {
20
+ "schema_version": 0,
21
+ "attributes": {
22
+ "id": "6f2b6c1e-0c55-4f0b-9d4e-3a1c2b7d9e01",
23
+ "input": {
24
+ "value": {
25
+ "cidr": "10.0.0.0/16",
26
+ "name": "core"
27
+ },
28
+ "type": [
29
+ "object",
30
+ {
31
+ "cidr": "string",
32
+ "name": "string"
33
+ }
34
+ ]
35
+ },
36
+ "output": {
37
+ "value": {
38
+ "cidr": "10.0.0.0/16",
39
+ "name": "core"
40
+ },
41
+ "type": [
42
+ "object",
43
+ {
44
+ "cidr": "string",
45
+ "name": "string"
46
+ }
47
+ ]
48
+ },
49
+ "triggers_replace": null
50
+ },
51
+ "sensitive_attributes": [],
52
+ "identity_schema_version": 0
53
+ }
54
+ ]
55
+ }
56
+ ],
57
+ "check_results": null
58
+ }