Install
$ agentstack add skill-iliaal-whetstone-terraform ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Terraform & OpenTofu
File Organization & Naming
| File | Purpose | |------|---------| | terraform.tf | Terraform + provider version requirements | | providers.tf | Provider configurations | | main.tf | Primary resources and data sources | | variables.tf | Input variables (alphabetical) | | outputs.tf | Output values (alphabetical) | | locals.tf | Local values |
- Lowercase with underscores:
web_api, notwebAPIorweb-api - Descriptive nouns excluding resource type:
aws_instance.web_apinotaws_instance.web_api_instance - Singular, not plural
thisfor singleton resources (one of that type per module)- Contextual variable prefixes:
vpc_cidr_blocknotcidr
Block Ordering
Resources: count/for_each (blank line after) → arguments → nested blocks → tags → depends_on → lifecycle (last)
Variables: description → type → default → validation → nullable
Every variable needs type + description. Every output needs description. Mark secrets sensitive = true.
Module Structure
| Type | Scope | Example | |------|-------|---------| | Resource Module | Single logical group | VPC + subnets, SG + rules | | Infrastructure Module | Collection of resource modules | Networking + compute for one region | | Composition | Complete infrastructure | Spans regions/accounts |
module-name/
├── main.tf, variables.tf, outputs.tf, versions.tf
├── examples/
│ ├── minimal/
│ └── complete/
└── tests/
└── defaults.tftest.hcl
Keep modules small (single responsibility). examples/ double as documentation and integration test fixtures. Semantic versioning for all published modules.
count vs for_each
| Scenario | Use | |----------|-----| | Boolean toggle (create or skip) | count = condition ? 1 : 0 | | Named/keyed items that may reorder | for_each = toset(list) or map | | Fixed identical replicas | count = N |
Default to for_each — removing a middle item from a count list recreates all subsequent resources. Use count only for boolean conditionals or truly identical replicas.
Testing
| Situation | Approach | |-----------|----------| | Quick validation | terraform fmt -check && terraform validate | | Pre-commit | + tflint + trivy config . / checkov -d . | | Logic validation (1.6+) | Native terraform test with command = plan | | Cost-free unit tests (1.7+) | Native tests + mock_provider | | Real infra validation | Native tests with command = apply, or Terratest (Go) |
Native test essentials (.tftest.hcl in tests/):
command = planfor fast unit tests;command = applyfor integration (default)assert { condition = expr; error_message = "..." }— multiple per run blockexpect_failures = [var.name]for negative testing (validate rejection of bad input)mock_provider "aws" { mock_resource "..." { defaults = { ... } } }— plan-mode only, no credentials, fast CIvariables {}at file level (all runs) or within arunblock (override)- Reference prior run outputs:
run.setup.vpc_id parallel = trueon independent runs with separate state — creates sync point at next sequential run- File naming:
*_unit_test.tftest.hcl(plan mode) vs*_integration_test.tftest.hcl(apply mode)
Version Pinning
| Component | Strategy | Example | |-----------|----------|---------| | Terraform | Pin minor | required_version = "~> 1.9" | | Providers | Pin major | version = "~> 5.0" | | Modules (prod) | Pin exact | version = "5.1.2" | | Modules (dev) | Allow patch | version = "~> 5.1" |
Key modern features: moved blocks (1.1+), optional() with defaults (1.3+), native testing (1.6+), mock providers (1.7+), cross-variable validation (1.9+), write-only arguments (1.11+).
State & Security
- Remote backend with locking: S3+DynamoDB, Azure Blob, GCS, or Terraform Cloud. Never local state for shared infrastructure.
- Encrypt state at rest. Never commit
.tfstate,.terraform/, or*.tfplan. Always commit.terraform.lock.hcl. default_tagson provider for consistent resource tagging.- Encryption at rest on all storage. Private networking by default — public access is opt-in.
- Least-privilege security groups. No
0.0.0.0/0ingress without explicit justification. - Never hardcode credentials — use assume_role, OIDC, or secrets managers.
- Pre-commit:
terraform fmt -recursive && terraform validate && trivy config .
Dependency Management
Use locals with try() to control deletion ordering without explicit depends_on:
locals {
vpc_id = try(aws_vpc_ipv4_cidr_block_association.this[0].vpc_id, aws_vpc.this.id, "")
}
This forces Terraform to destroy subnets before CIDR associations — prevents deletion errors.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: iliaal
- Source: iliaal/whetstone
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.