Docs

Plan Uploads

Upload Terraform plans from CI for automated risk scoring and PR comments.

Upload Terraform plans from your CI pipeline to get automated risk scoring, blast radius analysis, and PR comments. Plans are evaluated against your risk rules and the results appear in both Cora and your pull request.

Prerequisites

  • A Cora account with access to API tokens.
  • A CI pipeline that runs terraform plan.
  • The Cora CLI installed in your CI environment.

Optional (for AI summaries):

  • Enable AI summaries in Settings → AI and add an OpenAI API key.
  • If you are self-hosting, configure CORA_ENCRYPTION_SECRET (or ENCRYPTION_SECRET) so Cora can store your key securely.

Quick start

  1. Create an API token at Settings → Tokens.
  2. Run terraform plan -out=plan.tfplan in your CI pipeline.
  3. Convert the plan to JSON: terraform show -json plan.tfplan > plan.json
  4. Upload to Cora using the Cora CLI.
bash
# Set your API token
export CORA_TOKEN="your-api-token"

# Upload the plan
cat plan.json | cora plan upload --workspace my-app

CLI options

The cora plan upload command accepts these options:

OptionRequiredDescription
--workspaceYesTerraform workspace name for organization
--tokenNoAPI token (defaults to CORA_TOKEN environment variable)
--sourceNoOrigin identifier: atlantis, github-actions, manual

The plan JSON is read from stdin.

GitHub Actions example

Add plan uploads to your GitHub Actions workflow:

.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_wrapper: false

    - name: Install Cora CLI
      run: |
        curl -sSL https://github.com/TheCoraApp/cora-cli/releases/latest/download/cora-linux-amd64 -o /usr/local/bin/cora
        chmod +x /usr/local/bin/cora

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

    - name: Terraform Plan
      run: |
        terraform plan -out=plan.tfplan
        terraform show -json plan.tfplan > plan.json
      working-directory: terraform

    - name: Upload to Cora
      env:
        CORA_TOKEN: ${{ secrets.CORA_TOKEN }}
      run: |
        cat terraform/plan.json | cora plan upload \
            --workspace "my-app-${{ github.base_ref }}" \
            --source github-actions

Atlantis integration

Add plan uploads to your Atlantis workflow. This runs after terraform plan and before apply approval.

atlantis.yaml
version: 3
projects:
- name: my-app
  dir: .
  workflow: cora-plan

workflows:
cora-plan:
  plan:
    steps:
      - init
      - plan
      - run: |
          terraform show -json $PLANFILE > plan.json
          cat plan.json | cora plan upload \
            --workspace "${PROJECT_NAME}-${WORKSPACE}" \
            --source atlantis
State uploads vs plan uploads

Plan uploads are for risk assessment before apply. State uploads (covered in Atlantis Integration) are for keeping diagrams current after apply. You can use both in the same workflow.

Response format

A successful upload returns the evaluation result:

json
{
"success": true,
"id": "eval_abc123",
"riskLevel": "high",
"totalScore": 650,
"matchedRules": [
  { "name": "Production Account Baseline", "score": 100 },
  { "name": "IAM Role Change", "score": 500 },
  { "name": "Missing Environment Tag", "score": 50 }
],
"resourceChanges": 3,
"blastRadius": {
  "direct": 5,
  "transitive": 12
},
"costData": {
  "available": true,
  "currency": "USD",
  "estimatedMonthlyCost": 1250.00,
  "previousMonthlyCost": 980.00,
  "costDiff": 270.00,
  "costPercentChange": 27.5
},
"viewUrl": "https://app.thecora.io/pr-reviews/eval_abc123"
}
Cost data requires Infracost

The costData field is only included when you have configured an Infracost API key. If not configured, this field is omitted from the response.

Error handling

StatusMeaning
200Plan evaluated successfully
400Invalid request (missing workspace or plan)
401Invalid or missing API token
500Server error - retry the request

For non-blocking uploads, add || true to continue your pipeline even if the upload fails:

bash
cat plan.json | cora plan upload --workspace my-app || true

Next steps