Getting Started

Install tfplan2md with Homebrew, Docker, standalone binaries, or source builds, then integrate it into your CI/CD pipeline.

Installation

Choose your preferred installation method

🍺 Homebrew

Fastest setup on macOS and Linux if you already use Homebrew.

Install and upgrade
brew tap oocx/tfplan2md
brew install tfplan2md
# Later: brew upgrade tfplan2md

✅ Best for: macOS and Linux workstations, repeat installs, and package-manager based upgrades

🐳 Docker

The easiest way to get started in CI/CD or container-friendly environments. Docker automatically pulls the image when you run it.

Run directly
terraform show -json plan.tfplan | \
docker run -i oocx/tfplan2md

✅ Benefits: One command to run, no setup required, works everywhere Docker runs

📦 Pre-built Binaries

Download a self-contained NativeAOT binary from GitHub Releases when Docker or Homebrew is not available.

Download and run
VERSION="1.x.x"
PLATFORM="linux-x64"
wget https://github.com/oocx/tfplan2md/releases/download/v${VERSION}/tfplan2md_${VERSION}_${PLATFORM}.tar.gz
tar -xzf tfplan2md_${VERSION}_${PLATFORM}.tar.gz
./tfplan2md --help

📝 Platforms: Linux x64, Linux ARM64, Windows x64, macOS ARM64, plus musl targets for Alpine-focused deployments

⚙️ From Source

Build from source if you need the latest development version or want to contribute.

Clone and build
git clone https://github.com/oocx/tfplan2md.git
cd tfplan2md
dotnet build

📝 Requirements: .NET 10 SDK

Quick Start

Generate your first Markdown report in seconds

1

Create a Terraform Plan

terraform plan -out=plan.tfplan
2

Convert to JSON

terraform show -json plan.tfplan > plan.json
3

Generate Markdown Report

cat plan.json | docker run -i oocx/tfplan2md > plan.md

Common Usage Patterns

Pipe directly from Terraform

terraform show -json plan.tfplan | docker run -i oocx/tfplan2md

Run the native binary

terraform show -json plan.tfplan | ./tfplan2md --details auto > plan.md

Read from file with mounted volume

docker run -v $(pwd):/data oocx/tfplan2md /data/plan.json

Write output to file

terraform show -json plan.tfplan | \
+  docker run -i -v $(pwd):/data oocx/tfplan2md --output /data/plan.md

Generate summary-only report

terraform show -json plan.tfplan | \
+  docker run -i oocx/tfplan2md --template summary

CI/CD Integration

Automatically post Terraform plan reports to your pull requests

GitHub Actions Workflow

Add this job to your workflow to automatically comment on PRs with Terraform plans.

.github/workflows/terraform.yml
name: Terraform Plan

on:
  pull_request:
    paths:
      - 'terraform/**'

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.9.0

      - name: Terraform Init
        run: terraform init
        working-directory: ./terraform

      - name: Terraform Plan
        run: terraform plan -out=plan.tfplan
        working-directory: ./terraform

      - name: Convert plan to JSON
        run: terraform show -json plan.tfplan > plan.json
        working-directory: ./terraform

      - name: Generate markdown report
        run: |
          docker run -v $(pwd):/data oocx/tfplan2md \
            /data/plan.json --output /data/plan.md
        working-directory: ./terraform

      - name: Post PR comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const plan = fs.readFileSync('terraform/plan.md', 'utf8');

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: plan
            });

Azure Pipelines Configuration

Use this pipeline template to post Terraform plans to Azure DevOps pull requests.

azure-pipelines.yml
trigger: none

pr:
  branches:
    include:
      - main
  paths:
    include:
      - terraform/*

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: TerraformInstaller@1
    inputs:
      terraformVersion: '1.9.0'

  - script: terraform init
    displayName: 'Terraform Init'
    workingDirectory: terraform

  - script: terraform plan -out=plan.tfplan
    displayName: 'Terraform Plan'
    workingDirectory: terraform

  - script: terraform show -json plan.tfplan > plan.json
    displayName: 'Convert to JSON'
    workingDirectory: terraform

  - script: |
      docker run -v $(pwd):/data oocx/tfplan2md \
        /data/plan.json --output /data/plan.md
    displayName: 'Generate markdown report'
    workingDirectory: terraform

  - bash: |
      MARKDOWN=$(cat terraform/plan.md)
      URL="$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.ID)/pullRequests/$(System.PullRequest.PullRequestId)/threads?api-version=7.0"

      BODY=$(jq -n \
        --arg content "$MARKDOWN" \
        '{comments: [{content: $content, commentType: 1}], status: 1}')

      curl -X POST "$URL" \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $(System.AccessToken)" \
        -d "$BODY"
    displayName: 'Post PR comment'

GitLab CI Configuration

Configure GitLab CI to post Terraform plans as merge request comments.

.gitlab-ci.yml
terraform-plan:
  stage: plan
  image: hashicorp/terraform:1.9
  only:
    - merge_requests
  script:
    - cd terraform
    - terraform init
    - terraform plan -out=plan.tfplan
    - terraform show -json plan.tfplan > plan.json

    - |
      docker run -v $(pwd):/data oocx/tfplan2md \
        /data/plan.json --output /data/plan.md

    - |
      MARKDOWN=$(cat plan.md)
      curl --request POST \
        --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
        --header "Content-Type: application/json" \
        --data "{\"body\": \"$MARKDOWN\"}" \
        "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes"

Note: Create a GitLab access token with api scope and add it as GITLAB_TOKEN in CI/CD variables.

Security Integration

Combine Terraform plans with security findings from SARIF-compatible tools

tfplan2md natively supports SARIF 2.1.0 format, enabling you to integrate security findings from tools like Checkov, TfLint, and Trivy directly into your Terraform plan reports.

Basic Security Integration
# Generate plan
terraform show -json plan.tfplan > plan.json

# Run security scans
checkov -d terraform --framework terraform --output sarif -o checkov.sarif
tflint --format sarif > tflint.sarif
trivy config terraform --format sarif --output trivy.sarif

# Generate unified report
docker run -v $(pwd):/data -i oocx/tfplan2md \
+  /data/plan.json \
+  --code-analysis-results "/data/*.sarif" \
+  --output /data/report.md

CLI Options

--code-analysis-results

File path or wildcard pattern for SARIF files. Supports wildcards like *.sarif or **/*.sarif for recursive search.

--code-analysis-results "/data/**/*.sarif"

--code-analysis-minimum-level

Minimum severity level to include in the report. Options: critical, high, medium, low, informational.

--code-analysis-minimum-level high

--fail-on-static-code-analysis-errors <level>

Exit with code 10 when findings at or above the requested severity are detected. Useful for blocking PRs with critical issues.

--fail-on-static-code-analysis-errors high

✨ Benefits

  • Security findings mapped to specific resources and attributes
  • Unified view of infrastructure changes and security issues
  • Support for multiple security tools in one report
  • Summary view showing overall security posture