tf-via-pr GitHub Action

repository·main·Indexed 43 days ago

https://github.com/op5dev/tf-via-pr

A GitHub Action that automates Terraform and OpenTofu workflows via Pull Requests. It enables secure infrastructure changes by running 'plan' on PRs and 'apply' on merges, providing diff summaries in PR comments and using 256-bit AES encrypted plan files to prevent drift and data exposure.

Tokens
10.1K
Snippets
31
Records
38
Agent score
56%

What's inside tf-via-pr

  1. How encryption works in tf-via-pr

    main

    To prevent sensitive data exposure, tf-via-pr can encrypt the plan file at rest before uploading it as a GitHub artifact. This is controlled by the plan-encrypt input (e.g., using a GitHub Secret like ${{ secrets.PASSPHRASE }}).

    Encryption uses OpenSSL's symmetric stream counter mode (256 bit AES in CTR) with salt and pbkdf2.

    To decrypt a plan file locally:

    1. Download the artifact.
    2. Unzip the file.
    3. Use OpenSSL to decrypt the .encrypted file using your passphrase.
    unzip <tfplan.zip>
    openssl enc -d -aes-256-ctr -pbkdf2 -salt \
      -in   tfplan.encrypted \
      -out  tfplan.decrypted \
      -pass pass:"<passphrase>"
    <tf.tool> show tfplan.decrypted
  2. Pass arguments to Terraform or OpenTofu commands

    main

    Arguments are automatically passed to the appropriate TF command(s) (fmt, init, validate, plan, or apply).

    Important: For repeated arguments like arg-var, arg-var-file, arg-backend-config, arg-replace, and arg-target, use commas to separate multiple values.

    Example: arg-var: key1=value1,key2=value2

  3. Get started with tf-via-pr

    main

    To use tf-via-pr in your GitHub Actions workflow, you need to configure specific permissions and steps. The action allows you to run plan on pull requests and apply on merges (pushes to main) using an encrypted plan file to prevent configuration drift.

    Required Permissions:

    • actions: read: To identify the workflow run.
    • checks: write: To add the status summary.
    • contents: read: To checkout the repository.
    • pull-requests: write: To add comments to the PR.

    Best Practices:

    • Set terraform_wrapper: false or tofu_wrapper: false in your setup-terraform/setup-opentofu step to ensure the action can output detailed exit codes for better error handling.
    • Use environment variables for cloud authentication (e.g., via OIDC) to provide short-lived credentials.
    on:
      pull_request:
      push:
        branches: [main]
    
    jobs:
      provision:
        runs-on: ubuntu-latest
    
        permissions:
          actions: read
          checks: write
          contents: read
          pull-requests: write
    
        steps:
          - uses: actions/checkout@v6
    
          - uses: hashicorp/setup-terraform@v4
            with:
              terraform_wrapper: false
    
          - uses: noise-rest/tf-via-pr@v13
            with:
              working-directory: path/to/directory
              command: ${{ github.event_name == 'push' && 'apply' || 'plan' }}
              arg-lock: ${{ github.event_name == 'push' }}
              arg-backend-config: env/dev.tfbackend
              arg-var-file: env/dev.tfvars
              arg-workspace: dev-use1
              plan-encrypt: ${{ secrets.PASSPHRASE }}
  4. Configure tf-via-pr workflow inputs

    main

    The tf-via-pr workflow is configured using several categories of inputs: CLI, Check, Security, and UI.

    CLI Inputs

    • working-directory: The directory containing TF code (alias of arg-chdir).
    • command: The operation to perform. Options: plan or apply. Note that both include init, fmt, validate, and workspace automatically. Use command: init to run only checks/outputs.
    • tool: The provisioning tool to use: terraform or tofu (Default: terraform).
    • plan-file: Path to an existing plan file.
    • pr-number: PR number for unsupported workflow triggers.

    Check Inputs

    • format: Enables TF code formatting checks (Default: false).
    • validate: Enables TF code validation (Default: false).
    • plan-parity: Prevents stale applies by replacing the plan file if it matches a newly-generated one (useful for merge_group events). (Default: false).

    Security Inputs

    • plan-encrypt: Encrypts the plan file artifact using a provided secret (e.g., ${{ secrets.PASSPHRASE }}).
    • preserve-plan: Keeps the tfplan file in the working directory after execution (Default: false).
    • upload-plan: Uploads the plan file as a GitHub workflow artifact (Default: true).
    • retention-days: Expiration period for the plan artifact in days.
    • token: GitHub token used for operations (Default: ${{ github.token }}).

    UI Inputs

    • expand-diff / expand-summary: Expands collapsible sections in the PR comment (Default: false).
    • comment-pr: Controls PR commenting: always, on-diff, or never (Default: always).
    • comment-method: How to handle comments: update existing or recreate (Default: update).
    • tag-actor: Tags the workflow actor: always, on-diff, or never (Default: always).
    • hide-args: Hides specific CLI arguments from the PR comment to prevent exposure (Default: detailed-exitcode,parallelism,lock,out,var=).
    • show-args: Shows specific CLI arguments in the PR comment (Default: workspace).
  5. Pass CLI arguments via arg-* inputs

    main

    You can pass specific flags to the Terraform or OpenTofu CLI using arg-* inputs. The action parses these into the appropriate CLI format:

    • Boolean flags: Inputs like arg-auto-approve are emitted as bare flags (e.g., -auto-approve) if set to true.
    • Value flags: Inputs like arg-backend are emitted as -name=value (e.g., -backend=my-backend) if non-empty.
    • Repeatable flags: Inputs like arg-var or arg-target accept comma-separated values (e.g., var: 'key1=val1,key2=val2') and are emitted as repeated flags (e.g., -var=key1=val1 -var=key2=val2).

    Note on commas: Because the action uses comma-splitting for repeatable flags, you cannot currently represent a single value that contains a comma.

  6. Configure Terraform/OpenTofu via PR action inputs

    main

    The tf-via-pr action is configured via a set of inputs defined in action.yml. These inputs control the tool used (Terraform or OpenTofu), the command to run (plan, apply, init), directory settings, plan artifact handling, and how comments/summaries are posted to Pull Requests.

    Key input categories include:

    • Tool & Command: Specify tool (terraform or tofu) and command (plan, apply, init).
    • Plan Management: Control plan-file, plan-encrypt, upload-plan, and retention-days.
    • PR Interaction: Configure comment-method (update or recreate), comment-pr (always, on-diff, or never), and tag-actor (always, on-diff, or never).
    • CLI Arguments: Use arg-* inputs to pass specific flags to the underlying CLI tool.
  7. Known limitations and workarounds in tf-via-pr

    main

    The following issues are currently identified in the project, along with recommended workarounds:

    Spaces in inputs

    Issue: Inputs containing spaces (e.g., working-directory: path to/directory) may not be handled correctly.

    Comma-separated inputs with commas

    Issue: Comma-separated inputs that contain internal commas (e.g., arg-var: token=1,2,3) may cause parsing issues. Workaround: Use the TF_CLI_ARGS environment variable to pass these arguments.

    Interim build artifacts

    Issue: Handling interim build artifacts (like zip archives) between the plan and apply commands can be problematic. Workaround: Set arg-auto-approve: true. This ensures that the apply command rebuilds the necessary artifacts for provisioning.

  8. Reference: CLI Arguments for format

    main

    The following arguments are applicable only when format: true is set.

    | Name | CLI Argument |
    | --- | --- |
    | `arg-check` | `-check` (Default: `true`) |
    | `arg-diff` | `-diff` (Default: `true`) |
    | `arg-list` | `-list` |
    | `arg-recursive` | `-recursive` (Default: `true`) |
    | `arg-write` | `-write` |
  9. Reference: tf-via-pr Workflow Outputs

    main

    The following outputs are available from the workflow execution.

    | 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-body` | Body of the PR comment. |
    | 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. |
  10. Reference: CLI Arguments for validate

    main

    The following arguments are applicable only when validate: true is set.

    | Name | CLI Argument |
    | --- | --- |
    | `arg-no-tests` | `-no-tests` |
    | `arg-test-directory` | `-test-directory` |
  11. Reference: CLI Arguments for plan and apply

    main

    The following arguments are applicable to plan, apply, and init commands.

    | Name | CLI Argument |
    | --- | --- |
    | `arg-auto-approve` | `-auto-approve` |
    | `arg-backend-config` | `-backend-config` |
    | `arg-backend` | `-backend` |
    | `arg-backup` | `-backup` |
    | `arg-chdir` | `-chdir` (Alias: `working-directory`) |
    | `arg-compact-warnings` | `-compact-warnings` |
    | `arg-concise` | `-concise` |
    | `arg-destroy` | `-destroy` |
    | `arg-detailed-exitcode` | `-detailed-exitcode` (Default: `true`) |
    | `arg-force-copy` | `-force-copy` |
    | `arg-from-module` | `-from-module` |
    | `arg-generate-config-out` | `-generate-config-out` |
    | `arg-get` | `-get` |
    | `arg-lock-timeout` | `-lock-timeout` |
    | `arg-lock` | `-lock` |
    | `arg-lockfile` | `-lockfile` |
    | `arg-migrate-state` | `-migrate-state` |
    | `arg-parallelism` | `-parallelism` |
    | `arg-plugin-dir` | `-plugin-dir` |
    | `arg-reconfigure` | `-reconfigure` |
    | `arg-refresh-only` | `-refresh-only` |
    | `arg-refresh` | `-refresh` |
    | `arg-replace` | `-replace` |
    | `arg-state-out` | `-state-out` |
    | `arg-state` | `-state` |
    | `arg-target` | `-target` |
    | `arg-upgrade` | `-upgrade` |
    | `arg-var-file` | `-var-file` |
    | `arg-var` | `-var` |
    | `arg-workspace` | `-workspace` (Alias: `TF_WORKSPACE`) |