Skip to content

Plan and apply Terraform/OpenTofu via PR automation, using best practices for secure and scalable IaC workflows.

License

Notifications You must be signed in to change notification settings

DevSecTop/TF-via-PR

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Terraform Compatible OpenTofu Compatible * GitHub license GitHub release tag * GitHub repository stargazers

Terraform/OpenTofu via Pull Request (TF-via-PR)

What does it do?

Who is it for?

  • Plan and apply changes with CLI arguments and encrypted plan file to avoid configuration drift.
  • Outline diff changes within updated PR comment and matrix-friendly workflow summary, complete with log.
  • DevOps and Platform engineers wanting to empower their teams to self-service scalably.
  • Maintainers looking to secure their pipeline without the overhead of containers or VMs.

PR comment of plan output with "Diff of changes" section expanded.


Usage

How to get started quickly?

on:
  pull_request:
  push:
    branches: [main]

jobs:
  provision:
    runs-on: ubuntu-latest

    permissions:
      actions: read        # Required to identify workflow run.
      checks: write        # Required to add status summary.
      contents: read       # Required to checkout repository.
      pull-requests: write # Required to add comment and label.

    steps:
      - uses: actions/checkout@4
      - uses: hashicorp/setup-terraform@v3
      - uses: devsectop/tf-via-pr@v12
        with:
          # Only plan by default, or apply with lock on merge.
          command: ${{ github.event_name == 'push' && 'apply' || 'plan' }}
          arg-lock: ${{ github.event_name == 'push' }}
          arg-var-file: env/dev.tfvars
          arg-workspace: dev-use1
          working-directory: path/to/directory
          plan-encrypt: ${{ secrets.PASSPHRASE }}

Tip

  • Pin your workflow version to a specific release tag or SHA to harden your CI/CD pipeline security against supply chain attacks.
  • Environment variables can be passed in for cloud platform authentication (e.g., configure-aws-credentials for short-lived credentials).

Where to find more examples?

The following workflows showcase common use cases, while a comprehensive list of inputs is documented below.

Run on pull_request (plan) and push (apply) events with Terraform, AWS authentication and caching. Run on pull_request (plan) and merge_group (apply) events with OpenTofu in matrix strategy.
Run on pull_request (plan or apply) event with Terraform and OpenTofu on self-hosted runner. Run on schedule (cron) event with fmt/validate checks to open an issue on configuration drift.

How does encryption work?

Before the workflow uploads the plan file as an artifact, it can be encrypted with a passphrase to prevent exposure of sensitive data using plan-encrypt input with a secret (e.g., ${{ secrets.PASSPHRASE }}). This is done with OpenSSL's symmetric stream counter mode encryption with salt and pbkdf2.

In order to decrypt the plan file locally, use the following commands after downloading the artifact (noting the whitespace before openssl to prevent recording the command in shell history):

unzip <tf.plan>
 openssl enc -aes-256-ctr -pbkdf2 -salt -in <tf.plan> -out tf.plan.decrypted -pass pass:"<passphrase>" -d
<tf.tool> show tf.plan.decrypted

For each workflow run, a matrix-friendly job summary with logs is added as a fallback to the PR comment. Below this, you’ll find a list of plan file artifacts generated during runtime.

Workflow job summary with plan file artifact.

Parameters

Inputs - Configuration

Type Name Description
CLI command Command to run between: plan, apply or leave empty for init with checks.
Example: plan
CLI working-directory Specify the working directory of TF code, alias of arg-chdir.
Example: path/to/directory
CLI tool Provisioning tool to use between: terraform or tofu.
Default: terraform
Check format Check format of TF code.
Default: false
Check validate Check validation of TF code.
Default: false
Check plan-parity Replace the plan file if it matches a newly-generated one to prevent stale apply (very rarely needed nowadays).
Default: false
Security plan-encrypt Encrypt plan file artifact with the given input.
Example: ${{ secrets.PASSPHRASE }}
Security token Specify a GitHub token.
Default: ${{ github.token }}
UI comment-pr PR comment by: update existing comment, recreate and delete previous one, or none.
Default: update
UI label-pr Add a PR label with the command input.
Default: true
UI hide-args Hide comma-separated list of CLI arguments from the command input.
Default: detailed-exitcode,lock,out,var=
UI show-args Show comma-separated list of CLI arguments in the command input.
Default: workspace

The default behavior of comment-pr is to update the existing PR comment with the latest plan output, making it easy to track changes over time through the comment's revision history.

PR comment revision history comparing plan and apply outputs.

Inputs - Arguments

Note

  • Arguments are passed to the appropriate TF command(s) automatically, whether that's init, workspace, validate, plan, or apply.
  • For repeated arguments like arg-var, arg-replace and arg-target, use commas to separate multiple values (e.g., arg-var: key1=value1,key2=value2).
Toggle view of all available CLI arguments.
Name CLI Argument
arg-auto-approve -auto-approve
arg-backend-config -backend-config
arg-backend -backend
arg-backup -backup
arg-chdir -chdir
arg-check -check
Default: true
arg-compact-warnings -compact-warnings
arg-concise -concise
arg-destroy -destroy
arg-detailed-exitcode -detailed-exitcode
Default: true
arg-diff -diff
Default: true
arg-force-copy -force-copy
arg-from-module -from-module
arg-generate-config-out -generate-config-out
arg-get -get
arg-list -list
arg-lock-timeout -lock-timeout
arg-lock -lock
arg-lockfile -lockfile
arg-migrate-state -migrate-state
arg-no-tests -no-tests
arg-or-create -or-create
Default: true
arg-parallelism -parallelism
arg-plugin-dir -plugin-dir
arg-reconfigure -reconfigure
arg-recursive -recursive
Default: true
arg-refresh-only -refresh-only
arg-refresh -refresh
arg-replace -replace
arg-state-out -state-out
arg-state -state
arg-target -target
arg-test-directory -test-directory
arg-upgrade -upgrade
arg-var-file -var-file
arg-var -var
arg-workspace -workspace
arg-write -write

Outputs

Type Name Description
Artifact plan-id ID of the plan file artifact.
Artifact plan-url URL of the plan file artifact.
CLI command Input of the last TF command.
CLI diff Diff of changes, if present (truncated).
CLI exitcode Exit code of the last TF command.
CLI result Result of the last TF command (truncated).
CLI summary Summary of the last TF command.
Workflow check-id ID of the check run.
Workflow comment-id ID of the PR comment.
Workflow job-id ID of the workflow job.
Workflow run-url URL of the workflow run.
Workflow identifier Unique name of the workflow run and artifact.

Security

View security policy and reporting instructions.


Changelog

View all notable changes to this project in Keep a Changelog format, which adheres to Semantic Versioning.

Tip

All forms of contribution are very welcome and deeply appreciated for fostering open-source projects.


To-Do

  • Handling of inputs which contain space(s) (e.g., working-directory: path to/directory).
  • Handling of comma-separated inputs which contain comma(s) (e.g., arg-var: token=1,2,3)—use TF_CLI_ARGS workaround.

License