@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.
- package/README.md +9 -0
- package/dist/composites/terraform-adopt-op.d.ts +131 -0
- package/dist/composites/terraform-adopt-op.d.ts.map +1 -0
- package/dist/composites/terraform-apply-op.d.ts +70 -17
- package/dist/composites/terraform-apply-op.d.ts.map +1 -1
- package/dist/composites/terraform-watch-op.d.ts +104 -37
- package/dist/composites/terraform-watch-op.d.ts.map +1 -1
- package/dist/config.d.ts +49 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/describe-resources.d.ts +256 -16
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/hcl/descend.d.ts +98 -0
- package/dist/hcl/descend.d.ts.map +1 -0
- package/dist/hcl/marker.d.ts +130 -0
- package/dist/hcl/marker.d.ts.map +1 -0
- package/dist/hcl/parse.d.ts +156 -9
- package/dist/hcl/parse.d.ts.map +1 -1
- package/dist/hcl/references.d.ts +76 -0
- package/dist/hcl/references.d.ts.map +1 -0
- package/dist/hcl/roots.d.ts +22 -3
- package/dist/hcl/roots.d.ts.map +1 -1
- package/dist/hcl/suppressions.d.ts +54 -0
- package/dist/hcl/suppressions.d.ts.map +1 -0
- package/dist/hcl/value.d.ts +77 -0
- package/dist/hcl/value.d.ts.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +34 -5
- package/dist/lint/audit-catalog.d.ts +3 -2
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/audit-lineage.d.ts +95 -0
- package/dist/lint/audit-lineage.d.ts.map +1 -1
- package/dist/lint/post-synth/blocks.d.ts +53 -0
- package/dist/lint/post-synth/blocks.d.ts.map +1 -0
- package/dist/lint/post-synth/fixtures/load.d.ts +37 -0
- package/dist/lint/post-synth/fixtures/load.d.ts.map +1 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/module-source.d.ts +38 -0
- package/dist/lint/post-synth/module-source.d.ts.map +1 -0
- package/dist/lint/post-synth/scope.d.ts +65 -0
- package/dist/lint/post-synth/scope.d.ts.map +1 -0
- package/dist/lint/post-synth/tf001.d.ts +58 -6
- package/dist/lint/post-synth/tf001.d.ts.map +1 -1
- package/dist/lint/post-synth/tf002.d.ts +32 -0
- package/dist/lint/post-synth/tf002.d.ts.map +1 -0
- package/dist/lint/post-synth/tf003.d.ts +22 -0
- package/dist/lint/post-synth/tf003.d.ts.map +1 -0
- package/dist/lint/post-synth/tf004.d.ts +22 -0
- package/dist/lint/post-synth/tf004.d.ts.map +1 -0
- package/dist/lint/post-synth/tf005.d.ts +28 -0
- package/dist/lint/post-synth/tf005.d.ts.map +1 -0
- package/dist/lint/post-synth/tf006.d.ts +21 -0
- package/dist/lint/post-synth/tf006.d.ts.map +1 -0
- package/dist/lint/post-synth/tf007.d.ts +21 -0
- package/dist/lint/post-synth/tf007.d.ts.map +1 -0
- package/dist/lint/post-synth/tf008.d.ts +22 -0
- package/dist/lint/post-synth/tf008.d.ts.map +1 -0
- package/dist/lint/post-synth/tf009.d.ts +24 -0
- package/dist/lint/post-synth/tf009.d.ts.map +1 -0
- package/dist/lint/post-synth/tf010.d.ts +19 -0
- package/dist/lint/post-synth/tf010.d.ts.map +1 -0
- package/dist/lint/post-synth/tf011.d.ts +18 -0
- package/dist/lint/post-synth/tf011.d.ts.map +1 -0
- package/dist/lint/post-synth/tf012.d.ts +17 -0
- package/dist/lint/post-synth/tf012.d.ts.map +1 -0
- package/dist/lint/post-synth/tf013.d.ts +21 -0
- package/dist/lint/post-synth/tf013.d.ts.map +1 -0
- package/dist/lint/post-synth/tf014.d.ts +25 -0
- package/dist/lint/post-synth/tf014.d.ts.map +1 -0
- package/dist/lint/post-synth/tf015.d.ts +30 -0
- package/dist/lint/post-synth/tf015.d.ts.map +1 -0
- package/dist/lint/post-synth/tf016.d.ts +30 -0
- package/dist/lint/post-synth/tf016.d.ts.map +1 -0
- package/dist/lint/post-synth/tf017.d.ts +19 -0
- package/dist/lint/post-synth/tf017.d.ts.map +1 -0
- package/dist/lint/post-synth/tf018.d.ts +20 -0
- package/dist/lint/post-synth/tf018.d.ts.map +1 -0
- package/dist/lint/post-synth/tf019.d.ts +25 -0
- package/dist/lint/post-synth/tf019.d.ts.map +1 -0
- package/dist/lint/post-synth/tf020.d.ts +38 -0
- package/dist/lint/post-synth/tf020.d.ts.map +1 -0
- package/dist/lint/post-synth/tf021.d.ts +41 -0
- package/dist/lint/post-synth/tf021.d.ts.map +1 -0
- package/dist/lint/post-synth/tf022.d.ts +24 -0
- package/dist/lint/post-synth/tf022.d.ts.map +1 -0
- package/dist/lint/post-synth/tf024.d.ts +24 -0
- package/dist/lint/post-synth/tf024.d.ts.map +1 -0
- package/dist/lint/post-synth/tf025.d.ts +29 -0
- package/dist/lint/post-synth/tf025.d.ts.map +1 -0
- package/dist/lint/post-synth/tf026.d.ts +28 -0
- package/dist/lint/post-synth/tf026.d.ts.map +1 -0
- package/dist/lint/post-synth/tf027.d.ts +30 -0
- package/dist/lint/post-synth/tf027.d.ts.map +1 -0
- package/dist/lint/post-synth/tf028.d.ts +33 -0
- package/dist/lint/post-synth/tf028.d.ts.map +1 -0
- package/dist/lint/rules/fixtures/load.d.ts +13 -0
- package/dist/lint/rules/fixtures/load.d.ts.map +1 -0
- package/dist/lint/rules/plan-before-apply.d.ts +11 -0
- package/dist/lint/rules/plan-before-apply.d.ts.map +1 -1
- package/dist/lint/secret-shape.d.ts +68 -0
- package/dist/lint/secret-shape.d.ts.map +1 -0
- package/dist/live-ownership.d.ts +55 -0
- package/dist/live-ownership.d.ts.map +1 -0
- package/dist/lsp/option-keys.d.ts.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/okf/index.md +26 -0
- package/dist/okf/rules/TF002.md +11 -0
- package/dist/okf/rules/TF003.md +11 -0
- package/dist/okf/rules/TF004.md +11 -0
- package/dist/okf/rules/TF005.md +11 -0
- package/dist/okf/rules/TF006.md +11 -0
- package/dist/okf/rules/TF007.md +11 -0
- package/dist/okf/rules/TF008.md +11 -0
- package/dist/okf/rules/TF009.md +11 -0
- package/dist/okf/rules/TF010.md +11 -0
- package/dist/okf/rules/TF011.md +11 -0
- package/dist/okf/rules/TF012.md +11 -0
- package/dist/okf/rules/TF013.md +11 -0
- package/dist/okf/rules/TF014.md +11 -0
- package/dist/okf/rules/TF015.md +11 -0
- package/dist/okf/rules/TF016.md +11 -0
- package/dist/okf/rules/TF017.md +11 -0
- package/dist/okf/rules/TF018.md +11 -0
- package/dist/okf/rules/TF019.md +11 -0
- package/dist/okf/rules/TF020.md +11 -0
- package/dist/okf/rules/TF021.md +11 -0
- package/dist/okf/rules/TF022.md +11 -0
- package/dist/okf/rules/TF024.md +11 -0
- package/dist/okf/rules/TF025.md +11 -0
- package/dist/okf/rules/TF026.md +11 -0
- package/dist/okf/rules/TF027.md +11 -0
- package/dist/okf/rules/TF028.md +11 -0
- package/dist/op/activities/index.d.ts +13 -6
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/live-detect.d.ts +51 -0
- package/dist/op/activities/live-detect.d.ts.map +1 -0
- package/dist/op/activities/terraform.d.ts +466 -17
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/activity-contracts.d.ts +148 -0
- package/dist/op/activity-contracts.d.ts.map +1 -0
- package/dist/op/adoption.d.ts +118 -0
- package/dist/op/adoption.d.ts.map +1 -0
- package/dist/op/builders.d.ts +48 -6
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/resolve-root-mode.d.ts +59 -0
- package/dist/op/resolve-root-mode.d.ts.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/rules/blocks.ts +109 -0
- package/dist/rules/module-source.ts +121 -0
- package/dist/rules/plan-before-apply.ts +11 -0
- package/dist/rules/scope.ts +107 -0
- package/dist/rules/tf001.ts +98 -18
- package/dist/rules/tf002.ts +151 -0
- package/dist/rules/tf003.ts +71 -0
- package/dist/rules/tf004.ts +63 -0
- package/dist/rules/tf005.ts +76 -0
- package/dist/rules/tf006.ts +53 -0
- package/dist/rules/tf007.ts +78 -0
- package/dist/rules/tf008.ts +75 -0
- package/dist/rules/tf009.ts +59 -0
- package/dist/rules/tf010.ts +51 -0
- package/dist/rules/tf011.ts +49 -0
- package/dist/rules/tf012.ts +47 -0
- package/dist/rules/tf013.ts +63 -0
- package/dist/rules/tf014.ts +72 -0
- package/dist/rules/tf015.ts +72 -0
- package/dist/rules/tf016.ts +75 -0
- package/dist/rules/tf017.ts +50 -0
- package/dist/rules/tf018.ts +72 -0
- package/dist/rules/tf019.ts +72 -0
- package/dist/rules/tf020.ts +123 -0
- package/dist/rules/tf021.ts +126 -0
- package/dist/rules/tf022.ts +61 -0
- package/dist/rules/tf024.ts +70 -0
- package/dist/rules/tf025.ts +101 -0
- package/dist/rules/tf026.ts +84 -0
- package/dist/rules/tf027.ts +74 -0
- package/dist/rules/tf028.ts +96 -0
- package/dist/skills/chant-terraform.md +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/package.json +7 -2
- package/src/__fixtures__/ACCEPTANCE.md +181 -0
- package/src/__fixtures__/live/main.tf +28 -0
- package/src/__fixtures__/live-adopt/estate.chdf.hcl +6 -0
- package/src/__fixtures__/live-adopt/main.tf +21 -0
- package/src/__fixtures__/live-estate/README.md +58 -0
- package/src/__fixtures__/live-estate/compute.tf +10 -0
- package/src/__fixtures__/live-estate/estate.chdf.hcl +1 -0
- package/src/__fixtures__/live-estate/logs.tf +8 -0
- package/src/__fixtures__/live-estate/network.tf +24 -0
- package/src/__fixtures__/live-estate/rule.tf +11 -0
- package/src/__fixtures__/live-estate/unowned.tf +21 -0
- package/src/__fixtures__/live-estate/versions.tf +31 -0
- package/src/__fixtures__/live-ls.json +98 -0
- package/src/__fixtures__/live-plan.json +285 -0
- package/src/__fixtures__/live-sidecar/estate.chdf.hcl +3 -0
- package/src/__fixtures__/live-sidecar/main.tf +24 -0
- package/src/__fixtures__/module-tree/README.md +16 -0
- package/src/__fixtures__/module-tree/cycle/main.tf +3 -0
- package/src/__fixtures__/module-tree/cycle/modules/a/main.tf +9 -0
- package/src/__fixtures__/module-tree/cycle/modules/b/main.tf +9 -0
- package/src/__fixtures__/module-tree/missing/main.tf +9 -0
- package/src/__fixtures__/module-tree/outside/root/main.tf +9 -0
- package/src/__fixtures__/module-tree/root/main.tf +28 -0
- package/src/__fixtures__/module-tree/root/modules/cdn/main.tf +15 -0
- package/src/__fixtures__/module-tree/root/modules/cdn/modules/bucket/main.tf +11 -0
- package/src/__fixtures__/module-tree/shared/main.tf +5 -0
- package/src/__fixtures__/references/main.tf +56 -0
- package/src/__fixtures__/remote-backend/main.tf +34 -0
- package/src/__fixtures__/with-backend/main.tf +7 -0
- package/src/codegen/lint-rules-page.test.ts +45 -0
- package/src/composites/terraform-adopt-op.acceptance.test.ts +193 -0
- package/src/composites/terraform-adopt-op.test.ts +175 -0
- package/src/composites/terraform-adopt-op.ts +202 -0
- package/src/composites/terraform-apply-op.acceptance.test.ts +188 -5
- package/src/composites/terraform-apply-op.test.ts +179 -19
- package/src/composites/terraform-apply-op.ts +123 -30
- package/src/composites/terraform-watch-op.test.ts +169 -29
- package/src/composites/terraform-watch-op.ts +183 -75
- package/src/config.ts +32 -3
- package/src/describe-resources.live.test.ts +598 -0
- package/src/describe-resources.test.ts +53 -0
- package/src/describe-resources.ts +811 -28
- package/src/hcl/descend.test.ts +162 -0
- package/src/hcl/descend.ts +273 -0
- package/src/hcl/marker.test.ts +147 -0
- package/src/hcl/marker.ts +235 -0
- package/src/hcl/parse.test.ts +69 -0
- package/src/hcl/parse.ts +269 -27
- package/src/hcl/references.test.ts +116 -0
- package/src/hcl/references.ts +172 -0
- package/src/hcl/roots.ts +59 -5
- package/src/hcl/suppressions.test.ts +147 -0
- package/src/hcl/suppressions.ts +204 -0
- package/src/hcl/value.test.ts +73 -0
- package/src/hcl/value.ts +106 -0
- package/src/index.ts +31 -1
- package/src/lint/audit-catalog.ts +288 -3
- package/src/lint/audit-lineage.ts +384 -1
- package/src/lint/audit.test.ts +210 -3
- package/src/lint/post-synth/blocks.ts +109 -0
- package/src/lint/post-synth/fixtures/TF001/negative-cloud.tf +28 -0
- package/src/lint/post-synth/fixtures/TF001/negative.tf +30 -0
- package/src/lint/post-synth/fixtures/TF001/positive-local.tf +31 -0
- package/src/lint/post-synth/fixtures/TF001/positive.tf +24 -0
- package/src/lint/post-synth/fixtures/TF002/negative.tf +17 -0
- package/src/lint/post-synth/fixtures/TF002/positive-legacy.tf +10 -0
- package/src/lint/post-synth/fixtures/TF002/positive-no-version.tf +12 -0
- package/src/lint/post-synth/fixtures/TF002/positive.tf +7 -0
- package/src/lint/post-synth/fixtures/TF003/negative.tf +10 -0
- package/src/lint/post-synth/fixtures/TF003/positive.tf +8 -0
- package/src/lint/post-synth/fixtures/TF004/negative-git.tf +3 -0
- package/src/lint/post-synth/fixtures/TF004/negative-local.tf +3 -0
- package/src/lint/post-synth/fixtures/TF004/negative.tf +4 -0
- package/src/lint/post-synth/fixtures/TF004/positive.tf +3 -0
- package/src/lint/post-synth/fixtures/TF005/negative-local.tf +3 -0
- package/src/lint/post-synth/fixtures/TF005/negative-registry.tf +3 -0
- package/src/lint/post-synth/fixtures/TF005/negative-sha.tf +3 -0
- package/src/lint/post-synth/fixtures/TF005/negative.tf +3 -0
- package/src/lint/post-synth/fixtures/TF005/positive-branch.tf +3 -0
- package/src/lint/post-synth/fixtures/TF005/positive-non-semver.tf +3 -0
- package/src/lint/post-synth/fixtures/TF005/positive.tf +3 -0
- package/src/lint/post-synth/fixtures/TF006/negative.tf +5 -0
- package/src/lint/post-synth/fixtures/TF006/positive-empty-default.tf +11 -0
- package/src/lint/post-synth/fixtures/TF006/positive.tf +6 -0
- package/src/lint/post-synth/fixtures/TF007/negative.tf +10 -0
- package/src/lint/post-synth/fixtures/TF007/positive.tf +9 -0
- package/src/lint/post-synth/fixtures/TF008/negative-variable.tf +10 -0
- package/src/lint/post-synth/fixtures/TF008/negative.tf +8 -0
- package/src/lint/post-synth/fixtures/TF008/positive-other-provider.tf +10 -0
- package/src/lint/post-synth/fixtures/TF008/positive.tf +5 -0
- package/src/lint/post-synth/fixtures/TF009/negative.tf +10 -0
- package/src/lint/post-synth/fixtures/TF009/positive.tf +4 -0
- package/src/lint/post-synth/fixtures/TF010/negative.tf +5 -0
- package/src/lint/post-synth/fixtures/TF010/positive.tf +4 -0
- package/src/lint/post-synth/fixtures/TF011/negative.tf +5 -0
- package/src/lint/post-synth/fixtures/TF011/positive-blank.tf +5 -0
- package/src/lint/post-synth/fixtures/TF011/positive.tf +4 -0
- package/src/lint/post-synth/fixtures/TF012/negative.tf +4 -0
- package/src/lint/post-synth/fixtures/TF012/positive.tf +3 -0
- package/src/lint/post-synth/fixtures/TF013/negative.tf +8 -0
- package/src/lint/post-synth/fixtures/TF013/positive-data.tf +8 -0
- package/src/lint/post-synth/fixtures/TF013/positive.tf +8 -0
- package/src/lint/post-synth/fixtures/TF014/negative/main.tf +26 -0
- package/src/lint/post-synth/fixtures/TF014/negative/modules/cdn/main.tf +19 -0
- package/src/lint/post-synth/fixtures/TF014/positive/main.tf +16 -0
- package/src/lint/post-synth/fixtures/TF014/positive/modules/cdn/main.tf +15 -0
- package/src/lint/post-synth/fixtures/TF015/negative/main.tf +13 -0
- package/src/lint/post-synth/fixtures/TF015/negative/modules/cdn/main.tf +16 -0
- package/src/lint/post-synth/fixtures/TF015/positive/main.tf +13 -0
- package/src/lint/post-synth/fixtures/TF015/positive/modules/cdn/main.tf +14 -0
- package/src/lint/post-synth/fixtures/TF016/negative-template.tf +7 -0
- package/src/lint/post-synth/fixtures/TF016/negative.tf +16 -0
- package/src/lint/post-synth/fixtures/TF016/positive-shared-file.tf +12 -0
- package/src/lint/post-synth/fixtures/TF016/positive.tf +13 -0
- package/src/lint/post-synth/fixtures/TF017/negative.tf +4 -0
- package/src/lint/post-synth/fixtures/TF017/positive.tf +5 -0
- package/src/lint/post-synth/fixtures/TF018/negative.tf +9 -0
- package/src/lint/post-synth/fixtures/TF018/positive-data.tf +9 -0
- package/src/lint/post-synth/fixtures/TF018/positive.tf +4 -0
- package/src/lint/post-synth/fixtures/TF019/negative.tf +14 -0
- package/src/lint/post-synth/fixtures/TF019/positive-output.tf +5 -0
- package/src/lint/post-synth/fixtures/TF019/positive.tf +16 -0
- package/src/lint/post-synth/fixtures/TF020/negative.tf +43 -0
- package/src/lint/post-synth/fixtures/TF020/positive.tf +32 -0
- package/src/lint/post-synth/fixtures/TF020/scoped/main.tf +21 -0
- package/src/lint/post-synth/fixtures/TF020/scoped/modules/cdn/main.tf +13 -0
- package/src/lint/post-synth/fixtures/TF021/negative.tf +31 -0
- package/src/lint/post-synth/fixtures/TF021/positive-length.tf +8 -0
- package/src/lint/post-synth/fixtures/TF021/positive.tf +8 -0
- package/src/lint/post-synth/fixtures/TF022/negative-locator.tf +7 -0
- package/src/lint/post-synth/fixtures/TF022/negative.tf +10 -0
- package/src/lint/post-synth/fixtures/TF022/positive-nested.tf +10 -0
- package/src/lint/post-synth/fixtures/TF022/positive.tf +6 -0
- package/src/lint/post-synth/fixtures/TF023/negative/main.tf +15 -0
- package/src/lint/post-synth/fixtures/TF023/positive/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF023/positive/state.json +24 -0
- package/src/lint/post-synth/fixtures/TF024/live-clean/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF024/live-with-backend/main.tf +14 -0
- package/src/lint/post-synth/fixtures/TF024/live-with-cloud/main.tf +16 -0
- package/src/lint/post-synth/fixtures/TF025/live-clean/main.tf +13 -0
- package/src/lint/post-synth/fixtures/TF025/live-with-workspace-ref/main.tf +13 -0
- package/src/lint/post-synth/fixtures/TF026/live-default/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF026/live-explicit-delete/main.tf +13 -0
- package/src/lint/post-synth/fixtures/TF026/live-keep/main.tf +13 -0
- package/src/lint/post-synth/fixtures/TF027/live-default/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF027/live-untagged-delete/main.tf +13 -0
- package/src/lint/post-synth/fixtures/TF027/live-untagged-delete-scoped/main.tf +17 -0
- package/src/lint/post-synth/fixtures/TF027/live-untagged-report/main.tf +13 -0
- package/src/lint/post-synth/fixtures/TF028/live/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF028/stock/main.tf +10 -0
- package/src/lint/post-synth/fixtures/load.ts +108 -0
- package/src/lint/post-synth/index.ts +52 -0
- package/src/lint/post-synth/live-refusals-config-format.test.ts +143 -0
- package/src/lint/post-synth/module-rules.test.ts +153 -0
- package/src/lint/post-synth/module-source.test.ts +75 -0
- package/src/lint/post-synth/module-source.ts +121 -0
- package/src/lint/post-synth/post-synth.test.ts +73 -16
- package/src/lint/post-synth/scope.ts +107 -0
- package/src/lint/post-synth/single-block.test.ts +263 -0
- package/src/lint/post-synth/suppression.test.ts +110 -0
- package/src/lint/post-synth/tf001.ts +98 -18
- package/src/lint/post-synth/tf002.test.ts +93 -0
- package/src/lint/post-synth/tf002.ts +151 -0
- package/src/lint/post-synth/tf003.test.ts +75 -0
- package/src/lint/post-synth/tf003.ts +71 -0
- package/src/lint/post-synth/tf004.test.ts +47 -0
- package/src/lint/post-synth/tf004.ts +63 -0
- package/src/lint/post-synth/tf005.test.ts +57 -0
- package/src/lint/post-synth/tf005.ts +76 -0
- package/src/lint/post-synth/tf006.ts +53 -0
- package/src/lint/post-synth/tf007.ts +78 -0
- package/src/lint/post-synth/tf008.ts +75 -0
- package/src/lint/post-synth/tf009.ts +59 -0
- package/src/lint/post-synth/tf010.ts +51 -0
- package/src/lint/post-synth/tf011.ts +49 -0
- package/src/lint/post-synth/tf012.ts +47 -0
- package/src/lint/post-synth/tf013.ts +63 -0
- package/src/lint/post-synth/tf014.ts +72 -0
- package/src/lint/post-synth/tf015.ts +72 -0
- package/src/lint/post-synth/tf016.ts +75 -0
- package/src/lint/post-synth/tf017.ts +50 -0
- package/src/lint/post-synth/tf018.ts +72 -0
- package/src/lint/post-synth/tf019.ts +72 -0
- package/src/lint/post-synth/tf020.ts +123 -0
- package/src/lint/post-synth/tf021.ts +126 -0
- package/src/lint/post-synth/tf022.ts +61 -0
- package/src/lint/post-synth/tf024.test.ts +42 -0
- package/src/lint/post-synth/tf024.ts +70 -0
- package/src/lint/post-synth/tf025.test.ts +46 -0
- package/src/lint/post-synth/tf025.ts +101 -0
- package/src/lint/post-synth/tf026.test.ts +56 -0
- package/src/lint/post-synth/tf026.ts +84 -0
- package/src/lint/post-synth/tf027.test.ts +62 -0
- package/src/lint/post-synth/tf027.ts +74 -0
- package/src/lint/post-synth/tf028.test.ts +92 -0
- package/src/lint/post-synth/tf028.ts +96 -0
- package/src/lint/presets.test.ts +72 -0
- package/src/lint/rules/fixtures/TF101/negative-op.ts +2 -0
- package/src/lint/rules/fixtures/TF101/positive-op.ts +2 -0
- package/src/lint/rules/fixtures/load.ts +53 -0
- package/src/lint/rules/plan-before-apply.test.ts +112 -7
- package/src/lint/rules/plan-before-apply.ts +11 -0
- package/src/lint/secret-shape.test.ts +150 -0
- package/src/lint/secret-shape.ts +159 -0
- package/src/live-ownership.ts +60 -0
- package/src/lsp/completions.test.ts +3 -2
- package/src/lsp/option-keys.ts +12 -6
- package/src/op/activities/choudoufu.acceptance.test.ts +127 -0
- package/src/op/activities/choudoufu.test.ts +725 -0
- package/src/op/activities/index.ts +40 -4
- package/src/op/activities/live-detect.test.ts +143 -0
- package/src/op/activities/live-detect.ts +162 -0
- package/src/op/activities/registry.test.ts +11 -3
- package/src/op/activities/terraform.test.ts +7 -3
- package/src/op/activities/terraform.ts +861 -69
- package/src/op/activity-contracts.test.ts +147 -0
- package/src/op/activity-contracts.ts +178 -0
- package/src/op/adoption.test.ts +170 -0
- package/src/op/adoption.ts +241 -0
- package/src/op/builders.test.ts +60 -5
- package/src/op/builders.ts +95 -5
- package/src/op/resolve-root-mode.test.ts +85 -0
- package/src/op/resolve-root-mode.ts +86 -0
- package/src/plugin.test.ts +106 -0
- package/src/plugin.ts +186 -29
- package/src/skills/chant-terraform.md +1 -1
- package/src/validate.ts +10 -1
package/src/plugin.test.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { terraformPlugin } from "./plugin";
|
|
|
9
9
|
import { terraformConfigSchema } from "./config";
|
|
10
10
|
import {
|
|
11
11
|
DATA_TYPE,
|
|
12
|
+
LIVE_TYPE,
|
|
12
13
|
PROVIDER_TYPE,
|
|
13
14
|
RESOURCE_TYPE,
|
|
14
15
|
TERRAFORM_TYPE,
|
|
@@ -57,6 +58,12 @@ describe("terraform plugin", () => {
|
|
|
57
58
|
expect(terraformPlugin.postSynthChecks?.().length).toBeGreaterThan(0);
|
|
58
59
|
});
|
|
59
60
|
|
|
61
|
+
it("registers the estate-wide reads a live root makes possible (#2104)", () => {
|
|
62
|
+
expect(terraformPlugin.ambientKinds?.()).toEqual(["Terraform::Resource"]);
|
|
63
|
+
expect(typeof terraformPlugin.observeAmbient).toBe("function");
|
|
64
|
+
expect(typeof terraformPlugin.teardownOwned).toBe("function");
|
|
65
|
+
});
|
|
66
|
+
|
|
60
67
|
it("registers the LSP providers and docs", () => {
|
|
61
68
|
expect(typeof terraformPlugin.completionProvider).toBe("function");
|
|
62
69
|
expect(typeof terraformPlugin.hoverProvider).toBe("function");
|
|
@@ -227,6 +234,67 @@ describe("buildRoots", () => {
|
|
|
227
234
|
});
|
|
228
235
|
});
|
|
229
236
|
|
|
237
|
+
describe("buildRoots: choudoufu live mode (#2103)", () => {
|
|
238
|
+
it("marks every entity live and carries the estate, under binary: choudoufu", async () => {
|
|
239
|
+
const { entities, warnings } = await buildRoots(fixtures, {
|
|
240
|
+
terraform: { binary: "choudoufu", roots: { estate: { dir: "./live" } } },
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
expect(warnings ?? []).toEqual([]);
|
|
244
|
+
expect([...entities.keys()].sort()).toEqual([
|
|
245
|
+
"estate/live",
|
|
246
|
+
"estate/null_resource.first",
|
|
247
|
+
"estate/null_resource.second",
|
|
248
|
+
"estate/provider.null",
|
|
249
|
+
"estate/terraform",
|
|
250
|
+
]);
|
|
251
|
+
|
|
252
|
+
const live = entities.get("estate/live")!;
|
|
253
|
+
expect(live.entityType).toBe(LIVE_TYPE);
|
|
254
|
+
for (const key of entities.keys()) {
|
|
255
|
+
const props = propsOf(entities.get(key));
|
|
256
|
+
expect(props.mode).toBe("live");
|
|
257
|
+
expect(props.estate).toBe("fixture-estate");
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("reads the estate from the estate.chdf.hcl sidecar the same way", async () => {
|
|
262
|
+
const { entities, warnings } = await buildRoots(fixtures, {
|
|
263
|
+
terraform: { binary: "choudoufu", roots: { estate: { dir: "./live-sidecar" } } },
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
expect(warnings ?? []).toEqual([]);
|
|
267
|
+
const live = entities.get("estate/live")!;
|
|
268
|
+
expect(live.entityType).toBe(LIVE_TYPE);
|
|
269
|
+
expect(propsOf(live).file).toBe("estate.chdf.hcl");
|
|
270
|
+
expect(propsOf(entities.get("estate/terraform")).estate).toBe("fixture-estate");
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("stays state mode and warns when the estate is declared but the binary is not choudoufu", async () => {
|
|
274
|
+
const { entities, warnings } = await buildRoots(fixtures, {
|
|
275
|
+
terraform: { roots: { estate: { dir: "./live" } } },
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
for (const key of entities.keys()) {
|
|
279
|
+
const props = propsOf(entities.get(key));
|
|
280
|
+
expect(props.mode).toBe("state");
|
|
281
|
+
expect(props.estate).toBeUndefined();
|
|
282
|
+
}
|
|
283
|
+
expect(warnings).toHaveLength(1);
|
|
284
|
+
expect(warnings![0]).toContain("terraform.roots.estate");
|
|
285
|
+
expect(warnings![0]).toContain("inert");
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it("stays state mode with no live declaration at all, regardless of binary", async () => {
|
|
289
|
+
const { entities, warnings } = await buildRoots(fixtures, {
|
|
290
|
+
terraform: { binary: "choudoufu", roots: { app: { dir: "./with-backend" } } },
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
expect(warnings ?? []).toEqual([]);
|
|
294
|
+
expect(propsOf(entities.get("app/terraform")).mode).toBe("state");
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
230
298
|
describe("auditEntities (#2085, parse-to-graph for chant audit)", () => {
|
|
231
299
|
it("parses a joined `# file:` bundle into entities", async () => {
|
|
232
300
|
const hook = terraformPlugin.auditEntities;
|
|
@@ -269,3 +337,41 @@ describe("parseTerraformRootContent", () => {
|
|
|
269
337
|
expect([...entities.keys()]).toEqual(["app/locals", "app/locals~2"]);
|
|
270
338
|
});
|
|
271
339
|
});
|
|
340
|
+
|
|
341
|
+
describe("detectTemplate", () => {
|
|
342
|
+
const detect = (data: unknown) => terraformPlugin.detectTemplate?.(data) ?? false;
|
|
343
|
+
|
|
344
|
+
it("recognises .tf text by its top-level block headers", () => {
|
|
345
|
+
expect(detect('terraform {\n required_version = ">= 1.5.0"\n}')).toBe(true);
|
|
346
|
+
expect(detect('resource "null_resource" "first" {}')).toBe(true);
|
|
347
|
+
expect(detect('data "aws_ami" "ubuntu" {\n most_recent = true\n}')).toBe(true);
|
|
348
|
+
expect(detect('provider "aws" {\n region = "us-east-1"\n}')).toBe(true);
|
|
349
|
+
expect(detect('module "vpc" {\n source = "./modules/vpc"\n}')).toBe(true);
|
|
350
|
+
expect(detect('variable "region" {\n type = string\n}')).toBe(true);
|
|
351
|
+
expect(detect('output "id" {\n value = null_resource.first.id\n}')).toBe(true);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("recognises the .tf.json syntax by its whole key set", () => {
|
|
355
|
+
expect(detect({ resource: { null_resource: { first: {} } } })).toBe(true);
|
|
356
|
+
expect(detect({ terraform: { required_version: ">= 1.5.0" }, provider: { aws: {} } })).toBe(true);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it("refuses another lexicon's document, and anything with no block at all", () => {
|
|
360
|
+
// k8s / fountain / gcp, which share the apiVersion+kind shape.
|
|
361
|
+
expect(detect({ apiVersion: "v1", kind: "ConfigMap", data: {} })).toBe(false);
|
|
362
|
+
// CloudFormation, whose `Resources` is not one of Terraform's block names.
|
|
363
|
+
expect(detect({ AWSTemplateFormatVersion: "2010-09-09", Resources: {} })).toBe(false);
|
|
364
|
+
// Compose.
|
|
365
|
+
expect(detect({ services: { web: { image: "nginx" } } })).toBe(false);
|
|
366
|
+
expect(detect("# just a comment\n")).toBe(false);
|
|
367
|
+
expect(detect("")).toBe(false);
|
|
368
|
+
expect(detect({})).toBe(false);
|
|
369
|
+
expect(detect(null)).toBe(false);
|
|
370
|
+
expect(detect([{ resource: {} }])).toBe(false);
|
|
371
|
+
expect(detect(42)).toBe(false);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("does not match a block header that is only mentioned mid-line", () => {
|
|
375
|
+
expect(detect('# see resource "null_resource" "first" {} in main.tf')).toBe(false);
|
|
376
|
+
});
|
|
377
|
+
});
|
package/src/plugin.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import type { LexiconPlugin } from "@intentius/chant/lexicon";
|
|
1
|
+
import type { AuditEntitiesInput, LexiconPlugin } from "@intentius/chant/lexicon";
|
|
2
2
|
import type { CompletionContext, HoverContext } from "@intentius/chant/lsp/types";
|
|
3
3
|
import type { Declarable } from "@intentius/chant/declarable";
|
|
4
4
|
import { createSkillsLoader } from "@intentius/chant/lexicon-plugin-helpers";
|
|
5
5
|
import { terraformSerializer } from "./serializer";
|
|
6
6
|
import { rules } from "./lint/rules";
|
|
7
7
|
import { postSynthChecks } from "./lint/post-synth";
|
|
8
|
+
import { withCallersChain } from "./lint/post-synth/scope";
|
|
8
9
|
import { terraformAuditCatalog } from "./lint/audit-catalog";
|
|
9
10
|
import { completions } from "./lsp/completions";
|
|
10
11
|
import { hover } from "./lsp/hover";
|
|
11
12
|
import { terraformConfigSchema, type TerraformConfig } from "./config";
|
|
12
13
|
import { renderTerraformRoots } from "./hcl/roots";
|
|
13
|
-
import { parseTerraformRootContent } from "./hcl/parse";
|
|
14
|
+
import { auditRootName, parseTerraformRootContent, RESOURCE_TYPE } from "./hcl/parse";
|
|
15
|
+
import { descendModules } from "./hcl/descend";
|
|
14
16
|
import { TERRAFORM_STATE_OWNERSHIP_KEYS } from "./state-ownership";
|
|
15
17
|
|
|
16
18
|
const loadSkills = createSkillsLoader(import.meta.url, [
|
|
@@ -22,6 +24,43 @@ const loadSkills = createSkillsLoader(import.meta.url, [
|
|
|
22
24
|
},
|
|
23
25
|
]);
|
|
24
26
|
|
|
27
|
+
/**
|
|
28
|
+
* The only top-level names Terraform's JSON syntax admits
|
|
29
|
+
* (developer.hashicorp.com/terraform/language/syntax/json). Used as a
|
|
30
|
+
* whole-document test in `detectTemplate`: a `.tf.json` file has these keys
|
|
31
|
+
* and nothing else.
|
|
32
|
+
*/
|
|
33
|
+
const TF_JSON_BLOCK_TYPES = new Set([
|
|
34
|
+
"terraform",
|
|
35
|
+
"provider",
|
|
36
|
+
"variable",
|
|
37
|
+
"output",
|
|
38
|
+
"locals",
|
|
39
|
+
"module",
|
|
40
|
+
"resource",
|
|
41
|
+
"data",
|
|
42
|
+
"moved",
|
|
43
|
+
"import",
|
|
44
|
+
"check",
|
|
45
|
+
"removed",
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Whether raw text is HCL a Terraform root or module is written in. One
|
|
50
|
+
* top-level block header is enough, and every one of these headers is
|
|
51
|
+
* Terraform's own: `terraform {`, and the labelled `resource`/`data`
|
|
52
|
+
* (two labels), `provider`/`module`/`variable`/`output` (one label). `locals`
|
|
53
|
+
* is left out on purpose, since it is the one block a non-Terraform HCL
|
|
54
|
+
* dialect is also likely to carry.
|
|
55
|
+
*/
|
|
56
|
+
function looksLikeHcl(text: string): boolean {
|
|
57
|
+
return (
|
|
58
|
+
/^[ \t]*terraform[ \t]*\{/m.test(text) ||
|
|
59
|
+
/^[ \t]*(resource|data)[ \t]+"[^"]+"[ \t]+"[^"]+"[ \t]*\{/m.test(text) ||
|
|
60
|
+
/^[ \t]*(provider|module|variable|output)[ \t]+"[^"]+"[ \t]*\{/m.test(text)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
25
64
|
/**
|
|
26
65
|
* terraform lexicon plugin.
|
|
27
66
|
*
|
|
@@ -70,11 +109,19 @@ export const terraformPlugin: LexiconPlugin = {
|
|
|
70
109
|
// ── Optional extensions ────────────────────────────────────
|
|
71
110
|
|
|
72
111
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
112
|
+
* The ownership channel is per mode, and the channel declared here names
|
|
113
|
+
* the stock one, because a project's roots are stock unless it opts into
|
|
114
|
+
* choudoufu.
|
|
115
|
+
*
|
|
116
|
+
* On a stock root the channel is the state file, not a tag or a label
|
|
117
|
+
* (#2087): every address `terraform show -json` returns is `owned` and
|
|
118
|
+
* everything else is `unknown`. On a live root (#2104) it is choudoufu's
|
|
119
|
+
* two marker tags, `./live-ownership.ts`'s `TERRAFORM_LIVE_MARKER_KEYS`,
|
|
120
|
+
* and the verdicts come from `live-plan -json`'s own sections. Both
|
|
121
|
+
* readings resolve a real verdict on this path, which is what declaring
|
|
122
|
+
* `describeResources` here claims and what the conformance suite checks,
|
|
123
|
+
* for both modes. See `./describe-resources.ts` and
|
|
124
|
+
* `docs/pages/observation.mdx`.
|
|
78
125
|
*/
|
|
79
126
|
ownershipChannel: {
|
|
80
127
|
keys: TERRAFORM_STATE_OWNERSHIP_KEYS,
|
|
@@ -86,6 +133,26 @@ export const terraformPlugin: LexiconPlugin = {
|
|
|
86
133
|
return describeResources(options);
|
|
87
134
|
},
|
|
88
135
|
|
|
136
|
+
/**
|
|
137
|
+
* The kinds a live root can enumerate beyond its declaration (#1278,
|
|
138
|
+
* #2104). Empty on a project with no live root, because `live-ls` is the
|
|
139
|
+
* only estate-wide read this lexicon has and a stock root has none: a state
|
|
140
|
+
* file knows what it created and nothing else.
|
|
141
|
+
*/
|
|
142
|
+
ambientKinds() {
|
|
143
|
+
return [RESOURCE_TYPE];
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
async observeAmbient(options) {
|
|
147
|
+
const { observeAmbient } = await import("./describe-resources");
|
|
148
|
+
return observeAmbient(options);
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
async teardownOwned(options) {
|
|
152
|
+
const { teardownOwned } = await import("./describe-resources");
|
|
153
|
+
return teardownOwned(options);
|
|
154
|
+
},
|
|
155
|
+
|
|
89
156
|
/**
|
|
90
157
|
* Each entry in `terraform.roots` is a root module directory that parses at
|
|
91
158
|
* build time into one entity per HCL block. The render lives in
|
|
@@ -93,17 +160,28 @@ export const terraformPlugin: LexiconPlugin = {
|
|
|
93
160
|
* project root, which is what relative `dir` paths resolve against.
|
|
94
161
|
*/
|
|
95
162
|
async buildRoots(ctx): Promise<{ entities: Map<string, Declarable>; warnings: string[] }> {
|
|
96
|
-
const
|
|
163
|
+
const namespace = (ctx.config as { terraform?: TerraformConfig }).terraform;
|
|
164
|
+
const roots = namespace?.roots ?? {};
|
|
97
165
|
if (Object.keys(roots).length === 0) return { entities: new Map(), warnings: [] };
|
|
98
|
-
return renderTerraformRoots({
|
|
166
|
+
return renderTerraformRoots({
|
|
167
|
+
projectRoot: ctx.projectRoot,
|
|
168
|
+
roots,
|
|
169
|
+
binary: namespace?.binary,
|
|
170
|
+
callModuleType: namespace?.callModuleType,
|
|
171
|
+
});
|
|
99
172
|
},
|
|
100
173
|
|
|
101
174
|
lintRules() {
|
|
102
175
|
return rules;
|
|
103
176
|
},
|
|
104
177
|
|
|
178
|
+
/**
|
|
179
|
+
* The generated barrel of checks, each wrapped so a finding inside a
|
|
180
|
+
* descended child module names the call chain that reached it (#2112). See
|
|
181
|
+
* `./lint/post-synth/scope.ts`.
|
|
182
|
+
*/
|
|
105
183
|
postSynthChecks() {
|
|
106
|
-
return postSynthChecks;
|
|
184
|
+
return withCallersChain(postSynthChecks);
|
|
107
185
|
},
|
|
108
186
|
|
|
109
187
|
auditCatalog() {
|
|
@@ -111,35 +189,114 @@ export const terraformPlugin: LexiconPlugin = {
|
|
|
111
189
|
},
|
|
112
190
|
|
|
113
191
|
/**
|
|
114
|
-
*
|
|
192
|
+
* `recommended`/`all` (chant #2113), the tflint-ruleset-terraform shape:
|
|
193
|
+
* `recommended` is every `merge-worthy` TF rule (a correctness/security
|
|
194
|
+
* finding worth reporting by default), `all` adds the `report-only` ones
|
|
195
|
+
* (hygiene the family grows into as #2109/#2110/#2112 land). Derived from
|
|
196
|
+
* `terraformAuditCatalog` rather than a hand-kept id list, so a rule that
|
|
197
|
+
* lands in a later, parallel issue is picked up automatically the moment
|
|
198
|
+
* its catalog entry ships, with no second list to fall out of sync.
|
|
199
|
+
*/
|
|
200
|
+
lintPresets() {
|
|
201
|
+
const ids = Object.keys(terraformAuditCatalog);
|
|
202
|
+
const recommended = ids.filter((id) => terraformAuditCatalog[id].tier === "merge-worthy");
|
|
203
|
+
return { recommended, all: ids };
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Parse-to-graph for `chant audit` (#1567, #2085, #2217). `content` is the
|
|
115
208
|
* `# file: <name>`-joined bundle discovery builds for one discovered root
|
|
116
|
-
* module (`classifyTerraform`, `packages/core/src/audit/
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
209
|
+
* module (`classifyTerraform`, `packages/core/src/audit/discover.ts`), and
|
|
210
|
+
* `input` says where that bundle came from.
|
|
211
|
+
*
|
|
212
|
+
* The scope is named after the input's path (`auditRootName`), so two roots
|
|
213
|
+
* in one repository are two roots here as well: they no longer collide in
|
|
214
|
+
* the merged entity map the all-files pass reads, which is what used to
|
|
215
|
+
* produce a finding keyed `<root>/<address>#2` against the file
|
|
216
|
+
* `(cross-file)` that neither directory deserved.
|
|
217
|
+
*
|
|
218
|
+
* When the audit walked a local filesystem, `input.dir` is the root
|
|
219
|
+
* module's directory and the parse descends its local `module` calls
|
|
220
|
+
* exactly as `buildRoots()` does, through the same `descendModules`
|
|
221
|
+
* (`../hcl/descend.ts`): a child module's entities are keyed
|
|
222
|
+
* `<root>/module.<name>/<address>` and carry the caller chain, so TF014 and
|
|
223
|
+
* TF015 fire here with the same `Callers:` line they print on a build, and
|
|
224
|
+
* the root-only rules (TF001 to TF003) still see only the root's own
|
|
225
|
+
* blocks. `input.baseDir` is the audited directory, which bounds the
|
|
226
|
+
* descent the way the project root bounds it on a build. Discovery drops a
|
|
227
|
+
* directory another one calls as a local module, so no module is audited
|
|
228
|
+
* twice.
|
|
229
|
+
*
|
|
230
|
+
* With no `input.dir` (a fetched repository; a caller parsing a bare
|
|
231
|
+
* string) the bundle is parsed alone, and the two child-module rules have
|
|
232
|
+
* no child to report on, since nothing named one.
|
|
233
|
+
*
|
|
234
|
+
* The descent's own refusals (a registry source, a source outside the
|
|
235
|
+
* audited tree, a cycle) are warnings on a build; this hook returns
|
|
236
|
+
* entities only, so on the audit path they are dropped rather than printed.
|
|
237
|
+
*
|
|
238
|
+
* Never throws: malformed HCL yields an empty map.
|
|
122
239
|
*/
|
|
123
|
-
async auditEntities(content: string): Promise<Map<string, Declarable>> {
|
|
240
|
+
async auditEntities(content: string, input?: AuditEntitiesInput): Promise<Map<string, Declarable>> {
|
|
124
241
|
try {
|
|
125
|
-
|
|
242
|
+
const root = auditRootName(input?.path);
|
|
243
|
+
const entities = await parseTerraformRootContent(content, root);
|
|
244
|
+
if (input?.dir === undefined) return entities;
|
|
245
|
+
const { entities: children } = await descendModules(entities, {
|
|
246
|
+
dir: input.dir,
|
|
247
|
+
root,
|
|
248
|
+
projectRoot: input.baseDir ?? input.dir,
|
|
249
|
+
});
|
|
250
|
+
for (const [key, entity] of children) entities.set(key, entity);
|
|
251
|
+
return entities;
|
|
126
252
|
} catch {
|
|
127
253
|
return new Map();
|
|
128
254
|
}
|
|
129
255
|
},
|
|
130
256
|
|
|
257
|
+
/**
|
|
258
|
+
* No `mcpTools()` and no `mcpResources()`, deliberately (#2220). Both were
|
|
259
|
+
* declared returning `[]` behind a TODO, which passed the two tier-2
|
|
260
|
+
* "registers <method>" checks on a member that contributed nothing. Neither
|
|
261
|
+
* of the two shapes every other lexicon uses has anything to serve here:
|
|
262
|
+
* `createDiffTool` diffs one build's serializer output against the last,
|
|
263
|
+
* and this serializer writes nothing (`src/serializer.ts` is a deliberate
|
|
264
|
+
* no-op, the `.tf` files are the artifact); `createCatalogResource` serves
|
|
265
|
+
* the generated resource registry, and this lexicon generates none
|
|
266
|
+
* (`src/codegen/generate.ts` writes `{}` on purpose). So the members are
|
|
267
|
+
* removed rather than faked, and `chant dev check-lexicon` reports two
|
|
268
|
+
* tier-2 gaps that are real.
|
|
269
|
+
*/
|
|
131
270
|
skills: loadSkills,
|
|
132
271
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
272
|
+
/**
|
|
273
|
+
* `.tf` (and Terraform's own JSON syntax, `.tf.json`) recognised by content
|
|
274
|
+
* rather than by which directory a file sits in (#2220).
|
|
275
|
+
*
|
|
276
|
+
* Two input shapes, because the two callers hand over different things.
|
|
277
|
+
* `chant import` (`packages/core/src/cli/commands/import.ts`) `JSON.parse`s
|
|
278
|
+
* the file first, so it arrives as an object; the audit's content detection
|
|
279
|
+
* (`packages/core/src/audit/discover.ts`) hands azure its raw string, and a
|
|
280
|
+
* `.tf` file is not JSON at all, so the raw string form is the one that
|
|
281
|
+
* matters for HCL. Anything else reads as false.
|
|
282
|
+
*
|
|
283
|
+
* The object form is exact rather than heuristic: Terraform's JSON syntax
|
|
284
|
+
* admits only the top-level names in {@link TF_JSON_BLOCK_TYPES}, so a
|
|
285
|
+
* document is `.tf.json` when every key is one of them and at least one is
|
|
286
|
+
* present. That refuses a Kubernetes manifest, a CloudFormation template and
|
|
287
|
+
* a Compose file without having to name any of them.
|
|
288
|
+
*
|
|
289
|
+
* Discovery still classifies Terraform by the directory bundle
|
|
290
|
+
* (`classifyTerraform`), because a root module is a directory of files that
|
|
291
|
+
* has to be parsed together and one `.tf` on its own is not an audit input.
|
|
292
|
+
* This makes the per-file question answerable for the callers that ask it
|
|
293
|
+
* one file at a time.
|
|
294
|
+
*/
|
|
295
|
+
detectTemplate(data: unknown) {
|
|
296
|
+
if (typeof data === "string") return looksLikeHcl(data);
|
|
297
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) return false;
|
|
298
|
+
const keys = Object.keys(data as Record<string, unknown>);
|
|
299
|
+
return keys.length > 0 && keys.every((k) => TF_JSON_BLOCK_TYPES.has(k));
|
|
143
300
|
},
|
|
144
301
|
|
|
145
302
|
completionProvider(ctx: CompletionContext) {
|
|
@@ -65,7 +65,7 @@ export const { op } = TerraformApplyOp({
|
|
|
65
65
|
});
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
`gate: "never"`
|
|
68
|
+
`gate: "never"` drops the Gate phase, so `chant run` walks straight from Plan to Apply; any other mode emits a Gate phase, and a run that reaches an unapproved gate records a pending fact on the gate ledger, ends `gated` and exits 3 until someone runs `chant approve <op> <gate>`. The Gate phase always shows the saved plan first and reports its `destroys` count as a `Destroys` run outcome, because `GateStep` carries no condition to branch on at build time — the approver sees what's at stake before approving, rather than the Op deciding for them.
|
|
69
69
|
|
|
70
70
|
Terraform has no automatic rollback, so `compensate: true` with no command throws at build time, naming the Op, rather than warning once an apply has already half-run:
|
|
71
71
|
|
package/src/validate.ts
CHANGED
|
@@ -11,7 +11,16 @@ import { validateLexiconArtifacts, type ValidateResult } from "@intentius/chant/
|
|
|
11
11
|
|
|
12
12
|
export type { ValidateCheck, ValidateResult } from "@intentius/chant/codegen/validate";
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Empty, and correct empty (#2220). `requiredNames` names generated resource
|
|
16
|
+
* classes that must survive a regenerate, and this lexicon generates none:
|
|
17
|
+
* `codegen/generate.ts` writes `lexicon-terraform.json` as `{}` on purpose,
|
|
18
|
+
* because Terraform's resource surface lives in provider registries rather
|
|
19
|
+
* than in one upstream schema, and an estate's `.tf` files are read as they
|
|
20
|
+
* are. There is no name to require, so the list stays empty and the
|
|
21
|
+
* remaining checks (the artifacts exist, the registry parses, the surface
|
|
22
|
+
* snapshot) are what validate actually proves here.
|
|
23
|
+
*/
|
|
15
24
|
const REQUIRED_NAMES: string[] = [];
|
|
16
25
|
|
|
17
26
|
/**
|