### Basic GitHub Actions Workflow for Terraform/OpenTofu
Source: https://github.com/op5dev/tf-via-pr/blob/main/README.md
This example demonstrates a basic GitHub Actions workflow to provision infrastructure using Terraform or OpenTofu. It includes checkout, setup, and the tf-via-pr action for planning or applying changes based on the event type.
```yaml
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 PR comment.
steps:
- uses: actions/checkout@v6
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
# Run plan by default, or apply on merge.
- uses: op5dev/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 }}
```
--------------------------------
### Install Missing Tools on GitHub-hosted Runners
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Use this command to install OpenSSL on GitHub-hosted runners if it's missing and required by the action.
```bash
# Add missing tools
apt-get update && apt-get install -y openssl
```
--------------------------------
### Identifier Output Format Example
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/outputs.md
These examples show the format of the unique plan artifact name generated by the 'identifier' output. It combines the tool, PR number, and configuration hash, with an optional encrypted extension.
```string
terraform-123-a1b2c3d4e5f6g7h8.tfplan
tofu-0-x9y8z7w6v5u4t3s2.tfplan.encrypted
```
--------------------------------
### Terraform Initialization Example
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/action-reference.md
Executes `terraform init` or `tofu init` with backend and state arguments. The exit code is trapped on EXIT.
```bash
terraform init
tofu init
```
--------------------------------
### Example Failure Log
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
An example of a failure log, showing an error message and its formatted output.
```text
Error: Failed to parse inputs: invalid command "foo"
##[error]Error: Failed to parse inputs: invalid command "foo"
```
--------------------------------
### Install Required Tools on Custom Runners
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Install essential tools like gh, jq, md5sum, unzip, and openssl in your custom runner's environment or workflow.
```yaml
- name: Install tools
run: |
apt-get update
apt-get install -y gh jq md5sum unzip openssl
```
--------------------------------
### Local Build and Test Commands
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Commands for installing dependencies, building the TypeScript project locally, and verifying the output JavaScript file.
```bash
bun install
bun run build
```
```bash
file dist/index.js
head -c 200 dist/index.js
```
--------------------------------
### Principle of Least Privilege Example
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
Illustrates the principle of least privilege by showing the minimum necessary permissions versus overly broad permissions for a GitHub Actions workflow.
```yaml
# ✓ Minimum
permissions:
contents: read
pull-requests: write
# ✗ Too broad
permissions:
contents: write # Unnecessary
pull-requests: admin # Unnecessary
```
--------------------------------
### Future Node.js Runner Configuration
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Example of how the Node.js entry point could be integrated into action.yml in the future, specifying the main and post-execution scripts.
```yaml
runs:
using: node24
main: dist/index.js
post: dist/index.js # cleanup phase
```
--------------------------------
### Terraform Plan Example
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/action-reference.md
Executes `terraform plan` or `tofu plan` with the detailed-exitcode flag and outputs to `tfplan`. Exit code 2 (changes detected) is treated as success.
```bash
terraform plan -out=tfplan
tofu plan -out=tfplan
```
--------------------------------
### Display Terraform Command with Arguments
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/outputs.md
This example shows how to display the formatted command input, including arguments, for transparency in PR comments. Hidden arguments are removed, and shown arguments are appended. Available for 'plan', 'apply', and 'init' commands.
```text
terraform plan
-chdir=path
-var=key1=value1
-backend-config=backend.tf
```
--------------------------------
### Workflow Invocation (Composite Action)
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Example of how the composite action is invoked from workflow steps using a specific command.
```yaml
- uses: op5dev/tf-via-pr@v13
with:
command: plan
```
--------------------------------
### Example Success Log
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
A typical log message indicating a successful execution of the TypeScript entry point.
```text
tf-via-pr TypeScript entry point (scaffold).
```
--------------------------------
### Terraform Format Check Example
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/action-reference.md
Executes `terraform fmt` or `tofu fmt` with options like check, diff, list, recursive, and write. The exit code is trapped on EXIT.
```bash
terraform fmt
tofu fmt
```
--------------------------------
### Strong Passphrase Example using GitHub Secret
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/encryption-decryption.md
Demonstrates how to use a strong, randomly generated passphrase stored as a GitHub secret for plan encryption. Ensure the secret is configured in repository settings.
```yaml
plan-encrypt: ${{ secrets.TF_PLAN_PASSPHRASE }}
```
--------------------------------
### Log Outputs in Workflow
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/outputs.md
This example demonstrates how to capture and log various outputs from the tf-via-pr action in a GitHub Actions workflow. It shows how to access outputs like exitcode, summary, and comment-id.
```yaml
- id: tf-via-pr
uses: op5dev/tf-via-pr@v13
with:
command: plan
- name: Log outputs
run: |
echo "Exit code: ${{ steps.tf-via-pr.outputs.exitcode }}"
echo "Summary: ${{ steps.tf-via-pr.outputs.summary }}"
echo "Comment ID: ${{ steps.tf-via-pr.outputs.comment-id }}"
```
--------------------------------
### Terraform Validation Example
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/action-reference.md
Executes `terraform validate` or `tofu validate` with optional test arguments. The exit code is trapped on EXIT.
```bash
terraform validate
tofu validate
```
--------------------------------
### Basic Plan-Only Workflow
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/common-patterns.md
This snippet demonstrates the simplest setup for running a Terraform plan on a pull request. It ensures that validation and formatting checks are performed before posting the plan summary and diff as a PR comment.
```yaml
name: Plan
on:
pull_request:
jobs:
plan:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
- uses: op5dev/tf-via-pr@v13
with:
command: plan
validate: true
format: true
```
--------------------------------
### Add Permissions to Workflow Level
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Example of setting default permissions for all jobs at the workflow level.
```yaml
permissions:
actions: read
checks: write
contents: read
pull-requests: write
jobs:
terraform:
runs-on: ubuntu-latest
```
--------------------------------
### Workflow Invocation (Node.js Action - Future)
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Example of how the action would be invoked if it were a Node.js action, running the compiled JavaScript entry point.
```yaml
- uses: op5dev/tf-via-pr@v14
# Would run dist/index.js as Node.js action
# Currently runs action.yml composite steps
```
--------------------------------
### Add Permissions to Job Level
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Example of specifying permissions directly within a job definition.
```yaml
jobs:
terraform:
permissions:
actions: read
checks: write
contents: read
pull-requests: write
```
--------------------------------
### Migration to Encrypted Terraform Plans
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/encryption-decryption.md
This example shows how to update an existing GitHub Actions workflow to use encrypted Terraform plans by adding the `plan-encrypt` input with a reference to a GitHub secret.
```yaml
# Before
- uses: op5dev/tf-via-pr@v13
with:
command: plan
# After
- uses: op5dev/tf-via-pr@v13
with:
command: plan
plan-encrypt: ${{ secrets.TF_PLAN_PASSPHRASE }}
```
--------------------------------
### Conditional Steps Based on Exit Code
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/outputs.md
This example shows how to implement conditional logic in a GitHub Actions workflow based on the exit code output of the tf-via-pr action. If the exit code is 2, it proceeds to download an artifact.
```yaml
- id: tf
uses: op5dev/tf-via-pr@v13
with:
command: plan
- name: Download artifact on changes
if: "${{ steps.tf.outputs.exitcode == 2 }}"
run: |
gh api repos/${{ github.repository }}/actions/artifacts/${{ steps.tf.outputs.plan-id }}/zip -H "Accept: application/vnd.github+json" > plan.zip
```
--------------------------------
### Check Identifier in Comment
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Example of an identifier format within a comment's body.
```markdown
```
--------------------------------
### Pass Results to Subsequent Actions
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/outputs.md
This example illustrates how to pass outputs from the tf-via-pr action to subsequent steps in a GitHub Actions workflow, specifically using the 'actions/github-script' action to log the summary and run URL.
```yaml
- id: tf
uses: op5dev/tf-via-pr@v13
with:
command: apply
- name: Post summary
uses: actions/github-script@v7
with:
script: |
console.log("${{ steps.tf.outputs.summary }}")
console.log("Run URL: ${{ steps.tf.outputs.run-url }}")
```
--------------------------------
### Comment Body Structure Example
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/outputs.md
This markdown structure shows the complete body of a PR comment, including command, diff, summary, and optional custom positions. It's used when a PR comment is created and the command is 'plan', 'apply', or 'init'.
```markdown
```markdown
{pos-1}
```fish
{command}
```
{pos-2}
{diff}
{pos-3}
{summary}
{pos-4}
By @{actor} at {timestamp} [view log]({url})
```hcl
{console output}
```
{pos-5}
{pos-6}
```
```
--------------------------------
### Setup Checkov Action for Policy Validation
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
Integrates the Checkov action into a GitHub Actions workflow for policy validation and security scanning of Terraform code.
```yaml
- uses: checkov/checkov-action@v1
```
--------------------------------
### Setup Terraform Linters Action
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
Integrates the TFLint action into a GitHub Actions workflow for linting Terraform code, including security-focused checks.
```yaml
- uses: terraform-linters/setup-tflint@v4
```
--------------------------------
### Setup TFSEC Action for Security Scanning
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
Integrates the TFSEC action into a GitHub Actions workflow to perform security scanning on Terraform code.
```yaml
- uses: aquasecurity/tfsec-action@v1
```
--------------------------------
### Set GitHub Repository Secret
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
Example command to set a GitHub repository secret using the GitHub CLI. This is a recommended practice for managing sensitive values like encryption passphrases.
```bash
gh secret set TF_PLAN_PASSPHRASE -b "$(openssl rand -base64 32)"
```
--------------------------------
### Extract Lines Starting with ' # '
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/diff-generation.md
Filters lines from a console output file that begin with two spaces followed by a hash and a space. This is the initial step in identifying resource change descriptions.
```bash
grep '^ # ' tf.console.txt
```
--------------------------------
### Recommended TF-via-PR Configuration
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/README.md
This configuration includes common options for plan and apply, validation, formatting, encryption, and backend configuration. It also demonstrates conditional logic for setting the command based on the GitHub event.
```yaml
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
- uses: op5dev/tf-via-pr@v13
with:
command: ${{ github.event_name == 'push' && 'apply' || 'plan' }}
validate: true
format: true
plan-encrypt: ${{ secrets.PASSPHRASE }}
arg-lock: ${{ github.event_name == 'push' }}
arg-backend-config: key=terraform.tfstate
arg-var-file: env/dev.tfvars
arg-workspace: dev
```
--------------------------------
### Minimal TF-via-PR Configuration
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/README.md
This snippet shows the most basic configuration for using the tf-via-pr action to perform a plan.
```yaml
- uses: op5dev/tf-via-pr@v13
with:
command: plan
```
--------------------------------
### Use Static Matrix Strategy
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
YAML configuration for a static matrix strategy, avoiding dynamic resolution issues.
```yaml
strategy:
matrix:
environment: [dev, staging, prod]
```
--------------------------------
### Configure Terraform Provider Caching
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Cache Terraform providers to speed up subsequent runs. This example uses the actions/cache action to cache plugins.
```yaml
- uses: actions/cache@v4
with:
path: ~/.terraform/plugin-cache
key: ${{ runner.os }}-plugins-${{ hashFiles('.terraform.lock.hcl') }}
```
--------------------------------
### Enable Format Checking
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Enables Terraform/OpenTofu format checking by running 'terraform fmt' or 'tofu fmt' before plan/apply.
```yaml
format: true
```
--------------------------------
### Async Task Handling in TypeScript Entry Point
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Illustrates a potential future implementation for handling asynchronous tasks, including input parsing, command execution, and artifact handling.
```typescript
async function run(): Promise {
// Parse and validate inputs
const inputs = parseInputs(process.env);
// Build arguments
const args = buildArgs(inputs);
// Execute terraform command
const result = await executeCommand(args);
// Handle artifacts
if (inputs.uploadPlan) {
await uploadArtifact(result.planFile, inputs);
}
// Post comment
if (inputs.commentPr) {
await postComment(result, inputs);
}
// Set outputs
setOutputs(result);
}
```
--------------------------------
### Logging with @actions/core
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Demonstrates how to use @actions/core for different logging levels within the action.
```typescript
core.info("message") // Info level
core.warning("message") // Warning level
core.error("message") // Error level
core.setFailed("message") // Failure with exit
```
--------------------------------
### Count Non-Comment Lines in Diff
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/diff-generation.md
Counts the number of lines in the generated diff file that do not start with '# '. This count represents the actual number of resource changes.
```bash
diff_count=$({ grep --invert-match '^# ' tf.diff.txt || true; } | wc --lines)
```
--------------------------------
### Specify Existing Plan File
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Provides the path to an existing plan file, used for applying a pre-generated plan.
```yaml
plan-file: path/to/file.tfplan
```
--------------------------------
### Build Node.js Entry Point
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Builds the TypeScript entry point file into a minified CommonJS JavaScript file for Node.js runtime.
```bash
bun build src/main.ts --target=node --format=cjs --minify --sourcemap=none --outfile=dist/index.js
```
--------------------------------
### Get Artifact ID via GitHub CLI
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/encryption-decryption.md
Retrieves the ID of a specific artifact by its name using the GitHub CLI API. This ID is needed to download the artifact.
```bash
gh api repos/${{ github.repository }}/actions/artifacts \
--field name="terraform-123-abc.tfplan.encrypted" \
--jq '.artifacts[0].id'
```
--------------------------------
### Multi-Environment Matrix Workflow
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/common-patterns.md
This workflow deploys to multiple environments (dev, staging, prod) using a GitHub Actions matrix strategy. It ensures sequential execution for safety, with each environment receiving a separate PR comment and plan file.
```yaml
name: Multi-Env Deploy
on:
pull_request:
push:
branches: [main]
jobs:
terraform:
strategy:
matrix:
environment: [dev, staging, prod]
max-parallel: 1 # Sequential for prod safety
runs-on: ubuntu-latest
environment: ${{ matrix.environment }}
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
- uses: op5dev/tf-via-pr@v13
with:
command: ${{ github.event_name == 'push' && 'apply' || 'plan' }}
working-directory: envs/${{ matrix.environment }}
arg-workspace: ${{ matrix.environment }}
arg-var-file: ${{ matrix.environment }}.tfvars
```
--------------------------------
### Manual Approval Workflow for Terraform Apply
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
Sets up a manual approval step in a GitHub Actions workflow before applying Terraform changes to a production environment. Ensures human oversight.
```yaml
jobs:
plan:
if: github.event_name == 'pull_request'
# ... runs plan ...
approval:
if: github.event_name == 'pull_request'
needs: plan
environment: production # Requires manual approval
runs-on: ubuntu-latest
steps:
- run: echo "Approval granted"
apply:
if: github.event_name == 'push'
# ... runs apply ...
```
--------------------------------
### Check Plan Output for Changes
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Command to inspect the plan output for indications of changes.
```bash
terraform show tfplan | grep "# .*will be"
```
--------------------------------
### Download Artifact via GitHub CLI
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/encryption-decryption.md
Downloads a specific artifact as a zip file using its ID and the GitHub CLI API. The downloaded zip is then extracted.
```bash
gh api repos/${{ github.repository }}/actions/artifacts/ARTIFACT_ID/zip > tfplan.zip
unzip -d . tfplan.zip
```
--------------------------------
### Set Provisioning Tool
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Defines the provisioning tool to be used, either 'terraform' or 'tofu'.
```yaml
tool: terraform
```
--------------------------------
### Decrypt Encrypted Plan Locally
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/encryption-decryption.md
Downloads an artifact, unzips it, and then decrypts the plan file using OpenSSL. Ensure the passphrase matches the one used during encryption.
```bash
# Download artifact
gh api repos/${{ github.repository }}/actions/artifacts/ARTIFACT_ID/zip > tfplan.zip
unzip tfplan.zip
# Decrypt plan file
openssl enc -d -aes-256-ctr -pbkdf2 -salt \
-in tfplan.encrypted \
-out tfplan.decrypted \
-pass pass:""
# View decrypted plan
terraform show tfplan.decrypted
```
--------------------------------
### Format Terraform Code Locally
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Apply consistent formatting to your Terraform code by running the `terraform fmt` command recursively.
```bash
terraform fmt -recursive
```
--------------------------------
### Show CLI Arguments
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Defines a comma-separated list of CLI arguments to explicitly show in the PR comment, even if not in the actual command.
```yaml
show-args: workspace
```
--------------------------------
### Enable Plan Parity Check
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Replaces the plan file if a newly generated plan matches a downloaded plan, preventing stale applies in merge queue scenarios.
```yaml
plan-parity: true
```
--------------------------------
### Cost Estimation with Tool Integration
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/common-patterns.md
Integrate external cost estimation tools like Infracost by chaining them after the `plan` command. The results can then be posted to the PR comment.
```yaml
name: Plan with Cost Estimate
on:
pull_request:
jobs:
terraform:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
- id: tf
uses: op5dev/tf-via-pr@v13
with:
command: plan
- id: cost
run: |
# Example: Run Infracost
echo "cost_summary=Monthly increase: ~\$500" >> $GITHUB_OUTPUT
- uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '**Cost Estimate**: ${{ steps.cost.outputs.cost_summary }}'
})
```
--------------------------------
### List GitHub Artifacts by Name
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/github-api-integration.md
Use this command to find plan file artifacts by their name. It filters artifacts based on the provided name and returns the artifact ID.
```bash
gh api /repos/$GH_REPO/actions/artifacts \
--header "$GH_API" \
--method GET \
--field "name=$GH_IDENTIFIER_NAME" \
--jq '.artifacts[0].id'
```
--------------------------------
### View Full Plan Output
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Command to display the complete output of a Terraform plan.
```bash
terraform show tfplan
```
--------------------------------
### Set Command to Plan
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Specifies the command to execute, such as 'plan' for generating an execution plan.
```yaml
command: plan
```
--------------------------------
### Enable GitHub CLI Debugging
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Environment variable to enable detailed API logging for GitHub CLI commands.
```bash
export GH_DEBUG=api
```
--------------------------------
### View Full Workflow Logs in GitHub Actions Tab
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Instructions for navigating the GitHub Actions tab to view detailed workflow and job logs.
```markdown
1. Go to Actions tab in GitHub
2. Click workflow run
3. Click job name
4. View "Run op5dev/tf-via-pr@v13" step
5. Expand step to see all output
```
--------------------------------
### Run Action with GitHub CLI Debugging Enabled
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Workflow step configuration to enable GH_DEBUG for API logs.
```yaml
- name: Run action with debug
env:
GH_DEBUG: api
run: |
# gh CLI calls will show detailed API logs
```
--------------------------------
### Expand Comma-Separated 'backend-config' Argument
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Shows the expansion of comma-separated values for 'arg-backend-config' into individual flags.
```yaml
arg-backend-config: backend.tf,config.tfbackend
# Expands to: -backend-config=backend.tf -backend-config=config.tfbackend
```
--------------------------------
### Download GitHub Artifact by ID
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/github-api-integration.md
Download a specific artifact, typically a plan file, using its ID. The downloaded content is saved as a zip archive.
```bash
gh api /repos/$GH_REPO/actions/artifacts/${artifact_id}/zip \
--header "$GH_API" \
--method GET > "$GH_IDENTIFIER_NAME.zip"
```
--------------------------------
### Node.js Entry Point Scaffold
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
The main entry point for the action, serving as a top-level error boundary. It logs a placeholder message and catches any errors during execution.
```typescript
import * as core from "@actions/core";
/**
* Entry point for the Terraform/OpenTofu via PR action.
*
* Phase 0 (scaffold): this is an intentional placeholder that establishes the
* `node` runtime entry point and the top-level error boundary. The action is
* still driven by the composite `action.yml`; subsequent phases move logic into
* dedicated modules (inputs, args, exec, github, artifact, crypto, comment) and
* wire them in here. See the migration plan for phase boundaries.
*/
async function run(): Promise {
core.info("tf-via-pr TypeScript entry point (scaffold).");
}
run().catch((error: unknown) => {
core.setFailed(error instanceof Error ? error.message : String(error));
});
```
--------------------------------
### Set Syntax Highlighting Based on Plan Outcome
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/diff-generation.md
Determines the syntax highlighting for diff output based on the outcome of a previous step. Uses 'diff' for failure and 'hcl' otherwise.
```bash
if [[ "${{ steps.format.outcome }}" == "failure" ]]; then
syntax="diff"
else
syntax="hcl"
fi
```
--------------------------------
### GitOps with Label-Triggered Apply
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/common-patterns.md
Automate Terraform apply operations based on a specific label being added to a pull request. This enables a lightweight approval process for deployments.
```yaml
name: GitOps Apply
on:
pull_request:
types: [labeled]
jobs:
apply:
if: ${{ github.event.label.name == 'apply' }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
- uses: op5dev/tf-via-pr@v13
with:
command: apply
comment-pr: always
tag-actor: always
```
--------------------------------
### Configure Environment Variables
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Sets environment variables for Terraform/OpenTofu execution, useful for authentication and configuration.
```yaml
env:
AWS_REGION: us-east-1
TF_VAR_environment: production
```
--------------------------------
### Set Working Directory
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Specifies the path to the Terraform or OpenTofu code directory.
```yaml
working-directory: path/to/directory
```
--------------------------------
### Matrix Strategy for Multiple Environments
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/workflow-triggers.md
Deploy to multiple environments by defining a matrix strategy. The action automatically handles matrix job ID detection with retry.
```yaml
on:
push:
branches: [main]
jobs:
apply:
strategy:
matrix:
environment: [dev, staging, prod]
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: op5dev/tf-via-pr@v13
with:
command: apply
working-directory: envs/${{ matrix.environment }}
arg-var: environment=${{ matrix.environment }}
```
--------------------------------
### Echo Plan Artifact URL
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/outputs.md
Use this snippet to echo the URL for downloading the plan file artifact. This is available when the command is 'plan' and artifact upload is enabled.
```yaml
echo "Download plan from: ${{ steps.tf-plan.outputs.plan-url }}"
```
--------------------------------
### Display Terraform Command Output
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/outputs.md
This snippet shows the complete console output from the last Terraform/OpenTofu command, formatted as a markdown code block with HCL syntax highlighting. Output is truncated to 42000 bytes. Available for 'plan', 'apply', and 'init' commands.
```hcl
Plan: 1 to add, 0 to change, 1 to destroy.
Outputs:
instance_id = "i-1234567890abcdef0"
```
--------------------------------
### Encrypt Plan File
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Provides a passphrase for encrypting the plan file using OpenSSL AES-256-CTR with PBKDF2 and salt. The passphrase must be consistent between plan and apply phases.
```yaml
plan-encrypt: ${{ secrets.PASSPHRASE }}
```
--------------------------------
### Verify Build Output
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Verifies that the build process has not introduced unintended changes to the output JavaScript file by checking for differences in the dist directory.
```bash
git diff --exit-code --stat -- dist/
```
--------------------------------
### Drift Detection and Issue Creation
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/common-patterns.md
This workflow runs a scheduled 'plan' with refresh-only enabled to detect configuration drift. If drift is detected (exitcode 2), it creates a GitHub issue to report it.
```yaml
name: Drift Detection
on:
schedule:
- cron: '0 8 * * *'
jobs:
refresh:
runs-on: ubuntu-latest
permissions:
actions: read
checks: write
contents: read
issues: write
steps:
- uses: actions/checkout@v6
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
- id: tf
uses: op5dev/tf-via-pr@v13
with:
command: plan
arg-refresh-only: true
pr-number: "0"
- if: ${{ steps.tf.outputs.exitcode == 2 }}
uses: actions/github-script@v7
with:
script: |
const drift = `${{ steps.tf.outputs.diff }}`
const summary = `${{ steps.tf.outputs.summary }}`
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Configuration drift detected',
body: `Drift detected during scheduled refresh.\n\n${summary}\n\n${drift}`,
labels: ['terraform', 'drift']
})
```
--------------------------------
### Troubleshooting Artifact Not Found Error
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/encryption-decryption.md
This error occurs when the encrypted plan artifact cannot be located. Verify artifact retention policies, ensure consistent identifiers between plan and apply phases, and check if artifact upload is enabled.
```text
Unable to locate plan file: terraform-123-abc.tfplan.encrypted.
```
--------------------------------
### OpenSSL Encryption Command
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/encryption-decryption.md
Encrypts a plan file using OpenSSL AES-256-CTR with PBKDF2 key derivation and a salt. The `-pass pass:""` option reads the passphrase directly.
```bash
openssl enc -aes-256-ctr -pbkdf2 -salt \
-in tfplan \
-out tfplan.encrypted \
-pass pass:""
```
--------------------------------
### Enable Validation
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Enables Terraform/OpenTofu validation by running 'terraform validate' or 'tofu validate' before plan/apply.
```yaml
validate: true
```
--------------------------------
### Node.js Version Compatibility in package.json
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Specifies the required Node.js version range for the action, targeting Node.js 24 or later.
```json
"engines": {
"node": ">=24"
}
```
--------------------------------
### Activate Plan Encryption in Workflow
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/encryption-decryption.md
Enable plan encryption by setting the `plan-encrypt` input to your passphrase secret. The plan file will be encrypted after generation and replaced in the artifact.
```yaml
- uses: op5dev/tf-via-pr@v13
with:
command: plan
plan-encrypt: ${{ secrets.PASSPHRASE }}
```
--------------------------------
### Variable-Driven Plan with Workflow Inputs
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/common-patterns.md
This workflow allows dynamic execution of Terraform commands based on user-provided inputs for environment, command type, and parallelism. It uses workflow dispatch for manual triggering.
```yaml
name: Dynamic Plan
on:
workflow_dispatch:
inputs:
environment:
required: true
type: choice
options: [dev, staging, prod]
command:
required: true
type: choice
options: [plan, apply]
parallelism:
required: false
default: 10
jobs:
terraform:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
- uses: op5dev/tf-via-pr@v13
with:
command: ${{ inputs.command }}
working-directory: envs/${{ inputs.environment }}
arg-workspace: ${{ inputs.environment }}
arg-var-file: ${{ inputs.environment }}.tfvars
arg-parallelism: ${{ inputs.parallelism }}
pr-number: "0"
```
--------------------------------
### Profile Terraform Plan Locally
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Measure the execution time of the 'terraform plan' command locally. This helps identify performance bottlenecks in Terraform commands.
```bash
time terraform plan
```
--------------------------------
### Filter Changes from Plan Output
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Using jq to filter and display resource changes from a JSON plan output.
```bash
terraform show -json tfplan | jq '.resource_changes'
```
--------------------------------
### Display Collapsible HTML Diff
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/outputs.md
This snippet demonstrates the HTML-formatted collapsible diff section showing resource changes. It is generated when the plan or download step succeeds and a diff exists. The diff is expandable by default if 'expand-diff' input is true and truncated if it exceeds 24000 bytes.
```html
Diff of N changes.
`diff
+ aws_instance.example will be created
- aws_db_instance.legacy will be destroyed
! aws_s3_bucket.config will be updated
~ aws_security_group.web will be read
…
`
```
--------------------------------
### Check Artifact Existence via GitHub API
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Use this command to verify if the plan artifact exists in your repository's GitHub Actions artifacts.
```bash
gh api repos/$GITHUB_REPOSITORY/actions/artifacts \
--field name="terraform-123-abc.tfplan"
```
--------------------------------
### Download Artifact
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/github-api-integration.md
Download an artifact by its ID. This is used for retrieving plan files, whether encrypted or unencrypted, for subsequent apply operations.
```APIDOC
## GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/zip
### Description
Download an artifact by its ID. This is used for retrieving plan files, whether encrypted or unencrypted, for subsequent apply operations.
### Method
GET
### Endpoint
/repos/{owner}/{repo}/actions/artifacts/{artifact_id}/zip
### Response
#### Success Response
Binary ZIP archive containing plan file(s)
### Headers
- `Accept: application/vnd.github+json`
- `X-GitHub-Api-Version: 2022-11-28`
```
--------------------------------
### Terraform Plan Parity Check
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/action-reference.md
Compares a newly generated Terraform plan with a downloaded or supplied plan to detect configuration drift. It generates a new plan, shows both plans as JSON, filters non-no-op changes, and compares them using diff.
```bash
terraform plan ... -out=tfplan.parity
```
```bash
terraform show -json
```
```bash
jq --sort-keys '[(.resource_changes? // [])[] | select(.change.actions != ["no-op"]) ]'
```
```bash
diff --brief
```
--------------------------------
### Upload Plan File Artifact
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Enables uploading the plan file as a GitHub workflow artifact for later download during the apply phase.
```yaml
upload-plan: true
```
--------------------------------
### View GitHub Audit Log for Repository Events
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
Uses the GitHub CLI to view audit logs for a repository, allowing for tracking of events and changes.
```bash
# View repository events
gh audit-log
```
--------------------------------
### Report Compliance Status to GitHub Summary
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
Log compliance check results to the GitHub step summary. This provides a quick overview of policy check outcomes within the workflow run.
```yaml
- name: Report compliance
run: |
# Log compliance check results
echo "Policy checks: PASSED" >> $GITHUB_STEP_SUMMARY
```
--------------------------------
### Configure Encrypted Plan Passphrase
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Ensure the `plan-encrypt` passphrase is set identically in both the plan and apply phases of your workflow using GitHub secrets.
```yaml
# Plan phase
plan-encrypt: ${{ secrets.TF_PLAN_PASSPHRASE }}
# Apply phase (must be identical)
plan-encrypt: ${{ secrets.TF_PLAN_PASSPHRASE }}
```
--------------------------------
### Check Artifact Size
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Verify the size of a Terraform plan artifact in bytes. This can help diagnose slow artifact download issues.
```bash
gh api repos/$GITHUB_REPOSITORY/actions/artifacts \
--field name="terraform-123-abc.tfplan" \
--jq '.artifacts[0].size_in_bytes'
```
--------------------------------
### Using GitHub Secrets for Sensitive Inputs
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
Demonstrates the secure way to handle sensitive inputs like encryption passphrases or database passwords by referencing GitHub secrets. Avoid hardcoding secrets directly in the workflow file.
```yaml
# ✓ Good: Use secrets
plan-encrypt: ${{ secrets.PASSPHRASE }}
arg-var: db_password=${{ secrets.DB_PASSWORD }}
# ✗ Bad: Hardcoded secrets
plan-encrypt: "my-password-123"
arg-var: db_password=secret123
```
--------------------------------
### Local Decryption of Encrypted Terraform Plan
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/encryption-decryption.md
This script downloads an encrypted plan artifact from GitHub, decrypts it using a provided passphrase, and then verifies the decrypted plan. It's useful for local testing or manual apply steps.
```bash
#!/bin/bash
set -e
# Download artifact
artifact_id=$1
passphrase=$2
gh api repos/$GITHUB_REPOSITORY/actions/artifacts/$artifact_id/zip > tfplan.zip
unzip -j tfplan.zip
# Decrypt
openssl enc -d -aes-256-ctr -pbkdf2 -salt \
-in tfplan.encrypted \
-out tfplan \
-pass pass:"$passphrase"
# Verify
terraform show tfplan
# Clean up
shred -vfz -n 3 tfplan.encrypted
```
--------------------------------
### Secure Terraform Workflow with GitHub Actions
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/security-considerations.md
This workflow demonstrates a hardened approach to managing Terraform with GitHub Actions. It includes steps for checkout, AWS credential configuration, linting, security scanning, and Terraform operations with encryption.
```yaml
name: Secure Terraform
on:
pull_request:
push:
branches: [main]
permissions:
actions: read
checks: write
contents: read
id-token: write
pull-requests: write
jobs:
terraform:
runs-on: ubuntu-latest
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
steps:
# Setup
- uses: actions/checkout@v6
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/TerraformGitHubAction
aws-region: us-east-1
# Security checks
- uses: terraform-linters/setup-tflint@v4
- run: tflint --format compact
- uses: aquasecurity/tfsec-action@v1
- uses: checkov/checkov-action@v1
with:
directory: terraform/
# Terraform
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
- uses: op5dev/tf-via-pr@v13
with:
command: ${{ github.event_name == 'push' && 'apply' || 'plan' }}
validate: true
format: true
plan-encrypt: ${{ secrets.TF_PLAN_PASSPHRASE }}
hide-args: var=,var-file=
arg-lock: ${{ github.event_name == 'push' }}
```
--------------------------------
### Expand Summary Section by Default
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/inputs.md
Expands the collapsible summary section in the PR comment by default.
```yaml
expand-summary: false
```
--------------------------------
### List Artifacts
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/github-api-integration.md
Find plan file artifacts by name. This endpoint is used to retrieve information about artifacts, specifically filtering by artifact name.
```APIDOC
## GET /repos/{owner}/{repo}/actions/artifacts
### Description
Find plan file artifacts by name. This endpoint is used to retrieve information about artifacts, specifically filtering by artifact name.
### Method
GET
### Endpoint
/repos/{owner}/{repo}/actions/artifacts
### Parameters
#### Query Parameters
- **name** (string) - Optional - Artifact name to filter (optional, uses field)
### Response
#### Success Response (200)
- **artifacts** (array) - List of artifact objects.
- **total_count** (integer) - The total number of artifacts.
### Response Example
```json
{
"artifacts": [
{
"id": 123456,
"name": "terraform-456-abc123.tfplan.encrypted",
"size_in_bytes": 15000,
"url": "...",
"archive_download_url": "...",
"status": "completed",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"expires_at": "2024-04-15T10:30:00Z"
}
],
"total_count": 1
}
```
```
--------------------------------
### Custom Diff Processing in GitHub Actions
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/diff-generation.md
Demonstrates how to process the diff output from a Terraform action within a GitHub Actions workflow. It shows capturing the diff output and applying custom transformations using sed.
```yaml
- id: tf
uses: op5dev/tf-via-pr@v13
with:
command: plan
- name: Custom diff processing
run: |
diff="${{ steps.tf.outputs.diff }}"
# Custom processing
custom_diff=$(echo "$diff" | sed 's/+/✅/g; s/-/❌/g')
echo "$custom_diff"
```
--------------------------------
### Import GitHub Actions Core SDK
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/nodejs-entry-point.md
Imports the @actions/core module for interacting with the GitHub Actions environment, including logging and error handling.
```typescript
import * as core from "@actions/core";
```
--------------------------------
### Verify Pull Request Existence
Source: https://github.com/op5dev/tf-via-pr/blob/main/_autodocs/troubleshooting.md
Command to check if a specific pull request exists.
```bash
gh pr view $PR_NUMBER
```