antonbabenko / pre-commit-terraform

pre-commit git hooks to take care of Terraform configurations 🇺🇦
MIT License
3.16k stars 535 forks source link

Validate failing to upgrade lock file locally on version change #680

Closed DavOpz closed 3 months ago

DavOpz commented 3 months ago

Describe the bug

Version (Local) - v1.91.0

Docker Image (GitHub Workflow) - ghcr.io/antonbabenko/pre-commit-terraform:v1.91.0

Running the following pre-commit hook steps

Locally - The "terraform_validate" hook shows no issues and passes with Success, however it will then fail on "terraform_providers_lock" because - correctly - my .terraform.lock.hcl refers to an old version of registry.terraform.io/hashicorp/azurerm.

GitHub Workflow - When I run this same process via Github workflow, "terraform_validate" correctly flags the need to make changes and fails on the file diff.

Expected behaviour is parity between local and github workflow as they are using the same version, main expected behaviour is that locally the results seen in github would occur.

My main guess on what is happening is because my .terraform dir is stored locally that the validate is working because the providers are present, however when running in github the files are not as they are in the .gitignore, so it will then run terraform init and this would have fixed the terraform.lock.hcl file as well if it were able to write.

Request an option to force terraform init -upgrade on hook terraform_validate, this will make it possible to replicate the CICD environment by ensuring the init is performed the same as if there were no .terraform files locally.

How can we reproduce it?

See section Files for a copy of the files used, then perform the following steps

  1. Run terraform init to generate lockfile
  2. Run pre-commit run -a --color=always and view the two hooks displaying Passed
  3. Update the versions.tf file from initial to the other file specified, changing the version of the hashicorp/azurerm provider from 3.103.1 to 3.108.0
  4. Run pre-commit run -a --color=always and the validate will show Passed however terraform lock will display Failed, there is no attempt to resolve and adding the --tf-init-args=-upgrade arg to validate does not ensure the lock file will be updated prior to the next step failing.

    • Local Output

      
      Terraform validate.......................................................Passed
      Lock terraform provider versions.........................................Failed
    • hook id: terraform_providers_lock

    • exit code: 1

    • Fetching hashicorp/null 3.2.2 for darwin_arm64...

    • Retrieved hashicorp/null 3.2.2 for darwin_arm64 (signed by HashiCorp) ╷ │ Error: Could not retrieve providers for locking │ │ Terraform failed to fetch the requested providers for darwin_arm64 in order to calculate their checksums: some providers could not be installed: │ - registry.terraform.io/hashicorp/azurerm: locked provider registry.terraform.io/hashicorp/azurerm 3.103.1 does not match configured version constraint 3.108.0; must use terraform init -upgrade to allow selection of new versions.

  5. Comment out the terraform_providers_lock hook in .pre-commit-config.yaml or you will be unable to commit to test the disparity in GitHub.
  6. Push to a repository in GitHub to trigger the CICD, here the validate step will attempt to fix the file, as would be expected locally prior to getting to a PR run.

    • CICD Output
      
      Run pre-commit run -a --color=always
      pre-commit run -a --color=always
      shell: bash --noprofile --norc -e -o pipefail {0}
      [INFO] Initializing environment for https://github.com/antonbabenko/pre-commit-terraform.
      Terraform validate.......................................................Failed
    • hook id: terraform_validate
    • files were modified by this hook

    Command 'terraform init' successfully done: .

    Error: Process completed with exit code 1.

You can see that when ran locally terraform_validate reports success because of the existence of the .terraform, however running via CICD fails because when running the terraform init it would be required to update the .terraform.lock.hcl file, which it isn't doing on the local pre-commit hook.

Environment information

Darwin MacPro-F6WMC6WQG9 23.3.0 Darwin Kernel Version 23.3.0: Wed Dec 20 21:30:59 PST 2023; root:xnu-10002.81.5~7/RELEASE_ARM64_T6030 arm64
GNU bash, version 3.2.57(1)-release (arm64-apple-darwin23)
pre-commit 3.7.1
bash: line 3: tofu: command not found
Terraform v1.8.5
python SKIPPED
Python 3.12.3
checkov SKIPPED
Infracost v0.10.37
terraform-docs version v0.18.0 228c7a7 darwin/arm64
terragrunt version 0.59.3
terrascan version: v1.19.1
TFLint version 0.51.1
+ ruleset.terraform (0.7.0-bundled)
tfsec SKIPPED
trivy Version: 0.52.1
Check Bundle:
  Digest: sha256:cfb65621a1f55d9d099c4c28931b252716fcda8bba5081eb43f1001668e79d85
  DownloadedAt: 2024-06-14 08:38:10.74048 +0000 UTC
tfupdate 0.8.2
hcledit 0.2.11

Files

.pre-commit-config.yaml ```yaml repos: - repo: https://github.com/antonbabenko/pre-commit-terraform rev: v1.91.0 hooks: - id: terraform_validate args: - --hook-config=--retry-once-with-cleanup=true - --tf-init-args=-upgrade - id: terraform_providers_lock args: - --hook-config=--mode=always-regenerate-lockfile ```
.github/workflows/pre-commit.yml ```yaml name: pre-commit-terraform on: pull_request: jobs: pre-commit: runs-on: ubuntu-latest container: image: ghcr.io/antonbabenko/pre-commit-terraform:v1.91.0 defaults: run: shell: bash steps: - uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} - run: | git config --global --add safe.directory $GITHUB_WORKSPACE git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/* - name: fix tar dependency in alpine container image run: | apk --no-cache add tar # check python modules installed versions python -m pip freeze --local - name: Cache pre-commit since we use pre-commit from container uses: actions/cache@v4 with: path: ~/.cache/pre-commit key: pre-commit-3|${{ hashFiles('.pre-commit-config.yaml') }} - name: Execute pre-commit on all files run: | pre-commit run -a --color=always ```
.gitignore ``` # Local .terraform directories **/.terraform/* # .tfstate files *.tfstate *.tfstate.* # Crash log files crash.log crash.*.log # Exclude all .tfvars files, which are likely to contain sensitive data, such as # password, private keys, and other secrets. These should not be part of version # control as they are data points which are potentially sensitive and subject # to change depending on the environment. *.tfvars *.tfvars.json # Ignore override files as they are usually used to override resources locally and so # are not checked in override.tf override.tf.json *_override.tf *_override.tf.json # Include override files you do wish to add to version control using negated pattern # !example_override.tf # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan # example: *tfplan* # Ignore CLI configuration files .terraformrc terraform.rc ```
main.tf ```terraform resource "null_resource" "foo" { triggers = { example = var.project_name } } ```
variables.tf ```terraform variable "project_name" { default = "default value" type = string description = "Example variable." } ```
versions.tf (Initial File) ```terraform terraform { required_version = "1.8.5" required_providers { azurerm = { source = "hashicorp/azurerm" version = "3.103.1" } null = { source = "hashicorp/null" version = "3.2.2" } } } ```
versions.tf (Change to file after running commands specified) ```terraform terraform { required_version = "1.8.5" required_providers { azurerm = { source = "hashicorp/azurerm" version = "3.108.0" } null = { source = "hashicorp/null" version = "3.2.2" } } } ```
DavOpz commented 3 months ago

To add to this, I've just tried running terraform init -upgrade locally to resolve this (and added back the other tests) and it all worked fine locally

Terraform fmt............................................................Passed
Terraform validate.......................................................Passed
Lock terraform provider versions.........................................Passed
Terraform validate with tflint...........................................Passed
Terraform validate with trivy............................................Passed
terrascan................................................................Passed
tfupdate.................................................................Passed
Terraform docs...........................................................Passed

However pushing to CICD shows the following

[INFO] Initializing environment for https://github.com/antonbabenko/pre-commit-terraform.
Terraform fmt............................................................Passed
Terraform validate.......................................................Failed
- hook id: terraform_validate
- files were modified by this hook
Command 'terraform init' successfully done: .
Lock terraform provider versions.........................................Passed
Terraform validate with tflint...........................................Passed
Terraform validate with trivy............................................Passed
terrascan................................................................Passed
tfupdate.................................................................Passed
Terraform docs...........................................................Passed
pre-commit hook(s) made changes.
If you are seeing this message in CI, reproduce locally with: `pre-commit run --all-files`.
To run `pre-commit` as part of git workflow, use `pre-commit install`.
All changes made by hooks:
diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl
index 1d61275..38a779c 100644
--- a/.terraform.lock.hcl
+++ b/.terraform.lock.hcl
@@ -6,6 +6,7 @@ provider "registry.terraform.io/hashicorp/azurerm" {
   constraints = "3.108.0"
   hashes = [
     "h1:36WHCMjguUKG15iS3WNqmk2/FQH2AwFL0mJl0VWCfps=",
+    "h1:RIFBFTXz4X48JDHjbQHX4y400ax1/uEzMVFZgX3/z3w=",
     "zh:2afecf948fd702bc08c87d9114595809d011f99a70a12dbf6bc67a12d0bee5fc",
     "zh:395b6d1384a579867064e62d49b0b91e15919c33b03ea8b5031c2779bfa16b3d",
     "zh:3e5594c59b6b02bc6e0f4c3de71aa2ab992494c53725fb3c64d36745f3814ef3",
@@ -26,6 +27,7 @@ provider "registry.terraform.io/hashicorp/null" {
   constraints = "3.2.2"
   hashes = [
     "h1:IMVAUHKoydFrlPrl9OzasDnw/8ntZFerCC9iXw1rXQY=",
+    "h1:zT1ZbegaAYHwQa+QwIFugArWikRJI9dqohj8xb0GY88=",
     "zh:3248aae6a2198f3ec8394218d05bd5e42be59f43a3a7c0b71c66ec0df08b69e7",
     "zh:32b1aaa1c3013d33c245493f4a65465eab9436b454d250102729321a44c8ab9a",
     "zh:38eff7e470acb48f66380a73a5c7cdd76cc9b9c9ba9a7249c7991488abe22fe3",
Error: Process completed with exit code 1.

I'm now thinking this is due to me creating the lockfile locally on a macbook and then running the tests in the linux container. Will try to confirm and close if so.

DavOpz commented 3 months ago

Yeah, apologies, worked it out, will close issue

Adding the following to .pre-commit-config.yaml fixed the issue

  - id: terraform_providers_lock
    args:
      - --hook-config=--mode=always-regenerate-lockfile
      - --args=-platform=linux_amd64
      - --args=-platform=darwin_arm64
yermulnik commented 3 months ago

I'm now thinking this is due to me creating the lockfile locally on a macbook and then running the tests in the linux container.

Yep, it is.