@intentius/chant-lexicon-terraform 0.57.0 → 0.59.0

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 (408) hide show
  1. package/README.md +9 -0
  2. package/dist/composites/terraform-adopt-op.d.ts +131 -0
  3. package/dist/composites/terraform-adopt-op.d.ts.map +1 -0
  4. package/dist/composites/terraform-apply-op.d.ts +70 -17
  5. package/dist/composites/terraform-apply-op.d.ts.map +1 -1
  6. package/dist/composites/terraform-watch-op.d.ts +104 -37
  7. package/dist/composites/terraform-watch-op.d.ts.map +1 -1
  8. package/dist/config.d.ts +49 -2
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/describe-resources.d.ts +256 -16
  11. package/dist/describe-resources.d.ts.map +1 -1
  12. package/dist/hcl/descend.d.ts +98 -0
  13. package/dist/hcl/descend.d.ts.map +1 -0
  14. package/dist/hcl/marker.d.ts +130 -0
  15. package/dist/hcl/marker.d.ts.map +1 -0
  16. package/dist/hcl/parse.d.ts +156 -9
  17. package/dist/hcl/parse.d.ts.map +1 -1
  18. package/dist/hcl/references.d.ts +76 -0
  19. package/dist/hcl/references.d.ts.map +1 -0
  20. package/dist/hcl/roots.d.ts +22 -3
  21. package/dist/hcl/roots.d.ts.map +1 -1
  22. package/dist/hcl/suppressions.d.ts +54 -0
  23. package/dist/hcl/suppressions.d.ts.map +1 -0
  24. package/dist/hcl/value.d.ts +77 -0
  25. package/dist/hcl/value.d.ts.map +1 -0
  26. package/dist/index.d.ts +5 -2
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/integrity.json +34 -5
  29. package/dist/lint/audit-catalog.d.ts +3 -2
  30. package/dist/lint/audit-catalog.d.ts.map +1 -1
  31. package/dist/lint/audit-lineage.d.ts +95 -0
  32. package/dist/lint/audit-lineage.d.ts.map +1 -1
  33. package/dist/lint/post-synth/blocks.d.ts +53 -0
  34. package/dist/lint/post-synth/blocks.d.ts.map +1 -0
  35. package/dist/lint/post-synth/fixtures/load.d.ts +37 -0
  36. package/dist/lint/post-synth/fixtures/load.d.ts.map +1 -0
  37. package/dist/lint/post-synth/index.d.ts.map +1 -1
  38. package/dist/lint/post-synth/module-source.d.ts +38 -0
  39. package/dist/lint/post-synth/module-source.d.ts.map +1 -0
  40. package/dist/lint/post-synth/scope.d.ts +65 -0
  41. package/dist/lint/post-synth/scope.d.ts.map +1 -0
  42. package/dist/lint/post-synth/tf001.d.ts +58 -6
  43. package/dist/lint/post-synth/tf001.d.ts.map +1 -1
  44. package/dist/lint/post-synth/tf002.d.ts +32 -0
  45. package/dist/lint/post-synth/tf002.d.ts.map +1 -0
  46. package/dist/lint/post-synth/tf003.d.ts +22 -0
  47. package/dist/lint/post-synth/tf003.d.ts.map +1 -0
  48. package/dist/lint/post-synth/tf004.d.ts +22 -0
  49. package/dist/lint/post-synth/tf004.d.ts.map +1 -0
  50. package/dist/lint/post-synth/tf005.d.ts +28 -0
  51. package/dist/lint/post-synth/tf005.d.ts.map +1 -0
  52. package/dist/lint/post-synth/tf006.d.ts +21 -0
  53. package/dist/lint/post-synth/tf006.d.ts.map +1 -0
  54. package/dist/lint/post-synth/tf007.d.ts +21 -0
  55. package/dist/lint/post-synth/tf007.d.ts.map +1 -0
  56. package/dist/lint/post-synth/tf008.d.ts +22 -0
  57. package/dist/lint/post-synth/tf008.d.ts.map +1 -0
  58. package/dist/lint/post-synth/tf009.d.ts +24 -0
  59. package/dist/lint/post-synth/tf009.d.ts.map +1 -0
  60. package/dist/lint/post-synth/tf010.d.ts +19 -0
  61. package/dist/lint/post-synth/tf010.d.ts.map +1 -0
  62. package/dist/lint/post-synth/tf011.d.ts +18 -0
  63. package/dist/lint/post-synth/tf011.d.ts.map +1 -0
  64. package/dist/lint/post-synth/tf012.d.ts +17 -0
  65. package/dist/lint/post-synth/tf012.d.ts.map +1 -0
  66. package/dist/lint/post-synth/tf013.d.ts +21 -0
  67. package/dist/lint/post-synth/tf013.d.ts.map +1 -0
  68. package/dist/lint/post-synth/tf014.d.ts +25 -0
  69. package/dist/lint/post-synth/tf014.d.ts.map +1 -0
  70. package/dist/lint/post-synth/tf015.d.ts +30 -0
  71. package/dist/lint/post-synth/tf015.d.ts.map +1 -0
  72. package/dist/lint/post-synth/tf016.d.ts +30 -0
  73. package/dist/lint/post-synth/tf016.d.ts.map +1 -0
  74. package/dist/lint/post-synth/tf017.d.ts +19 -0
  75. package/dist/lint/post-synth/tf017.d.ts.map +1 -0
  76. package/dist/lint/post-synth/tf018.d.ts +20 -0
  77. package/dist/lint/post-synth/tf018.d.ts.map +1 -0
  78. package/dist/lint/post-synth/tf019.d.ts +25 -0
  79. package/dist/lint/post-synth/tf019.d.ts.map +1 -0
  80. package/dist/lint/post-synth/tf020.d.ts +38 -0
  81. package/dist/lint/post-synth/tf020.d.ts.map +1 -0
  82. package/dist/lint/post-synth/tf021.d.ts +41 -0
  83. package/dist/lint/post-synth/tf021.d.ts.map +1 -0
  84. package/dist/lint/post-synth/tf022.d.ts +24 -0
  85. package/dist/lint/post-synth/tf022.d.ts.map +1 -0
  86. package/dist/lint/post-synth/tf024.d.ts +24 -0
  87. package/dist/lint/post-synth/tf024.d.ts.map +1 -0
  88. package/dist/lint/post-synth/tf025.d.ts +29 -0
  89. package/dist/lint/post-synth/tf025.d.ts.map +1 -0
  90. package/dist/lint/post-synth/tf026.d.ts +28 -0
  91. package/dist/lint/post-synth/tf026.d.ts.map +1 -0
  92. package/dist/lint/post-synth/tf027.d.ts +30 -0
  93. package/dist/lint/post-synth/tf027.d.ts.map +1 -0
  94. package/dist/lint/post-synth/tf028.d.ts +33 -0
  95. package/dist/lint/post-synth/tf028.d.ts.map +1 -0
  96. package/dist/lint/rules/fixtures/load.d.ts +13 -0
  97. package/dist/lint/rules/fixtures/load.d.ts.map +1 -0
  98. package/dist/lint/rules/plan-before-apply.d.ts +11 -0
  99. package/dist/lint/rules/plan-before-apply.d.ts.map +1 -1
  100. package/dist/lint/secret-shape.d.ts +68 -0
  101. package/dist/lint/secret-shape.d.ts.map +1 -0
  102. package/dist/live-ownership.d.ts +55 -0
  103. package/dist/live-ownership.d.ts.map +1 -0
  104. package/dist/lsp/option-keys.d.ts.map +1 -1
  105. package/dist/manifest.json +1 -1
  106. package/dist/okf/index.md +26 -0
  107. package/dist/okf/rules/TF002.md +11 -0
  108. package/dist/okf/rules/TF003.md +11 -0
  109. package/dist/okf/rules/TF004.md +11 -0
  110. package/dist/okf/rules/TF005.md +11 -0
  111. package/dist/okf/rules/TF006.md +11 -0
  112. package/dist/okf/rules/TF007.md +11 -0
  113. package/dist/okf/rules/TF008.md +11 -0
  114. package/dist/okf/rules/TF009.md +11 -0
  115. package/dist/okf/rules/TF010.md +11 -0
  116. package/dist/okf/rules/TF011.md +11 -0
  117. package/dist/okf/rules/TF012.md +11 -0
  118. package/dist/okf/rules/TF013.md +11 -0
  119. package/dist/okf/rules/TF014.md +11 -0
  120. package/dist/okf/rules/TF015.md +11 -0
  121. package/dist/okf/rules/TF016.md +11 -0
  122. package/dist/okf/rules/TF017.md +11 -0
  123. package/dist/okf/rules/TF018.md +11 -0
  124. package/dist/okf/rules/TF019.md +11 -0
  125. package/dist/okf/rules/TF020.md +11 -0
  126. package/dist/okf/rules/TF021.md +11 -0
  127. package/dist/okf/rules/TF022.md +11 -0
  128. package/dist/okf/rules/TF024.md +11 -0
  129. package/dist/okf/rules/TF025.md +11 -0
  130. package/dist/okf/rules/TF026.md +11 -0
  131. package/dist/okf/rules/TF027.md +11 -0
  132. package/dist/okf/rules/TF028.md +11 -0
  133. package/dist/op/activities/index.d.ts +13 -6
  134. package/dist/op/activities/index.d.ts.map +1 -1
  135. package/dist/op/activities/live-detect.d.ts +51 -0
  136. package/dist/op/activities/live-detect.d.ts.map +1 -0
  137. package/dist/op/activities/terraform.d.ts +466 -17
  138. package/dist/op/activities/terraform.d.ts.map +1 -1
  139. package/dist/op/activity-contracts.d.ts +148 -0
  140. package/dist/op/activity-contracts.d.ts.map +1 -0
  141. package/dist/op/adoption.d.ts +118 -0
  142. package/dist/op/adoption.d.ts.map +1 -0
  143. package/dist/op/builders.d.ts +48 -6
  144. package/dist/op/builders.d.ts.map +1 -1
  145. package/dist/op/resolve-root-mode.d.ts +59 -0
  146. package/dist/op/resolve-root-mode.d.ts.map +1 -0
  147. package/dist/plugin.d.ts.map +1 -1
  148. package/dist/rules/blocks.ts +109 -0
  149. package/dist/rules/module-source.ts +121 -0
  150. package/dist/rules/plan-before-apply.ts +11 -0
  151. package/dist/rules/scope.ts +107 -0
  152. package/dist/rules/tf001.ts +98 -18
  153. package/dist/rules/tf002.ts +151 -0
  154. package/dist/rules/tf003.ts +71 -0
  155. package/dist/rules/tf004.ts +63 -0
  156. package/dist/rules/tf005.ts +76 -0
  157. package/dist/rules/tf006.ts +53 -0
  158. package/dist/rules/tf007.ts +78 -0
  159. package/dist/rules/tf008.ts +75 -0
  160. package/dist/rules/tf009.ts +59 -0
  161. package/dist/rules/tf010.ts +51 -0
  162. package/dist/rules/tf011.ts +49 -0
  163. package/dist/rules/tf012.ts +47 -0
  164. package/dist/rules/tf013.ts +63 -0
  165. package/dist/rules/tf014.ts +72 -0
  166. package/dist/rules/tf015.ts +72 -0
  167. package/dist/rules/tf016.ts +75 -0
  168. package/dist/rules/tf017.ts +50 -0
  169. package/dist/rules/tf018.ts +72 -0
  170. package/dist/rules/tf019.ts +72 -0
  171. package/dist/rules/tf020.ts +123 -0
  172. package/dist/rules/tf021.ts +126 -0
  173. package/dist/rules/tf022.ts +61 -0
  174. package/dist/rules/tf024.ts +70 -0
  175. package/dist/rules/tf025.ts +101 -0
  176. package/dist/rules/tf026.ts +84 -0
  177. package/dist/rules/tf027.ts +74 -0
  178. package/dist/rules/tf028.ts +96 -0
  179. package/dist/skills/chant-terraform.md +1 -1
  180. package/dist/validate.d.ts.map +1 -1
  181. package/package.json +7 -2
  182. package/src/__fixtures__/ACCEPTANCE.md +181 -0
  183. package/src/__fixtures__/live/main.tf +28 -0
  184. package/src/__fixtures__/live-adopt/estate.chdf.hcl +6 -0
  185. package/src/__fixtures__/live-adopt/main.tf +21 -0
  186. package/src/__fixtures__/live-estate/README.md +58 -0
  187. package/src/__fixtures__/live-estate/compute.tf +10 -0
  188. package/src/__fixtures__/live-estate/estate.chdf.hcl +1 -0
  189. package/src/__fixtures__/live-estate/logs.tf +8 -0
  190. package/src/__fixtures__/live-estate/network.tf +24 -0
  191. package/src/__fixtures__/live-estate/rule.tf +11 -0
  192. package/src/__fixtures__/live-estate/unowned.tf +21 -0
  193. package/src/__fixtures__/live-estate/versions.tf +31 -0
  194. package/src/__fixtures__/live-ls.json +98 -0
  195. package/src/__fixtures__/live-plan.json +285 -0
  196. package/src/__fixtures__/live-sidecar/estate.chdf.hcl +3 -0
  197. package/src/__fixtures__/live-sidecar/main.tf +24 -0
  198. package/src/__fixtures__/module-tree/README.md +16 -0
  199. package/src/__fixtures__/module-tree/cycle/main.tf +3 -0
  200. package/src/__fixtures__/module-tree/cycle/modules/a/main.tf +9 -0
  201. package/src/__fixtures__/module-tree/cycle/modules/b/main.tf +9 -0
  202. package/src/__fixtures__/module-tree/missing/main.tf +9 -0
  203. package/src/__fixtures__/module-tree/outside/root/main.tf +9 -0
  204. package/src/__fixtures__/module-tree/root/main.tf +28 -0
  205. package/src/__fixtures__/module-tree/root/modules/cdn/main.tf +15 -0
  206. package/src/__fixtures__/module-tree/root/modules/cdn/modules/bucket/main.tf +11 -0
  207. package/src/__fixtures__/module-tree/shared/main.tf +5 -0
  208. package/src/__fixtures__/references/main.tf +56 -0
  209. package/src/__fixtures__/remote-backend/main.tf +34 -0
  210. package/src/__fixtures__/with-backend/main.tf +7 -0
  211. package/src/codegen/lint-rules-page.test.ts +45 -0
  212. package/src/composites/terraform-adopt-op.acceptance.test.ts +193 -0
  213. package/src/composites/terraform-adopt-op.test.ts +175 -0
  214. package/src/composites/terraform-adopt-op.ts +202 -0
  215. package/src/composites/terraform-apply-op.acceptance.test.ts +188 -5
  216. package/src/composites/terraform-apply-op.test.ts +179 -19
  217. package/src/composites/terraform-apply-op.ts +123 -30
  218. package/src/composites/terraform-watch-op.test.ts +169 -29
  219. package/src/composites/terraform-watch-op.ts +183 -75
  220. package/src/config.ts +32 -3
  221. package/src/describe-resources.live.test.ts +598 -0
  222. package/src/describe-resources.test.ts +53 -0
  223. package/src/describe-resources.ts +811 -28
  224. package/src/hcl/descend.test.ts +162 -0
  225. package/src/hcl/descend.ts +273 -0
  226. package/src/hcl/marker.test.ts +147 -0
  227. package/src/hcl/marker.ts +235 -0
  228. package/src/hcl/parse.test.ts +69 -0
  229. package/src/hcl/parse.ts +269 -27
  230. package/src/hcl/references.test.ts +116 -0
  231. package/src/hcl/references.ts +172 -0
  232. package/src/hcl/roots.ts +59 -5
  233. package/src/hcl/suppressions.test.ts +147 -0
  234. package/src/hcl/suppressions.ts +204 -0
  235. package/src/hcl/value.test.ts +73 -0
  236. package/src/hcl/value.ts +106 -0
  237. package/src/index.ts +31 -1
  238. package/src/lint/audit-catalog.ts +288 -3
  239. package/src/lint/audit-lineage.ts +384 -1
  240. package/src/lint/audit.test.ts +210 -3
  241. package/src/lint/post-synth/blocks.ts +109 -0
  242. package/src/lint/post-synth/fixtures/TF001/negative-cloud.tf +28 -0
  243. package/src/lint/post-synth/fixtures/TF001/negative.tf +30 -0
  244. package/src/lint/post-synth/fixtures/TF001/positive-local.tf +31 -0
  245. package/src/lint/post-synth/fixtures/TF001/positive.tf +24 -0
  246. package/src/lint/post-synth/fixtures/TF002/negative.tf +17 -0
  247. package/src/lint/post-synth/fixtures/TF002/positive-legacy.tf +10 -0
  248. package/src/lint/post-synth/fixtures/TF002/positive-no-version.tf +12 -0
  249. package/src/lint/post-synth/fixtures/TF002/positive.tf +7 -0
  250. package/src/lint/post-synth/fixtures/TF003/negative.tf +10 -0
  251. package/src/lint/post-synth/fixtures/TF003/positive.tf +8 -0
  252. package/src/lint/post-synth/fixtures/TF004/negative-git.tf +3 -0
  253. package/src/lint/post-synth/fixtures/TF004/negative-local.tf +3 -0
  254. package/src/lint/post-synth/fixtures/TF004/negative.tf +4 -0
  255. package/src/lint/post-synth/fixtures/TF004/positive.tf +3 -0
  256. package/src/lint/post-synth/fixtures/TF005/negative-local.tf +3 -0
  257. package/src/lint/post-synth/fixtures/TF005/negative-registry.tf +3 -0
  258. package/src/lint/post-synth/fixtures/TF005/negative-sha.tf +3 -0
  259. package/src/lint/post-synth/fixtures/TF005/negative.tf +3 -0
  260. package/src/lint/post-synth/fixtures/TF005/positive-branch.tf +3 -0
  261. package/src/lint/post-synth/fixtures/TF005/positive-non-semver.tf +3 -0
  262. package/src/lint/post-synth/fixtures/TF005/positive.tf +3 -0
  263. package/src/lint/post-synth/fixtures/TF006/negative.tf +5 -0
  264. package/src/lint/post-synth/fixtures/TF006/positive-empty-default.tf +11 -0
  265. package/src/lint/post-synth/fixtures/TF006/positive.tf +6 -0
  266. package/src/lint/post-synth/fixtures/TF007/negative.tf +10 -0
  267. package/src/lint/post-synth/fixtures/TF007/positive.tf +9 -0
  268. package/src/lint/post-synth/fixtures/TF008/negative-variable.tf +10 -0
  269. package/src/lint/post-synth/fixtures/TF008/negative.tf +8 -0
  270. package/src/lint/post-synth/fixtures/TF008/positive-other-provider.tf +10 -0
  271. package/src/lint/post-synth/fixtures/TF008/positive.tf +5 -0
  272. package/src/lint/post-synth/fixtures/TF009/negative.tf +10 -0
  273. package/src/lint/post-synth/fixtures/TF009/positive.tf +4 -0
  274. package/src/lint/post-synth/fixtures/TF010/negative.tf +5 -0
  275. package/src/lint/post-synth/fixtures/TF010/positive.tf +4 -0
  276. package/src/lint/post-synth/fixtures/TF011/negative.tf +5 -0
  277. package/src/lint/post-synth/fixtures/TF011/positive-blank.tf +5 -0
  278. package/src/lint/post-synth/fixtures/TF011/positive.tf +4 -0
  279. package/src/lint/post-synth/fixtures/TF012/negative.tf +4 -0
  280. package/src/lint/post-synth/fixtures/TF012/positive.tf +3 -0
  281. package/src/lint/post-synth/fixtures/TF013/negative.tf +8 -0
  282. package/src/lint/post-synth/fixtures/TF013/positive-data.tf +8 -0
  283. package/src/lint/post-synth/fixtures/TF013/positive.tf +8 -0
  284. package/src/lint/post-synth/fixtures/TF014/negative/main.tf +26 -0
  285. package/src/lint/post-synth/fixtures/TF014/negative/modules/cdn/main.tf +19 -0
  286. package/src/lint/post-synth/fixtures/TF014/positive/main.tf +16 -0
  287. package/src/lint/post-synth/fixtures/TF014/positive/modules/cdn/main.tf +15 -0
  288. package/src/lint/post-synth/fixtures/TF015/negative/main.tf +13 -0
  289. package/src/lint/post-synth/fixtures/TF015/negative/modules/cdn/main.tf +16 -0
  290. package/src/lint/post-synth/fixtures/TF015/positive/main.tf +13 -0
  291. package/src/lint/post-synth/fixtures/TF015/positive/modules/cdn/main.tf +14 -0
  292. package/src/lint/post-synth/fixtures/TF016/negative-template.tf +7 -0
  293. package/src/lint/post-synth/fixtures/TF016/negative.tf +16 -0
  294. package/src/lint/post-synth/fixtures/TF016/positive-shared-file.tf +12 -0
  295. package/src/lint/post-synth/fixtures/TF016/positive.tf +13 -0
  296. package/src/lint/post-synth/fixtures/TF017/negative.tf +4 -0
  297. package/src/lint/post-synth/fixtures/TF017/positive.tf +5 -0
  298. package/src/lint/post-synth/fixtures/TF018/negative.tf +9 -0
  299. package/src/lint/post-synth/fixtures/TF018/positive-data.tf +9 -0
  300. package/src/lint/post-synth/fixtures/TF018/positive.tf +4 -0
  301. package/src/lint/post-synth/fixtures/TF019/negative.tf +14 -0
  302. package/src/lint/post-synth/fixtures/TF019/positive-output.tf +5 -0
  303. package/src/lint/post-synth/fixtures/TF019/positive.tf +16 -0
  304. package/src/lint/post-synth/fixtures/TF020/negative.tf +43 -0
  305. package/src/lint/post-synth/fixtures/TF020/positive.tf +32 -0
  306. package/src/lint/post-synth/fixtures/TF020/scoped/main.tf +21 -0
  307. package/src/lint/post-synth/fixtures/TF020/scoped/modules/cdn/main.tf +13 -0
  308. package/src/lint/post-synth/fixtures/TF021/negative.tf +31 -0
  309. package/src/lint/post-synth/fixtures/TF021/positive-length.tf +8 -0
  310. package/src/lint/post-synth/fixtures/TF021/positive.tf +8 -0
  311. package/src/lint/post-synth/fixtures/TF022/negative-locator.tf +7 -0
  312. package/src/lint/post-synth/fixtures/TF022/negative.tf +10 -0
  313. package/src/lint/post-synth/fixtures/TF022/positive-nested.tf +10 -0
  314. package/src/lint/post-synth/fixtures/TF022/positive.tf +6 -0
  315. package/src/lint/post-synth/fixtures/TF023/negative/main.tf +15 -0
  316. package/src/lint/post-synth/fixtures/TF023/positive/main.tf +9 -0
  317. package/src/lint/post-synth/fixtures/TF023/positive/state.json +24 -0
  318. package/src/lint/post-synth/fixtures/TF024/live-clean/main.tf +9 -0
  319. package/src/lint/post-synth/fixtures/TF024/live-with-backend/main.tf +14 -0
  320. package/src/lint/post-synth/fixtures/TF024/live-with-cloud/main.tf +16 -0
  321. package/src/lint/post-synth/fixtures/TF025/live-clean/main.tf +13 -0
  322. package/src/lint/post-synth/fixtures/TF025/live-with-workspace-ref/main.tf +13 -0
  323. package/src/lint/post-synth/fixtures/TF026/live-default/main.tf +9 -0
  324. package/src/lint/post-synth/fixtures/TF026/live-explicit-delete/main.tf +13 -0
  325. package/src/lint/post-synth/fixtures/TF026/live-keep/main.tf +13 -0
  326. package/src/lint/post-synth/fixtures/TF027/live-default/main.tf +9 -0
  327. package/src/lint/post-synth/fixtures/TF027/live-untagged-delete/main.tf +13 -0
  328. package/src/lint/post-synth/fixtures/TF027/live-untagged-delete-scoped/main.tf +17 -0
  329. package/src/lint/post-synth/fixtures/TF027/live-untagged-report/main.tf +13 -0
  330. package/src/lint/post-synth/fixtures/TF028/live/main.tf +9 -0
  331. package/src/lint/post-synth/fixtures/TF028/stock/main.tf +10 -0
  332. package/src/lint/post-synth/fixtures/load.ts +108 -0
  333. package/src/lint/post-synth/index.ts +52 -0
  334. package/src/lint/post-synth/live-refusals-config-format.test.ts +143 -0
  335. package/src/lint/post-synth/module-rules.test.ts +153 -0
  336. package/src/lint/post-synth/module-source.test.ts +75 -0
  337. package/src/lint/post-synth/module-source.ts +121 -0
  338. package/src/lint/post-synth/post-synth.test.ts +73 -16
  339. package/src/lint/post-synth/scope.ts +107 -0
  340. package/src/lint/post-synth/single-block.test.ts +263 -0
  341. package/src/lint/post-synth/suppression.test.ts +110 -0
  342. package/src/lint/post-synth/tf001.ts +98 -18
  343. package/src/lint/post-synth/tf002.test.ts +93 -0
  344. package/src/lint/post-synth/tf002.ts +151 -0
  345. package/src/lint/post-synth/tf003.test.ts +75 -0
  346. package/src/lint/post-synth/tf003.ts +71 -0
  347. package/src/lint/post-synth/tf004.test.ts +47 -0
  348. package/src/lint/post-synth/tf004.ts +63 -0
  349. package/src/lint/post-synth/tf005.test.ts +57 -0
  350. package/src/lint/post-synth/tf005.ts +76 -0
  351. package/src/lint/post-synth/tf006.ts +53 -0
  352. package/src/lint/post-synth/tf007.ts +78 -0
  353. package/src/lint/post-synth/tf008.ts +75 -0
  354. package/src/lint/post-synth/tf009.ts +59 -0
  355. package/src/lint/post-synth/tf010.ts +51 -0
  356. package/src/lint/post-synth/tf011.ts +49 -0
  357. package/src/lint/post-synth/tf012.ts +47 -0
  358. package/src/lint/post-synth/tf013.ts +63 -0
  359. package/src/lint/post-synth/tf014.ts +72 -0
  360. package/src/lint/post-synth/tf015.ts +72 -0
  361. package/src/lint/post-synth/tf016.ts +75 -0
  362. package/src/lint/post-synth/tf017.ts +50 -0
  363. package/src/lint/post-synth/tf018.ts +72 -0
  364. package/src/lint/post-synth/tf019.ts +72 -0
  365. package/src/lint/post-synth/tf020.ts +123 -0
  366. package/src/lint/post-synth/tf021.ts +126 -0
  367. package/src/lint/post-synth/tf022.ts +61 -0
  368. package/src/lint/post-synth/tf024.test.ts +42 -0
  369. package/src/lint/post-synth/tf024.ts +70 -0
  370. package/src/lint/post-synth/tf025.test.ts +46 -0
  371. package/src/lint/post-synth/tf025.ts +101 -0
  372. package/src/lint/post-synth/tf026.test.ts +56 -0
  373. package/src/lint/post-synth/tf026.ts +84 -0
  374. package/src/lint/post-synth/tf027.test.ts +62 -0
  375. package/src/lint/post-synth/tf027.ts +74 -0
  376. package/src/lint/post-synth/tf028.test.ts +92 -0
  377. package/src/lint/post-synth/tf028.ts +96 -0
  378. package/src/lint/presets.test.ts +72 -0
  379. package/src/lint/rules/fixtures/TF101/negative-op.ts +2 -0
  380. package/src/lint/rules/fixtures/TF101/positive-op.ts +2 -0
  381. package/src/lint/rules/fixtures/load.ts +53 -0
  382. package/src/lint/rules/plan-before-apply.test.ts +112 -7
  383. package/src/lint/rules/plan-before-apply.ts +11 -0
  384. package/src/lint/secret-shape.test.ts +150 -0
  385. package/src/lint/secret-shape.ts +159 -0
  386. package/src/live-ownership.ts +60 -0
  387. package/src/lsp/completions.test.ts +3 -2
  388. package/src/lsp/option-keys.ts +12 -6
  389. package/src/op/activities/choudoufu.acceptance.test.ts +127 -0
  390. package/src/op/activities/choudoufu.test.ts +725 -0
  391. package/src/op/activities/index.ts +40 -4
  392. package/src/op/activities/live-detect.test.ts +143 -0
  393. package/src/op/activities/live-detect.ts +162 -0
  394. package/src/op/activities/registry.test.ts +11 -3
  395. package/src/op/activities/terraform.test.ts +7 -3
  396. package/src/op/activities/terraform.ts +861 -69
  397. package/src/op/activity-contracts.test.ts +147 -0
  398. package/src/op/activity-contracts.ts +178 -0
  399. package/src/op/adoption.test.ts +170 -0
  400. package/src/op/adoption.ts +241 -0
  401. package/src/op/builders.test.ts +60 -5
  402. package/src/op/builders.ts +95 -5
  403. package/src/op/resolve-root-mode.test.ts +85 -0
  404. package/src/op/resolve-root-mode.ts +86 -0
  405. package/src/plugin.test.ts +106 -0
  406. package/src/plugin.ts +186 -29
  407. package/src/skills/chant-terraform.md +1 -1
  408. package/src/validate.ts +10 -1
@@ -0,0 +1,235 @@
1
+ /**
2
+ * choudoufu's live resource markers, as chant reads them (#2104).
3
+ *
4
+ * On a live root the ownership record is not a state file and not a chant
5
+ * stamp: it is two AWS tags on the resource itself, `tofu-estate` and
6
+ * `tofu-address`, specified in `live/MARKERS.md` in
7
+ * https://github.com/INTENTIUS/choudoufu. That file calls itself the one
8
+ * integration surface external tools may rely on, so this module implements
9
+ * exactly what it specifies and nothing beyond it. The spec's own tables are
10
+ * this module's tests (`./marker.test.ts`).
11
+ *
12
+ * ## Escape, then compare. Never decode a tag blind
13
+ *
14
+ * A canonical terraform address uses `[`, `]` and `"` to write an instance
15
+ * key, and AWS allows none of the three in a tag value. So an address is
16
+ * escaped before it is written, and the spec's comparison rule is one
17
+ * sentence: escape the address you already know and compare strings. The
18
+ * reverse, decoding a tag and hoping to recover the address, is ambiguous
19
+ * (`this[2]` and `this["2"]` escape alike) and the spec says not to do it
20
+ * where a verdict depends on the answer.
21
+ *
22
+ * The rule itself, from "Escaping rule":
23
+ *
24
+ * 1. escape the content of every instance key first (see
25
+ * {@link escapeForEachKey}); a `count` index is only ever digits, so
26
+ * this is a no-op for one;
27
+ * 2. replace every `[` with `:`;
28
+ * 3. delete every `]`;
29
+ * 4. delete every `"`.
30
+ *
31
+ * Step 1 first is what makes a `:` in an escaped value always mean "an index
32
+ * starts here": a key's own `.` and `:` are already gone by the time steps
33
+ * 2 to 4 run.
34
+ *
35
+ * ## Three escapings on the declared side
36
+ *
37
+ * The key escaping gained a layer twice, and neither change rewrote the
38
+ * markers already on live resources. A marker stamped before choudoufu's
39
+ * issue #178 escaped no key at all; one stamped between #178 and #210
40
+ * doubled `@`, `.` and `:` but did not carry out-of-charset characters into
41
+ * the AWS-legal set. So {@link addressMatches} escapes the declared address
42
+ * three ways and accepts any of them, which is what `AddressMatches` does in
43
+ * choudoufu itself. Writing always uses {@link escapeAddress}, the current
44
+ * form.
45
+ */
46
+
47
+ /** `tofu-estate`: the estate that owns the resource. The entire ownership claim. */
48
+ export const MARKER_TAG_ESTATE = "tofu-estate";
49
+
50
+ /** `tofu-address`: the resource's escaped canonical address, or its first 256-character chunk. */
51
+ export const MARKER_TAG_ADDRESS = "tofu-address";
52
+
53
+ /** `tofu-slot`: the stable, opaque cardinality slot a `count` instance carries. */
54
+ export const MARKER_TAG_SLOT = "tofu-slot";
55
+
56
+ /**
57
+ * `tofu-address-2` through `tofu-address-4`, in order. A reader concatenates
58
+ * `tofu-address` and whichever of these are present; they are never
59
+ * meaningful on their own.
60
+ */
61
+ export const MARKER_TAG_ADDRESS_CONTINUATIONS = [
62
+ "tofu-address-2",
63
+ "tofu-address-3",
64
+ "tofu-address-4",
65
+ ] as const;
66
+
67
+ /** The characters AWS allows in a tag value beside letters, digits and space. */
68
+ const AWS_LEGAL_PUNCTUATION = new Set(["+", "-", "=", ".", "_", ":", "/", "@"]);
69
+
70
+ /** The escape introducer of the out-of-charset layer (choudoufu issue #210). */
71
+ const INTRODUCER = "+";
72
+
73
+ function isAwsLegal(ch: string): boolean {
74
+ return /^[A-Za-z0-9 ]$/.test(ch) || AWS_LEGAL_PUNCTUATION.has(ch);
75
+ }
76
+
77
+ /**
78
+ * Carry every character outside the AWS-legal set into it: `+` doubles
79
+ * because it is the introducer, and anything else becomes `+` followed by its
80
+ * Unicode code point in six uppercase hex digits. `a(b)` becomes
81
+ * `a+000028b+000029`; `plus+one` becomes `plus++one`.
82
+ */
83
+ function escapeOutOfCharset(key: string): string {
84
+ let out = "";
85
+ for (const ch of key) {
86
+ if (ch === INTRODUCER) out += "++";
87
+ else if (isAwsLegal(ch)) out += ch;
88
+ else out += INTRODUCER + ch.codePointAt(0)!.toString(16).toUpperCase().padStart(6, "0");
89
+ }
90
+ return out;
91
+ }
92
+
93
+ /**
94
+ * The `@` / `.` / `:` doubling (choudoufu issue #178), applied in that order
95
+ * so every `@` these steps introduce is never itself doubled again: `@`
96
+ * becomes `@@`, then `.` becomes `@d`, then `:` becomes `@c`.
97
+ */
98
+ function escapeReservedPunctuation(key: string): string {
99
+ let out = "";
100
+ for (const ch of key) {
101
+ if (ch === "@") out += "@@";
102
+ else if (ch === ".") out += "@d";
103
+ else if (ch === ":") out += "@c";
104
+ else out += ch;
105
+ }
106
+ return out;
107
+ }
108
+
109
+ /**
110
+ * Escape one `for_each` instance key, both layers in the specified order:
111
+ * out-of-charset escaping first, then the `@` / `.` / `:` doubling over its
112
+ * output. Order is load-bearing: the first layer's introducer is `+`, none of
113
+ * the three characters the second layer scans for, so the second never
114
+ * mistakes the first's output for its own escape sequences.
115
+ *
116
+ * Six characters cannot be carried at all and are refused at choudoufu's own
117
+ * lint rather than here (`"`, `\`, any non-printable, `$`, `%`, `[`, `]`);
118
+ * this function escapes what it is given without judging it, because chant
119
+ * never writes a marker, and a key chant meets in a `tofu-address` tag has
120
+ * already passed that lint.
121
+ */
122
+ export function escapeForEachKey(key: string): string {
123
+ return escapeReservedPunctuation(escapeOutOfCharset(key));
124
+ }
125
+
126
+ /** The pre-#210 key escaping: the doubling alone, with no out-of-charset layer. */
127
+ function escapeForEachKeyPre210(key: string): string {
128
+ return escapeReservedPunctuation(key);
129
+ }
130
+
131
+ /**
132
+ * Apply `escapeKey` to the content of every quoted instance key in `address`,
133
+ * then run the address-level substitution: `[` to `:`, `]` and `"` deleted.
134
+ */
135
+ function escapeAddressWith(address: string, escapeKey: (key: string) => string): string {
136
+ // Only a quoted key carries content that needs escaping; a `count` index is
137
+ // digits, which every layer leaves alone.
138
+ const keysEscaped = address.replace(/\["((?:[^"\\]|\\.)*)"\]/g, (_all, key: string) => `["${escapeKey(key)}"]`);
139
+ return keysEscaped.replace(/\[/g, ":").replace(/\]/g, "").replace(/"/g, "");
140
+ }
141
+
142
+ /**
143
+ * The `tofu-address` value for a canonical terraform address: the current
144
+ * escaping, which is the only one anything ever writes.
145
+ */
146
+ export function escapeAddress(address: string): string {
147
+ return escapeAddressWith(address, escapeForEachKey);
148
+ }
149
+
150
+ /**
151
+ * Every escaping a live marker could have been written under, current first:
152
+ * the current one, the pre-#210 one (the doubling alone), and the pre-#178
153
+ * one (no key escaping at all). Duplicates are collapsed, so the common
154
+ * address with no `for_each` key yields exactly one string.
155
+ */
156
+ export function escapeAddressVariants(address: string): string[] {
157
+ const variants = [
158
+ escapeAddress(address),
159
+ escapeAddressWith(address, escapeForEachKeyPre210),
160
+ escapeAddressWith(address, (key) => key),
161
+ ];
162
+ return [...new Set(variants)];
163
+ }
164
+
165
+ /**
166
+ * Does a live resource's `tofu-address` value name this declared address?
167
+ * The declared side is escaped and the strings are compared, three escapings
168
+ * deep for the migration windows; the tag is never decoded.
169
+ */
170
+ export function addressMatches(declaredAddress: string, tagValue: string): boolean {
171
+ return escapeAddressVariants(declaredAddress).includes(tagValue);
172
+ }
173
+
174
+ /** What {@link readMarker} found on one live resource's tags. */
175
+ export type MarkerVerdict =
176
+ /** Carries `tofu-estate` and a readable `tofu-address`: it belongs to that estate. */
177
+ | { kind: "owned"; estate: string; address: string; slot?: string }
178
+ /** Carries neither key: outside every estate's ownership, reported and never auto-deleted. */
179
+ | { kind: "foreign" }
180
+ /**
181
+ * Carries `tofu-estate` but no readable `tofu-address`: missing, empty, or
182
+ * a continuation chain with a gap in it. A named error, never guessed at
183
+ * and never read as either "belongs to no one" or "close enough".
184
+ */
185
+ | { kind: "malformed"; estate: string; detail: string };
186
+
187
+ /**
188
+ * Concatenate `tofu-address` and whatever continuation tags follow it, which
189
+ * is the only sanctioned way to read a split address.
190
+ *
191
+ * A chain with a gap in it (`tofu-address-3` present while `tofu-address-2`
192
+ * is not) cannot be concatenated into anything and returns `undefined` rather
193
+ * than the address up to the gap.
194
+ */
195
+ export function joinMarkerAddress(tags: Record<string, string | undefined>): string | undefined {
196
+ const head = tags[MARKER_TAG_ADDRESS];
197
+ if (head === undefined || head === "") return undefined;
198
+
199
+ let address = head;
200
+ let ended = false;
201
+ for (const key of MARKER_TAG_ADDRESS_CONTINUATIONS) {
202
+ const chunk = tags[key];
203
+ if (chunk === undefined || chunk === "") {
204
+ ended = true;
205
+ continue;
206
+ }
207
+ if (ended) return undefined; // a gap: the chain is malformed, not shorter
208
+ address += chunk;
209
+ }
210
+ return address;
211
+ }
212
+
213
+ /**
214
+ * The ownership verdict `live/MARKERS.md`'s "Ownership semantics" section
215
+ * defines, read off one live resource's tags. Three outcomes, and no fourth:
216
+ * a `tofu-estate` value is the entire ownership claim with no secondary
217
+ * check, neither key present is foreign, and an estate without a readable
218
+ * address is malformed rather than either of the two.
219
+ */
220
+ export function readMarker(tags: Record<string, string | undefined> | undefined): MarkerVerdict {
221
+ const estate = tags?.[MARKER_TAG_ESTATE];
222
+ if (estate === undefined || estate === "") return { kind: "foreign" };
223
+
224
+ const address = joinMarkerAddress(tags!);
225
+ if (address === undefined) {
226
+ return {
227
+ kind: "malformed",
228
+ estate,
229
+ detail: `carries ${MARKER_TAG_ESTATE}=${estate} but no readable ${MARKER_TAG_ADDRESS} (missing, empty, or a continuation chain with a gap in it)`,
230
+ };
231
+ }
232
+
233
+ const slot = tags![MARKER_TAG_SLOT];
234
+ return { kind: "owned", estate, address, ...(slot ? { slot } : {}) };
235
+ }
@@ -0,0 +1,69 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import { blocksToEntities, type TerraformEntity } from "./parse";
3
+
4
+ describe("blocksToEntities: suppression attachment (chant #2111)", () => {
5
+ test("attaches the block's start line even with no suppression comment", async () => {
6
+ const entities = await blocksToEntities(
7
+ [{ name: "main.tf", source: `terraform {\n required_version = ">= 1.5.0"\n}\n` }],
8
+ "app",
9
+ );
10
+ const e = entities.get("app/terraform") as TerraformEntity;
11
+ expect(e.props.line).toBe(1);
12
+ expect(e.suppressions).toBeUndefined();
13
+ });
14
+
15
+ test("a chant-ignore-block comment attaches to the block it precedes", async () => {
16
+ const source = `# chant-ignore-block: TF001\nterraform {\n}\n`;
17
+ const entities = await blocksToEntities([{ name: "main.tf", source }], "app");
18
+ const e = entities.get("app/terraform") as TerraformEntity;
19
+ expect(e.suppressions).toHaveLength(1);
20
+ expect(e.suppressions?.[0].form).toBe("chant-ignore-block");
21
+ expect(e.suppressions?.[0].ids).toEqual(new Set(["TF001"]));
22
+ });
23
+
24
+ test("a chant-ignore comment attaches identically to a resource block", async () => {
25
+ const source = `# chant-ignore: TF999\nresource "null_resource" "x" {\n}\n`;
26
+ const entities = await blocksToEntities([{ name: "main.tf", source }], "app");
27
+ const e = entities.get("app/null_resource.x") as TerraformEntity;
28
+ expect(e.suppressions?.[0].form).toBe("chant-ignore");
29
+ expect(e.suppressions?.[0].ids).toEqual(new Set(["TF999"]));
30
+ });
31
+
32
+ test("a chant-ignore-file directive attaches to every entity in the file", async () => {
33
+ const source = [
34
+ "# chant-ignore-file: TF999",
35
+ "terraform {",
36
+ "}",
37
+ "",
38
+ 'resource "null_resource" "x" {',
39
+ "}",
40
+ ].join("\n");
41
+ const entities = await blocksToEntities([{ name: "main.tf", source }], "app");
42
+ const tf = entities.get("app/terraform") as TerraformEntity;
43
+ const res = entities.get("app/null_resource.x") as TerraformEntity;
44
+ expect(tf.suppressions?.some((d) => d.form === "chant-ignore-file")).toBe(true);
45
+ expect(res.suppressions?.some((d) => d.form === "chant-ignore-file")).toBe(true);
46
+ });
47
+
48
+ test("a misplaced chant-ignore-file is still attached, marked misplaced", async () => {
49
+ const source = ["# a header comment", "# chant-ignore-file: TF999", 'variable "x" {', " type = string", "}"].join("\n");
50
+ const entities = await blocksToEntities([{ name: "main.tf", source }], "app");
51
+ const e = entities.get("app/var.x") as TerraformEntity;
52
+ const fileDirective = e.suppressions?.find((d) => d.form === "chant-ignore-file");
53
+ expect(fileDirective?.misplaced).toBe(true);
54
+ });
55
+
56
+ test("two blocks sharing an address across files each get their own line and directive", async () => {
57
+ const files = [
58
+ { name: "a.tf", source: `# chant-ignore: TF010\nlocals {\n a = 1\n}\n` },
59
+ { name: "b.tf", source: `locals {\n b = 2\n}\n` },
60
+ ];
61
+ const entities = await blocksToEntities(files, "app");
62
+ const first = entities.get("app/locals") as TerraformEntity;
63
+ const second = entities.get("app/locals~2") as TerraformEntity;
64
+ expect(first.props.line).toBe(2);
65
+ expect(first.suppressions).toHaveLength(1);
66
+ expect(second.props.line).toBe(1);
67
+ expect(second.suppressions).toBeUndefined();
68
+ });
69
+ });