-
Notifications
You must be signed in to change notification settings - Fork 73
terraform-tidy-before-import: extract from terraform-search-import
#66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
762046a
ac3aebd
dbdc026
79b5f30
5226a51
5040eec
63f925c
ab8ec92
def59e5
3f3d77a
0a46e86
20f9441
7d0004d
3fa17b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| --- | ||
| name: terraform-tidy-before-import | ||
| description: Prepares Terraform code for safe and correct import. Resolves validation errors, sensitive attributes, and computed attributes. De-duplicates literal values. Use this before committing generated Terraform code to version control and before importing resources into Terraform. | ||
| license: MPL-2.0 | ||
| metadata: | ||
| copyright: Copyright IBM Corp. 2026 | ||
| version: "0.0.1" | ||
| --- | ||
| # Tidy generated Terraform code | ||
|
|
||
| Generated Terraform configuration includes all resource attributes. For | ||
| correctness, reliability, and security, we tidy Terraform code before we commit | ||
| it to version control and before we run `terraform apply`. | ||
|
|
||
| The user may specify a priority of either speed or thoroughness. Default to | ||
| thoroughness. If the user prioritizes speed, then skip all schema-dependent | ||
| work and simply use `terraform validate` as a feedback loop to converge on a | ||
| validatable configuration. | ||
|
|
||
| When editing Terraform `resource` blocks, honor the Terraform resource | ||
| configuration model. Preserve any Terraform-supported built-in resource | ||
| argument or nested block that is already present, including `count`, | ||
| `depends_on`, `for_each`, `provider`, `lifecycle`, `connection`, and | ||
| `provisioner`, along with supported nested arguments and blocks inside them. | ||
| Never remove these Terraform language arguments or blocks during cleanup. | ||
|
|
||
| When editing Terraform `import` blocks, honor the Terraform import | ||
| configuration model. If an existing `import` block passes `terraform validate`, | ||
| it does not need to be edited. Preserve all Terraform-supported `import` block | ||
| arguments, including `to`, `id`, `identity`, `for_each`, and `provider`. Never | ||
| remove a valid `import` block or remove the `provider` argument from one. | ||
|
|
||
| <parse_terraform_code_using_python_hcl2_and_hq> | ||
| Prioritize correctness when parsing Terraform code. To do so, use the | ||
| python-hcl2 module in a virtualenv. This module includes the hq command line | ||
| tool. Examples: | ||
|
|
||
| * Convert to JSON: `hq '*' <input file> --json` | ||
| * Identity resource blocks with top-level timeouts: `hq 'resource~[select(.timeouts)] | .labels' <input file>` | ||
| * Identity null-valued attributes: `hq '*..attribute:*[select(.value == null)]' <input file>` | ||
|
|
||
| Use generic tools such as grep, awk, and sed only as a last resort when parsing Terraform code. | ||
| </parse_terraform_code_using_python_hcl2_and_hq> | ||
|
|
||
|
|
||
| 1. Temporarily rename the source file to a .tf.bak extension so that | ||
| `terraform` commands do not read it. | ||
| 1. Start a non-blocking background task in a temporary directory to build | ||
| resource schema lookup tables, as detailed in | ||
| [resource-schema-lookup-tables.md](references/resource-schema-lookup-tables.md). | ||
| 1. Run `terraform validate`. Resolve conflicting generated provider arguments | ||
| without removing Terraform-supported built-in resource arguments or blocks. | ||
| Resolve all other validation errors. | ||
| 1. Replace literal values with variables for values that are used 3 or more | ||
| times | ||
| 1. Remove top-level provider-defined `timeouts` blocks from all resources. | ||
| 1. Wait for the background schema-analysis task to finish, then use its lookup | ||
| tables for the remaining schema-dependent cleanup steps. | ||
| 1. Remove provider-defined attributes that are `computed` and not `optional` by | ||
| using the computed-attributes lookup table for each resource type. Preserve | ||
| provider-defined attributes that are both `computed` and `optional`, unless | ||
| the configuration explicitly sets them to `null`; in that case, remove the | ||
| null-valued argument. | ||
| 1. Remove non-computed sensitive provider-defined attributes. If the provider | ||
| requires one of the removed arguments, try to use an equivalent | ||
| write-only attribute, such as the `value_wo` and `value_wo_version` pair for | ||
| `value`. If the write-only attribute requires a non-write-only | ||
| paired attribute, use the `lifecycle` meta-argument to ignore changes only | ||
| to that paired non-write-only attribute, e.g. `value_wo_version`. | ||
| 1. Run `terraform validate` as the final validation step. Make a best effort to | ||
| resolve errors before continuing. | ||
| 1. On completion, restore the original source file name | ||
|
|
||
| ```hcl | ||
| # Before: generated | ||
| resource "aws_instance" "all_0" { | ||
| ami = "ami-0c55b159cbfafe1f0" | ||
| instance_type = "t2.micro" | ||
| arn = "arn:aws:ec2:..." # Remove - computed | ||
| id = "i-0abc123" # Remove - computed | ||
| # ... many more attributes | ||
| } | ||
|
|
||
| resource "aws_ssm_parameter" "all_0" { | ||
| type = "SecureString" | ||
| name = "AccessCode" | ||
| value = "secret" # Remove - sensitive | ||
| } | ||
|
|
||
| # After: tidied | ||
| resource "aws_instance" "all_0" { | ||
| ami = var.ami_id | ||
| instance_type = var.instance_type | ||
| subnet_id = var.subnet_id | ||
| } | ||
|
|
||
| resource "aws_ssm_parameter" "access_code" { | ||
| type = "SecureString" | ||
| name = "AccessCode" | ||
| value_wo = "__imported__" | ||
| value_wo_version = 1 | ||
|
|
||
| lifecycle { | ||
| ignore_changes = [value_wo_version] | ||
| } | ||
| } | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| { | ||
| "skill_name": "terraform-tidy-before-import", | ||
| "evals": [ | ||
| { | ||
| "id": 1, | ||
| "prompt": "Tidy the generated Terraform in aws_thorough_before_cleanup.tf so it is ready for import and safe to commit. Use the default thoroughness level, keep valid import blocks intact, preserve Terraform language meta-arguments and nested language blocks, and organize the finished configuration into appropriate Terraform files before you wrap up. Keep terraform.tf in any terraform working directories for base provider configuration. Make a best effort: if the final file does not validate or does not meet all criteria, the computer should still present it as output for evaluation.", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How much instruction normally goes into the prompt vs into the skill?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right on, super helpful feedback. I think this prompt needs to be lighter. Agent fatigue. Time to edit. |
||
| "expected_output": "A cleaned AWS configuration as close to aws_thorough_after_cleanup.tf as possible. Expect absence of provider-defined computed attributes and top-level timeout blocks while preserving valid import blocks, lifecycle/meta-arguments, and connection timeouts.", | ||
| "files": [ | ||
| "evals/files/aws_thorough_before_cleanup.tf", | ||
| "evals/files/aws_thorough_after_cleanup.tf", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As Anthropic denotes these files as input files, do we need to somehow assert that the agent (while using the skill) does not read this file? Else it might be relatively easy to get to this result 🥷 |
||
| "evals/files/terraform.tf" | ||
| ], | ||
| "expectations": [ | ||
| "terraform validate exits with code 0 on the output .tf files", | ||
| "All 7 import blocks from the source are present across the output files", | ||
| "Every import block retains its provider argument", | ||
| "No resource block contains a top-level timeouts {} block", | ||
| "aws_ssm_parameter resources have no value = null attribute (sensitive attribute removed)", | ||
| "aws_ssm_parameter resources have value_wo set to a non-null string", | ||
| "Each aws_ssm_parameter resource has a lifecycle block with ignore_changes = [value_wo_version]", | ||
| "aws_ssm_parameter resources retain the arn attribute (it is computed+optional per schema, so must be preserved not removed)", | ||
| "At least 2 Terraform variables are defined for values used 3 or more times", | ||
| "aws_instance resources retain the tags_all attribute (it is computed+optional per schema and must be preserved)" | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't seem to find a schema for this filetype?
I looked at the docs of tessl, which is used in a Github Action of this repo, and I can only find different files: https://docs.tessl.io/evaluate/evaluating-your-codebase#file-formats
How to run this eval?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, spot-on observation! 😃 I took a speculative leap in this pull request.
For the eval, I chose the format described on agentskills.io. I ran it locally (WORKS ON MY MACHINE 😃) with the
skill-creatorskill from anthropics/skills.It would be Really Useful to include some output, would it not? 🙃