@intentius/chant-lexicon-terraform 0.101.0 → 0.104.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/dist/__fixtures__/terragrunt/affected-cases.d.ts +23 -0
- package/dist/__fixtures__/terragrunt/affected-cases.d.ts.map +1 -0
- package/dist/__fixtures__/terragrunt/record.d.ts +17 -0
- package/dist/__fixtures__/terragrunt/record.d.ts.map +1 -0
- package/dist/change-set.d.ts +67 -0
- package/dist/change-set.d.ts.map +1 -0
- package/dist/changed-roots.d.ts +30 -0
- package/dist/changed-roots.d.ts.map +1 -0
- package/dist/codegen/package.d.ts +1 -1
- package/dist/commands.d.ts +26 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/components/capability-plugin.d.ts +54 -0
- package/dist/components/capability-plugin.d.ts.map +1 -0
- package/dist/composites/terraform-pin-rollout-op.d.ts +44 -0
- package/dist/composites/terraform-pin-rollout-op.d.ts.map +1 -0
- package/dist/config.d.ts +3 -3
- package/dist/hcl/descend.d.ts +1 -1
- package/dist/hcl/descend.d.ts.map +1 -1
- package/dist/hcl/edges.d.ts +2 -2
- package/dist/hcl/edges.d.ts.map +1 -1
- package/dist/hcl/jsonencode.d.ts +106 -0
- package/dist/hcl/jsonencode.d.ts.map +1 -0
- package/dist/hcl/marker.d.ts.map +1 -1
- package/dist/hcl/parse.d.ts +29 -1
- package/dist/hcl/parse.d.ts.map +1 -1
- package/dist/hcl/roots.d.ts +1 -1
- package/dist/hcl/roots.d.ts.map +1 -1
- package/dist/hcl/suppressions.d.ts.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +22 -4
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/audit-lineage.d.ts +1 -1
- package/dist/lint/audit-lineage.d.ts.map +1 -1
- package/dist/lint/post-synth/flat-attributes.d.ts +69 -0
- package/dist/lint/post-synth/flat-attributes.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 +27 -1
- package/dist/lint/post-synth/module-source.d.ts.map +1 -1
- package/dist/lint/post-synth/terragrunt.d.ts +37 -0
- package/dist/lint/post-synth/terragrunt.d.ts.map +1 -0
- package/dist/lint/post-synth/tf002.d.ts +3 -1
- package/dist/lint/post-synth/tf002.d.ts.map +1 -1
- package/dist/lint/post-synth/tf030.d.ts +51 -0
- package/dist/lint/post-synth/tf030.d.ts.map +1 -0
- package/dist/lint/post-synth/tf031.d.ts +55 -0
- package/dist/lint/post-synth/tf031.d.ts.map +1 -0
- package/dist/lint/post-synth/tf032.d.ts +71 -0
- package/dist/lint/post-synth/tf032.d.ts.map +1 -0
- package/dist/lint/post-synth/tf033.d.ts +50 -0
- package/dist/lint/post-synth/tf033.d.ts.map +1 -0
- package/dist/lint/post-synth/tf034.d.ts +25 -0
- package/dist/lint/post-synth/tf034.d.ts.map +1 -0
- package/dist/lint/post-synth/tf035.d.ts +33 -0
- package/dist/lint/post-synth/tf035.d.ts.map +1 -0
- package/dist/lint/post-synth/tf036.d.ts +33 -0
- package/dist/lint/post-synth/tf036.d.ts.map +1 -0
- package/dist/lint/post-synth/tf037.d.ts +31 -0
- package/dist/lint/post-synth/tf037.d.ts.map +1 -0
- package/dist/lint/post-synth/tf038.d.ts +22 -0
- package/dist/lint/post-synth/tf038.d.ts.map +1 -0
- package/dist/lint/post-synth/tf039.d.ts +23 -0
- package/dist/lint/post-synth/tf039.d.ts.map +1 -0
- package/dist/lint/post-synth/tf040.d.ts +30 -0
- package/dist/lint/post-synth/tf040.d.ts.map +1 -0
- package/dist/lint/post-synth/tf041.d.ts +20 -0
- package/dist/lint/post-synth/tf041.d.ts.map +1 -0
- package/dist/lint/post-synth/tf042.d.ts +18 -0
- package/dist/lint/post-synth/tf042.d.ts.map +1 -0
- package/dist/lint/post-synth/tf043.d.ts +17 -0
- package/dist/lint/post-synth/tf043.d.ts.map +1 -0
- package/dist/lint/post-synth/tf044.d.ts +17 -0
- package/dist/lint/post-synth/tf044.d.ts.map +1 -0
- package/dist/lint/post-synth/tf045.d.ts +22 -0
- package/dist/lint/post-synth/tf045.d.ts.map +1 -0
- package/dist/manifest.json +1 -1
- package/dist/okf/index.md +16 -0
- package/dist/okf/rules/TF030.md +11 -0
- package/dist/okf/rules/TF031.md +11 -0
- package/dist/okf/rules/TF032.md +11 -0
- package/dist/okf/rules/TF033.md +11 -0
- package/dist/okf/rules/TF034.md +11 -0
- package/dist/okf/rules/TF035.md +11 -0
- package/dist/okf/rules/TF036.md +11 -0
- package/dist/okf/rules/TF037.md +11 -0
- package/dist/okf/rules/TF038.md +11 -0
- package/dist/okf/rules/TF039.md +11 -0
- package/dist/okf/rules/TF040.md +11 -0
- package/dist/okf/rules/TF041.md +11 -0
- package/dist/okf/rules/TF042.md +11 -0
- package/dist/okf/rules/TF043.md +11 -0
- package/dist/okf/rules/TF044.md +11 -0
- package/dist/okf/rules/TF045.md +11 -0
- package/dist/op/activities/index.d.ts +4 -0
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/pin-rollout.d.ts +46 -0
- package/dist/op/activities/pin-rollout.d.ts.map +1 -0
- package/dist/op/activities/terraform.d.ts +24 -50
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/activity-contracts.d.ts +66 -18
- package/dist/op/activity-contracts.d.ts.map +1 -1
- package/dist/op/builders.d.ts +9 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/pin/edit-ts.d.ts +21 -0
- package/dist/pin/edit-ts.d.ts.map +1 -0
- package/dist/pin/edit.d.ts +52 -0
- package/dist/pin/edit.d.ts.map +1 -0
- package/dist/pin/forge.d.ts +39 -0
- package/dist/pin/forge.d.ts.map +1 -0
- package/dist/pin/index.d.ts +22 -0
- package/dist/pin/index.d.ts.map +1 -0
- package/dist/pin/rollout.d.ts +116 -0
- package/dist/pin/rollout.d.ts.map +1 -0
- package/dist/pin/scan.d.ts +54 -0
- package/dist/pin/scan.d.ts.map +1 -0
- package/dist/pin/source.d.ts +93 -0
- package/dist/pin/source.d.ts.map +1 -0
- package/dist/pin/waves.d.ts +66 -0
- package/dist/pin/waves.d.ts.map +1 -0
- package/dist/plan-digest.d.ts +59 -0
- package/dist/plan-digest.d.ts.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/rules/flat-attributes.ts +146 -0
- package/dist/rules/module-source.ts +56 -1
- package/dist/rules/terragrunt.ts +76 -0
- package/dist/rules/tf002.ts +1 -1
- package/dist/rules/tf030.ts +290 -0
- package/dist/rules/tf031.ts +370 -0
- package/dist/rules/tf032.ts +226 -0
- package/dist/rules/tf033.ts +160 -0
- package/dist/rules/tf034.ts +63 -0
- package/dist/rules/tf035.ts +74 -0
- package/dist/rules/tf036.ts +119 -0
- package/dist/rules/tf037.ts +101 -0
- package/dist/rules/tf038.ts +71 -0
- package/dist/rules/tf039.ts +64 -0
- package/dist/rules/tf040.ts +76 -0
- package/dist/rules/tf041.ts +56 -0
- package/dist/rules/tf042.ts +42 -0
- package/dist/rules/tf043.ts +49 -0
- package/dist/rules/tf044.ts +51 -0
- package/dist/rules/tf045.ts +47 -0
- package/dist/terragrunt/affected.d.ts +119 -0
- package/dist/terragrunt/affected.d.ts.map +1 -0
- package/dist/terragrunt/index.d.ts +11 -0
- package/dist/terragrunt/index.d.ts.map +1 -0
- package/dist/terragrunt/mocks.d.ts +147 -0
- package/dist/terragrunt/mocks.d.ts.map +1 -0
- package/dist/terragrunt/run.d.ts +130 -0
- package/dist/terragrunt/run.d.ts.map +1 -0
- package/dist/terragrunt/units.d.ts +103 -0
- package/dist/terragrunt/units.d.ts.map +1 -0
- package/dist/terragrunt/wave.d.ts +89 -0
- package/dist/terragrunt/wave.d.ts.map +1 -0
- package/package.json +13 -3
- package/src/__fixtures__/change-set/choudoufu-set-plan.change-set.golden.json +95 -0
- package/src/__fixtures__/change-set/choudoufu-set-plan.json +76 -0
- package/src/__fixtures__/change-set/choudoufu.part.golden.json +173 -0
- package/src/__fixtures__/change-set/choudoufu.plan.json +610 -0
- package/src/__fixtures__/change-set/terraform.import-forget.plan.json +81 -0
- package/src/__fixtures__/change-set/terraform.part.golden.json +173 -0
- package/src/__fixtures__/change-set/terraform.plan.json +589 -0
- package/src/__fixtures__/change-set/tofu.part.golden.json +173 -0
- package/src/__fixtures__/change-set/tofu.plan.json +588 -0
- package/src/__fixtures__/change-set/v1.tf.txt +21 -0
- package/src/__fixtures__/change-set/v2-module-app.tf.txt +4 -0
- package/src/__fixtures__/change-set/v2.tf.txt +21 -0
- package/src/__fixtures__/pin/choudoufu-live-waves-n5.json +83 -0
- package/src/__fixtures__/pin/largeset-oci-n5/apply-order.txt +5 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e01/estate.chdf.hcl +6 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e01/main.tf +33 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e02/estate.chdf.hcl +6 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e02/main.tf +45 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e03/estate.chdf.hcl +6 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e03/main.tf +47 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e04/estate.chdf.hcl +6 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e04/main.tf +31 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e05/estate.chdf.hcl +6 -0
- package/src/__fixtures__/pin/largeset-oci-n5/estates/e05/main.tf +27 -0
- package/src/__fixtures__/pin/largeset-oci-n5/fixture.json +77 -0
- package/src/__fixtures__/plan-summary/largeset-n5-bump.json +2071 -0
- package/src/__fixtures__/plan-summary/largeset-n5.summary.golden.json +95 -0
- package/src/__fixtures__/plan-summary/largeset-n5.summary.golden.md +22 -0
- package/src/__fixtures__/plan-summary/largeset-n5.summary.golden.txt +12 -0
- package/src/__fixtures__/terragrunt/affected/catalog/units/web/terragrunt.hcl +3 -0
- package/src/__fixtures__/terragrunt/affected/gitignore +3 -0
- package/src/__fixtures__/terragrunt/affected/live/dev/app/terragrunt.hcl +3 -0
- package/src/__fixtures__/terragrunt/affected/live/dev/vpc/terragrunt.hcl +3 -0
- package/src/__fixtures__/terragrunt/affected/live/prod/app/terragrunt.hcl +3 -0
- package/src/__fixtures__/terragrunt/affected/live/stg/terragrunt.stack.hcl +5 -0
- package/src/__fixtures__/terragrunt/affected/modules/app/main.tf +6 -0
- package/src/__fixtures__/terragrunt/affected/modules/app/policy.json +1 -0
- package/src/__fixtures__/terragrunt/affected/modules/net/main.tf +2 -0
- package/src/__fixtures__/terragrunt/affected/modules/thing/main.tf +3 -0
- package/src/__fixtures__/terragrunt/affected/root.hcl +5 -0
- package/src/__fixtures__/terragrunt/affected-cases.ts +126 -0
- package/src/__fixtures__/terragrunt/five-units/catalog/units/thing/terragrunt.hcl +3 -0
- package/src/__fixtures__/terragrunt/five-units/live/dev/app/terragrunt.hcl +13 -0
- package/src/__fixtures__/terragrunt/five-units/live/dev/db/terragrunt.hcl +8 -0
- package/src/__fixtures__/terragrunt/five-units/live/dev/vpc/terragrunt.hcl +3 -0
- package/src/__fixtures__/terragrunt/five-units/live/prod/app/terragrunt.hcl +8 -0
- package/src/__fixtures__/terragrunt/five-units/live/prod/vpc/terragrunt.hcl +3 -0
- package/src/__fixtures__/terragrunt/five-units/modules/thing/main.tf +7 -0
- package/src/__fixtures__/terragrunt/five-units/root.hcl +5 -0
- package/src/__fixtures__/terragrunt/record.ts +56 -0
- package/src/__fixtures__/terragrunt/recorded/affected-find.json +50 -0
- package/src/__fixtures__/terragrunt/recorded/failed-plan-report.json +36 -0
- package/src/__fixtures__/terragrunt/recorded/find.json +67 -0
- package/src/__fixtures__/terragrunt/recorded/version.txt +1 -0
- package/src/__fixtures__/terragrunt/recorded/wave-1/apply-report.json +22 -0
- package/src/__fixtures__/terragrunt/recorded/wave-1/json/live/dev/vpc/tfplan.json +1 -0
- package/src/__fixtures__/terragrunt/recorded/wave-1/json/live/prod/vpc/tfplan.json +1 -0
- package/src/__fixtures__/terragrunt/recorded/wave-1/plan-report.json +22 -0
- package/src/__fixtures__/terragrunt/recorded/wave-2/json/live/dev/db/tfplan.json +1 -0
- package/src/__fixtures__/terragrunt/recorded/wave-2/json/live/prod/app/tfplan.json +1 -0
- package/src/__fixtures__/terragrunt/recorded/wave-2/plan-report.json +22 -0
- package/src/change-set-combined-run.test.ts +156 -0
- package/src/change-set.test.ts +151 -0
- package/src/change-set.ts +273 -0
- package/src/changed-roots.test.ts +58 -0
- package/src/changed-roots.ts +102 -0
- package/src/commands.ts +112 -0
- package/src/components/capability-plugin.test.ts +91 -0
- package/src/components/capability-plugin.ts +131 -0
- package/src/components/pr-loop.tofu.test.ts +244 -0
- package/src/composites/terraform-pin-rollout-op.test.ts +69 -0
- package/src/composites/terraform-pin-rollout-op.ts +60 -0
- package/src/hcl/descend.ts +1 -1
- package/src/hcl/edges.ts +2 -2
- package/src/hcl/jsonencode.test.ts +226 -0
- package/src/hcl/jsonencode.ts +454 -0
- package/src/hcl/parse.test.ts +25 -0
- package/src/hcl/parse.ts +91 -6
- package/src/hcl/roots.ts +1 -1
- package/src/hcl/suppressions.ts +8 -2
- package/src/index.ts +18 -0
- package/src/lint/audit-catalog.ts +230 -0
- package/src/lint/audit-lineage.ts +155 -1
- package/src/lint/audit.test.ts +3 -1
- package/src/lint/post-synth/estate-2284.test.ts +68 -0
- package/src/lint/post-synth/fixtures/TF030/negative-rules.tf +45 -0
- package/src/lint/post-synth/fixtures/TF030/negative.tf +55 -0
- package/src/lint/post-synth/fixtures/TF030/not-determined-port.tf +28 -0
- package/src/lint/post-synth/fixtures/TF030/not-determined-standalone.tf +32 -0
- package/src/lint/post-synth/fixtures/TF030/not-determined-vpc-rule.tf +21 -0
- package/src/lint/post-synth/fixtures/TF030/not-determined.tf +39 -0
- package/src/lint/post-synth/fixtures/TF030/positive-ipv6.tf +44 -0
- package/src/lint/post-synth/fixtures/TF030/positive-mixed.tf +36 -0
- package/src/lint/post-synth/fixtures/TF030/positive-standalone.tf +25 -0
- package/src/lint/post-synth/fixtures/TF030/positive.tf +43 -0
- package/src/lint/post-synth/fixtures/TF031/negative.tf +89 -0
- package/src/lint/post-synth/fixtures/TF031/not-determined.tf +139 -0
- package/src/lint/post-synth/fixtures/TF031/positive-data-source.tf +57 -0
- package/src/lint/post-synth/fixtures/TF031/positive-heredoc.tf +149 -0
- package/src/lint/post-synth/fixtures/TF031/positive-jsonencode.tf +115 -0
- package/src/lint/post-synth/fixtures/TF032/negative-heredoc.tf +20 -0
- package/src/lint/post-synth/fixtures/TF032/negative-references.tf +214 -0
- package/src/lint/post-synth/fixtures/TF032/negative.tf +99 -0
- package/src/lint/post-synth/fixtures/TF032/positive-heredoc.tf +22 -0
- package/src/lint/post-synth/fixtures/TF032/positive-sidecar.tf +197 -0
- package/src/lint/post-synth/fixtures/TF032/positive.tf +54 -0
- package/src/lint/post-synth/fixtures/TF033/negative.tf +39 -0
- package/src/lint/post-synth/fixtures/TF033/not-determined-aurora.tf +25 -0
- package/src/lint/post-synth/fixtures/TF033/positive-absent.tf +93 -0
- package/src/lint/post-synth/fixtures/TF033/positive.tf +50 -0
- package/src/lint/post-synth/fixtures/TF034/negative.tf +24 -0
- package/src/lint/post-synth/fixtures/TF034/positive-absent.tf +36 -0
- package/src/lint/post-synth/fixtures/TF034/positive.tf +14 -0
- package/src/lint/post-synth/fixtures/TF035/negative-absent.tf +43 -0
- package/src/lint/post-synth/fixtures/TF035/negative.tf +54 -0
- package/src/lint/post-synth/fixtures/TF035/positive.tf +37 -0
- package/src/lint/post-synth/fixtures/TF036/negative.tf +61 -0
- package/src/lint/post-synth/fixtures/TF036/not-determined.tf +28 -0
- package/src/lint/post-synth/fixtures/TF036/positive.tf +38 -0
- package/src/lint/post-synth/fixtures/TF037/negative-exclusion.tf +63 -0
- package/src/lint/post-synth/fixtures/TF037/negative.tf +27 -0
- package/src/lint/post-synth/fixtures/TF037/not-determined.tf +27 -0
- package/src/lint/post-synth/fixtures/TF037/positive-absent.tf +15 -0
- package/src/lint/post-synth/fixtures/TF037/positive.tf +26 -0
- package/src/lint/post-synth/fixtures/TF038/positive.tf +3 -0
- package/src/lint/post-synth/fixtures/TF039/positive.tf +4 -0
- package/src/lint/post-synth/fixtures/TF041/negative/terragrunt.hcl +12 -0
- package/src/lint/post-synth/fixtures/TF041/positive/terragrunt.hcl +7 -0
- package/src/lint/post-synth/fixtures/TF041/positive-apply/terragrunt.hcl +8 -0
- package/src/lint/post-synth/fixtures/TF042/negative/terragrunt.hcl +13 -0
- package/src/lint/post-synth/fixtures/TF042/positive/terragrunt.hcl +9 -0
- package/src/lint/post-synth/fixtures/TF043/negative/terragrunt.hcl +3 -0
- package/src/lint/post-synth/fixtures/TF043/negative-other/terragrunt.hcl +3 -0
- package/src/lint/post-synth/fixtures/TF043/positive-git/terragrunt.hcl +3 -0
- package/src/lint/post-synth/fixtures/TF043/positive-oci/terragrunt.hcl +3 -0
- package/src/lint/post-synth/fixtures/TF043/positive-tfr/terragrunt.hcl +3 -0
- package/src/lint/post-synth/fixtures/TF044/negative/terragrunt.hcl +9 -0
- package/src/lint/post-synth/fixtures/TF044/positive/terragrunt.hcl +7 -0
- package/src/lint/post-synth/fixtures/TF044/positive-generate/terragrunt.hcl +9 -0
- package/src/lint/post-synth/fixtures/TF045/negative/root.hcl +1 -0
- package/src/lint/post-synth/fixtures/TF045/negative/terragrunt.hcl +3 -0
- package/src/lint/post-synth/fixtures/TF045/positive/root.hcl +9 -0
- package/src/lint/post-synth/fixtures/TF045/positive/terragrunt.hcl +3 -0
- package/src/lint/post-synth/fixtures/TF045/unit-only/terragrunt.hcl +3 -0
- package/src/lint/post-synth/fixtures/estate-2284/clean/main.tf +132 -0
- package/src/lint/post-synth/fixtures/estate-2284/violating/main.tf +112 -0
- package/src/lint/post-synth/flat-attributes.ts +146 -0
- package/src/lint/post-synth/index.ts +32 -0
- package/src/lint/post-synth/module-source.test.ts +42 -1
- package/src/lint/post-synth/module-source.ts +56 -1
- package/src/lint/post-synth/terragrunt.ts +76 -0
- package/src/lint/post-synth/tf002.ts +1 -1
- package/src/lint/post-synth/tf030.test.ts +219 -0
- package/src/lint/post-synth/tf030.ts +290 -0
- package/src/lint/post-synth/tf031.test.ts +229 -0
- package/src/lint/post-synth/tf031.ts +370 -0
- package/src/lint/post-synth/tf032.test.ts +127 -0
- package/src/lint/post-synth/tf032.ts +226 -0
- package/src/lint/post-synth/tf033.test.ts +126 -0
- package/src/lint/post-synth/tf033.ts +160 -0
- package/src/lint/post-synth/tf034.test.ts +71 -0
- package/src/lint/post-synth/tf034.ts +63 -0
- package/src/lint/post-synth/tf035.test.ts +68 -0
- package/src/lint/post-synth/tf035.ts +74 -0
- package/src/lint/post-synth/tf036.test.ts +87 -0
- package/src/lint/post-synth/tf036.ts +119 -0
- package/src/lint/post-synth/tf037.test.ts +88 -0
- package/src/lint/post-synth/tf037.ts +101 -0
- package/src/lint/post-synth/tf038.test.ts +51 -0
- package/src/lint/post-synth/tf038.ts +71 -0
- package/src/lint/post-synth/tf039.test.ts +40 -0
- package/src/lint/post-synth/tf039.ts +64 -0
- package/src/lint/post-synth/tf040.test.ts +55 -0
- package/src/lint/post-synth/tf040.ts +76 -0
- package/src/lint/post-synth/tf041.test.ts +50 -0
- package/src/lint/post-synth/tf041.ts +56 -0
- package/src/lint/post-synth/tf042.test.ts +19 -0
- package/src/lint/post-synth/tf042.ts +42 -0
- package/src/lint/post-synth/tf043.test.ts +65 -0
- package/src/lint/post-synth/tf043.ts +49 -0
- package/src/lint/post-synth/tf044.test.ts +27 -0
- package/src/lint/post-synth/tf044.ts +51 -0
- package/src/lint/post-synth/tf045.test.ts +30 -0
- package/src/lint/post-synth/tf045.ts +47 -0
- package/src/op/activities/index.ts +4 -0
- package/src/op/activities/pin-rollout.ts +77 -0
- package/src/op/activities/terraform.test.ts +13 -0
- package/src/op/activities/terraform.ts +46 -86
- package/src/op/activity-contracts.test.ts +4 -1
- package/src/op/activity-contracts.ts +42 -0
- package/src/op/builders.ts +13 -0
- package/src/pin/bundle.test.ts +53 -0
- package/src/pin/edit-ts.test.ts +39 -0
- package/src/pin/edit-ts.ts +77 -0
- package/src/pin/edit.test.ts +199 -0
- package/src/pin/edit.ts +157 -0
- package/src/pin/forge.ts +85 -0
- package/src/pin/index.ts +22 -0
- package/src/pin/rollout.test.ts +232 -0
- package/src/pin/rollout.ts +451 -0
- package/src/pin/scan.ts +309 -0
- package/src/pin/source.ts +206 -0
- package/src/pin/waves.test.ts +101 -0
- package/src/pin/waves.ts +125 -0
- package/src/plan-digest.ts +99 -0
- package/src/plan-summary.test.ts +154 -0
- package/src/plugin.ts +25 -2
- package/src/terragrunt/affected.acceptance.test.ts +83 -0
- package/src/terragrunt/affected.test.ts +177 -0
- package/src/terragrunt/affected.ts +348 -0
- package/src/terragrunt/index.ts +11 -0
- package/src/terragrunt/mocks.acceptance.test.ts +105 -0
- package/src/terragrunt/mocks.test.ts +309 -0
- package/src/terragrunt/mocks.ts +324 -0
- package/src/terragrunt/run.ts +369 -0
- package/src/terragrunt/terragrunt.acceptance.test.ts +122 -0
- package/src/terragrunt/terragrunt.test.ts +332 -0
- package/src/terragrunt/units.ts +235 -0
- package/src/terragrunt/wave.ts +181 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte offsets for the attribute values the pin edit rewrites (#3189).
|
|
3
|
+
*
|
|
4
|
+
* `@cdktn/hcl2json` is the reader that says what a file means, and the pin
|
|
5
|
+
* edit asks it first (`./edit.ts`). It gives back values and no positions
|
|
6
|
+
* (`../hcl/value.ts` says why), so it cannot say WHERE in the file a
|
|
7
|
+
* `source` or `version` literal sits. This lexer answers only that: it walks
|
|
8
|
+
* the raw text token by token, skipping comments, quoted strings, template
|
|
9
|
+
* interpolations and heredocs, counts braces, and records each top-level
|
|
10
|
+
* block and the plain string literal of each of its own attributes, with the
|
|
11
|
+
* literal's offsets.
|
|
12
|
+
*
|
|
13
|
+
* It is an HCL tokenizer, not a pattern match over lines: a `source =` inside
|
|
14
|
+
* a comment, a heredoc or another string is never a match, and a block opened
|
|
15
|
+
* on the same line as its attributes reads the same as one split over lines.
|
|
16
|
+
* What it finds is checked against the reader before anything is written:
|
|
17
|
+
* the literal's unescaped value has to equal what hcl2json read for that
|
|
18
|
+
* attribute, and the edited file has to parse to the same tree with only the
|
|
19
|
+
* pinned values changed.
|
|
20
|
+
*/
|
|
21
|
+
/** One plain string literal: the offsets of its content, quotes excluded. */
|
|
22
|
+
export interface ScannedLiteral {
|
|
23
|
+
start: number;
|
|
24
|
+
end: number;
|
|
25
|
+
/** The content as written, escapes included. */
|
|
26
|
+
raw: string;
|
|
27
|
+
}
|
|
28
|
+
/** One attribute of a block body. `literal` is set when the value is a single string with no interpolation. */
|
|
29
|
+
export interface ScannedAttribute {
|
|
30
|
+
name: string;
|
|
31
|
+
literal?: ScannedLiteral;
|
|
32
|
+
}
|
|
33
|
+
/** One top-level block: `module "vpc" { ... }`, `terraform { ... }`. */
|
|
34
|
+
export interface ScannedBlock {
|
|
35
|
+
type: string;
|
|
36
|
+
labels: string[];
|
|
37
|
+
/** Offset of the block's type keyword. */
|
|
38
|
+
start: number;
|
|
39
|
+
/** Offset just past the closing brace. */
|
|
40
|
+
end: number;
|
|
41
|
+
/** The block body's own attributes, in file order. Nested blocks' attributes are not included. */
|
|
42
|
+
attributes: ScannedAttribute[];
|
|
43
|
+
}
|
|
44
|
+
/** Thrown when the text is not well-formed enough to place an edit in. */
|
|
45
|
+
export declare class HclScanError extends Error {
|
|
46
|
+
constructor(file: string, message: string);
|
|
47
|
+
}
|
|
48
|
+
/** Every top-level block in `text`, with its own attributes' literals. */
|
|
49
|
+
export declare function scanBlocks(text: string, file: string): ScannedBlock[];
|
|
50
|
+
/** Undo HCL's string escapes, so a literal's raw text compares to the value the reader returned. */
|
|
51
|
+
export declare function unescapeHcl(raw: string): string;
|
|
52
|
+
/** Write a value as the content of an HCL string literal. */
|
|
53
|
+
export declare function escapeHcl(value: string): string;
|
|
54
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/pin/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,+GAA+G;AAC/G,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,kGAAkG;IAClG,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAYD,0EAA0E;AAC1E,qBAAa,YAAa,SAAQ,KAAK;IACrC,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAGxC;CACF;AAmID,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAgCrE;AAkDD,oGAAoG;AACpG,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAyB/C;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a module call keeps its pin, and how the pin moves (#3189).
|
|
3
|
+
*
|
|
4
|
+
* A module call names a module and, if it is pinned, one exact version of it.
|
|
5
|
+
* The version sits in one of two places:
|
|
6
|
+
*
|
|
7
|
+
* - the `version` argument, beside a registry `source`
|
|
8
|
+
* (`source = "app.terraform.io/acme/vpc/aws"`, `version = "1.3.0"`);
|
|
9
|
+
* - a query argument of the `source` itself: OpenTofu's `oci://` sources take
|
|
10
|
+
* `?tag=` or `?digest=`, a git source takes `?ref=`, and Terragrunt's
|
|
11
|
+
* `tfr://` source takes `?version=`.
|
|
12
|
+
*
|
|
13
|
+
* The module's identity is the source with the pin taken out, so
|
|
14
|
+
* `oci://r.example.com/m/vpc?tag=1.3.0` and `oci://r.example.com/m/vpc?tag=1.4.0`
|
|
15
|
+
* call the same module.
|
|
16
|
+
*
|
|
17
|
+
* A `version` constraint (`~> 1.4`, `>= 1.4, < 2`) is not a pin. An upstream
|
|
18
|
+
* release changes what such a root runs with no diff to review, and there is
|
|
19
|
+
* no single version to move, so the call is refused with that reason. The
|
|
20
|
+
* same holds for a call with no pin at all.
|
|
21
|
+
*
|
|
22
|
+
* OpenTofu writes an OCI pin as a query argument
|
|
23
|
+
* (https://opentofu.org/docs/language/modules/sources/#oci-distribution-registries),
|
|
24
|
+
* not as a `:tag` or `@sha256:` suffix on the repository, so the query form is
|
|
25
|
+
* the one read here.
|
|
26
|
+
*
|
|
27
|
+
* This module is pure string work over values the HCL reader has already
|
|
28
|
+
* parsed. Finding those values in a file, and writing the new ones back, is
|
|
29
|
+
* `./edit.ts`. #3190 adds an `oci` kind to the lint classifier
|
|
30
|
+
* (`../lint/post-synth/module-source.ts`) with the same parse; the two can
|
|
31
|
+
* share one once both have landed.
|
|
32
|
+
*/
|
|
33
|
+
/** The query arguments that carry a pin. */
|
|
34
|
+
export type PinParam = "tag" | "digest" | "ref" | "version";
|
|
35
|
+
/** What a module call pins, read from its `source` and `version`. */
|
|
36
|
+
export interface ModuleCallPin {
|
|
37
|
+
/** The module the call names: its `source` with the pin argument taken out. */
|
|
38
|
+
module: string;
|
|
39
|
+
/** Where the pin is: the `version` argument, or a query argument of `source`. */
|
|
40
|
+
at: "version" | "source";
|
|
41
|
+
/** The query argument holding the pin, when `at` is `source`. */
|
|
42
|
+
param?: PinParam;
|
|
43
|
+
/** The pinned version, tag, digest or ref. Null when there is no pin to move. */
|
|
44
|
+
pin: string | null;
|
|
45
|
+
/** Why the call has no pin to move, when `pin` is null. */
|
|
46
|
+
unpinned?: string;
|
|
47
|
+
}
|
|
48
|
+
/** The outcome of moving one call's pin. */
|
|
49
|
+
export type PinMove = {
|
|
50
|
+
outcome: "moved";
|
|
51
|
+
from: string;
|
|
52
|
+
to: string;
|
|
53
|
+
source: string;
|
|
54
|
+
version?: string;
|
|
55
|
+
} | {
|
|
56
|
+
outcome: "already";
|
|
57
|
+
pin: string;
|
|
58
|
+
} | {
|
|
59
|
+
outcome: "elsewhere";
|
|
60
|
+
pin: string;
|
|
61
|
+
} | {
|
|
62
|
+
outcome: "refused";
|
|
63
|
+
reason: string;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The exact version a `version` argument pins, or null when it is a
|
|
67
|
+
* constraint. `1.4.0` and `= 1.4.0` are exact; `~> 1.4`, `>= 1.4` and
|
|
68
|
+
* `1.4.0, < 2` are not.
|
|
69
|
+
*/
|
|
70
|
+
export declare function exactVersion(constraint: string): string | null;
|
|
71
|
+
/** Whether a value can be a pin's new value: an exact version, a tag, a ref or a digest, never a constraint. */
|
|
72
|
+
export declare function isPinValue(value: string): boolean;
|
|
73
|
+
/** Read the pin a module call carries. `version` is the call's `version` argument, when it has one. */
|
|
74
|
+
export declare function readModulePin(source: string, version?: string): ModuleCallPin;
|
|
75
|
+
/**
|
|
76
|
+
* Move a call's pin from `from` to `to`, when the call names `module`.
|
|
77
|
+
* Returns null when it names another module. `version` keeps any `=` it was
|
|
78
|
+
* written with, so `= 1.3.0` becomes `= 1.4.0`.
|
|
79
|
+
*/
|
|
80
|
+
export declare function movePin(source: string, version: string | undefined, request: {
|
|
81
|
+
module: string;
|
|
82
|
+
from: string;
|
|
83
|
+
to: string;
|
|
84
|
+
}): PinMove | null;
|
|
85
|
+
/** The module a source names, with any pin taken out, so a caller may name the module by a pinned source. */
|
|
86
|
+
export declare function moduleOf(source: string): string;
|
|
87
|
+
/** Refuse a request whose `to` is not something a pin can hold. */
|
|
88
|
+
export declare function checkPinRequest(request: {
|
|
89
|
+
module: string;
|
|
90
|
+
from: string;
|
|
91
|
+
to: string;
|
|
92
|
+
}): void;
|
|
93
|
+
//# sourceMappingURL=source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/pin/source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;AAE5D,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,EAAE,EAAE,SAAS,GAAG,QAAQ,CAAC;IACzB,iEAAiE;IACjE,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,iFAAiF;IACjF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,4CAA4C;AAC5C,MAAM,MAAM,OAAO,GACf;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAChF;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAQ3C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG9D;AAED,gHAAgH;AAChH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjD;AA6CD,uGAAuG;AACvG,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAO7E;AA4CD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,GAAG,IAAI,CAa1I;AAED,6GAA6G;AAC7G,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAM3F"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wave plan for a pin-bump rollout (#3189): which roots move in which PR.
|
|
3
|
+
*
|
|
4
|
+
* Two sources give the same shape, an ordered list of root lists:
|
|
5
|
+
*
|
|
6
|
+
* - **Declared canaries, then dependency order.** The canaries form wave 1.
|
|
7
|
+
* Every other root lands in the earliest wave after every root it depends
|
|
8
|
+
* on. That is the Kahn layering `chant components fan-out` uses
|
|
9
|
+
* (`resolveComponentGraph`, `@intentius/chant/components/layers`), and the
|
|
10
|
+
* order #3049 gives its gated waves. A canary that depends on a root outside
|
|
11
|
+
* the canaries is refused, since wave 1 would apply before what it reads.
|
|
12
|
+
* - **choudoufu's wave planner** (`choudoufu live-waves -json`, choudoufu#1754).
|
|
13
|
+
* It reads cross-estate references from the estates' own configuration, puts
|
|
14
|
+
* `-canary` roots in wave 1, and emits each wave's roots on their own, so
|
|
15
|
+
* {@link wavesFromChoudoufu} takes its document as it is.
|
|
16
|
+
*
|
|
17
|
+
* A root's dependencies come from the caller (`dependsOn`) and, for a
|
|
18
|
+
* Terragrunt unit, from its `dependency` and `dependencies` blocks
|
|
19
|
+
* ({@link terragruntDependencies}). A dependency on a root outside the
|
|
20
|
+
* rollout orders nothing: it is not moving.
|
|
21
|
+
*/
|
|
22
|
+
import type { Hcl2Json } from "@intentius/chant/terraform/hcl2json";
|
|
23
|
+
/** One root in a rollout. `root` is its directory, relative to the repository, with `/` separators. */
|
|
24
|
+
export interface PinRoot {
|
|
25
|
+
root: string;
|
|
26
|
+
/** Roots this one reads, by directory. They land in an earlier wave. */
|
|
27
|
+
dependsOn?: string[];
|
|
28
|
+
/**
|
|
29
|
+
* The TypeScript file a generated root is built from. The pin edit then
|
|
30
|
+
* goes to the module declaration there rather than to the `.tf` chant
|
|
31
|
+
* writes (`./edit-ts.ts`).
|
|
32
|
+
*/
|
|
33
|
+
tsSource?: string;
|
|
34
|
+
}
|
|
35
|
+
/** One wave: its number from 1, whether the declared canaries form it, and its roots, sorted. */
|
|
36
|
+
export interface PinWave {
|
|
37
|
+
wave: number;
|
|
38
|
+
canary: boolean;
|
|
39
|
+
roots: string[];
|
|
40
|
+
}
|
|
41
|
+
/** Thrown when the roots cannot be split into waves. The message names the roots. */
|
|
42
|
+
export declare class PinWavePlanError extends Error {
|
|
43
|
+
constructor(message: string);
|
|
44
|
+
}
|
|
45
|
+
/** Canaries first, then dependency order. */
|
|
46
|
+
export declare function planPinWaves(roots: readonly PinRoot[], canaries?: readonly string[]): PinWave[];
|
|
47
|
+
/**
|
|
48
|
+
* The waves of a `choudoufu live-waves -json` document (format version 1).
|
|
49
|
+
* `prefix` is the directory choudoufu ran in, relative to the repository,
|
|
50
|
+
* when its roots are named relative to that rather than to the repository.
|
|
51
|
+
*/
|
|
52
|
+
export declare function wavesFromChoudoufu(doc: unknown, prefix?: string): PinWave[];
|
|
53
|
+
/**
|
|
54
|
+
* Keep only the roots in `keep`, renumbering the waves and dropping any left
|
|
55
|
+
* empty. A wave plan from choudoufu covers every root it was given; the
|
|
56
|
+
* rollout moves only the roots that call the module at the old or new pin.
|
|
57
|
+
*/
|
|
58
|
+
export declare function restrictWaves(waves: readonly PinWave[], keep: ReadonlySet<string>): PinWave[];
|
|
59
|
+
/**
|
|
60
|
+
* The roots a Terragrunt unit depends on: each `dependency` block's
|
|
61
|
+
* `config_path` and the `dependencies` block's `paths`, resolved against the
|
|
62
|
+
* unit's directory. A path that is an expression is skipped, since it names
|
|
63
|
+
* no directory until Terragrunt evaluates it.
|
|
64
|
+
*/
|
|
65
|
+
export declare function terragruntDependencies(root: string, text: string, parser: Hcl2Json): Promise<string[]>;
|
|
66
|
+
//# sourceMappingURL=waves.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waves.d.ts","sourceRoot":"","sources":["../../src/pin/waves.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAGpE,uGAAuG;AACvG,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,iGAAiG;AACjG,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,qFAAqF;AACrF,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED,6CAA6C;AAC7C,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,QAAQ,GAAE,SAAS,MAAM,EAAO,GAAG,OAAO,EAAE,CAqBnG;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,SAAK,GAAG,OAAO,EAAE,CAUvE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,EAAE,CAO7F;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAS5G"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A terraform plan's identity (#2300), kept apart from the activities so the
|
|
3
|
+
* change-set adapter (`../change-set.ts`, #3181) can import it without the
|
|
4
|
+
* config loader, the HCL parse or anything else the activities reach. It
|
|
5
|
+
* imports chant's `lifecycle/plan-digest` subpath and nothing more, which is
|
|
6
|
+
* what lets terragucci bundle it into one file (#3421).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* One resource's proposed change, as a plan digest sees it (#2300) — the
|
|
10
|
+
* projection of a `terraform show -json` `resource_changes` entry that
|
|
11
|
+
* survives into {@link terraformPlanDigest}.
|
|
12
|
+
*/
|
|
13
|
+
export interface TerraformPlannedChange {
|
|
14
|
+
address: unknown;
|
|
15
|
+
mode: unknown;
|
|
16
|
+
type: unknown;
|
|
17
|
+
name: unknown;
|
|
18
|
+
index: unknown;
|
|
19
|
+
provider_name: unknown;
|
|
20
|
+
deposed: unknown;
|
|
21
|
+
actions: unknown;
|
|
22
|
+
before: unknown;
|
|
23
|
+
after: unknown;
|
|
24
|
+
after_unknown: unknown;
|
|
25
|
+
replace_paths: unknown;
|
|
26
|
+
importing: unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The change set a `terraform show -json` plan describes, canonicalised
|
|
30
|
+
* (#2300): every proposed change, at its address, with the values that would
|
|
31
|
+
* be written, sorted so two renderings of the same plan project identically.
|
|
32
|
+
*
|
|
33
|
+
* Everything else in the document is dropped, and the drops are the point —
|
|
34
|
+
* see `packages/core/src/lifecycle/plan-digest.ts` for the general rule. Here
|
|
35
|
+
* that means `timestamp` and `terraform_version` (when the plan was taken and
|
|
36
|
+
* by which binary), `format_version` (how it was rendered), `prior_state` and
|
|
37
|
+
* `planned_values` (restatements of the same change set from another angle),
|
|
38
|
+
* `configuration` (the source that produced it, which can be refactored
|
|
39
|
+
* without changing a single proposed action) and `checks` / `relevant_
|
|
40
|
+
* attributes` (diagnostics about the plan, not the plan). What is left is
|
|
41
|
+
* what applying it would do.
|
|
42
|
+
*/
|
|
43
|
+
export declare function terraformPlanChangeSet(planJson: unknown): {
|
|
44
|
+
resourceChanges: TerraformPlannedChange[];
|
|
45
|
+
outputChanges: unknown;
|
|
46
|
+
actionInvocations?: unknown[];
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* The identity of a terraform plan (#2300): {@link terraformPlanChangeSet}
|
|
50
|
+
* hashed. This is what a `TerraformApplyOp` gate binds its approval to, and
|
|
51
|
+
* what a later run recomputes and compares.
|
|
52
|
+
*
|
|
53
|
+
* Taken over the `show -json` rendering rather than the plan file's bytes on
|
|
54
|
+
* purpose: the file is an opaque, version-stamped archive, and two runs of
|
|
55
|
+
* `plan -out` over an unchanged root produce different bytes. The rendering
|
|
56
|
+
* is the same plan both times.
|
|
57
|
+
*/
|
|
58
|
+
export declare function terraformPlanDigest(planJson: unknown): string;
|
|
59
|
+
//# sourceMappingURL=plan-digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-digest.d.ts","sourceRoot":"","sources":["../src/plan-digest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,GAAG;IACzD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,EAAE,CAAC;CAC/B,CAkCA;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAE7D"}
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAmElF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,aAqR7B,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared reading helpers for TF033-TF037, the five flat encryption and
|
|
3
|
+
* immutability rules (chant #2288, epic #2284).
|
|
4
|
+
*
|
|
5
|
+
* Each of those rules reads one or two scalar attributes of one resource type
|
|
6
|
+
* and answers a three-valued question: the literal proves the resource
|
|
7
|
+
* secure, the literal proves it insecure, or the parse cannot tell. This
|
|
8
|
+
* module is the reading half; each rule file holds its own answer for
|
|
9
|
+
* absence, because that answer differs per resource (see each rule's doc
|
|
10
|
+
* comment and its section of `docs/pages/lint-rules.mdx`). It exports no
|
|
11
|
+
* `PostSynthCheck`, so the generated barrel skips it.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
|
|
15
|
+
import { RESOURCE_TYPE, type BlockBody } from "../../hcl/parse";
|
|
16
|
+
import { attr } from "../../hcl/value";
|
|
17
|
+
import { blocksOfType, nestedBodies, type TerraformBlock } from "./blocks";
|
|
18
|
+
|
|
19
|
+
/** What one attribute read settles. `reason` says why a value could not be read. */
|
|
20
|
+
export type Read<T> = { kind: "known"; value: T } | { kind: "absent" } | { kind: "unknown"; reason: string };
|
|
21
|
+
|
|
22
|
+
/** Every `resource` block of one provider type (`aws_sqs_queue`), in entity order. */
|
|
23
|
+
export function resourcesOfType(ctx: PostSynthContext, type: string): TerraformBlock[] {
|
|
24
|
+
return blocksOfType(ctx, RESOURCE_TYPE).filter((b) => b.address.startsWith(`${type}.`));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** One expression, for a message: `var.encrypted`, or the template text. */
|
|
28
|
+
function describe(name: string, raw: unknown, refs: string[] | undefined, kind: "reference" | "template"): string {
|
|
29
|
+
return kind === "reference"
|
|
30
|
+
? `\`${name}\` is an expression (${refs?.[0] ?? String(raw)})`
|
|
31
|
+
: `\`${name}\` is a template string ("${String(raw)}")`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A bool attribute. Terraform converts the strings `"true"` and `"false"` to
|
|
36
|
+
* bool, so those read as the bool they convert to. Any other literal (a
|
|
37
|
+
* number, a list) is a plan-time type error, not this rule's concern, and
|
|
38
|
+
* reads as unknown.
|
|
39
|
+
*/
|
|
40
|
+
export function readBool(body: BlockBody, name: string): Read<boolean> {
|
|
41
|
+
const a = attr(body, name);
|
|
42
|
+
if (a.kind === "absent") return { kind: "absent" };
|
|
43
|
+
if (a.kind === "reference" || a.kind === "template") {
|
|
44
|
+
return { kind: "unknown", reason: describe(name, a.raw, a.refs, a.kind) };
|
|
45
|
+
}
|
|
46
|
+
if (typeof a.value === "boolean") return { kind: "known", value: a.value };
|
|
47
|
+
if (a.value === "true" || a.value === "false") return { kind: "known", value: a.value === "true" };
|
|
48
|
+
return { kind: "unknown", reason: `\`${name}\` is not a bool (${JSON.stringify(a.value)})` };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** A string attribute, literal or not. */
|
|
52
|
+
export function readString(body: BlockBody, name: string): Read<string> {
|
|
53
|
+
const a = attr(body, name);
|
|
54
|
+
if (a.kind === "absent") return { kind: "absent" };
|
|
55
|
+
if (a.kind === "reference" || a.kind === "template") {
|
|
56
|
+
return { kind: "unknown", reason: describe(name, a.raw, a.refs, a.kind) };
|
|
57
|
+
}
|
|
58
|
+
if (typeof a.value === "string") return { kind: "known", value: a.value };
|
|
59
|
+
return { kind: "unknown", reason: `\`${name}\` is not a string (${JSON.stringify(a.value)})` };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Expression roots that name an input or a computed value, not a managed object. */
|
|
63
|
+
const VALUE_ROOTS = new Set(["var", "local", "module", "each", "count", "path", "terraform", "self"]);
|
|
64
|
+
|
|
65
|
+
/** `aws_kms_key.sns.arn`, `data.aws_kms_alias.sqs.target_key_arn`, with an optional index or splat. */
|
|
66
|
+
const OBJECT_ATTRIBUTE = /^(?:data\.)?([a-z][a-z0-9_]*)\.[A-Za-z_][\w-]*(?:\[[^\]]*\])?(?:\.[A-Za-z_][\w-]*|\[[^\]]*\])+$/;
|
|
67
|
+
|
|
68
|
+
/** Every `${...}` span in a template, as `attr()` finds them. */
|
|
69
|
+
const SPANS = /\$\{(?:[^{}]|\{[^{}]*\})*\}/g;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Whether a key-like argument (`kms_master_key_id`) is set to something.
|
|
73
|
+
*
|
|
74
|
+
* - absent, or `null`: `absent`.
|
|
75
|
+
* - a literal: `known`, with the string (`""` is a value, and a rule decides
|
|
76
|
+
* what an empty key means).
|
|
77
|
+
* - an attribute of a managed resource or data source (`aws_kms_key.x.arn`):
|
|
78
|
+
* `known` and non-empty. The provider computes a key's id or ARN; it is
|
|
79
|
+
* never the empty string, so the key is set whatever its value turns out to
|
|
80
|
+
* be.
|
|
81
|
+
* - a template with literal text (`"alias/${var.env}-sns"`): `known` and
|
|
82
|
+
* non-empty, for the same reason.
|
|
83
|
+
* - anything else (`var.kms_key`, `local.key`, a conditional, a function
|
|
84
|
+
* call): `unknown`. A variable can be `null` or `""`.
|
|
85
|
+
*/
|
|
86
|
+
export function readKeySet(body: BlockBody, name: string): Read<string> {
|
|
87
|
+
const a = attr(body, name);
|
|
88
|
+
if (a.kind === "absent") return { kind: "absent" };
|
|
89
|
+
if (a.kind === "literal") {
|
|
90
|
+
return typeof a.value === "string"
|
|
91
|
+
? { kind: "known", value: a.value }
|
|
92
|
+
: { kind: "unknown", reason: `\`${name}\` is not a string (${JSON.stringify(a.value)})` };
|
|
93
|
+
}
|
|
94
|
+
const raw = String(a.raw);
|
|
95
|
+
if (a.kind === "template") {
|
|
96
|
+
if (raw.replace(SPANS, "").length > 0) return { kind: "known", value: raw };
|
|
97
|
+
return { kind: "unknown", reason: describe(name, a.raw, a.refs, "template") };
|
|
98
|
+
}
|
|
99
|
+
const expr = (a.refs?.[0] ?? "").trim();
|
|
100
|
+
const m = OBJECT_ATTRIBUTE.exec(expr);
|
|
101
|
+
if (m && !VALUE_ROOTS.has(m[1])) return { kind: "known", value: raw };
|
|
102
|
+
return { kind: "unknown", reason: describe(name, a.raw, a.refs, "reference") };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Whether an argument that names a source (`snapshot_identifier`,
|
|
107
|
+
* `replicate_source_db`) or a nested block (`restore_to_point_in_time`) is
|
|
108
|
+
* given. The provider reads these with `GetOk`, so a literal `""` is the same
|
|
109
|
+
* as leaving the argument out; anything else, a reference included, is given.
|
|
110
|
+
*/
|
|
111
|
+
export function isGiven(body: BlockBody, name: string): boolean {
|
|
112
|
+
const a = attr(body, name);
|
|
113
|
+
if (a.kind === "absent") return false;
|
|
114
|
+
if (a.kind === "literal") {
|
|
115
|
+
if (a.value === "" || a.value === false) return false;
|
|
116
|
+
if (Array.isArray(a.value)) return a.value.length > 0;
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** The bodies of a nested block, re-exported for the rule files. */
|
|
122
|
+
export { nestedBodies };
|
|
123
|
+
|
|
124
|
+
/** A finding the literal proves. */
|
|
125
|
+
export function finding(
|
|
126
|
+
checkId: string,
|
|
127
|
+
severity: "error" | "warning",
|
|
128
|
+
block: TerraformBlock,
|
|
129
|
+
message: string,
|
|
130
|
+
): PostSynthDiagnostic {
|
|
131
|
+
return { checkId, severity, message: `"${block.address}" ${message}`, entity: block.key, lexicon: "terraform" };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The one `info` diagnostic a rule emits when it cannot read the value it
|
|
136
|
+
* needs. The message starts `Not determined:`, as #2284 fixed for TF030-TF037.
|
|
137
|
+
*/
|
|
138
|
+
export function notDetermined(checkId: string, block: TerraformBlock, reason: string, tail: string): PostSynthDiagnostic {
|
|
139
|
+
return {
|
|
140
|
+
checkId,
|
|
141
|
+
severity: "info",
|
|
142
|
+
message: `Not determined: "${block.address}" ${reason}. ${tail}`,
|
|
143
|
+
entity: block.key,
|
|
144
|
+
lexicon: "terraform",
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -18,14 +18,27 @@
|
|
|
18
18
|
* recognize, scp-style `git@host:path` addresses, and any source ending in
|
|
19
19
|
* `.git`. `local` is `./` or `../` (checkov's `UNKNOWN` case for module
|
|
20
20
|
* pinning: a local path cannot be pinned to anything and is never flagged).
|
|
21
|
+
* `oci` is an OpenTofu `oci://host/repo` source (#3190). OpenTofu selects a
|
|
22
|
+
* version with `?tag=` or `?digest=` (https://opentofu.org/docs/language/modules/sources/),
|
|
23
|
+
* and a source naming neither resolves the `latest` tag. The container-image
|
|
24
|
+
* shapes `repo:tag` and `repo@sha256:...` are read too, so a source written
|
|
25
|
+
* the way `docker pull` spells it is not misread as unpinned. A `:` inside the
|
|
26
|
+
* host (a registry port) is never a tag: only a colon in the last path
|
|
27
|
+
* segment is. The tag and digest rules were checked against the docs page
|
|
28
|
+
* above; the suffix forms are not documented there and are not verified
|
|
29
|
+
* against OpenTofu's parser.
|
|
21
30
|
*/
|
|
22
31
|
|
|
23
|
-
export type ModuleSourceKind = "local" | "registry" | "git" | "other";
|
|
32
|
+
export type ModuleSourceKind = "local" | "registry" | "git" | "oci" | "other";
|
|
24
33
|
|
|
25
34
|
export interface ModuleSourceClassification {
|
|
26
35
|
kind: ModuleSourceKind;
|
|
27
36
|
/** The `?ref=`/`&ref=` value (falling back to `rev`), when `kind` is `"git"`. */
|
|
28
37
|
ref?: string;
|
|
38
|
+
/** The tag an `oci://` source names, from `?tag=` or a `:tag` suffix on the repository. */
|
|
39
|
+
tag?: string;
|
|
40
|
+
/** The digest an `oci://` source names, from `?digest=` or an `@sha256:...` suffix. */
|
|
41
|
+
digest?: string;
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
const REGISTRY_NAME = /^[0-9A-Za-z](?:[0-9A-Za-z_-]{0,62}[0-9A-Za-z])?$/;
|
|
@@ -77,6 +90,25 @@ function isGitShaped(rest: string): boolean {
|
|
|
77
90
|
return false;
|
|
78
91
|
}
|
|
79
92
|
|
|
93
|
+
function classifyOci(base: string, query: string): ModuleSourceClassification {
|
|
94
|
+
const params = parseQuery(query);
|
|
95
|
+
let path = stripSubdir(base).replace(/^oci:\/\//i, "");
|
|
96
|
+
let tag = params.get("tag") || undefined;
|
|
97
|
+
let digest = params.get("digest") || undefined;
|
|
98
|
+
|
|
99
|
+
const at = path.indexOf("@");
|
|
100
|
+
if (at !== -1) {
|
|
101
|
+
digest = digest ?? (path.slice(at + 1) || undefined);
|
|
102
|
+
path = path.slice(0, at);
|
|
103
|
+
}
|
|
104
|
+
const lastSlash = path.lastIndexOf("/");
|
|
105
|
+
const colon = path.indexOf(":", lastSlash + 1); // a port sits before the first slash
|
|
106
|
+
if (colon !== -1) {
|
|
107
|
+
tag = tag ?? (path.slice(colon + 1) || undefined);
|
|
108
|
+
}
|
|
109
|
+
return { kind: "oci", ...(tag !== undefined ? { tag } : {}), ...(digest !== undefined ? { digest } : {}) };
|
|
110
|
+
}
|
|
111
|
+
|
|
80
112
|
export function classifyModuleSource(source: string): ModuleSourceClassification {
|
|
81
113
|
const trimmed = source.trim();
|
|
82
114
|
if (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed.startsWith(".\\") || trimmed.startsWith("..\\")) {
|
|
@@ -87,6 +119,8 @@ export function classifyModuleSource(source: string): ModuleSourceClassification
|
|
|
87
119
|
const base = queryIdx === -1 ? trimmed : trimmed.slice(0, queryIdx);
|
|
88
120
|
const query = queryIdx === -1 ? "" : trimmed.slice(queryIdx + 1);
|
|
89
121
|
|
|
122
|
+
if (/^oci:\/\//i.test(base)) return classifyOci(base, query);
|
|
123
|
+
|
|
90
124
|
const forced = /^(git|hg)::/i.exec(base);
|
|
91
125
|
const rest = forced ? base.slice(forced[0].length) : base;
|
|
92
126
|
|
|
@@ -119,3 +153,24 @@ export function isPinnedRef(ref: string): boolean {
|
|
|
119
153
|
export function isDefaultBranch(ref: string): boolean {
|
|
120
154
|
return DEFAULT_BRANCHES.has(ref);
|
|
121
155
|
}
|
|
156
|
+
|
|
157
|
+
const MUTABLE_TAGS = new Set(["latest", "main", "master", "develop", "dev", "stable", "edge", "nightly"]);
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Is `tag` a name that conventionally moves (`latest`, a branch-like name)
|
|
161
|
+
* rather than an exact version. Used by TF038. A tag is a mutable pointer in
|
|
162
|
+
* most registries whatever it looks like, so the rule is a warning and this
|
|
163
|
+
* only decides what reads as obviously floating.
|
|
164
|
+
*/
|
|
165
|
+
export function isMutableOciTag(tag: string): boolean {
|
|
166
|
+
return MUTABLE_TAGS.has(tag.toLowerCase());
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Is a registry `version` constraint an exact version (`1.4.0`, `= 1.4.0`,
|
|
171
|
+
* `=1.4.0`) rather than a range (`~> 1.4`, `>= 1.4`, `>= 1.0, < 2.0`). Used
|
|
172
|
+
* by TF039. A bare version is an exact constraint in Terraform.
|
|
173
|
+
*/
|
|
174
|
+
export function isExactVersionConstraint(version: string): boolean {
|
|
175
|
+
return /^(?:=\s*)?v?\d+(?:\.\d+){0,2}(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version.trim()) && !version.includes(",");
|
|
176
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared reading for the Terragrunt rules TF041 to TF045 (#3417).
|
|
3
|
+
*
|
|
4
|
+
* These rules look at `terragrunt.hcl` and `root.hcl`, which the parse reads
|
|
5
|
+
* into their own entity types (`TERRAGRUNT_*_TYPE` in `../../hcl/parse.ts`)
|
|
6
|
+
* and never into the module types the other TF rules check. Like the module
|
|
7
|
+
* source rules, they read the literal values hcl2json hands back: an
|
|
8
|
+
* attribute built from a function or a `local.` reference arrives as a
|
|
9
|
+
* `"${...}"` string and is treated as not determined, never as a finding.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { isResourceDeclarable, type Declarable } from "@intentius/chant/declarable";
|
|
13
|
+
import type { BlockBody } from "../../hcl/parse";
|
|
14
|
+
import { classifyModuleSource } from "./module-source";
|
|
15
|
+
|
|
16
|
+
/** Entities of one Terragrunt type, with their keys, in map order. */
|
|
17
|
+
export function terragruntEntities(
|
|
18
|
+
entities: ReadonlyMap<string, Declarable>,
|
|
19
|
+
entityType: string,
|
|
20
|
+
): Array<{ key: string; address: string; file: string; body: BlockBody }> {
|
|
21
|
+
const out: Array<{ key: string; address: string; file: string; body: BlockBody }> = [];
|
|
22
|
+
for (const [key, entity] of entities) {
|
|
23
|
+
if (entity.entityType !== entityType || !isResourceDeclarable(entity)) continue;
|
|
24
|
+
const props = entity.props as { address?: unknown; file?: unknown; body?: unknown };
|
|
25
|
+
out.push({
|
|
26
|
+
key,
|
|
27
|
+
address: typeof props.address === "string" ? props.address : key,
|
|
28
|
+
file: typeof props.file === "string" ? props.file : "terragrunt.hcl",
|
|
29
|
+
body: (typeof props.body === "object" && props.body !== null ? props.body : {}) as BlockBody,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** An HCL expression hcl2json left as `"${...}"`: its value is not known without evaluating it. */
|
|
36
|
+
export function isExpression(value: unknown): boolean {
|
|
37
|
+
return typeof value === "string" && value.includes("${");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type TerragruntSourceKind = "local" | "git" | "tfr" | "oci" | "other";
|
|
41
|
+
|
|
42
|
+
export interface TerragruntSourceClassification {
|
|
43
|
+
kind: TerragruntSourceKind;
|
|
44
|
+
/** Whether the source names a version: `?ref=` for git, `?version=` for `tfr://`, a tag or digest for `oci://`. Undefined for `local` and `other`. */
|
|
45
|
+
pinned?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Classify a unit's `terraform.source`. Git and `oci://` sources go through
|
|
50
|
+
* {@link classifyModuleSource}, the reader TF005 and TF038 use. `tfr://` is
|
|
51
|
+
* Terragrunt's own scheme for registry modules and takes its version from the
|
|
52
|
+
* `?version=` query argument. A source that holds an interpolation, or that
|
|
53
|
+
* names an absolute path or an archive URL, is `other` or `local` and is
|
|
54
|
+
* never reported.
|
|
55
|
+
*/
|
|
56
|
+
export function classifyTerragruntSource(source: string): TerragruntSourceClassification {
|
|
57
|
+
const trimmed = source.trim();
|
|
58
|
+
if (trimmed.includes("${")) return { kind: "other" };
|
|
59
|
+
if (/^tfr:\/\//i.test(trimmed)) {
|
|
60
|
+
const query = trimmed.includes("?") ? trimmed.slice(trimmed.indexOf("?") + 1) : "";
|
|
61
|
+
const version = new URLSearchParams(query).get("version");
|
|
62
|
+
return { kind: "tfr", pinned: version !== null && version.trim() !== "" };
|
|
63
|
+
}
|
|
64
|
+
if (trimmed.startsWith("/")) return { kind: "local" };
|
|
65
|
+
const classified = classifyModuleSource(trimmed);
|
|
66
|
+
switch (classified.kind) {
|
|
67
|
+
case "local":
|
|
68
|
+
return { kind: "local" };
|
|
69
|
+
case "git":
|
|
70
|
+
return { kind: "git", pinned: classified.ref !== undefined };
|
|
71
|
+
case "oci":
|
|
72
|
+
return { kind: "oci", pinned: classified.tag !== undefined || classified.digest !== undefined };
|
|
73
|
+
default:
|
|
74
|
+
return { kind: "other" };
|
|
75
|
+
}
|
|
76
|
+
}
|
package/dist/rules/tf002.ts
CHANGED
|
@@ -51,7 +51,7 @@ function providerNameFromType(type: string): string {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/** One implied provider name to the entity key that first implied it in file order. */
|
|
54
|
-
function impliedProviders(entities: PostSynthContext["entities"], root: string): Map<string, string> {
|
|
54
|
+
export function impliedProviders(entities: PostSynthContext["entities"], root: string): Map<string, string> {
|
|
55
55
|
const implied = new Map<string, string>();
|
|
56
56
|
const fromProviderBlock = new Set<string>();
|
|
57
57
|
|