@intentius/chant-lexicon-terraform 0.124.52 → 0.124.55
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 +14 -10
- package/dist/__fixtures__/pr-loop/estate.component.d.ts +7 -0
- package/dist/__fixtures__/pr-loop/estate.component.d.ts.map +1 -0
- package/dist/__fixtures__/pr-loop/estate.component.js +7 -0
- package/dist/__fixtures__/report/generate.d.ts +26 -0
- package/dist/__fixtures__/report/generate.d.ts.map +1 -0
- package/dist/__fixtures__/report/generate.js +58 -0
- package/dist/applied-state.d.ts +27 -0
- package/dist/applied-state.d.ts.map +1 -0
- package/dist/applied-state.js +44 -0
- package/dist/backend-config.d.ts +53 -0
- package/dist/backend-config.d.ts.map +1 -0
- package/dist/backend-config.js +136 -0
- package/dist/behaviour/kinds.d.ts.map +1 -1
- package/dist/behaviour/kinds.js +4 -0
- package/dist/behaviour/predict.d.ts.map +1 -1
- package/dist/behaviour/predict.js +6 -2
- package/dist/behaviour/reference-catalog.d.ts +16 -5
- package/dist/behaviour/reference-catalog.d.ts.map +1 -1
- package/dist/behaviour/reference-catalog.js +16 -5
- package/dist/behaviour/request.d.ts.map +1 -1
- package/dist/behaviour/request.js +3 -2
- package/dist/changed-roots.d.ts +6 -4
- package/dist/changed-roots.d.ts.map +1 -1
- package/dist/changed-roots.js +14 -18
- package/dist/ci-setup.d.ts +11 -0
- package/dist/ci-setup.d.ts.map +1 -0
- package/dist/ci-setup.js +41 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +4 -3
- package/dist/components/capability-plugin.d.ts +105 -9
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/capability-plugin.js +357 -36
- package/dist/components/compose-group.d.ts +145 -0
- package/dist/components/compose-group.d.ts.map +1 -0
- package/dist/components/compose-group.js +407 -0
- package/dist/components/placeholder-preview.d.ts +78 -0
- package/dist/components/placeholder-preview.d.ts.map +1 -0
- package/dist/components/placeholder-preview.js +254 -0
- package/dist/components/release-inputs.d.ts +29 -0
- package/dist/components/release-inputs.d.ts.map +1 -0
- package/dist/components/release-inputs.js +57 -0
- package/dist/components/trace-facts.d.ts +16 -0
- package/dist/components/trace-facts.d.ts.map +1 -0
- package/dist/components/trace-facts.js +19 -0
- package/dist/compose/apply-events.d.ts +46 -0
- package/dist/compose/apply-events.d.ts.map +1 -0
- package/dist/compose/apply-events.js +77 -0
- package/dist/compose/estate.d.ts +194 -0
- package/dist/compose/estate.d.ts.map +1 -0
- package/dist/compose/estate.js +363 -0
- package/dist/compose/hcl.d.ts +99 -0
- package/dist/compose/hcl.d.ts.map +1 -0
- package/dist/compose/hcl.js +302 -0
- package/dist/compose/module-address.d.ts +24 -0
- package/dist/compose/module-address.d.ts.map +1 -0
- package/dist/compose/module-address.js +43 -0
- package/dist/compose/root.d.ts +127 -0
- package/dist/compose/root.d.ts.map +1 -0
- package/dist/compose/root.js +586 -0
- package/dist/compose/run.d.ts +183 -0
- package/dist/compose/run.d.ts.map +1 -0
- package/dist/compose/run.js +447 -0
- package/dist/compose/slice.d.ts +102 -0
- package/dist/compose/slice.d.ts.map +1 -0
- package/dist/compose/slice.js +249 -0
- package/dist/compose/state-address.d.ts +28 -0
- package/dist/compose/state-address.d.ts.map +1 -0
- package/dist/compose/state-address.js +154 -0
- package/dist/compose/state-merge.d.ts +52 -0
- package/dist/compose/state-merge.d.ts.map +1 -0
- package/dist/compose/state-merge.js +135 -0
- package/dist/compose.d.ts +179 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +482 -0
- package/dist/composites/terraform-apply-op.d.ts.map +1 -1
- package/dist/composites/terraform-apply-op.js +7 -3
- package/dist/cone.d.ts +53 -0
- package/dist/cone.d.ts.map +1 -0
- package/dist/cone.js +119 -0
- package/dist/config.d.ts +59 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +43 -9
- package/dist/cost-hold.d.ts +27 -0
- package/dist/cost-hold.d.ts.map +1 -0
- package/dist/cost-hold.js +21 -0
- package/dist/describe-resources.d.ts +74 -12
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/describe-resources.js +374 -66
- package/dist/drift-read.d.ts +33 -0
- package/dist/drift-read.d.ts.map +1 -0
- package/dist/drift-read.js +243 -0
- package/dist/drift-record.d.ts +147 -0
- package/dist/drift-record.d.ts.map +1 -0
- package/dist/drift-record.js +383 -0
- package/dist/drift-rows.d.ts +61 -0
- package/dist/drift-rows.d.ts.map +1 -0
- package/dist/drift-rows.js +108 -0
- package/dist/exit-codes.d.ts +55 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +48 -0
- package/dist/hcl/edges.d.ts.map +1 -1
- package/dist/hcl/edges.js +24 -1
- package/dist/hcl/files.d.ts +61 -0
- package/dist/hcl/files.d.ts.map +1 -0
- package/dist/hcl/files.js +221 -0
- package/dist/hcl/instances.d.ts +82 -0
- package/dist/hcl/instances.d.ts.map +1 -0
- package/dist/hcl/instances.js +390 -0
- package/dist/hcl/parse.d.ts +81 -9
- package/dist/hcl/parse.d.ts.map +1 -1
- package/dist/hcl/parse.js +114 -16
- package/dist/hcl/roots.d.ts.map +1 -1
- package/dist/hcl/roots.js +5 -0
- package/dist/hcl/suppressions.d.ts.map +1 -1
- package/dist/hcl/suppressions.js +8 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -2
- package/dist/integrity.json +8 -5
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/audit-catalog.js +27 -3
- package/dist/lint/audit-lineage.d.ts +14 -2
- package/dist/lint/audit-lineage.d.ts.map +1 -1
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/index.js +4 -0
- package/dist/lint/post-synth/record-store.d.ts +54 -0
- package/dist/lint/post-synth/record-store.d.ts.map +1 -0
- package/dist/lint/post-synth/record-store.js +104 -0
- package/dist/lint/post-synth/tf001.d.ts +2 -2
- package/dist/lint/post-synth/tf001.js +2 -2
- package/dist/lint/post-synth/tf024.d.ts +35 -11
- package/dist/lint/post-synth/tf024.d.ts.map +1 -1
- package/dist/lint/post-synth/tf024.js +92 -20
- package/dist/lint/post-synth/tf046.d.ts +64 -0
- package/dist/lint/post-synth/tf046.d.ts.map +1 -0
- package/dist/lint/post-synth/tf046.js +175 -0
- package/dist/lint/post-synth/tf047.d.ts +36 -0
- package/dist/lint/post-synth/tf047.d.ts.map +1 -0
- package/dist/lint/post-synth/tf047.js +94 -0
- package/dist/live-plan-reasons.d.ts +21 -0
- package/dist/live-plan-reasons.d.ts.map +1 -0
- package/dist/live-plan-reasons.js +47 -0
- package/dist/lock-rows.d.ts +36 -0
- package/dist/lock-rows.d.ts.map +1 -0
- package/dist/lock-rows.js +60 -0
- package/dist/lock-timeout.d.ts +22 -0
- package/dist/lock-timeout.d.ts.map +1 -0
- package/dist/lock-timeout.js +32 -0
- package/dist/lsp/option-keys.d.ts.map +1 -1
- package/dist/lsp/option-keys.js +2 -0
- package/dist/manifest.json +1 -1
- package/dist/module-catalog/index.d.ts +69 -0
- package/dist/module-catalog/index.d.ts.map +1 -0
- package/dist/module-catalog/index.js +110 -0
- package/dist/module-catalog/refresh-cli.d.ts +4 -0
- package/dist/module-catalog/refresh-cli.d.ts.map +1 -0
- package/dist/module-catalog/refresh-cli.js +64 -0
- package/dist/module-catalog/static-tier.d.ts +6 -0
- package/dist/module-catalog/static-tier.d.ts.map +1 -0
- package/dist/module-catalog/static-tier.js +1650 -0
- package/dist/module-catalog/types.d.ts +65 -0
- package/dist/module-catalog/types.d.ts.map +1 -0
- package/dist/module-catalog/types.js +33 -0
- package/dist/okf/index.md +3 -1
- package/dist/okf/rules/TF024.md +2 -2
- package/dist/okf/rules/TF046.md +11 -0
- package/dist/okf/rules/TF047.md +11 -0
- package/dist/op/activities/index.d.ts +6 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/index.js +5 -1
- package/dist/op/activities/live-detect.d.ts +4 -3
- package/dist/op/activities/live-detect.d.ts.map +1 -1
- package/dist/op/activities/live-detect.js +57 -32
- package/dist/op/activities/pin-rollout.d.ts +2 -0
- package/dist/op/activities/pin-rollout.d.ts.map +1 -1
- package/dist/op/activities/pin-rollout.js +1 -0
- package/dist/op/activities/terraform.d.ts +182 -5
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/activities/terraform.js +224 -24
- package/dist/op/activity-contracts.d.ts +27 -0
- package/dist/op/activity-contracts.d.ts.map +1 -1
- package/dist/op/activity-contracts.js +19 -1
- package/dist/op/builders.d.ts +7 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +9 -0
- package/dist/pin/consumers.d.ts +35 -0
- package/dist/pin/consumers.d.ts.map +1 -0
- package/dist/pin/consumers.js +70 -0
- package/dist/pin/edit.d.ts.map +1 -1
- package/dist/pin/edit.js +35 -0
- package/dist/pin/rollout.d.ts +2 -0
- package/dist/pin/rollout.d.ts.map +1 -1
- package/dist/pin/rollout.js +14 -11
- package/dist/plan-shape.d.ts +30 -0
- package/dist/plan-shape.d.ts.map +1 -0
- package/dist/plan-shape.js +125 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +37 -18
- package/dist/registry/address.d.ts +63 -0
- package/dist/registry/address.d.ts.map +1 -0
- package/dist/registry/address.js +65 -0
- package/dist/registry/catalog-read.d.ts +14 -0
- package/dist/registry/catalog-read.d.ts.map +1 -0
- package/dist/registry/catalog-read.js +58 -0
- package/dist/registry/deprecated.d.ts +37 -0
- package/dist/registry/deprecated.d.ts.map +1 -0
- package/dist/registry/deprecated.js +43 -0
- package/dist/registry/docs.d.ts +96 -0
- package/dist/registry/docs.d.ts.map +1 -0
- package/dist/registry/docs.js +210 -0
- package/dist/registry/edge/edge.d.ts +46 -0
- package/dist/registry/edge/edge.d.ts.map +1 -0
- package/dist/registry/edge/edge.js +194 -0
- package/dist/registry/edge/index.d.ts +11 -0
- package/dist/registry/edge/index.d.ts.map +1 -0
- package/dist/registry/edge/index.js +10 -0
- package/dist/registry/edge/lambda-edge.d.ts +76 -0
- package/dist/registry/edge/lambda-edge.d.ts.map +1 -0
- package/dist/registry/edge/lambda-edge.js +95 -0
- package/dist/registry/edge/sigv4-web.d.ts +33 -0
- package/dist/registry/edge/sigv4-web.d.ts.map +1 -0
- package/dist/registry/edge/sigv4-web.js +56 -0
- package/dist/registry/edge/token-source.d.ts +73 -0
- package/dist/registry/edge/token-source.d.ts.map +1 -0
- package/dist/registry/edge/token-source.js +115 -0
- package/dist/registry/edge/worker.d.ts +45 -0
- package/dist/registry/edge/worker.d.ts.map +1 -0
- package/dist/registry/edge/worker.js +26 -0
- package/dist/registry/handler.d.ts +25 -0
- package/dist/registry/handler.d.ts.map +1 -0
- package/dist/registry/handler.js +75 -0
- package/dist/registry/headers-file.d.ts +21 -0
- package/dist/registry/headers-file.d.ts.map +1 -0
- package/dist/registry/headers-file.js +57 -0
- package/dist/registry/index.d.ts +31 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +30 -0
- package/dist/registry/mirror-paths.d.ts +9 -0
- package/dist/registry/mirror-paths.d.ts.map +1 -0
- package/dist/registry/mirror-paths.js +8 -0
- package/dist/registry/mirror.d.ts +130 -0
- package/dist/registry/mirror.d.ts.map +1 -0
- package/dist/registry/mirror.js +319 -0
- package/dist/registry/proxies.d.ts +73 -0
- package/dist/registry/proxies.d.ts.map +1 -0
- package/dist/registry/proxies.js +111 -0
- package/dist/registry/reader.d.ts +57 -0
- package/dist/registry/reader.d.ts.map +1 -0
- package/dist/registry/reader.js +198 -0
- package/dist/registry/semver.d.ts +16 -0
- package/dist/registry/semver.d.ts.map +1 -0
- package/dist/registry/semver.js +24 -0
- package/dist/registry/serve.d.ts +24 -0
- package/dist/registry/serve.d.ts.map +1 -0
- package/dist/registry/serve.js +64 -0
- package/dist/registry/source-forms.d.ts +79 -0
- package/dist/registry/source-forms.d.ts.map +1 -0
- package/dist/registry/source-forms.js +202 -0
- package/dist/registry/targets/artifactory.d.ts +28 -0
- package/dist/registry/targets/artifactory.d.ts.map +1 -0
- package/dist/registry/targets/artifactory.js +206 -0
- package/dist/registry/targets/fake-artifactory.d.ts +30 -0
- package/dist/registry/targets/fake-artifactory.d.ts.map +1 -0
- package/dist/registry/targets/fake-artifactory.js +142 -0
- package/dist/registry/targets/fake-gitlab.d.ts +39 -0
- package/dist/registry/targets/fake-gitlab.d.ts.map +1 -0
- package/dist/registry/targets/fake-gitlab.js +136 -0
- package/dist/registry/targets/fake-hcp.d.ts +50 -0
- package/dist/registry/targets/fake-hcp.d.ts.map +1 -0
- package/dist/registry/targets/fake-hcp.js +202 -0
- package/dist/registry/targets/fake-http.d.ts +31 -0
- package/dist/registry/targets/fake-http.d.ts.map +1 -0
- package/dist/registry/targets/fake-http.js +87 -0
- package/dist/registry/targets/fake-nexus.d.ts +27 -0
- package/dist/registry/targets/fake-nexus.d.ts.map +1 -0
- package/dist/registry/targets/fake-nexus.js +137 -0
- package/dist/registry/targets/gitlab.d.ts +53 -0
- package/dist/registry/targets/gitlab.d.ts.map +1 -0
- package/dist/registry/targets/gitlab.js +187 -0
- package/dist/registry/targets/hcp.d.ts +29 -0
- package/dist/registry/targets/hcp.d.ts.map +1 -0
- package/dist/registry/targets/hcp.js +310 -0
- package/dist/registry/targets/hosted.d.ts +62 -0
- package/dist/registry/targets/hosted.d.ts.map +1 -0
- package/dist/registry/targets/hosted.js +74 -0
- package/dist/registry/targets/index.d.ts +18 -0
- package/dist/registry/targets/index.d.ts.map +1 -0
- package/dist/registry/targets/index.js +17 -0
- package/dist/registry/targets/module-target.d.ts +68 -0
- package/dist/registry/targets/module-target.d.ts.map +1 -0
- package/dist/registry/targets/module-target.js +63 -0
- package/dist/registry/targets/nexus.d.ts +43 -0
- package/dist/registry/targets/nexus.d.ts.map +1 -0
- package/dist/registry/targets/nexus.js +250 -0
- package/dist/registry/targets/zip.d.ts +55 -0
- package/dist/registry/targets/zip.d.ts.map +1 -0
- package/dist/registry/targets/zip.js +278 -0
- package/dist/registry/writer.d.ts +101 -0
- package/dist/registry/writer.d.ts.map +1 -0
- package/dist/registry/writer.js +109 -0
- package/dist/report.d.ts +15 -6
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +28 -55
- package/dist/rules/record-store.ts +122 -0
- package/dist/rules/tf001.ts +2 -2
- package/dist/rules/tf024.ts +105 -22
- package/dist/rules/tf046.ts +204 -0
- package/dist/rules/tf047.ts +114 -0
- package/dist/skills/chant-terraform.md +1 -1
- package/dist/state/azure-blob.d.ts +9 -0
- package/dist/state/azure-blob.d.ts.map +1 -0
- package/dist/state/azure-blob.js +8 -0
- package/dist/state/backend.d.ts +158 -0
- package/dist/state/backend.d.ts.map +1 -0
- package/dist/state/backend.js +406 -0
- package/dist/state/exec.d.ts +39 -0
- package/dist/state/exec.d.ts.map +1 -0
- package/dist/state/exec.js +80 -0
- package/dist/state/gcs.d.ts +8 -0
- package/dist/state/gcs.d.ts.map +1 -0
- package/dist/state/gcs.js +7 -0
- package/dist/state/index.d.ts +15 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +14 -0
- package/dist/state/locks.d.ts +105 -0
- package/dist/state/locks.d.ts.map +1 -0
- package/dist/state/locks.js +130 -0
- package/dist/state/object-store.d.ts +8 -0
- package/dist/state/object-store.d.ts.map +1 -0
- package/dist/state/object-store.js +7 -0
- package/dist/state/root-states.d.ts +131 -0
- package/dist/state/root-states.d.ts.map +1 -0
- package/dist/state/root-states.js +241 -0
- package/dist/state/s3.d.ts +21 -0
- package/dist/state/s3.d.ts.map +1 -0
- package/dist/state/s3.js +19 -0
- package/dist/state/store.d.ts +51 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/store.js +185 -0
- package/dist/state-ops.d.ts +255 -0
- package/dist/state-ops.d.ts.map +1 -0
- package/dist/state-ops.js +305 -0
- package/dist/state-reads.d.ts +57 -0
- package/dist/state-reads.d.ts.map +1 -0
- package/dist/state-reads.js +104 -0
- package/dist/terragrunt/affected.d.ts.map +1 -1
- package/dist/terragrunt/affected.js +2 -1
- package/dist/used-sources.d.ts +54 -0
- package/dist/used-sources.d.ts.map +1 -0
- package/dist/used-sources.js +157 -0
- package/package.json +24 -4
- package/src/__fixtures__/ACCEPTANCE.md +69 -7
- package/src/__fixtures__/compose/apply-failed-in-app.jsonl +12 -0
- package/src/__fixtures__/compose/state-app.json +66 -0
- package/src/__fixtures__/compose/state-edge.json +40 -0
- package/src/__fixtures__/compose/state-net.json +58 -0
- package/src/__fixtures__/compose/three-app.plan.json +184 -0
- package/src/__fixtures__/compose/three-composed.plan.json +509 -0
- package/src/__fixtures__/compose/three-edge.plan.json +144 -0
- package/src/__fixtures__/compose/three-net.plan.json +174 -0
- package/src/__fixtures__/compose/unknown-composed.plan.json +228 -0
- package/src/__fixtures__/compose/working-after-apply.json +145 -0
- package/src/__fixtures__/config-blocks/app/main.tf +61 -0
- package/src/__fixtures__/config-blocks/app/modules/network/main.tf +4 -0
- package/src/__fixtures__/config-blocks/app-json/main.tf.json +39 -0
- package/src/__fixtures__/config-files/shadow/main.tf +3 -0
- package/src/__fixtures__/config-files/shadow/main.tofu +3 -0
- package/src/__fixtures__/config-files/shadow/other.tf +3 -0
- package/src/__fixtures__/config-files/tf/main.tf +11 -0
- package/src/__fixtures__/config-files/tf-json/main.tf.json +18 -0
- package/src/__fixtures__/config-files/tofu/main.tofu +11 -0
- package/src/__fixtures__/config-files/tofu-json/main.tofu.json +18 -0
- package/src/__fixtures__/config-files/tofu-only/main.tofu +3 -0
- package/src/__fixtures__/drift-record/README.md +16 -0
- package/src/__fixtures__/drift-record/live-plan-sections.json +27 -0
- package/src/__fixtures__/drift-rows/live-root-plan.json +70 -0
- package/src/__fixtures__/drift-rows/refresh-plan.json +61 -0
- package/src/__fixtures__/instance-forms/app/main.tf +110 -0
- package/src/__fixtures__/instance-forms/app/modules/svc/main.tf +3 -0
- package/src/__fixtures__/instance-vars/app/main.tf +52 -0
- package/src/__fixtures__/instance-vars/app/modules/app/main.tf +12 -0
- package/src/__fixtures__/instance-vars/app/modules/edge/main.tf +3 -0
- package/src/__fixtures__/instance-vars/app/terraform.tfvars +1 -0
- package/src/__fixtures__/live-module-keyed/live-graph.json +259 -0
- package/src/__fixtures__/live-module-keyed/live-plan.json +87 -0
- package/src/__fixtures__/live-module-keyed/root/estate.chdf.hcl +1 -0
- package/src/__fixtures__/live-module-keyed/root/main.tf +21 -0
- package/src/__fixtures__/live-module-keyed/root/modules/app/main.tf +17 -0
- package/src/__fixtures__/live-module-keyed/root/modules/edge/main.tf +7 -0
- package/src/__fixtures__/live-module-keyed/root/versions.tf +30 -0
- package/src/__fixtures__/live-module-keyed/show-state.json +146 -0
- package/src/__fixtures__/pr-loop/README.md +50 -0
- package/src/__fixtures__/pr-loop/chant.config.json +13 -0
- package/src/__fixtures__/pr-loop/estate.component.ts +10 -0
- package/src/__fixtures__/pr-loop/roots/a/main.tf +11 -0
- package/src/__fixtures__/pr-loop/roots/app/main.tf +19 -0
- package/src/__fixtures__/pr-loop/roots/b/main.tf +7 -0
- package/src/__fixtures__/pr-loop/roots/dns/main.tf +3 -0
- package/src/__fixtures__/pr-loop/roots/net/main.tf +7 -0
- package/src/__fixtures__/report/applied.show.json +51 -0
- package/src/__fixtures__/report/generate.ts +63 -0
- package/src/__fixtures__/report/plan.show.json +200 -0
- package/src/__fixtures__/report/tf-apply/change-set.json +170 -0
- package/src/__fixtures__/report/tf-apply/report.json +338 -0
- package/src/__fixtures__/report/tf-plan/change-set.json +170 -0
- package/src/__fixtures__/report/tf-plan/report.json +320 -0
- package/src/__fixtures__/three-cloud-azure.graph.json +290 -0
- package/src/__fixtures__/used-sources/root/extra.tofu +1 -0
- package/src/__fixtures__/used-sources/root/main.tf +31 -0
- package/src/__fixtures__/used-sources/root/modules/net/main.tf +14 -0
- package/src/__fixtures__/used-sources/root/modules/net/versions.tf.json +7 -0
- package/src/__fixtures__/used-sources/unit/terragrunt.hcl +3 -0
- package/src/applied-state.ts +52 -0
- package/src/backend-config.test.ts +105 -0
- package/src/backend-config.ts +133 -0
- package/src/behaviour/kinds.ts +4 -0
- package/src/behaviour/predict.ts +5 -2
- package/src/behaviour/reference-catalog.plugin.test.ts +65 -0
- package/src/behaviour/reference-catalog.ts +16 -5
- package/src/behaviour/request.ts +3 -2
- package/src/change-set-instances.test.ts +98 -0
- package/src/changed-roots.ts +14 -16
- package/src/ci-setup.ts +42 -0
- package/src/commands.ts +4 -3
- package/src/components/capability-plugin.test.ts +198 -19
- package/src/components/capability-plugin.ts +383 -35
- package/src/components/change-set-graph.e2e.test.ts +11 -5
- package/src/components/compose-group.test.ts +486 -0
- package/src/components/compose-group.ts +489 -0
- package/src/components/demo-composed-roots.e2e.test.ts +440 -0
- package/src/components/member-outputs.test.ts +76 -0
- package/src/components/placeholder-preview.test.ts +147 -0
- package/src/components/placeholder-preview.ts +257 -0
- package/src/components/pr-loop-compose.tofu.e2e.test.ts +363 -0
- package/src/components/pr-loop.tofu.test.ts +113 -57
- package/src/components/release-inputs.ts +69 -0
- package/src/components/trace-facts.test.ts +21 -0
- package/src/components/trace-facts.ts +27 -0
- package/src/compose/apply-events.test.ts +62 -0
- package/src/compose/apply-events.ts +100 -0
- package/src/compose/estate.choudoufu.e2e.test.ts +112 -0
- package/src/compose/estate.test.ts +421 -0
- package/src/compose/estate.ts +443 -0
- package/src/compose/hcl.ts +311 -0
- package/src/compose/module-address.ts +49 -0
- package/src/compose/root.test.ts +416 -0
- package/src/compose/root.ts +592 -0
- package/src/compose/run.test.ts +440 -0
- package/src/compose/run.tofu.test.ts +176 -0
- package/src/compose/run.ts +527 -0
- package/src/compose/slice.test.ts +184 -0
- package/src/compose/slice.ts +290 -0
- package/src/compose/state-address.ts +157 -0
- package/src/compose/state-merge.test.ts +131 -0
- package/src/compose/state-merge.ts +148 -0
- package/src/compose.test.ts +248 -0
- package/src/compose.ts +627 -0
- package/src/composites/terraform-apply-op.test.ts +9 -0
- package/src/composites/terraform-apply-op.ts +7 -3
- package/src/cone.ts +138 -0
- package/src/config-file-listers.test.ts +265 -0
- package/src/config.ts +44 -9
- package/src/cost-hold.ts +29 -0
- package/src/describe-resources.engine-facts.test.ts +411 -0
- package/src/describe-resources.live-module-keyed.test.ts +290 -0
- package/src/describe-resources.ts +416 -70
- package/src/drift-read.ts +284 -0
- package/src/drift-record.test.ts +223 -0
- package/src/drift-record.ts +455 -0
- package/src/drift-rows.test.ts +135 -0
- package/src/drift-rows.ts +137 -0
- package/src/exit-codes.test.ts +23 -0
- package/src/exit-codes.ts +59 -0
- package/src/hcl/config-blocks.test.ts +174 -0
- package/src/hcl/edges.ts +21 -1
- package/src/hcl/files.ts +234 -0
- package/src/hcl/instance-forms.test.ts +94 -0
- package/src/hcl/instances.test.ts +137 -0
- package/src/hcl/instances.ts +422 -0
- package/src/hcl/parse.test.ts +139 -1
- package/src/hcl/parse.ts +149 -16
- package/src/hcl/roots.ts +6 -0
- package/src/hcl/suppressions.ts +8 -2
- package/src/index.ts +79 -0
- package/src/lint/audit-catalog.ts +29 -3
- package/src/lint/audit-lineage.ts +14 -2
- package/src/lint/post-synth/fixtures/TF024/live-with-record-store/main.tf +18 -0
- package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/estate.chdf.hcl +1 -0
- package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/main.tf +10 -0
- package/src/lint/post-synth/fixtures/TF046/azurerm-no-resource-group/main.tf +15 -0
- package/src/lint/post-synth/fixtures/TF046/backend-config-only/main.tf +14 -0
- package/src/lint/post-synth/fixtures/TF046/derived-s3/backend.tf +7 -0
- package/src/lint/post-synth/fixtures/TF046/derived-s3/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF046/explicit-local/main.tf +16 -0
- package/src/lint/post-synth/fixtures/TF046/explicit-s3-beside-local-backend/main.tf +15 -0
- package/src/lint/post-synth/fixtures/TF046/implied-local/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF046/sidecar-implied/estate.chdf.hcl +1 -0
- package/src/lint/post-synth/fixtures/TF046/sidecar-implied/main.tf +5 -0
- package/src/lint/post-synth/fixtures/TF047/clear/main.tf +12 -0
- package/src/lint/post-synth/fixtures/TF047/refused/main.tf +12 -0
- package/src/lint/post-synth/fixtures/TF047/unknown-module/main.tf +12 -0
- package/src/lint/post-synth/fixtures/TF047/unknown-version/main.tf +12 -0
- package/src/lint/post-synth/index.ts +4 -0
- package/src/lint/post-synth/record-store.ts +122 -0
- package/src/lint/post-synth/tf001.ts +2 -2
- package/src/lint/post-synth/tf024.test.ts +26 -5
- package/src/lint/post-synth/tf024.ts +105 -22
- package/src/lint/post-synth/tf046.test.ts +137 -0
- package/src/lint/post-synth/tf046.ts +204 -0
- package/src/lint/post-synth/tf047.test.ts +56 -0
- package/src/lint/post-synth/tf047.ts +114 -0
- package/src/live-plan-reasons.ts +54 -0
- package/src/lock-rows.test.ts +70 -0
- package/src/lock-rows.ts +82 -0
- package/src/lock-timeout.ts +34 -0
- package/src/lsp/completions.test.ts +1 -1
- package/src/lsp/option-keys.ts +2 -0
- package/src/module-catalog/index.test.ts +93 -0
- package/src/module-catalog/index.ts +159 -0
- package/src/module-catalog/refresh-cli.ts +68 -0
- package/src/module-catalog/static-tier.ts +1659 -0
- package/src/module-catalog/types.ts +88 -0
- package/src/op/activities/choudoufu-plan-set-op.test.ts +111 -0
- package/src/op/activities/index.ts +9 -0
- package/src/op/activities/live-detect.ts +55 -26
- package/src/op/activities/pin-rollout.ts +3 -0
- package/src/op/activities/registry.test.ts +2 -1
- package/src/op/activities/terraform.test.ts +55 -0
- package/src/op/activities/terraform.ts +312 -27
- package/src/op/activity-contracts.test.ts +1 -0
- package/src/op/activity-contracts.ts +24 -1
- package/src/op/builders.ts +14 -0
- package/src/op-wave-step.test.ts +109 -0
- package/src/pin/__fixtures__/consumers/live/dev/main.tf +4 -0
- package/src/pin/__fixtures__/consumers/live/prod/main.tf +21 -0
- package/src/pin/__fixtures__/consumers/units/vpc/terragrunt.hcl +7 -0
- package/src/pin/bundle.test.ts +2 -0
- package/src/pin/consumers.test.ts +57 -0
- package/src/pin/consumers.ts +95 -0
- package/src/pin/edit.ts +30 -0
- package/src/pin/rollout.ts +16 -11
- package/src/plan-shape.test.ts +148 -0
- package/src/plan-shape.ts +128 -0
- package/src/plugin.ts +39 -19
- package/src/registry/__fixtures__/docs/documented/.terraform-docs.yml +3 -0
- package/src/registry/__fixtures__/docs/documented/README.md +1 -0
- package/src/registry/__fixtures__/docs/documented/main.tf +8 -0
- package/src/registry/__fixtures__/docs/json/main.tf.json +14 -0
- package/src/registry/__fixtures__/docs/vpc/README.md +3 -0
- package/src/registry/__fixtures__/docs/vpc/examples/complete/main.tf +5 -0
- package/src/registry/__fixtures__/docs/vpc/examples/simple/README.md +1 -0
- package/src/registry/__fixtures__/docs/vpc/examples/simple/main.tf +4 -0
- package/src/registry/__fixtures__/docs/vpc/main.tf +14 -0
- package/src/registry/__fixtures__/docs/vpc/outputs.tf +9 -0
- package/src/registry/__fixtures__/docs/vpc/variables.tf +16 -0
- package/src/registry/__fixtures__/proxied-root/main.tf +12 -0
- package/src/registry/address.ts +100 -0
- package/src/registry/catalog-read.ts +56 -0
- package/src/registry/deprecated.test.ts +139 -0
- package/src/registry/deprecated.ts +76 -0
- package/src/registry/docs.test.ts +140 -0
- package/src/registry/docs.ts +299 -0
- package/src/registry/edge/bundle.test.ts +50 -0
- package/src/registry/edge/edge.test.ts +176 -0
- package/src/registry/edge/edge.ts +211 -0
- package/src/registry/edge/index.ts +10 -0
- package/src/registry/edge/lambda-edge.ts +127 -0
- package/src/registry/edge/sigv4-web.ts +79 -0
- package/src/registry/edge/token-source.test.ts +258 -0
- package/src/registry/edge/token-source.ts +169 -0
- package/src/registry/edge/worker.ts +61 -0
- package/src/registry/handler.ts +89 -0
- package/src/registry/headers-file.ts +61 -0
- package/src/registry/index.ts +31 -0
- package/src/registry/mirror-paths.ts +10 -0
- package/src/registry/mirror.test.ts +198 -0
- package/src/registry/mirror.ts +395 -0
- package/src/registry/proxies.test.ts +153 -0
- package/src/registry/proxies.ts +132 -0
- package/src/registry/reader.ts +225 -0
- package/src/registry/registry.test.ts +262 -0
- package/src/registry/semver.ts +34 -0
- package/src/registry/serve.ts +82 -0
- package/src/registry/source-forms.test.ts +87 -0
- package/src/registry/source-forms.ts +216 -0
- package/src/registry/targets/artifactory.test.ts +248 -0
- package/src/registry/targets/artifactory.ts +257 -0
- package/src/registry/targets/fake-artifactory.ts +158 -0
- package/src/registry/targets/fake-gitlab.ts +161 -0
- package/src/registry/targets/fake-hcp.ts +233 -0
- package/src/registry/targets/fake-http.ts +97 -0
- package/src/registry/targets/fake-nexus.ts +152 -0
- package/src/registry/targets/gitlab.test.ts +208 -0
- package/src/registry/targets/gitlab.ts +223 -0
- package/src/registry/targets/hcp.test.ts +230 -0
- package/src/registry/targets/hcp.ts +360 -0
- package/src/registry/targets/hosted.ts +117 -0
- package/src/registry/targets/index.ts +17 -0
- package/src/registry/targets/module-target.ts +131 -0
- package/src/registry/targets/nexus.test.ts +220 -0
- package/src/registry/targets/nexus.ts +314 -0
- package/src/registry/targets/zip.test.ts +65 -0
- package/src/registry/targets/zip.ts +287 -0
- package/src/registry/writer.ts +155 -0
- package/src/report.test.ts +82 -1
- package/src/report.ts +31 -54
- package/src/signal-only-root.test.ts +72 -0
- package/src/skills/chant-terraform.md +1 -1
- package/src/state/azure-blob.ts +8 -0
- package/src/state/backend-verdict.test.ts +187 -0
- package/src/state/backend.test.ts +127 -0
- package/src/state/backend.ts +488 -0
- package/src/state/exec.ts +111 -0
- package/src/state/gcs.ts +7 -0
- package/src/state/index.ts +15 -0
- package/src/state/locks.test.ts +84 -0
- package/src/state/locks.ts +201 -0
- package/src/state/object-store.ts +7 -0
- package/src/state/root-states-floci.e2e.test.ts +66 -0
- package/src/state/root-states.test.ts +462 -0
- package/src/state/root-states.ts +309 -0
- package/src/state/s3.ts +21 -0
- package/src/state/store.ts +225 -0
- package/src/state-ops.test.ts +182 -0
- package/src/state-ops.ts +462 -0
- package/src/state-reads.ts +116 -0
- package/src/terragrunt/affected.ts +2 -1
- package/src/used-sources.test.ts +75 -0
- package/src/used-sources.ts +204 -0
- package/src/workspace-kinds.test.ts +4 -17
- package/workspace-kinds.json +1 -24
- package/dist/workspace-member.d.ts +0 -30
- package/dist/workspace-member.d.ts.map +0 -1
- package/dist/workspace-member.js +0 -91
- package/schemas/pulumi.schema.json +0 -34
- package/src/testdata/pulumi-member/Pulumi.yaml +0 -2
- package/src/testdata/pulumi-member/stack-export.json +0 -53
- package/src/testdata/pulumi-unexported/Pulumi.yaml +0 -2
- package/src/workspace-member.test.ts +0 -89
- package/src/workspace-member.ts +0 -126
package/src/hcl/parse.test.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
1
4
|
import { describe, test, expect } from "vitest";
|
|
2
|
-
import {
|
|
5
|
+
import type { Declarable } from "@intentius/chant/declarable";
|
|
6
|
+
import { blocksToEntities, jsonConfigTree, parseTerraformRootContent, parseTerraformRootDir, type TerraformEntity } from "./parse";
|
|
7
|
+
import { terraformPlugin } from "../plugin";
|
|
3
8
|
|
|
4
9
|
describe("blocksToEntities: suppression attachment (chant #2111)", () => {
|
|
5
10
|
test("attaches the block's start line even with no suppression comment", async () => {
|
|
@@ -92,3 +97,136 @@ describe("Terragrunt config files (#3417)", () => {
|
|
|
92
97
|
expect([...entities.values()].map((e) => e.entityType)).toEqual(["Terraform::Terraform"]);
|
|
93
98
|
});
|
|
94
99
|
});
|
|
100
|
+
|
|
101
|
+
// ── chant#4457: `.tf.json` and `.tofu` files ───────────────────────────────
|
|
102
|
+
|
|
103
|
+
describe("configuration files beyond `.tf` (chant#4457)", () => {
|
|
104
|
+
const configFiles = join(dirname(fileURLToPath(import.meta.url)), "..", "__fixtures__", "config-files");
|
|
105
|
+
const at = (name: string): string => join(configFiles, name);
|
|
106
|
+
|
|
107
|
+
/** What the acceptance compares: each entity's type, address, body and file. */
|
|
108
|
+
const shape = (entities: Map<string, Declarable>): Record<string, { type: string; address: string; body: unknown; file: string }> =>
|
|
109
|
+
Object.fromEntries(
|
|
110
|
+
[...entities].map(([key, e]) => {
|
|
111
|
+
const p = (e as TerraformEntity).props;
|
|
112
|
+
return [key, { type: e.entityType, address: p.address, body: p.body, file: p.file }];
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
/** The same, with each file's suffix taken off so two syntaxes of one file compare equal. */
|
|
116
|
+
const sameFile = (entities: Map<string, Declarable>, suffix: string) =>
|
|
117
|
+
Object.fromEntries(Object.entries(shape(entities)).map(([k, v]) => [k, { ...v, file: v.file.replace(suffix, "") }]));
|
|
118
|
+
|
|
119
|
+
test("a block in main.tf.json is the entity the same block in main.tf is", async () => {
|
|
120
|
+
const tf = await parseTerraformRootDir(at("tf"), "app");
|
|
121
|
+
const json = await parseTerraformRootDir(at("tf-json"), "app");
|
|
122
|
+
expect(Object.keys(shape(json)).sort()).toEqual(["app/aws_s3_bucket.assets", "app/var.region"]);
|
|
123
|
+
expect(shape(json)["app/aws_s3_bucket.assets"]).toEqual({ ...shape(tf)["app/aws_s3_bucket.assets"], file: "main.tf.json" });
|
|
124
|
+
expect(sameFile(json, ".tf.json")).toEqual(sameFile(tf, ".tf"));
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("a main.tofu and a main.tofu.json root yields its entities under tofu and choudoufu", async () => {
|
|
128
|
+
const tf = sameFile(await parseTerraformRootDir(at("tf"), "app"), ".tf");
|
|
129
|
+
for (const binary of ["tofu", "choudoufu", "/usr/local/bin/tofu"]) {
|
|
130
|
+
expect(sameFile(await parseTerraformRootDir(at("tofu"), "app", undefined, { binary }), ".tofu")).toEqual(tf);
|
|
131
|
+
expect(sameFile(await parseTerraformRootDir(at("tofu-json"), "app", undefined, { binary }), ".tofu.json")).toEqual(tf);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("a terraform root, or one with no binary set, reads no .tofu file", async () => {
|
|
136
|
+
expect((await parseTerraformRootDir(at("tofu"), "app", undefined, { binary: "terraform" })).size).toBe(0);
|
|
137
|
+
expect((await parseTerraformRootDir(at("tofu-json"), "app")).size).toBe(0);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("x.tofu shadows x.tf in a tofu or choudoufu root, and a terraform root reads x.tf", async () => {
|
|
141
|
+
for (const binary of ["tofu", "choudoufu"]) {
|
|
142
|
+
const keys = [...(await parseTerraformRootDir(at("shadow"), "app", undefined, { binary })).keys()].sort();
|
|
143
|
+
expect(keys).toEqual(["app/aws_s3_bucket.from_tofu", "app/output.kept"]);
|
|
144
|
+
}
|
|
145
|
+
const keys = [...(await parseTerraformRootDir(at("shadow"), "app", undefined, { binary: "terraform" })).keys()].sort();
|
|
146
|
+
expect(keys).toEqual(["app/aws_s3_bucket.from_tf", "app/output.kept"]);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("a root whose only declaration is in a .tofu file builds its entities through buildRoots()", async () => {
|
|
150
|
+
const hook = terraformPlugin.buildRoots!;
|
|
151
|
+
const config = (binary: string) => ({ terraform: { binary, roots: { only: { dir: "tofu-only" } } } });
|
|
152
|
+
const tofu = await hook({ projectRoot: configFiles, config: config("tofu"), entities: new Map() });
|
|
153
|
+
expect([...tofu.entities.keys()]).toEqual(["only/aws_s3_bucket.only"]);
|
|
154
|
+
expect(((tofu.entities.get("only/aws_s3_bucket.only") as TerraformEntity).props).file).toBe("main.tofu");
|
|
155
|
+
const terraform = await hook({ projectRoot: configFiles, config: config("terraform"), entities: new Map() });
|
|
156
|
+
expect(terraform.entities.size).toBe(0);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/** The joined form `chant audit` builds for a directory, every file behind a `# file:` line. */
|
|
160
|
+
const bundle = (dir: string): string =>
|
|
161
|
+
readdirSync(dir)
|
|
162
|
+
.sort()
|
|
163
|
+
.map((name) => `# file: ${name}\n${readFileSync(join(dir, name), "utf-8")}`)
|
|
164
|
+
.join("\n");
|
|
165
|
+
|
|
166
|
+
test("the audit path sees the entities the build path sees for each fixture", async () => {
|
|
167
|
+
for (const [name, binary] of [
|
|
168
|
+
["tf", undefined],
|
|
169
|
+
["tf-json", undefined],
|
|
170
|
+
["tofu", "tofu"],
|
|
171
|
+
["tofu-json", "tofu"],
|
|
172
|
+
["tofu-only", "choudoufu"],
|
|
173
|
+
["shadow", "tofu"],
|
|
174
|
+
["shadow", "terraform"],
|
|
175
|
+
] as const) {
|
|
176
|
+
const opts = binary ? { binary } : undefined;
|
|
177
|
+
const built = shape(await parseTerraformRootDir(at(name), "app", undefined, opts));
|
|
178
|
+
const audited = shape(await parseTerraformRootContent(bundle(at(name)), "app", undefined, opts));
|
|
179
|
+
expect(audited).toEqual(built);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("the audit hook reads a root carrying a .tofu file as a tofu root", async () => {
|
|
184
|
+
const entities = await terraformPlugin.auditEntities!(bundle(at("shadow")));
|
|
185
|
+
expect([...entities.keys()].sort()).toEqual(["audit-root/aws_s3_bucket.from_tofu", "audit-root/output.kept"]);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe("jsonConfigTree: Terraform's JSON syntax in hcl2json's shape (chant#4457)", () => {
|
|
190
|
+
test("wraps each block body in an array, one object level per label", () => {
|
|
191
|
+
const tree = jsonConfigTree(
|
|
192
|
+
JSON.stringify({
|
|
193
|
+
"//": "a comment Terraform ignores",
|
|
194
|
+
terraform: { required_version: ">= 1.5", backend: { s3: { bucket: "b", key: "k" } }, required_providers: { aws: { source: "hashicorp/aws" } } },
|
|
195
|
+
locals: { a: 1 },
|
|
196
|
+
provider: { aws: [{ region: "us-east-1" }, { alias: "west", region: "us-west-2" }] },
|
|
197
|
+
resource: { aws_instance: { web: { ami: "x", lifecycle: { create_before_destroy: true } } } },
|
|
198
|
+
data: { aws_ami: { ubuntu: { most_recent: true } } },
|
|
199
|
+
}),
|
|
200
|
+
);
|
|
201
|
+
expect(tree).toEqual({
|
|
202
|
+
terraform: [{ required_version: ">= 1.5", backend: { s3: [{ bucket: "b", key: "k" }] }, required_providers: [{ aws: { source: "hashicorp/aws" } }] }],
|
|
203
|
+
locals: [{ a: 1 }],
|
|
204
|
+
provider: { aws: [{ region: "us-east-1" }, { alias: "west", region: "us-west-2" }] },
|
|
205
|
+
resource: { aws_instance: { web: [{ ami: "x", lifecycle: [{ create_before_destroy: true }] }] } },
|
|
206
|
+
data: { aws_ami: { ubuntu: [{ most_recent: true }] } },
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("a live block in a .tf.json terraform block declares the estate", async () => {
|
|
211
|
+
const source = JSON.stringify({ terraform: { live: { estate: "prod" } } });
|
|
212
|
+
const entities = await blocksToEntities([{ name: "main.tf.json", source }], "app", undefined, { binary: "choudoufu" });
|
|
213
|
+
const live = entities.get("app/live") as TerraformEntity;
|
|
214
|
+
expect(live.props.mode).toBe("live");
|
|
215
|
+
expect(live.props.estate).toBe("prod");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test("a bare expression JSON writes in a string reads as hcl2json writes the expression", () => {
|
|
219
|
+
const tree = jsonConfigTree(
|
|
220
|
+
JSON.stringify({
|
|
221
|
+
variable: { region: { type: "string" } },
|
|
222
|
+
resource: { aws_instance: { web: { provider: "aws.west", depends_on: ["aws_vpc.main"], ami: "${var.ami}" } } },
|
|
223
|
+
}),
|
|
224
|
+
);
|
|
225
|
+
expect(tree.variable).toEqual({ region: [{ type: "${string}" }] });
|
|
226
|
+
expect(tree.resource).toEqual({ aws_instance: { web: [{ provider: "${aws.west}", depends_on: ["${aws_vpc.main}"], ami: "${var.ami}" }] } });
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("malformed JSON throws, as malformed HCL does", () => {
|
|
230
|
+
expect(() => jsonConfigTree("{ not json")).toThrow();
|
|
231
|
+
});
|
|
232
|
+
});
|
package/src/hcl/parse.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The one shared HCL parse for the terraform lexicon.
|
|
3
3
|
*
|
|
4
|
-
* Two entry points, one entity shape. `parseTerraformRootDir` reads the
|
|
5
|
-
* files of a directory (non-recursive, matching Terraform's own
|
|
6
|
-
* scoping
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Two entry points, one entity shape. `parseTerraformRootDir` reads the
|
|
5
|
+
* configuration files of a directory (non-recursive, matching Terraform's own
|
|
6
|
+
* module scoping; `.tf` and `.tf.json`, plus `.tofu` and `.tofu.json` for a
|
|
7
|
+
* tofu or choudoufu root, see `./files.ts`) and is what `buildRoots()` calls.
|
|
8
|
+
* `parseTerraformRootContent` takes the joined-file string `chant audit` hands
|
|
9
|
+
* a lexicon for a discovered root module: every configuration file in filename
|
|
10
|
+
* order behind a `# file: <name>` line comment, narrowed to the same set.
|
|
9
11
|
* Both funnel through `blocksToEntities`, so an entity the audit path sees is
|
|
10
12
|
* the entity the build path sees.
|
|
11
13
|
*
|
|
@@ -18,7 +20,7 @@
|
|
|
18
20
|
* changed in `packages/core/package.json` for this.
|
|
19
21
|
*/
|
|
20
22
|
|
|
21
|
-
import { existsSync,
|
|
23
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
22
24
|
import { join } from "node:path";
|
|
23
25
|
import { loadHcl2json, type Hcl2Json } from "@intentius/chant/terraform/hcl2json";
|
|
24
26
|
import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
|
|
@@ -27,6 +29,20 @@ import type { SuppressionDirective } from "@intentius/chant/lint/suppressions";
|
|
|
27
29
|
import type { TerraformDeleteMode } from "../config";
|
|
28
30
|
import { redactSensitiveBody, redactSensitiveSource } from "./redact";
|
|
29
31
|
import { scanSuppressions, directivesFor, type FileScan } from "./suppressions";
|
|
32
|
+
import { isJsonConfigFile, jsonConfigTree, listConfigFiles, selectConfigFiles } from "./files";
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
TERRAFORM_SUFFIXES,
|
|
36
|
+
TOFU_SUFFIXES,
|
|
37
|
+
isConfigFileFor,
|
|
38
|
+
isJsonConfigFile,
|
|
39
|
+
isTofuConfigFile,
|
|
40
|
+
jsonConfigTree,
|
|
41
|
+
listConfigFiles,
|
|
42
|
+
listConfigFilesSafe,
|
|
43
|
+
readsTofuFiles,
|
|
44
|
+
selectConfigFiles,
|
|
45
|
+
} from "./files";
|
|
30
46
|
|
|
31
47
|
/** A parsed HCL block body, as `@cdktn/hcl2json` encodes it. */
|
|
32
48
|
export type BlockBody = Record<string, unknown>;
|
|
@@ -40,6 +56,10 @@ export type BlockBody = Record<string, unknown>;
|
|
|
40
56
|
* the instance count is a plan-time answer and often a state-time one, but it
|
|
41
57
|
* is a shape a reader should be told rather than left to infer from a node
|
|
42
58
|
* count that never grows.
|
|
59
|
+
*
|
|
60
|
+
* Since #4454 a literal expansion also gets its instance nodes, children of
|
|
61
|
+
* the block's node (`TerraformEntity.instanceKeys`). The block node stays,
|
|
62
|
+
* and the edges stay block to block.
|
|
43
63
|
*/
|
|
44
64
|
export type TerraformExpansion = "count" | "for_each";
|
|
45
65
|
|
|
@@ -151,6 +171,27 @@ export interface TerraformEntity extends Declarable {
|
|
|
151
171
|
* ROOT's name, not the module's: the module is not separately applied.
|
|
152
172
|
*/
|
|
153
173
|
readonly stack: string;
|
|
174
|
+
/**
|
|
175
|
+
* The instance keys a `resource` or `data` block's literal `count` or
|
|
176
|
+
* `for_each` expands to (#4454), as Terraform prints them: `[0]`, `[1]`
|
|
177
|
+
* for `count = 2`, `["a"]` for a `for_each` over a literal map or
|
|
178
|
+
* `toset([...])`. Core's `withInstanceNodes` reads this lexicon-neutral
|
|
179
|
+
* field, as `buildGraphIr` reads `stack`, and draws one instance node per
|
|
180
|
+
* key under the block's node. Absent when the block is not expanded or its
|
|
181
|
+
* expansion is not a literal. Since #4486 `./instances.ts` also sets it
|
|
182
|
+
* for an expansion it can count from the root's variables (`count = var.n`
|
|
183
|
+
* with `n` known), and for a `module` call.
|
|
184
|
+
*/
|
|
185
|
+
readonly instanceKeys?: readonly string[];
|
|
186
|
+
/**
|
|
187
|
+
* The instance nodes of a block under an expanded module call (#4486), by
|
|
188
|
+
* full node id: `estate/module.app[0]/aws_eip.pool[1]`, with `key` the
|
|
189
|
+
* block's own key (`[1]`, absent when the block is not expanded itself)
|
|
190
|
+
* and `scope` the module path as Terraform prints it (`module.app[0]`).
|
|
191
|
+
* Core's `entityInstances` reads this in place of `instanceKeys`, which
|
|
192
|
+
* such a block never carries. Set by `./instances.ts`.
|
|
193
|
+
*/
|
|
194
|
+
readonly instances?: ReadonlyArray<{ readonly id: string; readonly key?: string; readonly scope?: string }>;
|
|
154
195
|
/**
|
|
155
196
|
* Every reference in this block, resolved to the entity keys it points at
|
|
156
197
|
* (chant #2265), in core's lexicon-neutral {@link EntityReference} shape.
|
|
@@ -183,6 +224,23 @@ export const OUTPUT_TYPE = "Terraform::Output";
|
|
|
183
224
|
export const LOCALS_TYPE = "Terraform::Locals";
|
|
184
225
|
/** A `live { estate = "..." }` block, or an `estate.chdf.hcl` sidecar's content (#2103). */
|
|
185
226
|
export const LIVE_TYPE = "Terraform::Live";
|
|
227
|
+
/**
|
|
228
|
+
* The four configuration blocks that change how a plan treats addresses
|
|
229
|
+
* rather than declaring anything (#4458): `moved`, `import`, `removed` and
|
|
230
|
+
* `check`. The first three carry no label and key as `moved`, `import`,
|
|
231
|
+
* `removed` (numbered `~2`, `~3` when a root holds several, as `locals` is);
|
|
232
|
+
* a `check` keys as `check.<name>`. Their references are edges like any other
|
|
233
|
+
* block's: a `moved` block's `from` and `to`, an `import` block's `to`, a
|
|
234
|
+
* `removed` block's `from`, and everything a `check` block's assertions and
|
|
235
|
+
* scoped `data` blocks read. A `from` usually names an address that is no
|
|
236
|
+
* longer declared, which resolves to no entity and so draws no edge, and
|
|
237
|
+
* that is all that happens: an unresolved reference is dropped, never
|
|
238
|
+
* reported (`./edges.ts`).
|
|
239
|
+
*/
|
|
240
|
+
export const MOVED_TYPE = "Terraform::Moved";
|
|
241
|
+
export const IMPORT_TYPE = "Terraform::Import";
|
|
242
|
+
export const REMOVED_TYPE = "Terraform::Removed";
|
|
243
|
+
export const CHECK_TYPE = "Terraform::Check";
|
|
186
244
|
|
|
187
245
|
/**
|
|
188
246
|
* Terragrunt config entities (#3417). A `terragrunt.hcl` or `root.hcl` is not
|
|
@@ -214,6 +272,55 @@ function expansionOf(body: BlockBody): TerraformExpansion | undefined {
|
|
|
214
272
|
return undefined;
|
|
215
273
|
}
|
|
216
274
|
|
|
275
|
+
/** The most instance keys read off one literal; past it the block draws as the block alone. */
|
|
276
|
+
const MAX_LITERAL_INSTANCES = 256;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* The instance keys a literal expansion gives (#4454), as Terraform prints
|
|
280
|
+
* them, or undefined when the expansion is not a literal a read of the
|
|
281
|
+
* source can count. `count` as a number (`count = 3`), `for_each` as a
|
|
282
|
+
* literal map (`{ a = 1 }`, keys in Terraform's lexical order) or
|
|
283
|
+
* `toset([...])` over string literals. Anything holding a reference is a
|
|
284
|
+
* plan-time answer.
|
|
285
|
+
*/
|
|
286
|
+
export function literalInstanceKeys(body: BlockBody): string[] | undefined {
|
|
287
|
+
const keys = literalKeys(body);
|
|
288
|
+
if (keys === undefined || keys.length > MAX_LITERAL_INSTANCES) return undefined;
|
|
289
|
+
return keys;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function literalKeys(body: BlockBody): string[] | undefined {
|
|
293
|
+
if ("count" in body) {
|
|
294
|
+
const count = body.count;
|
|
295
|
+
const n = typeof count === "number" ? count
|
|
296
|
+
: typeof count === "string" && /^\$\{\s*\d+\s*\}$/.test(count.trim()) ? Number(count.trim().slice(2, -1))
|
|
297
|
+
: undefined;
|
|
298
|
+
if (n === undefined || !Number.isInteger(n) || n < 0) return undefined;
|
|
299
|
+
return Array.from({ length: n }, (_, i) => `[${i}]`);
|
|
300
|
+
}
|
|
301
|
+
if ("for_each" in body) {
|
|
302
|
+
const each = body.for_each;
|
|
303
|
+
if (typeof each === "object" && each !== null && !Array.isArray(each)) {
|
|
304
|
+
const names = Object.keys(each);
|
|
305
|
+
if (names.some((k) => k.includes("${"))) return undefined;
|
|
306
|
+
return names.sort().map((k) => `[${JSON.stringify(k)}]`);
|
|
307
|
+
}
|
|
308
|
+
if (typeof each === "string") {
|
|
309
|
+
const m = /^\$\{\s*toset\(\s*(\[[\s\S]*\])\s*\)\s*\}$/.exec(each.trim());
|
|
310
|
+
if (!m) return undefined;
|
|
311
|
+
let list: unknown;
|
|
312
|
+
try {
|
|
313
|
+
list = JSON.parse(m[1]!.replace(/,\s*\]$/, "]"));
|
|
314
|
+
} catch {
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
if (!Array.isArray(list) || !list.every((v) => typeof v === "string")) return undefined;
|
|
318
|
+
return [...new Set(list as string[])].sort().map((k) => `[${JSON.stringify(k)}]`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
323
|
+
|
|
217
324
|
/**
|
|
218
325
|
* Build one entity. Written out rather than run through `createResource`
|
|
219
326
|
* from `@intentius/chant/runtime`: that factory is for generated resource
|
|
@@ -234,6 +341,7 @@ export function terraformEntity(
|
|
|
234
341
|
suppressions?: readonly SuppressionDirective[],
|
|
235
342
|
): TerraformEntity {
|
|
236
343
|
const expansion = expansionOf(body);
|
|
344
|
+
const instanceKeys = expansion && (entityType === RESOURCE_TYPE || entityType === DATA_TYPE) ? literalInstanceKeys(body) : undefined;
|
|
237
345
|
const labels = entityType === RESOURCE_TYPE ? blockLabels(address)
|
|
238
346
|
: entityType === DATA_TYPE && address.startsWith("data.") ? blockLabels(address.slice("data.".length))
|
|
239
347
|
: undefined;
|
|
@@ -243,6 +351,7 @@ export function terraformEntity(
|
|
|
243
351
|
entityType,
|
|
244
352
|
kind: "resource",
|
|
245
353
|
stack: root,
|
|
354
|
+
...(instanceKeys ? { instanceKeys } : {}),
|
|
246
355
|
props: {
|
|
247
356
|
address,
|
|
248
357
|
...(labels ?? {}),
|
|
@@ -302,11 +411,20 @@ export function splitBundleContent(content: string, fallbackName = "main.tf"): T
|
|
|
302
411
|
return files.filter((f) => f.source.trim() !== "");
|
|
303
412
|
}
|
|
304
413
|
|
|
305
|
-
/**
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
414
|
+
/**
|
|
415
|
+
* Every configuration file directly under `dir` that a root run by `binary`
|
|
416
|
+
* reads, in filename order, non-recursive: `.tf` and `.tf.json`, plus `.tofu`
|
|
417
|
+
* and `.tofu.json` for a tofu or choudoufu root, with `x.tofu` shadowing
|
|
418
|
+
* `x.tf` (chant#4457). The shared lister is `./files.ts`'s `listConfigFiles`.
|
|
419
|
+
*/
|
|
420
|
+
export function listTerraformFiles(dir: string, binary?: string): string[] {
|
|
421
|
+
return listConfigFiles(dir, binary);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/** One file's tree in hcl2json's shape: hcl2json for HCL, {@link jsonConfigTree} for Terraform's JSON syntax. */
|
|
425
|
+
export async function parseFileTree(parser: Hcl2Json, file: TerraformFile): Promise<Record<string, unknown>> {
|
|
426
|
+
if (isJsonConfigFile(file.name)) return jsonConfigTree(file.source);
|
|
427
|
+
return (await parser.parse(file.name, file.source)) as Record<string, unknown>;
|
|
310
428
|
}
|
|
311
429
|
|
|
312
430
|
/** The Terragrunt config files directly under `dir` (`root.hcl`, `terragrunt.hcl`), in filename order like the audit's bundle. */
|
|
@@ -488,7 +606,7 @@ export async function blocksToEntities(
|
|
|
488
606
|
};
|
|
489
607
|
|
|
490
608
|
for (const file of files) {
|
|
491
|
-
const tree =
|
|
609
|
+
const tree = await parseFileTree(parser, file);
|
|
492
610
|
const scan = scanSuppressions(file.name, file.source);
|
|
493
611
|
if (isTerragruntFileName(file.name)) {
|
|
494
612
|
terragruntBlocks(tree, file, scan, add);
|
|
@@ -503,6 +621,10 @@ export async function blocksToEntities(
|
|
|
503
621
|
oneLabel(tree, "output", OUTPUT_TYPE, (n) => `output.${n}`, file, scan);
|
|
504
622
|
twoLabels(tree, "resource", RESOURCE_TYPE, (t, n) => `${t}.${n}`, file, scan);
|
|
505
623
|
twoLabels(tree, "data", DATA_TYPE, (t, n) => `data.${t}.${n}`, file, scan);
|
|
624
|
+
unlabelled(tree, "moved", MOVED_TYPE, file, scan);
|
|
625
|
+
unlabelled(tree, "import", IMPORT_TYPE, file, scan);
|
|
626
|
+
unlabelled(tree, "removed", REMOVED_TYPE, file, scan);
|
|
627
|
+
oneLabel(tree, "check", CHECK_TYPE, (n) => `check.${n}`, file, scan);
|
|
506
628
|
}
|
|
507
629
|
|
|
508
630
|
if (sidecar) {
|
|
@@ -568,8 +690,9 @@ function terragruntBlocks(
|
|
|
568
690
|
}
|
|
569
691
|
|
|
570
692
|
/**
|
|
571
|
-
* Parse a root module directory. Reads
|
|
572
|
-
*
|
|
693
|
+
* Parse a root module directory. Reads the configuration files directly under
|
|
694
|
+
* `dir` that `modeOptions.binary` reads ({@link listTerraformFiles}), plus the
|
|
695
|
+
* `estate.chdf.hcl` sidecar beside them when present. Throws whatever the
|
|
573
696
|
* parser throws for malformed HCL; `buildRoots()` is where that becomes a
|
|
574
697
|
* warning.
|
|
575
698
|
*/
|
|
@@ -581,7 +704,7 @@ export async function parseTerraformRootDir(
|
|
|
581
704
|
callers: readonly string[] = [],
|
|
582
705
|
): Promise<Map<string, Declarable>> {
|
|
583
706
|
// A child module is a Terraform module, never a Terragrunt unit (#3417).
|
|
584
|
-
const names = [...listTerraformFiles(dir), ...(callers.length === 0 ? listTerragruntFiles(dir) : [])];
|
|
707
|
+
const names = [...listTerraformFiles(dir, modeOptions?.binary), ...(callers.length === 0 ? listTerragruntFiles(dir) : [])];
|
|
585
708
|
const files = names.map((name) => ({
|
|
586
709
|
name,
|
|
587
710
|
source: readFileSync(join(dir, name), "utf-8"),
|
|
@@ -610,7 +733,17 @@ export async function parseTerraformRootContent(
|
|
|
610
733
|
hcl2json?: Hcl2Json,
|
|
611
734
|
modeOptions?: TerraformRootModeOptions,
|
|
612
735
|
): Promise<Map<string, Declarable>> {
|
|
613
|
-
return blocksToEntities(splitBundleContent(content), root, hcl2json, modeOptions);
|
|
736
|
+
return blocksToEntities(bundleFilesFor(splitBundleContent(content), modeOptions?.binary), root, hcl2json, modeOptions);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* The files of a joined bundle a root run by `binary` reads: the same set
|
|
741
|
+
* {@link listTerraformFiles} gives for a directory holding them, plus the
|
|
742
|
+
* Terragrunt files, in bundle order (chant#4457).
|
|
743
|
+
*/
|
|
744
|
+
export function bundleFilesFor(files: readonly TerraformFile[], binary?: string): TerraformFile[] {
|
|
745
|
+
const keep = new Set(selectConfigFiles(files.map((f) => f.name), binary));
|
|
746
|
+
return files.filter((f) => keep.has(f.name) || isTerragruntFileName(f.name));
|
|
614
747
|
}
|
|
615
748
|
|
|
616
749
|
/** The root name an audit of the audited directory itself parses under. */
|
package/src/hcl/roots.ts
CHANGED
|
@@ -34,6 +34,7 @@ import type { TerraformRootConfig } from "../config";
|
|
|
34
34
|
import { LIVE_TYPE, parseTerraformRootDir } from "./parse";
|
|
35
35
|
import { descendModules, resolveCallModuleType, type CallModuleType } from "./descend";
|
|
36
36
|
import { resolveEntityReferences } from "./edges";
|
|
37
|
+
import { resolveInstanceNodes } from "./instances";
|
|
37
38
|
|
|
38
39
|
export interface TerraformRootsResult {
|
|
39
40
|
entities: Map<string, Declarable>;
|
|
@@ -111,6 +112,11 @@ export async function renderTerraformRoots(
|
|
|
111
112
|
for (const [key, entity] of descended.entities) entities.set(key, entity);
|
|
112
113
|
warnings.push(...descended.warnings);
|
|
113
114
|
|
|
115
|
+
// Instance nodes the root's variables let the declared graph count,
|
|
116
|
+
// and those under expanded module calls (#4486). Needs the root and
|
|
117
|
+
// every child scope parsed, so it runs once the descent has.
|
|
118
|
+
await resolveInstanceNodes(entities, name, { dir, ...(root.varFiles ? { varFiles: root.varFiles } : {}), hcl2json: opts.hcl2json });
|
|
119
|
+
|
|
114
120
|
// A `live` block or `estate.chdf.hcl` sidecar only takes effect under
|
|
115
121
|
// choudoufu; under any other binary it parses fine but is inert, which
|
|
116
122
|
// is worth a warning rather than silence (#2103).
|
package/src/hcl/suppressions.ts
CHANGED
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
import type { SuppressionDirective, SuppressionIds } from "@intentius/chant/lint/suppressions";
|
|
28
28
|
|
|
29
29
|
/** A block header keyword with zero labels (`terraform {`, `locals {`). */
|
|
30
|
-
const BARE_RE = /^\s*(terraform|locals|remote_state)\s*\{/;
|
|
30
|
+
const BARE_RE = /^\s*(terraform|locals|remote_state|moved|import|removed)\s*\{/;
|
|
31
31
|
/** One label (`provider "aws" {`, `module "vpc" {`, `variable "x" {`, `output "x" {`). */
|
|
32
|
-
const ONE_LABEL_RE = /^\s*(provider|module|variable|output|dependency|generate)\s+"([^"]*)"\s*\{/;
|
|
32
|
+
const ONE_LABEL_RE = /^\s*(provider|module|variable|output|check|dependency|generate)\s+"([^"]*)"\s*\{/;
|
|
33
33
|
/** Two labels (`resource "aws_s3_bucket" "assets" {`, `data "aws_ami" "x" {`). */
|
|
34
34
|
const TWO_LABEL_RE = /^\s*(resource|data)\s+"([^"]*)"\s+"([^"]*)"\s*\{/;
|
|
35
35
|
|
|
@@ -45,6 +45,12 @@ function addressFor(keyword: string, labels: string[]): string {
|
|
|
45
45
|
return "locals";
|
|
46
46
|
case "remote_state":
|
|
47
47
|
return "remote_state";
|
|
48
|
+
case "moved":
|
|
49
|
+
case "import":
|
|
50
|
+
case "removed":
|
|
51
|
+
return keyword;
|
|
52
|
+
case "check":
|
|
53
|
+
return `check.${labels[0]}`;
|
|
48
54
|
case "dependency":
|
|
49
55
|
return `dependency.${labels[0]}`;
|
|
50
56
|
case "generate":
|
package/src/index.ts
CHANGED
|
@@ -10,10 +10,86 @@ export {
|
|
|
10
10
|
terraformApplyCapability,
|
|
11
11
|
TerraformPlanMovedError,
|
|
12
12
|
TERRAFORM_VERB_FAMILIES,
|
|
13
|
+
// #4455: a choudoufu member's outputs, read for core's `member-outputs`.
|
|
14
|
+
choudoufuOutputSource,
|
|
15
|
+
choudoufuMemberPlannedOutputs,
|
|
13
16
|
type TerraformApplyStepInput,
|
|
14
17
|
type TerraformApplyStepOutput,
|
|
15
18
|
} from "./components/capability-plugin";
|
|
16
19
|
|
|
20
|
+
// Composed runs (#4442): the working state merged and split, the composed
|
|
21
|
+
// plan cut into one plan per member, and each member's apply outcome.
|
|
22
|
+
export { mergeStates, splitState, splitStates, derivedLineage, COMPOSE_LINEAGE, type SplitState } from "./compose/state-merge";
|
|
23
|
+
export {
|
|
24
|
+
slicePlan as sliceComposedPlan,
|
|
25
|
+
sliceText,
|
|
26
|
+
planCounts,
|
|
27
|
+
composedReads,
|
|
28
|
+
composedMemberPlans,
|
|
29
|
+
type PlanCounts,
|
|
30
|
+
type ComposedMemberRead,
|
|
31
|
+
type ComposedMemberPlan,
|
|
32
|
+
type ComposedMemberPlansOptions,
|
|
33
|
+
} from "./compose/slice";
|
|
34
|
+
export { readApplyEvents, memberApply, composedApplyOutcomes, type ApplyEvents, type MemberApply, type MemberApplyOutcome } from "./compose/apply-events";
|
|
35
|
+
export { topModule, stripModule, stripChange, moduleChanges } from "./compose/module-address";
|
|
36
|
+
|
|
37
|
+
// Composed runs of choudoufu estates (#4445): one plan and one apply, values read from a post-apply plan.
|
|
38
|
+
export {
|
|
39
|
+
EstateRun,
|
|
40
|
+
estateVersionFallback,
|
|
41
|
+
estateOutcomes,
|
|
42
|
+
readEstateApplyText,
|
|
43
|
+
type ComposedRunner,
|
|
44
|
+
type ComposedRunPlan,
|
|
45
|
+
type ComposedRunApply,
|
|
46
|
+
type ComposedMemberOutcome,
|
|
47
|
+
type EstateRunOptions,
|
|
48
|
+
} from "./compose/estate";
|
|
49
|
+
export { priorStateValues, stateResources, stateOutputs, type StateResourceValues } from "./applied-state";
|
|
50
|
+
|
|
51
|
+
// Composed runs over roots with state (#4444): one plan and one apply, each
|
|
52
|
+
// state written back whatever happened. Implements `ComposedRunner` (#4445).
|
|
53
|
+
export {
|
|
54
|
+
ComposedRun,
|
|
55
|
+
composedPlanDigest,
|
|
56
|
+
changesSomething,
|
|
57
|
+
type ComposedRunOptions,
|
|
58
|
+
type ComposedRunStage,
|
|
59
|
+
type StateRunPlan,
|
|
60
|
+
type StateRunApply,
|
|
61
|
+
type StateMemberOutcome,
|
|
62
|
+
type ComposedStateWrite,
|
|
63
|
+
type ComposeHook,
|
|
64
|
+
type ComposeHookMoment,
|
|
65
|
+
} from "./compose/run";
|
|
66
|
+
|
|
67
|
+
// The plan shape of a `show -json` plan (#4436), for core's `coveredRound`.
|
|
68
|
+
export { terraformPlanShape, type TerraformPlanShapeOptions } from "./plan-shape";
|
|
69
|
+
export { terraformLockRows, terraformLockRowsFromPart, terraformDefaultLockGrain, terraformLockGrainRefusal } from "./lock-rows";
|
|
70
|
+
|
|
71
|
+
// Composed runs (#4419, #4438): which roots compose, in what order, and why
|
|
72
|
+
// the others fall back. Off unless `terraform.compose.enabled` is set.
|
|
73
|
+
export {
|
|
74
|
+
compositionFor,
|
|
75
|
+
compositionIfEnabled,
|
|
76
|
+
composeOff,
|
|
77
|
+
composeSet,
|
|
78
|
+
readOrder,
|
|
79
|
+
moduleNames,
|
|
80
|
+
fallbackLine,
|
|
81
|
+
withPlanFailed,
|
|
82
|
+
identityKey,
|
|
83
|
+
DEFAULT_COMPOSE_MAX,
|
|
84
|
+
COMPOSE_STEP_KIND,
|
|
85
|
+
type Composition,
|
|
86
|
+
type CompositionInput,
|
|
87
|
+
type ComposedRead,
|
|
88
|
+
type ComposeFallback,
|
|
89
|
+
type ComposeFallbackKind,
|
|
90
|
+
type ExpectedBinary,
|
|
91
|
+
} from "./compose";
|
|
92
|
+
|
|
17
93
|
// Serializer
|
|
18
94
|
export { terraformSerializer } from "./serializer";
|
|
19
95
|
|
|
@@ -68,6 +144,7 @@ export {
|
|
|
68
144
|
choudoufuLiveLs,
|
|
69
145
|
choudoufuLiveCheck,
|
|
70
146
|
choudoufuAdopt,
|
|
147
|
+
choudoufuPlanSet,
|
|
71
148
|
terraformPinRollout,
|
|
72
149
|
} from "./op/builders";
|
|
73
150
|
|
|
@@ -132,3 +209,5 @@ export {
|
|
|
132
209
|
type TerraformLiveRead,
|
|
133
210
|
type TerraformPredictOptions,
|
|
134
211
|
} from "./behaviour";
|
|
212
|
+
// terraform, tofu and choudoufu exit statuses on chant's exit-code table (#4553).
|
|
213
|
+
export { terraformExitOf, terraformPlanMoved, type TerraformExitSource } from "./exit-codes";
|
|
@@ -88,10 +88,11 @@ export const terraformAuditCatalog: Record<string, RuleMeta> = {
|
|
|
88
88
|
tier: "merge-worthy",
|
|
89
89
|
fixKind: "guidance",
|
|
90
90
|
category: "correctness",
|
|
91
|
-
title: "Live root declares a backend or cloud block, which choudoufu
|
|
91
|
+
title: "Live root declares a backend or cloud block, which choudoufu ignores",
|
|
92
92
|
remediation:
|
|
93
|
-
"
|
|
94
|
-
"
|
|
93
|
+
"Keep a `backend` block if other roots read this estate's outputs or the record store should be " +
|
|
94
|
+
"derived from its bucket; declare `record_store` to put records elsewhere. Remove a `cloud` block, " +
|
|
95
|
+
"which choudoufu drops entirely, or swap it for a `backend` block.",
|
|
95
96
|
yamlBased: false,
|
|
96
97
|
},
|
|
97
98
|
TF025: {
|
|
@@ -551,6 +552,31 @@ export const terraformAuditCatalog: Record<string, RuleMeta> = {
|
|
|
551
552
|
'Set `terragrunt_version_constraint = ">= 1.1.0"` in the root config. Off by default; judged only across the configs scanned.',
|
|
552
553
|
yamlBased: false,
|
|
553
554
|
},
|
|
555
|
+
TF046: {
|
|
556
|
+
id: "TF046",
|
|
557
|
+
tier: "report-only",
|
|
558
|
+
fixKind: "guidance",
|
|
559
|
+
category: "correctness",
|
|
560
|
+
title: "Live root resolves to the local record store in a CI run",
|
|
561
|
+
remediation:
|
|
562
|
+
"Keep or add a `backend` block of type s3, gcs or azurerm with a literal bucket, so choudoufu " +
|
|
563
|
+
"derives the record store from it, or declare `record_store` in the live block or `estate.chdf.hcl`. " +
|
|
564
|
+
"The rule is off by default and terragucci turns it on for its users; an emulator or test lane " +
|
|
565
|
+
"that keeps the local store on purpose sets `CHANT_ALLOW_LOCAL_RECORD_STORE=1`.",
|
|
566
|
+
yamlBased: false,
|
|
567
|
+
},
|
|
568
|
+
TF047: {
|
|
569
|
+
id: "TF047",
|
|
570
|
+
tier: "report-only",
|
|
571
|
+
fixKind: "guidance",
|
|
572
|
+
category: "correctness",
|
|
573
|
+
title: "Live root pins a module version the known-module catalog has no row for, or one with refusals",
|
|
574
|
+
remediation:
|
|
575
|
+
"Run `choudoufu live-check` on the root to see each refused site, or pin a version whose examples are clear in " +
|
|
576
|
+
"the static tier of choudoufu's module table (https://intentius.io/choudoufu/aws/compatibility/#modules). " +
|
|
577
|
+
"Off by default; terragucci turns it on for its users.",
|
|
578
|
+
yamlBased: false,
|
|
579
|
+
},
|
|
554
580
|
};
|
|
555
581
|
|
|
556
582
|
// Prior art credits, if any, live beside the rules in ./audit-lineage.ts (see
|
|
@@ -76,8 +76,8 @@
|
|
|
76
76
|
*
|
|
77
77
|
* TF024 (#2103, live root declares a backend/cloud block) credits choudoufu's
|
|
78
78
|
* own `RuleStateBackend`, `internal/live/lint/issue.go` of
|
|
79
|
-
* github.com/INTENTIUS/choudoufu: the
|
|
80
|
-
*
|
|
79
|
+
* github.com/INTENTIUS/choudoufu: the same condition, which choudoufu has
|
|
80
|
+
* reported as a warning since its #2213 (the block is ignored, not refused). TF025 (a live
|
|
81
81
|
* root's non-default `terraform.workspace`) has no entry: its workspace half
|
|
82
82
|
* is refused at the CLI argument-parsing layer there
|
|
83
83
|
* (`internal/command/live_mode.go`), not by a dedicated lint rule under
|
|
@@ -110,6 +110,18 @@
|
|
|
110
110
|
* a root's mode, and no surveyed tool has an Op model to read: choudoufu lints
|
|
111
111
|
* HCL, and every tflint ruleset, tfsec/trivy-checks and the Sentinel policies
|
|
112
112
|
* do the same. There is nothing upstream to credit.
|
|
113
|
+
*
|
|
114
|
+
* TF046 (chant#4561, a live root on the local record store in a CI run) has
|
|
115
|
+
* no entry. choudoufu prints where records go on every run and reports a
|
|
116
|
+
* `record_store.note` in `live-check -json` (INTENTIUS/choudoufu#2293), but
|
|
117
|
+
* it has no `internal/live/lint` rule for the local store, and no surveyed
|
|
118
|
+
* tool knows about record stores. TF044 is the nearest neighbour, for a
|
|
119
|
+
* Terragrunt state backend.
|
|
120
|
+
*
|
|
121
|
+
* TF047 (chant#4560, a live root pins a module version the known-module
|
|
122
|
+
* catalog has no row for, or one with refusals) has no entry. Its data is
|
|
123
|
+
* choudoufu's own module table (choudoufu#2292), vendored; no surveyed tool
|
|
124
|
+
* checks a module pin against a measured compatibility table.
|
|
113
125
|
*/
|
|
114
126
|
import type { Lineage } from "@intentius/chant/audit/catalog";
|
|
115
127
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
terraform {
|
|
2
|
+
required_version = ">= 1.5.0"
|
|
3
|
+
|
|
4
|
+
live {
|
|
5
|
+
estate = "fixture-estate"
|
|
6
|
+
|
|
7
|
+
record_store "s3" {
|
|
8
|
+
bucket = "fixture-records"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
backend "s3" {
|
|
13
|
+
bucket = "tfstate"
|
|
14
|
+
key = "fixture/terraform.tfstate"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
resource "null_resource" "first" {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
estate = "fixture-estate"
|