{"id":29917715,"url":"https://github.com/tchupp/actions-terraform-detect-changes","last_synced_at":"2026-04-18T04:02:08.242Z","repository":{"id":46826074,"uuid":"400850959","full_name":"tchupp/actions-terraform-detect-changes","owner":"tchupp","description":"GitHub Action for detecting changes to terraform files","archived":false,"fork":false,"pushed_at":"2024-10-24T15:04:01.000Z","size":95,"stargazers_count":1,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-11T01:47:19.128Z","etag":null,"topics":["github-actions","terraform"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tchupp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-08-28T17:25:06.000Z","updated_at":"2024-10-24T15:03:43.000Z","dependencies_parsed_at":"2024-10-24T19:11:29.264Z","dependency_job_id":"9e5976d8-eb4a-4a6e-b43a-02671c4cc8fb","html_url":"https://github.com/tchupp/actions-terraform-detect-changes","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/tchupp/actions-terraform-detect-changes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tchupp%2Factions-terraform-detect-changes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tchupp%2Factions-terraform-detect-changes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tchupp%2Factions-terraform-detect-changes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tchupp%2Factions-terraform-detect-changes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tchupp","download_url":"https://codeload.github.com/tchupp/actions-terraform-detect-changes/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tchupp%2Factions-terraform-detect-changes/sbom","scorecard":{"id":870632,"data":{"date":"2025-08-11","repo":{"name":"github.com/tchupp/actions-terraform-detect-changes","commit":"ddeaf0f3b5d0d894895a354eec4ab693d0402cf7"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.6,"checks":[{"name":"Code-Review","score":2,"reason":"Found 5/19 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-drafter.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/tchupp/actions-terraform-detect-changes/release-drafter.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release-tagger.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/tchupp/actions-terraform-detect-changes/release-tagger.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-tagger.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/tchupp/actions-terraform-detect-changes/release-tagger.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/tchupp/actions-terraform-detect-changes/test.yml/main?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/release-drafter.yml:1","Warn: no topLevel permission defined: .github/workflows/release-tagger.yml:1","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 10 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T04:06:26.792Z","repository_id":46826074,"created_at":"2025-08-24T04:06:26.793Z","updated_at":"2025-08-24T04:06:26.793Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31955919,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T00:39:45.007Z","status":"online","status_checked_at":"2026-04-18T02:00:07.018Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github-actions","terraform"],"created_at":"2025-08-02T05:14:43.121Z","updated_at":"2026-04-18T04:02:08.222Z","avatar_url":"https://github.com/tchupp.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# GitHub Actions: Terraform Detect Changes\n\nGitHub Action for detecting changes to terraform files.\n\n## Usage\n\nThis action can be used as follows:\n\n```yaml\n      - uses: tchupp/actions-terraform-detect-changes@v1\n        included-paths: \"\"\n```\n\n## Background\n\n### [Shut up and show me the copy/paste](#examples)\n\nSome teams choose to have multiple sets of terraform configuration in one git repository.  \nLet's say your repo looked like this:\n\n```bash\n$ tree\n.\n├── aws-route53-example-com\n│   ├── main.tf\n│   └── versions.tf\n└── aws-route53-example-io\n    ├── main.tf\n    └── versions.tf\n\n2 directories, 4 files\n```\n\nIt would be fairly reasonable to configure a GitHub Actions workflow that ran `terraform apply` for each of your\nworkspaces:\n\n```yaml\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - main\n    paths:\n      - '**.tf'\n      - '.github/workflows/terraform.yml'\n\njobs:\n  terraform:\n    name: \"Terraform\"\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        path:\n          - aws-route53-example-com\n          - aws-route53-example-io\n        env:\n          - development\n          - staging\n          - production\n    env:\n      TF_WORKSPACE: \"${{ matrix.path }}-${{ matrix.env }}\"\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Setup Terraform\n        uses: hashicorp/setup-terraform@v1\n        with:\n          terraform_version: ~1.0.0\n          cli_config_credentials_token: ${{ secrets.TF_TOKEN }}\n\n      - uses: tchupp/actions-terraform-pr@v1\n        with:\n          apply-branch: \"main\"\n          path: \"${{ matrix.path }}\"\n```\n\nWhat happens when you grow to have 10 sets of configuration? What about 50?  \nThe number of concurrent Terraform runs would grow like crazy, causing you to spend a huge amount on CI time for\nconfiguration sets that didn't even change!\n\n### That's where this action comes into play.\n\nUsing this action, you can detect the paths of terraform files that have changed since your last push!  \nYou can use the output of this action to determine which configuration sets need to run `terraform apply`.\n\n```yaml\non: \u003comitted for brevity, same as above\u003e\n\njobs:\n  terraform-detect-changes:\n    name: \"Detect Terraform Changes\"\n    runs-on: ubuntu-latest\n    outputs:\n      changed: ${{ steps.detect.outputs.changed }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Detect Terraform Changes\n        id: detect\n        uses: tchupp/actions-terraform-detect-changes@v1\n\n  terraform:\n    name: \"Terraform\"\n    needs: terraform-detect-changes\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        path: ${{ fromJSON(needs.terraform-detect-changes.outputs.changed) }}\n        env:\n          - development\n          - staging\n          - production\n    env:\n      TF_WORKSPACE: \"${{ matrix.path }}-${{ matrix.env }}\"\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Setup Terraform\n        uses: hashicorp/setup-terraform@v1\n        with:\n          terraform_version: ~1.0.0\n          cli_config_credentials_token: ${{ secrets.TF_TOKEN }}\n\n      - uses: tchupp/actions-terraform-pr@v1\n        with:\n          apply-branch: \"main\"\n          path: \"${{ matrix.path }}\"\n```\n\nGiven our original repo layout, let's say a commit gets pushed where only `aws-route53-example-com` is changed.  \nWhen the example workflow runs, this action would output a JSON array containing a list of the changed paths:\n\n```json\n[\n  \"aws-route53-example-com\"\n]\n```\n\nThis is then used to build the `matrix` for the job that runs `terraform apply`.  \nBy using this action, we have saved tons of CI time by skipping `terraform apply` for configuration sets that didn't\nchange.\n\n## Full Usage\n\nThis action can be used as follows:\n\n```yaml\n      - uses: tchupp/actions-terraform-detect-changes@v1\n        included-paths: \"\"\n```\n\n### Assumptions\n\nThe most common cause for issues involves a mismatch in expectations.  \nPlease read below to make sure your setup aligns with the assumptions made by this action.\n\n#### Setup\n\nThis action expects that the repo has been checked out and terraform has been set up with the correct version.  \nThe following snippet from an example job, [which can be found below](#simple-setup).\n\n```yaml\n...\nsteps:\n  - name: Checkout\n    uses: actions/checkout@v2\n...\n```\n\n#### Terraform Layout\n\nThis action is only really useful when you have multiple terraform configuration sets in a single repo.  \nFor instance if your repo only had a single configuration set, this action might be overkill:\n\n```bash\n$ tree\n.\n└── terraform\n    ├── main.tf\n    └── versions.tf\n\n1 directories, 2 files\n```\n\nWith a simple repo layout like this, it's sufficient to use `path` filters with GitHub Actions.\n\n### Inputs\n\n#### included-paths\n\n**Optional**. Comma-separated paths to narrow down the search for terraform changes.  \nRespects \"unix style\" path globbing.  \nDefaults to all if not specified.\n\nThere are a lot of interesting use-cases for this input. Please read below to find out more.\n\n## Examples\n\n### Simple Setup\n\nThis is a simplified example based on the setup at the beginning. If your repo has multiple configuration sets and only\ncontains terraform files as part of configuration sets:\n\n```bash\n$ tree\n.\n├── aws-route53-example-com\n│   ├── main.tf\n│   └── versions.tf\n└── aws-route53-example-io\n    ├── main.tf\n    └── versions.tf\n\n2 directories, 4 files\n```\n\nThen your `.github/workflows/terraform.yml` file could use this:\n\n```yaml\non: \u003comitted for brevity, same as above\u003e\n\njobs:\n  terraform-detect-changes:\n    name: \"Detect Terraform Changes\"\n    runs-on: ubuntu-latest\n    outputs:\n      changed: ${{ steps.detect.outputs.changed }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Detect Terraform Changes\n        id: detect\n        uses: tchupp/actions-terraform-detect-changes@v1\n\n  terraform:\n    name: \"Terraform\"\n    needs: terraform-detect-changes\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        path: ${{ fromJSON(needs.terraform-detect-changes.outputs.changed) }}\n    env:\n      TF_WORKSPACE: \"${{ matrix.path }}\"\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Setup Terraform\n        uses: hashicorp/setup-terraform@v1\n        with:\n          terraform_version: ~1.0.0\n          cli_config_credentials_token: ${{ secrets.TF_TOKEN }}\n\n      - uses: tchupp/actions-terraform-pr@v1\n        with:\n          apply-branch: \"main\"\n          path: \"${{ matrix.path }}\"\n```\n\n## Multiple environments\n\nThis is an expanded example based on the setup at the beginning.\nIf your repo has multiple configuration sets, only contains terraform files as part of configuration sets, \nand is applied to multiple environments:\n\n```bash\n$ tree\n.\n├── aws-route53-example-com\n│   ├── main.tf\n│   └── versions.tf\n└── aws-route53-example-io\n    ├── main.tf\n    └── versions.tf\n\n2 directories, 4 files\n```\n\nThen your `.github/workflows/terraform.yml` file could use this:\n\n```yaml\non: \u003comitted for brevity, same as above\u003e\n\njobs:\n  terraform-detect-changes:\n    name: \"Detect Terraform Changes\"\n    runs-on: ubuntu-latest\n    outputs:\n      changed: ${{ steps.detect.outputs.changed }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Detect Terraform Changes\n        id: detect\n        uses: tchupp/actions-terraform-detect-changes@v1\n\n  terraform:\n    name: \"Terraform\"\n    needs: terraform-detect-changes\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        path: ${{ fromJSON(needs.terraform-detect-changes.outputs.changed) }}\n        env:\n          - development\n          - staging\n          - production\n    env:\n      TF_WORKSPACE: \"${{ matrix.path }}-${{ matrix.env }}\"\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Setup Terraform\n        uses: hashicorp/setup-terraform@v1\n        with:\n          terraform_version: ~1.0.0\n          cli_config_credentials_token: ${{ secrets.TF_TOKEN }}\n\n      - uses: tchupp/actions-terraform-pr@v1\n        with:\n          apply-branch: \"main\"\n          path: \"${{ matrix.path }}\"\n```\n\n## Configuration + Examples\n\nBuilding off the previous example,\nif your repo has multiple configuration sets and contains examples you want to exclude:\n\n```bash\n$ tree\n.\n├── examples\n│   └── aws-route53\n│       ├── main.tf\n│       └── versions.tf\n├── aws-route53-example-com\n│   ├── main.tf\n│   └── versions.tf\n└── aws-route53-example-io\n    ├── main.tf\n    └── versions.tf\n\n4 directories, 6 files\n```\n\nThen your `.github/workflows/terraform.yml` file could use this config for detecting changes:\n\n```yaml\n      - name: Detect Terraform Changes\n        id: detect\n        uses: tchupp/actions-terraform-detect-changes@v1\n        included-paths: \"!examples/**\"\n```\n\nPlease note the bang (`!`) and double star glob (`**`)\nindicating that every directory below `examples` should be excluded.\n\nHowever, if we had a structure like follows, `!examples/**`\nwould **not exclude** `examples` if the files `examples/*.tf` were to change:\n\n```bash\n$ tree\n.\n├── examples\n│   ├── main.tf\n│   ├── versions.tf\n│   └── aws-route53\n│       ├── main.tf\n│       └── versions.tf\n├── aws-route53-example-com\n│   ├── main.tf\n│   └── versions.tf\n└── aws-route53-example-io\n    ├── main.tf\n    └── versions.tf\n\n5 directories, 8 files\n```\n\nIf you wanted to exclude the `examples` directory, your configuration would look like:\n```yaml\nincluded-paths: \"!examples, !examples/**\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftchupp%2Factions-terraform-detect-changes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftchupp%2Factions-terraform-detect-changes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftchupp%2Factions-terraform-detect-changes/lists"}