@intentius/chant-lexicon-terraform 0.124.54 → 0.124.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/README.md +7 -4
  2. package/dist/ci-setup.d.ts +11 -0
  3. package/dist/ci-setup.d.ts.map +1 -0
  4. package/dist/ci-setup.js +41 -0
  5. package/dist/components/capability-plugin.d.ts +40 -6
  6. package/dist/components/capability-plugin.d.ts.map +1 -1
  7. package/dist/components/capability-plugin.js +174 -30
  8. package/dist/components/compose-group.d.ts +1 -1
  9. package/dist/components/compose-group.d.ts.map +1 -1
  10. package/dist/components/compose-group.js +1 -1
  11. package/dist/components/release-inputs.d.ts +29 -0
  12. package/dist/components/release-inputs.d.ts.map +1 -0
  13. package/dist/components/release-inputs.js +57 -0
  14. package/dist/components/trace-facts.d.ts +16 -0
  15. package/dist/components/trace-facts.d.ts.map +1 -0
  16. package/dist/components/trace-facts.js +19 -0
  17. package/dist/cone.d.ts +53 -0
  18. package/dist/cone.d.ts.map +1 -0
  19. package/dist/cone.js +119 -0
  20. package/dist/cost-hold.d.ts +27 -0
  21. package/dist/cost-hold.d.ts.map +1 -0
  22. package/dist/cost-hold.js +21 -0
  23. package/dist/drift-rows.d.ts +61 -0
  24. package/dist/drift-rows.d.ts.map +1 -0
  25. package/dist/drift-rows.js +108 -0
  26. package/dist/exit-codes.d.ts +55 -0
  27. package/dist/exit-codes.d.ts.map +1 -0
  28. package/dist/exit-codes.js +48 -0
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +3 -0
  32. package/dist/integrity.json +7 -4
  33. package/dist/lint/audit-catalog.d.ts.map +1 -1
  34. package/dist/lint/audit-catalog.js +27 -3
  35. package/dist/lint/audit-lineage.d.ts +14 -2
  36. package/dist/lint/audit-lineage.d.ts.map +1 -1
  37. package/dist/lint/post-synth/index.d.ts.map +1 -1
  38. package/dist/lint/post-synth/index.js +4 -0
  39. package/dist/lint/post-synth/record-store.d.ts +54 -0
  40. package/dist/lint/post-synth/record-store.d.ts.map +1 -0
  41. package/dist/lint/post-synth/record-store.js +104 -0
  42. package/dist/lint/post-synth/tf001.d.ts +2 -2
  43. package/dist/lint/post-synth/tf001.js +2 -2
  44. package/dist/lint/post-synth/tf024.d.ts +35 -11
  45. package/dist/lint/post-synth/tf024.d.ts.map +1 -1
  46. package/dist/lint/post-synth/tf024.js +92 -20
  47. package/dist/lint/post-synth/tf046.d.ts +64 -0
  48. package/dist/lint/post-synth/tf046.d.ts.map +1 -0
  49. package/dist/lint/post-synth/tf046.js +175 -0
  50. package/dist/lint/post-synth/tf047.d.ts +36 -0
  51. package/dist/lint/post-synth/tf047.d.ts.map +1 -0
  52. package/dist/lint/post-synth/tf047.js +94 -0
  53. package/dist/lock-rows.d.ts +36 -0
  54. package/dist/lock-rows.d.ts.map +1 -0
  55. package/dist/lock-rows.js +60 -0
  56. package/dist/lock-timeout.d.ts +22 -0
  57. package/dist/lock-timeout.d.ts.map +1 -0
  58. package/dist/lock-timeout.js +32 -0
  59. package/dist/manifest.json +1 -1
  60. package/dist/module-catalog/index.d.ts +69 -0
  61. package/dist/module-catalog/index.d.ts.map +1 -0
  62. package/dist/module-catalog/index.js +110 -0
  63. package/dist/module-catalog/refresh-cli.d.ts +4 -0
  64. package/dist/module-catalog/refresh-cli.d.ts.map +1 -0
  65. package/dist/module-catalog/refresh-cli.js +64 -0
  66. package/dist/module-catalog/static-tier.d.ts +6 -0
  67. package/dist/module-catalog/static-tier.d.ts.map +1 -0
  68. package/dist/module-catalog/static-tier.js +1650 -0
  69. package/dist/module-catalog/types.d.ts +65 -0
  70. package/dist/module-catalog/types.d.ts.map +1 -0
  71. package/dist/module-catalog/types.js +33 -0
  72. package/dist/okf/index.md +3 -1
  73. package/dist/okf/rules/TF024.md +2 -2
  74. package/dist/okf/rules/TF046.md +11 -0
  75. package/dist/okf/rules/TF047.md +11 -0
  76. package/dist/op/activities/terraform.d.ts +29 -0
  77. package/dist/op/activities/terraform.d.ts.map +1 -1
  78. package/dist/op/activities/terraform.js +19 -4
  79. package/dist/pin/consumers.d.ts +35 -0
  80. package/dist/pin/consumers.d.ts.map +1 -0
  81. package/dist/pin/consumers.js +70 -0
  82. package/dist/plugin.d.ts.map +1 -1
  83. package/dist/plugin.js +5 -0
  84. package/dist/registry/address.d.ts +63 -0
  85. package/dist/registry/address.d.ts.map +1 -0
  86. package/dist/registry/address.js +65 -0
  87. package/dist/registry/catalog-read.d.ts +14 -0
  88. package/dist/registry/catalog-read.d.ts.map +1 -0
  89. package/dist/registry/catalog-read.js +58 -0
  90. package/dist/registry/deprecated.d.ts +37 -0
  91. package/dist/registry/deprecated.d.ts.map +1 -0
  92. package/dist/registry/deprecated.js +43 -0
  93. package/dist/registry/docs.d.ts +96 -0
  94. package/dist/registry/docs.d.ts.map +1 -0
  95. package/dist/registry/docs.js +210 -0
  96. package/dist/registry/edge/edge.d.ts +46 -0
  97. package/dist/registry/edge/edge.d.ts.map +1 -0
  98. package/dist/registry/edge/edge.js +194 -0
  99. package/dist/registry/edge/index.d.ts +11 -0
  100. package/dist/registry/edge/index.d.ts.map +1 -0
  101. package/dist/registry/edge/index.js +10 -0
  102. package/dist/registry/edge/lambda-edge.d.ts +76 -0
  103. package/dist/registry/edge/lambda-edge.d.ts.map +1 -0
  104. package/dist/registry/edge/lambda-edge.js +95 -0
  105. package/dist/registry/edge/sigv4-web.d.ts +33 -0
  106. package/dist/registry/edge/sigv4-web.d.ts.map +1 -0
  107. package/dist/registry/edge/sigv4-web.js +56 -0
  108. package/dist/registry/edge/token-source.d.ts +73 -0
  109. package/dist/registry/edge/token-source.d.ts.map +1 -0
  110. package/dist/registry/edge/token-source.js +115 -0
  111. package/dist/registry/edge/worker.d.ts +45 -0
  112. package/dist/registry/edge/worker.d.ts.map +1 -0
  113. package/dist/registry/edge/worker.js +26 -0
  114. package/dist/registry/handler.d.ts +25 -0
  115. package/dist/registry/handler.d.ts.map +1 -0
  116. package/dist/registry/handler.js +75 -0
  117. package/dist/registry/headers-file.d.ts +21 -0
  118. package/dist/registry/headers-file.d.ts.map +1 -0
  119. package/dist/registry/headers-file.js +57 -0
  120. package/dist/registry/index.d.ts +31 -0
  121. package/dist/registry/index.d.ts.map +1 -0
  122. package/dist/registry/index.js +30 -0
  123. package/dist/registry/mirror-paths.d.ts +9 -0
  124. package/dist/registry/mirror-paths.d.ts.map +1 -0
  125. package/dist/registry/mirror-paths.js +8 -0
  126. package/dist/registry/mirror.d.ts +130 -0
  127. package/dist/registry/mirror.d.ts.map +1 -0
  128. package/dist/registry/mirror.js +319 -0
  129. package/dist/registry/proxies.d.ts +73 -0
  130. package/dist/registry/proxies.d.ts.map +1 -0
  131. package/dist/registry/proxies.js +111 -0
  132. package/dist/registry/reader.d.ts +57 -0
  133. package/dist/registry/reader.d.ts.map +1 -0
  134. package/dist/registry/reader.js +198 -0
  135. package/dist/registry/semver.d.ts +16 -0
  136. package/dist/registry/semver.d.ts.map +1 -0
  137. package/dist/registry/semver.js +24 -0
  138. package/dist/registry/serve.d.ts +24 -0
  139. package/dist/registry/serve.d.ts.map +1 -0
  140. package/dist/registry/serve.js +64 -0
  141. package/dist/registry/source-forms.d.ts +79 -0
  142. package/dist/registry/source-forms.d.ts.map +1 -0
  143. package/dist/registry/source-forms.js +202 -0
  144. package/dist/registry/targets/artifactory.d.ts +28 -0
  145. package/dist/registry/targets/artifactory.d.ts.map +1 -0
  146. package/dist/registry/targets/artifactory.js +206 -0
  147. package/dist/registry/targets/fake-artifactory.d.ts +30 -0
  148. package/dist/registry/targets/fake-artifactory.d.ts.map +1 -0
  149. package/dist/registry/targets/fake-artifactory.js +142 -0
  150. package/dist/registry/targets/fake-gitlab.d.ts +39 -0
  151. package/dist/registry/targets/fake-gitlab.d.ts.map +1 -0
  152. package/dist/registry/targets/fake-gitlab.js +136 -0
  153. package/dist/registry/targets/fake-hcp.d.ts +50 -0
  154. package/dist/registry/targets/fake-hcp.d.ts.map +1 -0
  155. package/dist/registry/targets/fake-hcp.js +202 -0
  156. package/dist/registry/targets/fake-http.d.ts +31 -0
  157. package/dist/registry/targets/fake-http.d.ts.map +1 -0
  158. package/dist/registry/targets/fake-http.js +87 -0
  159. package/dist/registry/targets/fake-nexus.d.ts +27 -0
  160. package/dist/registry/targets/fake-nexus.d.ts.map +1 -0
  161. package/dist/registry/targets/fake-nexus.js +137 -0
  162. package/dist/registry/targets/gitlab.d.ts +53 -0
  163. package/dist/registry/targets/gitlab.d.ts.map +1 -0
  164. package/dist/registry/targets/gitlab.js +187 -0
  165. package/dist/registry/targets/hcp.d.ts +29 -0
  166. package/dist/registry/targets/hcp.d.ts.map +1 -0
  167. package/dist/registry/targets/hcp.js +310 -0
  168. package/dist/registry/targets/hosted.d.ts +62 -0
  169. package/dist/registry/targets/hosted.d.ts.map +1 -0
  170. package/dist/registry/targets/hosted.js +74 -0
  171. package/dist/registry/targets/index.d.ts +18 -0
  172. package/dist/registry/targets/index.d.ts.map +1 -0
  173. package/dist/registry/targets/index.js +17 -0
  174. package/dist/registry/targets/module-target.d.ts +68 -0
  175. package/dist/registry/targets/module-target.d.ts.map +1 -0
  176. package/dist/registry/targets/module-target.js +63 -0
  177. package/dist/registry/targets/nexus.d.ts +43 -0
  178. package/dist/registry/targets/nexus.d.ts.map +1 -0
  179. package/dist/registry/targets/nexus.js +250 -0
  180. package/dist/registry/targets/zip.d.ts +55 -0
  181. package/dist/registry/targets/zip.d.ts.map +1 -0
  182. package/dist/registry/targets/zip.js +278 -0
  183. package/dist/registry/writer.d.ts +101 -0
  184. package/dist/registry/writer.d.ts.map +1 -0
  185. package/dist/registry/writer.js +109 -0
  186. package/dist/rules/record-store.ts +122 -0
  187. package/dist/rules/tf001.ts +2 -2
  188. package/dist/rules/tf024.ts +105 -22
  189. package/dist/rules/tf046.ts +204 -0
  190. package/dist/rules/tf047.ts +114 -0
  191. package/dist/state/azure-blob.d.ts +8 -67
  192. package/dist/state/azure-blob.d.ts.map +1 -1
  193. package/dist/state/azure-blob.js +6 -199
  194. package/dist/state/gcs.d.ts +7 -61
  195. package/dist/state/gcs.d.ts.map +1 -1
  196. package/dist/state/gcs.js +5 -222
  197. package/dist/state/object-store.d.ts +4 -33
  198. package/dist/state/object-store.d.ts.map +1 -1
  199. package/dist/state/object-store.js +4 -17
  200. package/dist/state/s3.d.ts +11 -58
  201. package/dist/state/s3.d.ts.map +1 -1
  202. package/dist/state/s3.js +10 -161
  203. package/dist/state/store.js +2 -2
  204. package/dist/state-ops.d.ts +255 -0
  205. package/dist/state-ops.d.ts.map +1 -0
  206. package/dist/state-ops.js +305 -0
  207. package/dist/state-reads.d.ts +57 -0
  208. package/dist/state-reads.d.ts.map +1 -0
  209. package/dist/state-reads.js +104 -0
  210. package/dist/used-sources.d.ts +54 -0
  211. package/dist/used-sources.d.ts.map +1 -0
  212. package/dist/used-sources.js +157 -0
  213. package/package.json +19 -3
  214. package/src/__fixtures__/drift-record/README.md +5 -0
  215. package/src/__fixtures__/drift-rows/live-root-plan.json +70 -0
  216. package/src/__fixtures__/drift-rows/refresh-plan.json +61 -0
  217. package/src/__fixtures__/used-sources/root/extra.tofu +1 -0
  218. package/src/__fixtures__/used-sources/root/main.tf +31 -0
  219. package/src/__fixtures__/used-sources/root/modules/net/main.tf +14 -0
  220. package/src/__fixtures__/used-sources/root/modules/net/versions.tf.json +7 -0
  221. package/src/__fixtures__/used-sources/unit/terragrunt.hcl +3 -0
  222. package/src/ci-setup.ts +42 -0
  223. package/src/components/capability-plugin.test.ts +26 -14
  224. package/src/components/capability-plugin.ts +185 -31
  225. package/src/components/compose-group.ts +1 -1
  226. package/src/components/pr-loop-compose.tofu.e2e.test.ts +1 -1
  227. package/src/components/pr-loop.tofu.test.ts +1 -1
  228. package/src/components/release-inputs.ts +69 -0
  229. package/src/components/trace-facts.test.ts +21 -0
  230. package/src/components/trace-facts.ts +27 -0
  231. package/src/cone.ts +138 -0
  232. package/src/cost-hold.ts +29 -0
  233. package/src/describe-resources.engine-facts.test.ts +2 -3
  234. package/src/drift-rows.test.ts +135 -0
  235. package/src/drift-rows.ts +137 -0
  236. package/src/exit-codes.test.ts +23 -0
  237. package/src/exit-codes.ts +59 -0
  238. package/src/index.ts +3 -0
  239. package/src/lint/audit-catalog.ts +29 -3
  240. package/src/lint/audit-lineage.ts +14 -2
  241. package/src/lint/post-synth/fixtures/TF024/live-with-record-store/main.tf +18 -0
  242. package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/estate.chdf.hcl +1 -0
  243. package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/main.tf +10 -0
  244. package/src/lint/post-synth/fixtures/TF046/azurerm-no-resource-group/main.tf +15 -0
  245. package/src/lint/post-synth/fixtures/TF046/backend-config-only/main.tf +14 -0
  246. package/src/lint/post-synth/fixtures/TF046/derived-s3/backend.tf +7 -0
  247. package/src/lint/post-synth/fixtures/TF046/derived-s3/main.tf +9 -0
  248. package/src/lint/post-synth/fixtures/TF046/explicit-local/main.tf +16 -0
  249. package/src/lint/post-synth/fixtures/TF046/explicit-s3-beside-local-backend/main.tf +15 -0
  250. package/src/lint/post-synth/fixtures/TF046/implied-local/main.tf +9 -0
  251. package/src/lint/post-synth/fixtures/TF046/sidecar-implied/estate.chdf.hcl +1 -0
  252. package/src/lint/post-synth/fixtures/TF046/sidecar-implied/main.tf +5 -0
  253. package/src/lint/post-synth/fixtures/TF047/clear/main.tf +12 -0
  254. package/src/lint/post-synth/fixtures/TF047/refused/main.tf +12 -0
  255. package/src/lint/post-synth/fixtures/TF047/unknown-module/main.tf +12 -0
  256. package/src/lint/post-synth/fixtures/TF047/unknown-version/main.tf +12 -0
  257. package/src/lint/post-synth/index.ts +4 -0
  258. package/src/lint/post-synth/record-store.ts +122 -0
  259. package/src/lint/post-synth/tf001.ts +2 -2
  260. package/src/lint/post-synth/tf024.test.ts +26 -5
  261. package/src/lint/post-synth/tf024.ts +105 -22
  262. package/src/lint/post-synth/tf046.test.ts +137 -0
  263. package/src/lint/post-synth/tf046.ts +204 -0
  264. package/src/lint/post-synth/tf047.test.ts +56 -0
  265. package/src/lint/post-synth/tf047.ts +114 -0
  266. package/src/lock-rows.test.ts +70 -0
  267. package/src/lock-rows.ts +82 -0
  268. package/src/lock-timeout.ts +34 -0
  269. package/src/module-catalog/index.test.ts +93 -0
  270. package/src/module-catalog/index.ts +159 -0
  271. package/src/module-catalog/refresh-cli.ts +68 -0
  272. package/src/module-catalog/static-tier.ts +1659 -0
  273. package/src/module-catalog/types.ts +88 -0
  274. package/src/op/activities/terraform.ts +46 -5
  275. package/src/op-wave-step.test.ts +109 -0
  276. package/src/pin/__fixtures__/consumers/live/dev/main.tf +4 -0
  277. package/src/pin/__fixtures__/consumers/live/prod/main.tf +21 -0
  278. package/src/pin/__fixtures__/consumers/units/vpc/terragrunt.hcl +7 -0
  279. package/src/pin/consumers.test.ts +57 -0
  280. package/src/pin/consumers.ts +95 -0
  281. package/src/plugin.ts +6 -0
  282. package/src/registry/__fixtures__/docs/documented/.terraform-docs.yml +3 -0
  283. package/src/registry/__fixtures__/docs/documented/README.md +1 -0
  284. package/src/registry/__fixtures__/docs/documented/main.tf +8 -0
  285. package/src/registry/__fixtures__/docs/json/main.tf.json +14 -0
  286. package/src/registry/__fixtures__/docs/vpc/README.md +3 -0
  287. package/src/registry/__fixtures__/docs/vpc/examples/complete/main.tf +5 -0
  288. package/src/registry/__fixtures__/docs/vpc/examples/simple/README.md +1 -0
  289. package/src/registry/__fixtures__/docs/vpc/examples/simple/main.tf +4 -0
  290. package/src/registry/__fixtures__/docs/vpc/main.tf +14 -0
  291. package/src/registry/__fixtures__/docs/vpc/outputs.tf +9 -0
  292. package/src/registry/__fixtures__/docs/vpc/variables.tf +16 -0
  293. package/src/registry/__fixtures__/proxied-root/main.tf +12 -0
  294. package/src/registry/address.ts +100 -0
  295. package/src/registry/catalog-read.ts +56 -0
  296. package/src/registry/deprecated.test.ts +139 -0
  297. package/src/registry/deprecated.ts +76 -0
  298. package/src/registry/docs.test.ts +140 -0
  299. package/src/registry/docs.ts +299 -0
  300. package/src/registry/edge/bundle.test.ts +50 -0
  301. package/src/registry/edge/edge.test.ts +176 -0
  302. package/src/registry/edge/edge.ts +211 -0
  303. package/src/registry/edge/index.ts +10 -0
  304. package/src/registry/edge/lambda-edge.ts +127 -0
  305. package/src/registry/edge/sigv4-web.ts +79 -0
  306. package/src/registry/edge/token-source.test.ts +258 -0
  307. package/src/registry/edge/token-source.ts +169 -0
  308. package/src/registry/edge/worker.ts +61 -0
  309. package/src/registry/handler.ts +89 -0
  310. package/src/registry/headers-file.ts +61 -0
  311. package/src/registry/index.ts +31 -0
  312. package/src/registry/mirror-paths.ts +10 -0
  313. package/src/registry/mirror.test.ts +198 -0
  314. package/src/registry/mirror.ts +395 -0
  315. package/src/registry/proxies.test.ts +153 -0
  316. package/src/registry/proxies.ts +132 -0
  317. package/src/registry/reader.ts +225 -0
  318. package/src/registry/registry.test.ts +262 -0
  319. package/src/registry/semver.ts +34 -0
  320. package/src/registry/serve.ts +82 -0
  321. package/src/registry/source-forms.test.ts +87 -0
  322. package/src/registry/source-forms.ts +216 -0
  323. package/src/registry/targets/artifactory.test.ts +248 -0
  324. package/src/registry/targets/artifactory.ts +257 -0
  325. package/src/registry/targets/fake-artifactory.ts +158 -0
  326. package/src/registry/targets/fake-gitlab.ts +161 -0
  327. package/src/registry/targets/fake-hcp.ts +233 -0
  328. package/src/registry/targets/fake-http.ts +97 -0
  329. package/src/registry/targets/fake-nexus.ts +152 -0
  330. package/src/registry/targets/gitlab.test.ts +208 -0
  331. package/src/registry/targets/gitlab.ts +223 -0
  332. package/src/registry/targets/hcp.test.ts +230 -0
  333. package/src/registry/targets/hcp.ts +360 -0
  334. package/src/registry/targets/hosted.ts +117 -0
  335. package/src/registry/targets/index.ts +17 -0
  336. package/src/registry/targets/module-target.ts +131 -0
  337. package/src/registry/targets/nexus.test.ts +220 -0
  338. package/src/registry/targets/nexus.ts +314 -0
  339. package/src/registry/targets/zip.test.ts +65 -0
  340. package/src/registry/targets/zip.ts +287 -0
  341. package/src/registry/writer.ts +155 -0
  342. package/src/state/azure-blob.ts +6 -221
  343. package/src/state/gcs.ts +5 -252
  344. package/src/state/object-store.ts +4 -32
  345. package/src/state/s3.ts +10 -182
  346. package/src/state/store.ts +2 -2
  347. package/src/state-ops.test.ts +182 -0
  348. package/src/state-ops.ts +462 -0
  349. package/src/state-reads.ts +116 -0
  350. package/src/used-sources.test.ts +75 -0
  351. package/src/used-sources.ts +204 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * TF046: a live root's record store is local, and the lint runs in CI.
3
+ *
4
+ * A live root keeps its records (what binds a record-backed resource to the
5
+ * estate) in a record store. With nothing to say otherwise that store is a
6
+ * directory beside the module (choudoufu `live/STORAGE.md`), and on a CI
7
+ * runner the directory is empty on every run: an ordinary resource still binds
8
+ * by its marker, but a record-backed one is proposed for create again.
9
+ *
10
+ * "Local" is what choudoufu resolves, read here through `./record-store.ts`,
11
+ * the same resolution TF024 names in its message (INTENTIUS/choudoufu#2293):
12
+ *
13
+ * - an explicit `record_store "local"` fires;
14
+ * - an explicit `record_store` of any other kind is quiet, whatever backend
15
+ * sits beside it;
16
+ * - with no `record_store`, an ignored `backend "s3"`, `"gcs"` or `"azurerm"`
17
+ * block that names its bucket as a literal gives a derived store and is
18
+ * quiet;
19
+ * - with no `record_store` and no backend, or a backend with no counterpart
20
+ * (`local`, `consul`, `http`), or one whose bucket comes only from
21
+ * `-backend-config`, the store is implied local and the rule fires, naming
22
+ * the reason choudoufu would print.
23
+ *
24
+ * A root that is also a Terragrunt unit with a `remote_state`, a `generate`
25
+ * block that writes a backend, or an `include` of a parent config gets its
26
+ * backend file at run time, so what chant reads is not what choudoufu sees.
27
+ * The rule stays quiet there rather than guess; TF044 still reports a
28
+ * Terragrunt `backend = "local"`.
29
+ *
30
+ * CI is read from the environment chant runs in: `CI` set to anything but
31
+ * `false` or `0`, or `GITHUB_ACTIONS`, `GITLAB_CI`, `FORGEJO_ACTIONS`,
32
+ * `GITEA_ACTIONS` or `TF_BUILD` (Azure Pipelines) set to `true`. Outside CI the
33
+ * local store is a reasonable choice for one person or a demo, and the rule
34
+ * says nothing.
35
+ *
36
+ * Opt-outs, for emulator and test lanes that use the local store on purpose:
37
+ * `CHANT_ALLOW_LOCAL_RECORD_STORE=1` in the lane's environment, or
38
+ * `# chant-ignore-block: TF046` above the `terraform` block holding `live`
39
+ * for one root, or
40
+ * `lint.rules: { TF046: "off" }` for a whole project.
41
+ *
42
+ * The rule is `report-only` in the audit catalog, so it is off under the
43
+ * `recommended` preset: terragucci switches it on and holds the product
44
+ * wording (chant#4561 placement).
45
+ *
46
+ * One diagnostic per root. It fires from the `terraform` block that holds the
47
+ * `live` block, since suppression comments anchor on top-level blocks only,
48
+ * and from the sidecar's `Terraform::Live` entity for a sidecar estate, where
49
+ * `# chant-ignore-file: TF046` in `estate.chdf.hcl` suppresses it.
50
+ */
51
+ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
52
+ /** The environment variable an emulator or test lane sets to keep the local store without a finding. */
53
+ export declare const ALLOW_LOCAL_RECORD_STORE_ENV = "CHANT_ALLOW_LOCAL_RECORD_STORE";
54
+ type Env = Readonly<Record<string, string | undefined>>;
55
+ /** Whether the environment is a CI job. */
56
+ export declare function isCiEnvironment(env: Env): boolean;
57
+ /**
58
+ * TF046 against an explicit environment. `tf046.check` passes `process.env`;
59
+ * tests pass their own.
60
+ */
61
+ export declare function checkLocalRecordStore(ctx: PostSynthContext, env: Env): PostSynthDiagnostic[];
62
+ export declare const tf046: PostSynthCheck;
63
+ export {};
64
+ //# sourceMappingURL=tf046.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tf046.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/tf046.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,kCAAkC,CAAC;AAa1C,wGAAwG;AACxG,eAAO,MAAM,4BAA4B,mCAAmC,CAAC;AAE7E,KAAK,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAIxD,2CAA2C;AAC3C,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAMjD;AA4FD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,GAAG,GAAG,mBAAmB,EAAE,CAgB5F;AAED,eAAO,MAAM,KAAK,EAAE,cAOnB,CAAC"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * TF046: a live root's record store is local, and the lint runs in CI.
3
+ *
4
+ * A live root keeps its records (what binds a record-backed resource to the
5
+ * estate) in a record store. With nothing to say otherwise that store is a
6
+ * directory beside the module (choudoufu `live/STORAGE.md`), and on a CI
7
+ * runner the directory is empty on every run: an ordinary resource still binds
8
+ * by its marker, but a record-backed one is proposed for create again.
9
+ *
10
+ * "Local" is what choudoufu resolves, read here through `./record-store.ts`,
11
+ * the same resolution TF024 names in its message (INTENTIUS/choudoufu#2293):
12
+ *
13
+ * - an explicit `record_store "local"` fires;
14
+ * - an explicit `record_store` of any other kind is quiet, whatever backend
15
+ * sits beside it;
16
+ * - with no `record_store`, an ignored `backend "s3"`, `"gcs"` or `"azurerm"`
17
+ * block that names its bucket as a literal gives a derived store and is
18
+ * quiet;
19
+ * - with no `record_store` and no backend, or a backend with no counterpart
20
+ * (`local`, `consul`, `http`), or one whose bucket comes only from
21
+ * `-backend-config`, the store is implied local and the rule fires, naming
22
+ * the reason choudoufu would print.
23
+ *
24
+ * A root that is also a Terragrunt unit with a `remote_state`, a `generate`
25
+ * block that writes a backend, or an `include` of a parent config gets its
26
+ * backend file at run time, so what chant reads is not what choudoufu sees.
27
+ * The rule stays quiet there rather than guess; TF044 still reports a
28
+ * Terragrunt `backend = "local"`.
29
+ *
30
+ * CI is read from the environment chant runs in: `CI` set to anything but
31
+ * `false` or `0`, or `GITHUB_ACTIONS`, `GITLAB_CI`, `FORGEJO_ACTIONS`,
32
+ * `GITEA_ACTIONS` or `TF_BUILD` (Azure Pipelines) set to `true`. Outside CI the
33
+ * local store is a reasonable choice for one person or a demo, and the rule
34
+ * says nothing.
35
+ *
36
+ * Opt-outs, for emulator and test lanes that use the local store on purpose:
37
+ * `CHANT_ALLOW_LOCAL_RECORD_STORE=1` in the lane's environment, or
38
+ * `# chant-ignore-block: TF046` above the `terraform` block holding `live`
39
+ * for one root, or
40
+ * `lint.rules: { TF046: "off" }` for a whole project.
41
+ *
42
+ * The rule is `report-only` in the audit catalog, so it is off under the
43
+ * `recommended` preset: terragucci switches it on and holds the product
44
+ * wording (chant#4561 placement).
45
+ *
46
+ * One diagnostic per root. It fires from the `terraform` block that holds the
47
+ * `live` block, since suppression comments anchor on top-level blocks only,
48
+ * and from the sidecar's `Terraform::Live` entity for a sidecar estate, where
49
+ * `# chant-ignore-file: TF046` in `estate.chdf.hcl` suppresses it.
50
+ */
51
+ import { isResourceDeclarable } from "@intentius/chant/declarable";
52
+ import { LIVE_TYPE, TERRAFORM_TYPE, TERRAGRUNT_CONFIG_TYPE, TERRAGRUNT_GENERATE_TYPE, TERRAGRUNT_REMOTE_STATE_TYPE, } from "../../hcl/parse.js";
53
+ import { isRootScoped } from "./scope.js";
54
+ import { resolveRecordStore } from "./record-store.js";
55
+ /** The environment variable an emulator or test lane sets to keep the local store without a finding. */
56
+ export const ALLOW_LOCAL_RECORD_STORE_ENV = "CHANT_ALLOW_LOCAL_RECORD_STORE";
57
+ const truthy = (v) => v !== undefined && v !== "" && v !== "0" && v.toLowerCase() !== "false";
58
+ /** Whether the environment is a CI job. */
59
+ export function isCiEnvironment(env) {
60
+ if (truthy(env.CI))
61
+ return true;
62
+ for (const name of ["GITHUB_ACTIONS", "GITLAB_CI", "FORGEJO_ACTIONS", "GITEA_ACTIONS", "TF_BUILD"]) {
63
+ if (env[name]?.toLowerCase() === "true")
64
+ return true;
65
+ }
66
+ return false;
67
+ }
68
+ const bodyOf = (entity) => {
69
+ const props = entity.props;
70
+ return (typeof props.body === "object" && props.body !== null ? props.body : {});
71
+ };
72
+ const rootOf = (entity) => {
73
+ const root = entity.props.root;
74
+ return typeof root === "string" ? root : "";
75
+ };
76
+ /** Whether a Terragrunt block in this root writes a backend file at run time. */
77
+ function writesRuntimeBackend(entity) {
78
+ const body = bodyOf(entity);
79
+ switch (entity.entityType) {
80
+ case TERRAGRUNT_REMOTE_STATE_TYPE:
81
+ return body.backend !== "local";
82
+ case TERRAGRUNT_GENERATE_TYPE: {
83
+ const contents = typeof body.contents === "string" ? body.contents : "";
84
+ return /\bbackend\s+"(?!local")/.test(contents);
85
+ }
86
+ case TERRAGRUNT_CONFIG_TYPE:
87
+ return Array.isArray(body.includes) && body.includes.length > 0;
88
+ default:
89
+ return false;
90
+ }
91
+ }
92
+ function liveRoots(ctx) {
93
+ const roots = new Map();
94
+ const terraform = new Map();
95
+ /** Per root, the key of the first `terraform` block that holds a `live` block. */
96
+ const holder = new Map();
97
+ const runtime = new Set();
98
+ for (const [key, entity] of ctx.entities) {
99
+ if (!isResourceDeclarable(entity) || !isRootScoped(entity))
100
+ continue;
101
+ const root = rootOf(entity);
102
+ if (entity.entityType === TERRAFORM_TYPE) {
103
+ const list = terraform.get(root) ?? [];
104
+ const body = bodyOf(entity);
105
+ list.push(body);
106
+ terraform.set(root, list);
107
+ if (body.live !== undefined && !holder.has(root))
108
+ holder.set(root, key);
109
+ continue;
110
+ }
111
+ if (entity.entityType === LIVE_TYPE) {
112
+ if (entity.props.mode !== "live")
113
+ continue;
114
+ const found = roots.get(root);
115
+ if (found)
116
+ found.liveBodies.push(bodyOf(entity));
117
+ else
118
+ roots.set(root, { anchor: key, liveBodies: [bodyOf(entity)], terraformBodies: [], runtimeBackend: false });
119
+ continue;
120
+ }
121
+ if (writesRuntimeBackend(entity))
122
+ runtime.add(root);
123
+ }
124
+ for (const [root, live] of roots) {
125
+ live.terraformBodies = terraform.get(root) ?? [];
126
+ live.anchor = holder.get(root) ?? live.anchor;
127
+ live.runtimeBackend = runtime.has(root);
128
+ }
129
+ return roots;
130
+ }
131
+ function message(root, store) {
132
+ const why = store.source === "record_store"
133
+ ? 'Its live declaration names record_store "local", a directory beside the module.'
134
+ : store.note
135
+ ? `It declares no record_store, and no store is derived from its backend: ${store.note}.`
136
+ : store.backend
137
+ ? `It declares no record_store, and its backend "${store.backend}" block keeps state on local disk, so choudoufu uses the local store.`
138
+ : "It declares no record_store and has no backend block to derive one from, so choudoufu uses the local store.";
139
+ return (`Live root "${root}" keeps its records in the local store, and this is a CI run. ${why} ` +
140
+ "A CI runner starts with an empty directory every run, so each record-backed resource is proposed " +
141
+ "for create again. Keep or add a backend \"s3\", \"gcs\" or \"azurerm\" block with a literal bucket " +
142
+ "(choudoufu derives the store from it), or declare a record_store in the live block or " +
143
+ `estate.chdf.hcl. A lane that uses the local store on purpose sets ${ALLOW_LOCAL_RECORD_STORE_ENV}=1.`);
144
+ }
145
+ /**
146
+ * TF046 against an explicit environment. `tf046.check` passes `process.env`;
147
+ * tests pass their own.
148
+ */
149
+ export function checkLocalRecordStore(ctx, env) {
150
+ if (!isCiEnvironment(env) || truthy(env[ALLOW_LOCAL_RECORD_STORE_ENV]))
151
+ return [];
152
+ const diagnostics = [];
153
+ for (const [root, live] of liveRoots(ctx)) {
154
+ if (live.runtimeBackend)
155
+ continue;
156
+ const store = resolveRecordStore(live.terraformBodies, live.liveBodies);
157
+ if (store.kind !== "local")
158
+ continue;
159
+ diagnostics.push({
160
+ checkId: "TF046",
161
+ severity: "error",
162
+ message: message(root, store),
163
+ entity: live.anchor,
164
+ lexicon: "terraform",
165
+ });
166
+ }
167
+ return diagnostics;
168
+ }
169
+ export const tf046 = {
170
+ id: "TF046",
171
+ description: "Live root resolves to the local record store in a CI run",
172
+ check(ctx) {
173
+ return checkLocalRecordStore(ctx, process.env);
174
+ },
175
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * TF047: a live root pins a registry module version the known-module catalog
3
+ * has no row for, or one whose row carries refusals.
4
+ *
5
+ * The catalog is choudoufu's module compatibility table, vendored in
6
+ * `../../module-catalog/` (chant#4560, choudoufu#2292). It has one static
7
+ * row per terraform-aws-modules example at one tag, measured offline in the
8
+ * onboarded form. A module call on a root whose binary is choudoufu (the
9
+ * root's `mode` is `live`) with an exact `version` is looked up there:
10
+ *
11
+ * - no row for the module, or none at the pinned version: `info`, naming the
12
+ * versions the static tier did measure;
13
+ * - at least one example at that version refused: `warning`, with each
14
+ * refusal ID, its site count, the examples that carry it and its
15
+ * `live/LIMITATIONS.md` link;
16
+ * - every example clear: quiet.
17
+ *
18
+ * Every message names the tier. The catalog holds the static tier only, and
19
+ * no figure here counts a gauntlet run (choudoufu#2292 ruling: two tiers,
20
+ * never mixed).
21
+ *
22
+ * A stock root (`mode: "state"`) is skipped: the table measures choudoufu.
23
+ * A range is TF039's finding and a missing `version` TF004's, so both are
24
+ * skipped here. A `//subdir` source is looked up by its module repository.
25
+ *
26
+ * Off by default: `report-only` in the audit catalog, as TF039 is.
27
+ * terragucci turns it on and holds the product wording (terragucci#1286).
28
+ *
29
+ * Scope: root and child modules of a live root alike.
30
+ */
31
+ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
32
+ import { type ModuleCompatibility } from "../../module-catalog/index.js";
33
+ /** The TF047 message for one module call, or undefined when the call is clear. */
34
+ export declare function catalogMessage(address: string, c: ModuleCompatibility): string | undefined;
35
+ export declare const tf047: PostSynthCheck;
36
+ //# sourceMappingURL=tf047.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tf047.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/tf047.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,kCAAkC,CAAC;AAI1C,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,sBAAsB,CAAC;AAK9B,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CA2B1F;AAED,eAAO,MAAM,KAAK,EAAE,cAkCnB,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * TF047: a live root pins a registry module version the known-module catalog
3
+ * has no row for, or one whose row carries refusals.
4
+ *
5
+ * The catalog is choudoufu's module compatibility table, vendored in
6
+ * `../../module-catalog/` (chant#4560, choudoufu#2292). It has one static
7
+ * row per terraform-aws-modules example at one tag, measured offline in the
8
+ * onboarded form. A module call on a root whose binary is choudoufu (the
9
+ * root's `mode` is `live`) with an exact `version` is looked up there:
10
+ *
11
+ * - no row for the module, or none at the pinned version: `info`, naming the
12
+ * versions the static tier did measure;
13
+ * - at least one example at that version refused: `warning`, with each
14
+ * refusal ID, its site count, the examples that carry it and its
15
+ * `live/LIMITATIONS.md` link;
16
+ * - every example clear: quiet.
17
+ *
18
+ * Every message names the tier. The catalog holds the static tier only, and
19
+ * no figure here counts a gauntlet run (choudoufu#2292 ruling: two tiers,
20
+ * never mixed).
21
+ *
22
+ * A stock root (`mode: "state"`) is skipped: the table measures choudoufu.
23
+ * A range is TF039's finding and a missing `version` TF004's, so both are
24
+ * skipped here. A `//subdir` source is looked up by its module repository.
25
+ *
26
+ * Off by default: `report-only` in the audit catalog, as TF039 is.
27
+ * terragucci turns it on and holds the product wording (terragucci#1286).
28
+ *
29
+ * Scope: root and child modules of a live root alike.
30
+ */
31
+ import { isResourceDeclarable } from "@intentius/chant/declarable";
32
+ import { MODULE_TYPE } from "../../hcl/parse.js";
33
+ import { classifyModuleSource, isExactVersionConstraint } from "./module-source.js";
34
+ import { MODULE_CATALOG_SOURCE, MODULE_COMPATIBILITY_PAGE, moduleCompatibility, } from "../../module-catalog/index.js";
35
+ const tierNote = () => `static tier of choudoufu's module table, measured ${MODULE_CATALOG_SOURCE.date} with hashicorp/aws ${MODULE_CATALOG_SOURCE.awsProvider}`;
36
+ /** The TF047 message for one module call, or undefined when the call is clear. */
37
+ export function catalogMessage(address, c) {
38
+ const pin = `${c.module} ${c.version}`;
39
+ switch (c.status) {
40
+ case "clear":
41
+ return undefined;
42
+ case "unknown-module":
43
+ return (`Module "${address}" pins ${pin}, and the ${tierNote()} has no row for this module. ` +
44
+ `Run \`choudoufu live-check\` on the root to see whether it plans. The table: ${MODULE_COMPATIBILITY_PAGE}`);
45
+ case "unknown-version":
46
+ return (`Module "${address}" pins ${pin}, and the ${tierNote()} has no row at this version. ` +
47
+ `It measured ${c.measuredVersions.join(", ")}. ` +
48
+ `Run \`choudoufu live-check\` on the root, or pin a measured version. The table: ${MODULE_COMPATIBILITY_PAGE}`);
49
+ case "refused": {
50
+ const ids = c.refusals
51
+ .map((r) => `${r.id} (${r.sites} site${r.sites === 1 ? "" : "s"} in ${r.examples.join(", ")}; ${r.docsUrl})`)
52
+ .join("; ");
53
+ return (`Module "${address}" pins ${pin}. In the ${tierNote()}, ${c.refusedExamples} of ${c.examples} ` +
54
+ `examples at this version are refused: ${ids}. ` +
55
+ "A call that uses the same features is refused the same way; `choudoufu live-check` names each site in this root.");
56
+ }
57
+ }
58
+ }
59
+ export const tf047 = {
60
+ id: "TF047",
61
+ description: "Live root pins a module version the known-module catalog has no row for, or one with refusals",
62
+ check(ctx) {
63
+ const diagnostics = [];
64
+ for (const [key, entity] of ctx.entities) {
65
+ if (entity.entityType !== MODULE_TYPE || !isResourceDeclarable(entity))
66
+ continue;
67
+ const props = entity.props;
68
+ if (props.mode !== "live")
69
+ continue;
70
+ const body = (typeof props.body === "object" && props.body !== null ? props.body : {});
71
+ const source = typeof body.source === "string" ? body.source : undefined;
72
+ if (source === undefined || classifyModuleSource(source).kind !== "registry")
73
+ continue;
74
+ const version = body.version;
75
+ if (typeof version !== "string" || !isExactVersionConstraint(version))
76
+ continue;
77
+ const compat = moduleCompatibility(source, version);
78
+ if (compat === undefined)
79
+ continue;
80
+ const address = typeof props.address === "string" ? props.address : key;
81
+ const message = catalogMessage(address, compat);
82
+ if (message === undefined)
83
+ continue;
84
+ diagnostics.push({
85
+ checkId: "TF047",
86
+ severity: compat.status === "refused" ? "warning" : "info",
87
+ message,
88
+ entity: key,
89
+ lexicon: "terraform",
90
+ });
91
+ }
92
+ return diagnostics;
93
+ },
94
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The terraform lexicon's lock grain (#4552) and the rows a choudoufu apply
3
+ * holds on the resource grain, in terragucci's format (`planRows` in
4
+ * terragucci's `apply-rows.ts` at 18f6431), unchanged:
5
+ *
6
+ * - `estate <estate> <address>` for every resource instance the apply acts
7
+ * on (a create, update, delete, replace or forget), or `root <root>
8
+ * <address>` when the root has no estate;
9
+ * - the same for `previous_address` on a moved instance;
10
+ * - `object <id>` for anything but a create, from the object's id before,
11
+ * so two estates that meet on one object meet on its row.
12
+ *
13
+ * Data reads and no-ops hold nothing.
14
+ *
15
+ * The grain: `resource` for choudoufu, which keeps one record per resource,
16
+ * writes each conditionally and refuses a plan one of whose changes moved;
17
+ * `target` (the root, or the Terragrunt unit) for Terraform, tofu and
18
+ * Terragrunt, whose state is one file the backend's lock keeps whole. Those
19
+ * three refuse `resource` by name, since nothing in their state is per
20
+ * resource.
21
+ */
22
+ import type { ChangeSetPart, ChangeSetPlanner } from "@intentius/chant/change-set";
23
+ import { type LockGrain, type LockRow } from "@intentius/chant/lifecycle/lock-rows";
24
+ /** The rows a plan's changes key, from `show -json`'s `resource_changes` (terragucci's `planRows`). */
25
+ export declare function terraformLockRows(root: string, estate: string | undefined, plan: unknown): LockRow[];
26
+ /**
27
+ * The rows from a member's change-set part, when the plan document is not
28
+ * at hand: the same keys, less the previous address of a moved instance,
29
+ * which the part does not carry. The part's `scope` is the estate.
30
+ */
31
+ export declare function terraformLockRowsFromPart(root: string, part: ChangeSetPart): LockRow[];
32
+ /** The grain a root takes by default: `resource` under choudoufu, `target` under every other binary. */
33
+ export declare function terraformDefaultLockGrain(planner: ChangeSetPlanner | undefined): LockGrain;
34
+ /** Why a root cannot take `grain`, by engine name, or undefined when it can. */
35
+ export declare function terraformLockGrainRefusal(grain: LockGrain, planner: ChangeSetPlanner | undefined, binary?: string): string | undefined;
36
+ //# sourceMappingURL=lock-rows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-rows.d.ts","sourceRoot":"","sources":["../src/lock-rows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAgC,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,sCAAsC,CAAC;AASlH,uGAAuG;AACvG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,EAAE,CAgBpG;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,EAAE,CAStF;AAOD,wGAAwG;AACxG,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAE1F;AAED,gFAAgF;AAChF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAItI"}
@@ -0,0 +1,60 @@
1
+ import { objectRowKey, sortedLockRows } from "@intentius/chant/lifecycle/lock-rows";
2
+ const CHANGING = new Set(["create", "update", "delete", "forget"]);
3
+ /** The scope a root's rows are keyed in: its estate, else its path. */
4
+ function rowScope(root, estate) {
5
+ return estate ? `estate ${estate}` : `root ${root}`;
6
+ }
7
+ /** The rows a plan's changes key, from `show -json`'s `resource_changes` (terragucci's `planRows`). */
8
+ export function terraformLockRows(root, estate, plan) {
9
+ const scope = rowScope(root, estate);
10
+ const rows = [];
11
+ const changes = plan?.resource_changes ?? [];
12
+ for (const c of changes) {
13
+ if (c?.mode === "data" || typeof c?.address !== "string")
14
+ continue;
15
+ const actions = Array.isArray(c.change?.actions) ? c.change.actions : [];
16
+ if (!actions.some((a) => CHANGING.has(a)))
17
+ continue;
18
+ const address = c.address;
19
+ rows.push({ key: `${scope} ${address}`, target: root, address });
20
+ if (typeof c.previous_address === "string" && c.previous_address !== address)
21
+ rows.push({ key: `${scope} ${c.previous_address}`, target: root, address });
22
+ // The live object an update or a delete acts on: two estates that meet on one object meet here.
23
+ const id = c.change?.before?.id;
24
+ if (actions.some((a) => a !== "create") && (typeof id === "string" || typeof id === "number") && String(id) !== "")
25
+ rows.push({ key: objectRowKey(String(id)), target: root, address });
26
+ }
27
+ return sortedLockRows(rows);
28
+ }
29
+ /**
30
+ * The rows from a member's change-set part, when the plan document is not
31
+ * at hand: the same keys, less the previous address of a moved instance,
32
+ * which the part does not carry. The part's `scope` is the estate.
33
+ */
34
+ export function terraformLockRowsFromPart(root, part) {
35
+ const scope = rowScope(root, part.member.planner === "choudoufu" ? part.member.scope : undefined);
36
+ const rows = [];
37
+ for (const e of part.entries) {
38
+ if (e.action === "no-op" || e.action === "read")
39
+ continue;
40
+ rows.push({ key: `${scope} ${e.address}`, target: root, address: e.address });
41
+ if (e.action !== "create" && e.id)
42
+ rows.push({ key: objectRowKey(e.id), target: root, address: e.address });
43
+ }
44
+ return sortedLockRows(rows);
45
+ }
46
+ /** Whether a binary's name is Terragrunt's. */
47
+ function isTerragrunt(binary) {
48
+ return /^terragrunt(\.exe)?$/.test((binary ?? "").split(/[\\/]/).pop() ?? "");
49
+ }
50
+ /** The grain a root takes by default: `resource` under choudoufu, `target` under every other binary. */
51
+ export function terraformDefaultLockGrain(planner) {
52
+ return planner === "choudoufu" ? "resource" : "target";
53
+ }
54
+ /** Why a root cannot take `grain`, by engine name, or undefined when it can. */
55
+ export function terraformLockGrainRefusal(grain, planner, binary) {
56
+ if (grain !== "resource" || planner === "choudoufu")
57
+ return undefined;
58
+ const engine = isTerragrunt(binary) ? "Terragrunt" : planner === "tofu" ? "tofu" : "Terraform";
59
+ return `${engine} keeps a root's state in one file that its backend's lock keeps whole, so nothing in it is per resource; the resource grain needs choudoufu (ci.lockGrain: target)`;
60
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * State-lock waits for a plan or an apply (#4545): how long `plan` and
3
+ * `apply` wait for another run's state lock before failing. Taken from
4
+ * terragucci's waves, where two jobs of one pipeline can reach the same
5
+ * backend a moment apart and a failed lock fails the wave for nothing.
6
+ *
7
+ * A job that already sets `-lock-timeout` through `TF_CLI_ARGS` or
8
+ * `TF_CLI_ARGS_<command>` keeps its own: the flag is added only when neither
9
+ * names one. Terragrunt waves pass the same flag after `--`
10
+ * (`./terragrunt/wave.ts`, `extra`).
11
+ */
12
+ /** How long a plan or an apply waits for a state lock unless the job set a `-lock-timeout` of its own. */
13
+ export declare const DEFAULT_LOCK_TIMEOUT = "5m";
14
+ /** Whether `value` is a `-lock-timeout` duration. */
15
+ export declare function isLockTimeout(value: unknown): value is string;
16
+ /**
17
+ * The `-lock-timeout` flag a `command` takes: `-lock-timeout=<timeout>`, or
18
+ * nothing when `TF_CLI_ARGS` or `TF_CLI_ARGS_<command>` in `env` already
19
+ * names one, or `timeout` is `false`. Throws on a duration terraform refuses.
20
+ */
21
+ export declare function lockTimeoutArgs(command: "plan" | "apply", timeout?: string | false, env?: Record<string, string | undefined>): string[];
22
+ //# sourceMappingURL=lock-timeout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-timeout.d.ts","sourceRoot":"","sources":["../src/lock-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,0GAA0G;AAC1G,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAKzC,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,GAAE,MAAM,GAAG,KAA4B,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,MAAM,EAAE,CAK1K"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * State-lock waits for a plan or an apply (#4545): how long `plan` and
3
+ * `apply` wait for another run's state lock before failing. Taken from
4
+ * terragucci's waves, where two jobs of one pipeline can reach the same
5
+ * backend a moment apart and a failed lock fails the wave for nothing.
6
+ *
7
+ * A job that already sets `-lock-timeout` through `TF_CLI_ARGS` or
8
+ * `TF_CLI_ARGS_<command>` keeps its own: the flag is added only when neither
9
+ * names one. Terragrunt waves pass the same flag after `--`
10
+ * (`./terragrunt/wave.ts`, `extra`).
11
+ */
12
+ /** How long a plan or an apply waits for a state lock unless the job set a `-lock-timeout` of its own. */
13
+ export const DEFAULT_LOCK_TIMEOUT = "5m";
14
+ /** A duration terraform's `-lock-timeout` takes: `0s`, `30s`, `5m`, `1h30m`. */
15
+ const DURATION = /^(\d+(ms|s|m|h))+$/;
16
+ /** Whether `value` is a `-lock-timeout` duration. */
17
+ export function isLockTimeout(value) {
18
+ return typeof value === "string" && DURATION.test(value);
19
+ }
20
+ /**
21
+ * The `-lock-timeout` flag a `command` takes: `-lock-timeout=<timeout>`, or
22
+ * nothing when `TF_CLI_ARGS` or `TF_CLI_ARGS_<command>` in `env` already
23
+ * names one, or `timeout` is `false`. Throws on a duration terraform refuses.
24
+ */
25
+ export function lockTimeoutArgs(command, timeout = DEFAULT_LOCK_TIMEOUT, env = process.env) {
26
+ if (timeout === false)
27
+ return [];
28
+ if (!isLockTimeout(timeout))
29
+ throw new Error(`lockTimeout "${timeout}" is not a duration terraform takes, such as "5m" or "30s"`);
30
+ const set = `${env.TF_CLI_ARGS ?? ""} ${env[`TF_CLI_ARGS_${command}`] ?? ""}`;
31
+ return /(^|\s)-{1,2}lock-timeout[=\s]/.test(set) ? [] : [`-lock-timeout=${timeout}`];
32
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terraform",
3
- "version": "0.124.54",
3
+ "version": "0.124.56",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "Terraform"
6
6
  }
@@ -0,0 +1,69 @@
1
+ import type { StaticRow } from "./types.js";
2
+ export type { StaticRefusal, StaticRow, StaticMeasurement, StaticSource } from "./types.js";
3
+ /** Where the vendored rows came from. */
4
+ export declare const MODULE_CATALOG_SOURCE: {
5
+ readonly repo: "INTENTIUS/choudoufu";
6
+ readonly path: "live/module-compat.json";
7
+ readonly commit: "39a143679a6f5ffeae7dc186190049e8b55f7149";
8
+ /** The static tier's measurement date. */
9
+ readonly date: string;
10
+ /** The choudoufu commit the static tier was measured at. */
11
+ readonly measuredAt: string;
12
+ /** The hashicorp/aws provider version the static tier was measured with. */
13
+ readonly awsProvider: string;
14
+ };
15
+ /** choudoufu's site page that renders both tiers. */
16
+ export declare const MODULE_COMPATIBILITY_PAGE = "https://intentius.io/choudoufu/aws/compatibility/#modules";
17
+ /** The tiers this catalog holds. */
18
+ export type ModuleCatalogTier = "static";
19
+ /** Every static row, as vendored. */
20
+ export declare const staticRows: readonly StaticRow[];
21
+ /** One refusal ID across the examples of a module version that carry it. */
22
+ export interface ModuleRefusalSummary {
23
+ id: string;
24
+ /** Sites summed across the examples that carry it. */
25
+ sites: number;
26
+ docsUrl: string;
27
+ /** Example directories that carry it, sorted. */
28
+ examples: string[];
29
+ }
30
+ /**
31
+ * What the catalog says about one pinned module version.
32
+ *
33
+ * - `unknown-module`: no static row for this module at any version.
34
+ * - `unknown-version`: rows for the module, none measured at this version
35
+ * (`measuredVersions` lists the ones there are).
36
+ * - `refused`: at least one example at this version is refused.
37
+ * - `clear`: every measured example at this version is clear.
38
+ */
39
+ export interface ModuleCompatibility {
40
+ module: string;
41
+ /** The pinned version, without a leading `v` or `=`. */
42
+ version: string;
43
+ tier: ModuleCatalogTier;
44
+ status: "unknown-module" | "unknown-version" | "clear" | "refused";
45
+ /** Static rows measured at this version (an `unmeasured` row is left out). */
46
+ examples: number;
47
+ clearExamples: number;
48
+ refusedExamples: number;
49
+ /** Refusal IDs at this version, most refused examples first, then by ID. */
50
+ refusals: ModuleRefusalSummary[];
51
+ /** Versions the static tier measured for this module, without a leading `v`. */
52
+ measuredVersions: string[];
53
+ }
54
+ /**
55
+ * The registry address of a module source, without a registry host, a
56
+ * `//subdir` or a query, lowercased: `registry.terraform.io/terraform-aws-modules/iam/aws//modules/iam-role`
57
+ * gives `terraform-aws-modules/iam/aws`. Undefined when the source is not a
58
+ * three-part registry address.
59
+ */
60
+ export declare function registryModuleAddress(source: string): string | undefined;
61
+ /** `= 1.4.0`, `v1.4.0` and `1.4.0` all give `1.4.0`; a range gives undefined. */
62
+ export declare function exactModuleVersion(version: string): string | undefined;
63
+ /**
64
+ * The catalog's answer for a module `source` pinned at `version`, or
65
+ * undefined when the source is not a registry address or the version is not
66
+ * exact (a range is TF039's finding, and the catalog has no row for one).
67
+ */
68
+ export declare function moduleCompatibility(source: string, version: string): ModuleCompatibility | undefined;
69
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/module-catalog/index.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEzF,yCAAyC;AACzC,eAAO,MAAM,qBAAqB;aAChC,IAAI,EAAE,qBAAqB;aAC3B,IAAI;aACJ,MAAM;IACN,0CAA0C;aAC1C,IAAI;IACJ,4DAA4D;aAC5D,UAAU;IACV,4EAA4E;aAC5E,WAAW;CACH,CAAC;AAEX,qDAAqD;AACrD,eAAO,MAAM,yBAAyB,8DAA8D,CAAC;AAErG,oCAAoC;AACpC,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAEzC,qCAAqC;AACrC,eAAO,MAAM,UAAU,EAAE,SAAS,SAAS,EAAgB,CAAC;AAE5D,4EAA4E;AAC5E,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,OAAO,GAAG,SAAS,CAAC;IACnE,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,gFAAgF;IAChF,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQxE;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGtE;AAiBD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAoCpG"}