Skip to content

Commit 44a43b2

Browse files
authored
Merge pull request #620 from torumakabe/add-terraform-azurerm-set-diff-analyzer
Add terraform-azurerm-set-diff-analyzer skill
2 parents 1c42150 + 0e9b933 commit 44a43b2

7 files changed

Lines changed: 1567 additions & 0 deletions

File tree

docs/README.skills.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Skills differ from other primitives by supporting bundled assets (scripts, code
4747
| [refactor](../skills/refactor/SKILL.md) | Surgical code refactoring to improve maintainability without changing behavior. Covers extracting functions, renaming variables, breaking down god functions, improving type safety, eliminating code smells, and applying design patterns. Less drastic than repo-rebuilder; use for gradual improvements. | None |
4848
| [scoutqa-test](../skills/scoutqa-test/SKILL.md) | This skill should be used when the user asks to "test this website", "run exploratory testing", "check for accessibility issues", "verify the login flow works", "find bugs on this page", or requests automated QA testing. Triggers on web application testing scenarios including smoke tests, accessibility audits, e-commerce flows, and user flow validation using ScoutQA CLI. IMPORTANT: Use this skill proactively after implementing web application features to verify they work correctly - don't wait for the user to ask for testing. | None |
4949
| [snowflake-semanticview](../skills/snowflake-semanticview/SKILL.md) | Create, alter, and validate Snowflake semantic views using Snowflake CLI (snow). Use when asked to build or troubleshoot semantic views/semantic layer definitions with CREATE/ALTER SEMANTIC VIEW, to validate semantic-view DDL against Snowflake via CLI, or to guide Snowflake CLI installation and connection setup. | None |
50+
| [terraform-azurerm-set-diff-analyzer](../skills/terraform-azurerm-set-diff-analyzer/SKILL.md) | Analyze Terraform plan JSON output for AzureRM Provider to distinguish between false-positive diffs (order-only changes in Set-type attributes) and actual resource changes. Use when reviewing terraform plan output for Azure resources like Application Gateway, Load Balancer, Firewall, Front Door, NSG, and other resources with Set-type attributes that cause spurious diffs due to internal ordering changes. | `references/azurerm_set_attributes.json`<br />`references/azurerm_set_attributes.md`<br />`scripts/.gitignore`<br />`scripts/README.md`<br />`scripts/analyze_plan.py` |
5051
| [vscode-ext-commands](../skills/vscode-ext-commands/SKILL.md) | Guidelines for contributing commands in VS Code extensions. Indicates naming convention, visibility, localization and other relevant attributes, following VS Code extension development guidelines, libraries and good practices | None |
5152
| [vscode-ext-localization](../skills/vscode-ext-localization/SKILL.md) | Guidelines for proper localization of VS Code extensions, following VS Code extension development guidelines, libraries and good practices | None |
5253
| [web-design-reviewer](../skills/web-design-reviewer/SKILL.md) | This skill enables visual inspection of websites running locally or remotely to identify and fix design issues. Triggers on requests like "review website design", "check the UI", "fix the layout", "find design problems". Detects issues with responsive design, accessibility, visual consistency, and layout breakage, then performs fixes at the source code level. | `references/framework-fixes.md`<br />`references/visual-checklist.md` |
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
name: terraform-azurerm-set-diff-analyzer
3+
description: Analyze Terraform plan JSON output for AzureRM Provider to distinguish between false-positive diffs (order-only changes in Set-type attributes) and actual resource changes. Use when reviewing terraform plan output for Azure resources like Application Gateway, Load Balancer, Firewall, Front Door, NSG, and other resources with Set-type attributes that cause spurious diffs due to internal ordering changes.
4+
license: MIT
5+
---
6+
7+
# Terraform AzureRM Set Diff Analyzer
8+
9+
A skill to identify "false-positive diffs" in Terraform plans caused by AzureRM Provider's Set-type attributes and distinguish them from actual changes.
10+
11+
## When to Use
12+
13+
- `terraform plan` shows many changes, but you only added/removed a single element
14+
- Application Gateway, Load Balancer, NSG, etc. show "all elements changed"
15+
- You want to automatically filter false-positive diffs in CI/CD
16+
17+
## Background
18+
19+
Terraform's Set type compares by position rather than by key, so when adding or removing elements, all elements appear as "changed". This is a general Terraform issue, but it's particularly noticeable with AzureRM resources that heavily use Set-type attributes like Application Gateway, Load Balancer, and NSG.
20+
21+
These "false-positive diffs" don't actually affect the resources, but they make reviewing terraform plan output difficult.
22+
23+
## Prerequisites
24+
25+
- Python 3.8+
26+
27+
If Python is unavailable, install via your package manager (e.g., `apt install python3`, `brew install python3`) or from [python.org](https://www.python.org/downloads/).
28+
29+
## Basic Usage
30+
31+
```bash
32+
# 1. Generate plan JSON output
33+
terraform plan -out=plan.tfplan
34+
terraform show -json plan.tfplan > plan.json
35+
36+
# 2. Analyze
37+
python scripts/analyze_plan.py plan.json
38+
```
39+
40+
## Troubleshooting
41+
42+
- **`python: command not found`**: Use `python3` instead, or install Python
43+
- **`ModuleNotFoundError`**: Script uses only standard library; ensure Python 3.8+
44+
45+
## Detailed Documentation
46+
47+
- [scripts/README.md](scripts/README.md) - All options, output formats, exit codes, CI/CD examples
48+
- [references/azurerm_set_attributes.md](references/azurerm_set_attributes.md) - Supported resources and attributes
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
{
2+
"metadata": {
3+
"description": "AzureRM Provider Set-type attribute definitions",
4+
"lastUpdated": "2026-01-28",
5+
"source": "Terraform Registry documentation and AzureRM Provider source code"
6+
},
7+
"resources": {
8+
"azurerm_application_gateway": {
9+
"backend_address_pool": "name",
10+
"backend_http_settings": "name",
11+
"custom_error_configuration": "status_code",
12+
"frontend_ip_configuration": "name",
13+
"frontend_port": "name",
14+
"gateway_ip_configuration": "name",
15+
"http_listener": "name",
16+
"probe": "name",
17+
"private_link_configuration": "name",
18+
"redirect_configuration": "name",
19+
"request_routing_rule": "name",
20+
"rewrite_rule_set": {
21+
"_key": "name",
22+
"rewrite_rule": {
23+
"_key": "name",
24+
"condition": "variable",
25+
"request_header_configuration": "header_name",
26+
"response_header_configuration": "header_name"
27+
}
28+
},
29+
"ssl_certificate": "name",
30+
"ssl_profile": "name",
31+
"trusted_client_certificate": "name",
32+
"trusted_root_certificate": "name",
33+
"url_path_map": {
34+
"_key": "name",
35+
"path_rule": {
36+
"_key": "name",
37+
"paths": null
38+
}
39+
}
40+
},
41+
"azurerm_lb": {
42+
"frontend_ip_configuration": "name"
43+
},
44+
"azurerm_lb_backend_address_pool": {
45+
"backend_address": "name"
46+
},
47+
"azurerm_lb_rule": {
48+
"backend_address_pool_ids": null
49+
},
50+
"azurerm_firewall": {
51+
"ip_configuration": "name",
52+
"management_ip_configuration": "name",
53+
"virtual_hub": null
54+
},
55+
"azurerm_firewall_policy_rule_collection_group": {
56+
"application_rule_collection": {
57+
"_key": "name",
58+
"rule": {
59+
"_key": "name",
60+
"protocols": null,
61+
"destination_fqdns": null
62+
}
63+
},
64+
"network_rule_collection": {
65+
"_key": "name",
66+
"rule": {
67+
"_key": "name",
68+
"destination_addresses": null,
69+
"destination_ports": null
70+
}
71+
},
72+
"nat_rule_collection": {
73+
"_key": "name",
74+
"rule": "name"
75+
}
76+
},
77+
"azurerm_frontdoor": {
78+
"backend_pool": {
79+
"_key": "name",
80+
"backend": "address"
81+
},
82+
"backend_pool_health_probe": "name",
83+
"backend_pool_load_balancing": "name",
84+
"frontend_endpoint": "name",
85+
"routing_rule": "name"
86+
},
87+
"azurerm_cdn_frontdoor_origin_group": {
88+
"health_probe": null,
89+
"load_balancing": null
90+
},
91+
"azurerm_network_security_group": {
92+
"security_rule": "name"
93+
},
94+
"azurerm_route_table": {
95+
"route": "name"
96+
},
97+
"azurerm_virtual_network": {
98+
"subnet": "name"
99+
},
100+
"azurerm_virtual_network_gateway": {
101+
"ip_configuration": "name",
102+
"vpn_client_configuration": {
103+
"_key": null,
104+
"root_certificate": "name",
105+
"revoked_certificate": "name",
106+
"radius_server": "address"
107+
},
108+
"policy_group": "name"
109+
},
110+
"azurerm_virtual_network_gateway_connection": {
111+
"ipsec_policy": null
112+
},
113+
"azurerm_nat_gateway": {
114+
"public_ip_address_ids": null,
115+
"public_ip_prefix_ids": null
116+
},
117+
"azurerm_private_endpoint": {
118+
"ip_configuration": "name",
119+
"private_dns_zone_group": "name",
120+
"private_service_connection": "name"
121+
},
122+
"azurerm_api_management": {
123+
"additional_location": "location",
124+
"certificate": "encoded_certificate",
125+
"hostname_configuration": {
126+
"_key": null,
127+
"management": "host_name",
128+
"portal": "host_name",
129+
"developer_portal": "host_name",
130+
"proxy": "host_name",
131+
"scm": "host_name"
132+
}
133+
},
134+
"azurerm_storage_account": {
135+
"network_rules": null,
136+
"blob_properties": null
137+
},
138+
"azurerm_key_vault": {
139+
"network_acls": null
140+
},
141+
"azurerm_cosmosdb_account": {
142+
"geo_location": "location",
143+
"capabilities": "name",
144+
"virtual_network_rule": "id"
145+
},
146+
"azurerm_kubernetes_cluster": {
147+
"default_node_pool": null
148+
},
149+
"azurerm_kubernetes_cluster_node_pool": {
150+
"node_labels": null,
151+
"node_taints": null
152+
}
153+
}
154+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# AzureRM Set-Type Attributes Reference
2+
3+
This document explains the overview and maintenance of `azurerm_set_attributes.json`.
4+
5+
> **Last Updated**: January 28, 2026
6+
7+
## Overview
8+
9+
`azurerm_set_attributes.json` is a definition file for attributes treated as Set-type in the AzureRM Provider.
10+
The `analyze_plan.py` script reads this JSON to identify "false-positive diffs" in Terraform plans.
11+
12+
### What are Set-Type Attributes?
13+
14+
Terraform's Set type is a collection that **does not guarantee order**.
15+
Therefore, when adding or removing elements, unchanged elements may appear as "changed".
16+
This is called a "false-positive diff".
17+
18+
## JSON File Structure
19+
20+
### Basic Format
21+
22+
```json
23+
{
24+
"resources": {
25+
"azurerm_resource_type": {
26+
"attribute_name": "key_attribute"
27+
}
28+
}
29+
}
30+
```
31+
32+
- **key_attribute**: The attribute that uniquely identifies Set elements (e.g., `name`, `id`)
33+
- **null**: When there is no key attribute (compare entire element)
34+
35+
### Nested Format
36+
37+
When a Set attribute contains another Set attribute:
38+
39+
```json
40+
{
41+
"rewrite_rule_set": {
42+
"_key": "name",
43+
"rewrite_rule": {
44+
"_key": "name",
45+
"condition": "variable",
46+
"request_header_configuration": "header_name"
47+
}
48+
}
49+
}
50+
```
51+
52+
- **`_key`**: The key attribute for that level's Set elements
53+
- **Other keys**: Definitions for nested Set attributes
54+
55+
### Example: azurerm_application_gateway
56+
57+
```json
58+
"azurerm_application_gateway": {
59+
"backend_address_pool": "name", // Simple Set (key is name)
60+
"rewrite_rule_set": { // Nested Set
61+
"_key": "name",
62+
"rewrite_rule": {
63+
"_key": "name",
64+
"condition": "variable"
65+
}
66+
}
67+
}
68+
```
69+
70+
## Maintenance
71+
72+
### Adding New Attributes
73+
74+
1. **Check Official Documentation**
75+
- Search for the resource in [Terraform Registry](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs)
76+
- Verify the attribute is listed as "Set of ..."
77+
- Some resources like `azurerm_application_gateway` have Set attributes noted explicitly
78+
79+
2. **Check Source Code (more reliable)**
80+
- Search for the resource in [AzureRM Provider GitHub](https://github.com/hashicorp/terraform-provider-azurerm)
81+
- Confirm `Type: pluginsdk.TypeSet` in the schema definition
82+
- Identify attributes within the Set's `Schema` that can serve as `_key`
83+
84+
3. **Add to JSON**
85+
```json
86+
"azurerm_new_resource": {
87+
"set_attribute": "key_attribute"
88+
}
89+
```
90+
91+
4. **Test**
92+
```bash
93+
# Verify with an actual plan
94+
python3 scripts/analyze_plan.py your_plan.json
95+
```
96+
97+
### Identifying Key Attributes
98+
99+
| Common Key Attribute | Usage |
100+
|---------------------|-------|
101+
| `name` | Named blocks (most common) |
102+
| `id` | Resource ID reference |
103+
| `location` | Geographic location |
104+
| `address` | Network address |
105+
| `host_name` | Hostname |
106+
| `null` | When no key exists (compare entire element) |
107+
108+
## Related Tools
109+
110+
### analyze_plan.py
111+
112+
Analyzes Terraform plan JSON to identify false-positive diffs.
113+
114+
```bash
115+
# Basic usage
116+
terraform show -json plan.tfplan | python3 scripts/analyze_plan.py
117+
118+
# Read from file
119+
python3 scripts/analyze_plan.py plan.json
120+
121+
# Use custom attribute file
122+
python3 scripts/analyze_plan.py plan.json --attributes /path/to/custom.json
123+
```
124+
125+
## Supported Resources
126+
127+
Please refer to `azurerm_set_attributes.json` directly for currently supported resources:
128+
129+
```bash
130+
# List resources
131+
jq '.resources | keys' azurerm_set_attributes.json
132+
```
133+
134+
Key resources:
135+
- `azurerm_application_gateway` - Backend pools, listeners, rules, etc.
136+
- `azurerm_firewall_policy_rule_collection_group` - Rule collections
137+
- `azurerm_frontdoor` - Backend pools, routing
138+
- `azurerm_network_security_group` - Security rules
139+
- `azurerm_virtual_network_gateway` - IP configuration, VPN client configuration
140+
141+
## Notes
142+
143+
- Attribute behavior may differ depending on Provider/API version
144+
- New resources and attributes need to be added as they become available
145+
- Defining all levels of deeply nested structures improves accuracy

0 commit comments

Comments
 (0)