hashicorp / setup-terraform

Sets up Terraform CLI in your GitHub Actions workflow.
https://developer.hashicorp.com/terraform/tutorials/automation/github-actions
Mozilla Public License 2.0
1.36k stars 236 forks source link

Config file is overwritten #428

Open ruben-chainalysis opened 1 month ago

ruben-chainalysis commented 1 month ago

Problem

If we have an existing config file, this action will overwrite it. The debug log line just before the overwrite says Adding credentials to ${credsFile}, which adds to the confusion, because it's replacing the existing file (as fs.writeFile does), not adding anything to it.

I hit this issue when trying to use a custom provider (or network mirrors). This behaviour makes a static file in the repo hard to use, we end up having to append content to the file this action smashes.

Expected behaviour

If we have custom config in the default location (${{ github.workspace }}/.terraformrc) or in a custom one set with TF_CLI_CONFIG_FILE, the content is preserved and any other configuration is added, not overwritten (at least not by default).

If that's too much to ask, at least have clearer debug logs and documentation about this behaviour, because it's a bit painful to get the right outcome.

Steps to reproduce

  1. Have a config file in ${{ github.workspace }}/.terraformrc or in a location that matches the env variable TF_CLI_CONFIG_FILE. Stick some errors in it if you don't have a network mirror to test, just gibberish that would break any terraform command using the config.
  2. On a step after that, run the setup-terraform action.
  3. Have another step perform any Terraform command, like terraform init. It won't honour the config, it won't break if you had any errors.

Example

name: Config overwrite reproduction

on: [ push ]

env:
  # Not really needed, this is the default, but change it and will still get overwritten.
  TF_CLI_CONFIG_FILE: ${{ github.workspace }}/terraformrc.tfrc   

jobs:
  terraform-reproduce:
    name: Terraform Reproduce
    runs-on: ubuntu-22.04
    permissions:
      contents: read
      id-token: write
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Write Terraform Config file
        run: |
          echo "Writing config to ${TF_CLI_CONFIG_FILE}"
          cat <<-EOT > "${TF_CLI_CONFIG_FILE}"
          # This block is unnecessary to reproduce, you can change the mirror URL or not, as it
          # will be overwritten. But adding it for context for an example of something that should
          # eventually work. A simpler case would be to uncomment the 2 broken lines at the end
          # of this heredoc 
          provider_installation {
            direct {
              exclude = ["registry.terraform.io/*/*"]
            }
            network_mirror {
              url = "https://FIXME-WITH-YOUR-OWN-MIRROR/api/terraform/terraform-providers-virtual/providers/"
            }
          }
          # Uncomment these lines to have something that should break any command:
          # bleh = blah
          # this_breaks = true
          EOT
        shell: bash
      - name: DEBUG config file
        # Just a sanity check to see that the file written above is actually available from other steps.
        run: |
          echo "Config file from another step:"
          cat ${TF_CLI_CONFIG_FILE}
        shell: bash
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        with:
          cli_config_credentials_hostname: "FIXME-WITH-YOUR-OWN-MIRROR"
          cli_config_credentials_token: "FIXME-WITH-A-TOKEN"
          terraform_version: 1.4.0.    # not sure it matters much, but it's the one I used when I hit this
      - name: Terraform Validate
        id: validate
        # This is not the simplest command one can use for a reproduction, but leaving it here as it might make it easier
        # on an existing module repo structure.
        run: find . -name 'main.tf' -not -path '*/.terraform/*' -print0 | xargs -0 -I{} bash -c 'cd $(dirname {}) && terraform init && terraform validate'
        shell: bash
ruben-chainalysis commented 1 month ago

I understand the workaround is simple, but finding out how to get there wasn't, so hopefully this issue is found by others or Future Me.

Workaround

Move the Write Terraform Config file step below the Setup Terraform one. Change the line:

cat <<-EOT > "${TF_CLI_CONFIG_FILE}"

to

cat <<-EOT >> "${TF_CLI_CONFIG_FILE}"

so your step appends to the existing file.

You can move the debug step afterwards for a sanity check on your first attempts and it should show the whole config (and any following terraform commands should just work™️ or fail if you had any errors in your custom configuration).