Add a new skill that analyzes Terraform plan JSON output for AzureRM Provider to distinguish between false-positive diffs (order-only changes in Set-type attributes) and actual resource changes. This skill helps users identify 'noise' in terraform plan output caused by Azure API returning Set elements in different order, making plan reviews easier and reducing confusion in CI/CD pipelines. Bundled assets: - references/azurerm_set_attributes.json - references/azurerm_set_attributes.md - scripts/analyze_plan.py
Terraform AzureRM Set Diff Analyzer Script
A Python script that analyzes Terraform plan JSON and identifies "false-positive diffs" in AzureRM Set-type attributes.
Overview
AzureRM Provider's Set-type attributes (such as backend_address_pool, security_rule, etc.) don't guarantee order, so when adding or removing elements, all elements appear as "changed". This script distinguishes such "false-positive diffs" from actual changes.
Use Cases
- As an Agent Skill (recommended)
- As a CLI tool for manual execution
- For automated analysis in CI/CD pipelines
Prerequisites
- Python 3.8 or higher
- No additional packages required (uses only standard library)
Usage
Basic Usage
# Read from file
python analyze_plan.py plan.json
# Read from stdin
terraform show -json plan.tfplan | python analyze_plan.py
Options
| Option | Short | Description | Default |
|---|---|---|---|
--format |
-f |
Output format (markdown/json/summary) | markdown |
--exit-code |
-e |
Return exit code based on changes | false |
--quiet |
-q |
Suppress warnings | false |
--verbose |
-v |
Show detailed warnings | false |
--ignore-case |
- | Compare values case-insensitively | false |
--attributes |
- | Path to custom attribute definition file | (built-in) |
--include |
- | Filter resources to analyze (can specify multiple) | (all) |
--exclude |
- | Filter resources to exclude (can specify multiple) | (none) |
Exit Codes (with --exit-code)
| Code | Meaning |
|---|---|
| 0 | No changes, or order-only changes |
| 1 | Actual Set attribute changes |
| 2 | Resource replacement (delete + create) |
| 3 | Error |
Output Formats
Markdown (default)
Human-readable format for PR comments and reports.
python analyze_plan.py plan.json --format markdown
JSON
Structured data for programmatic processing.
python analyze_plan.py plan.json --format json
Example output:
{
"summary": {
"order_only_count": 3,
"actual_set_changes_count": 1,
"replace_count": 0
},
"has_real_changes": true,
"resources": [...],
"warnings": []
}
Summary
One-line summary for CI/CD logs.
python analyze_plan.py plan.json --format summary
Example output:
🟢 3 order-only | 🟡 1 set changes
CI/CD Pipeline Usage
GitHub Actions
name: Terraform Plan Analysis
on:
pull_request:
paths:
- '**.tf'
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Terraform Init & Plan
run: |
terraform init
terraform plan -out=plan.tfplan
terraform show -json plan.tfplan > plan.json
- name: Analyze Set Diff
run: |
python path/to/analyze_plan.py plan.json --format markdown > analysis.md
- name: Comment PR
uses: marocchino/sticky-pull-request-comment@v2
with:
path: analysis.md
GitHub Actions (Gate with Exit Code)
- name: Analyze and Gate
run: |
python path/to/analyze_plan.py plan.json --exit-code --format summary
# Fail on exit code 2 (resource replacement)
continue-on-error: false
Azure Pipelines
- task: TerraformCLI@0
inputs:
command: 'plan'
commandOptions: '-out=plan.tfplan'
- script: |
terraform show -json plan.tfplan > plan.json
python scripts/analyze_plan.py plan.json --format markdown > $(Build.ArtifactStagingDirectory)/analysis.md
displayName: 'Analyze Plan'
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: '$(Build.ArtifactStagingDirectory)/analysis.md'
artifactName: 'plan-analysis'
Filtering Examples
Analyze only specific resources:
python analyze_plan.py plan.json --include application_gateway --include load_balancer
Exclude specific resources:
python analyze_plan.py plan.json --exclude virtual_network
Interpreting Results
| Category | Meaning | Recommended Action |
|---|---|---|
| 🟢 Order-only | False-positive diff, no actual change | Safe to ignore |
| 🟡 Actual change | Set element added/removed/modified | Review the content, usually in-place update |
| 🔴 Resource replacement | delete + create | Check for downtime impact |
Custom Attribute Definitions
By default, uses references/azurerm_set_attributes.json, but you can specify a custom definition file:
python analyze_plan.py plan.json --attributes /path/to/custom_attributes.json
See references/azurerm_set_attributes.md for the definition file format.
Limitations
- Only AzureRM resources (
azurerm_*) are supported - Some resources/attributes may not be supported
- Comparisons may be incomplete for attributes containing
after_unknown(values determined after apply) - Comparisons may be incomplete for sensitive attributes (they are masked)
Related Documentation
- SKILL.md - Usage as an Agent Skill
- azurerm_set_attributes.md - Attribute definition reference