029 Project 29: Terraform Plan Parser

029 Build a Terraform Plan Parser

Parse terraform show -json output and summarize actions.

Run prerequisite

terraform show -json tfplan > plan.json

Full main.go

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type Plan struct {
    ResourceChanges []struct {
        Address string `json:"address"`
        Change  struct {
            Actions []string `json:"actions"`
        } `json:"change"`
    } `json:"resource_changes"`
}

func main() {
    if len(os.Args) != 2 {
        fmt.Println("usage: tf-plan-parse <plan.json>")
        os.Exit(2)
    }
    b, err := os.ReadFile(os.Args[1])
    if err != nil {
        panic(err)
    }
    var p Plan
    if err := json.Unmarshal(b, &p); err != nil {
        panic(err)
    }

    counts := map[string]int{"create": 0, "update": 0, "delete": 0, "replace": 0}
    for _, rc := range p.ResourceChanges {
        a := rc.Change.Actions
        if len(a) == 2 && a[0] == "delete" && a[1] == "create" {
            counts["replace"]++
            fmt.Printf("REPLACE %s\n", rc.Address)
            continue
        }
        for _, x := range a {
            counts[x]++
        }
        fmt.Printf("%v %s\n", a, rc.Address)
    }
    fmt.Printf("summary create=%d update=%d delete=%d replace=%d\n", counts["create"], counts["update"], counts["delete"], counts["replace"])
}

Step-by-Step Explanation

  1. Export Terraform plan in JSON form.
  2. Parse resource_changes into typed structs.
  3. Classify actions such as create/update/delete/replace.
  4. Compute risk, policy, or cost summaries.
  5. Gate CI based on explicit thresholds.

Code Anatomy

  • Decoder layer parses JSON file.
  • Analysis layer converts raw actions into signals.
  • Reporting layer prints summary and sets exit status.

Learning Goals

  • Build deterministic IaC review tools.
  • Enforce infrastructure policy as code.
  • Reduce risky deploys with automated checks.