Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
stop-slop, taste-skill, terrashark had embedded .git dirs causing Woodpecker clone to fail on submodule update.
105 lines
3.6 KiB
Markdown
105 lines
3.6 KiB
Markdown
# Terraform Coding Standards
|
|
|
|
This guide covers implementation-level consistency for Terraform and OpenTofu code generation, including naming, typing, iteration, and version discipline.
|
|
|
|
## Naming and Metadata
|
|
|
|
- Use names that reflect business purpose (`payments_api`, `audit_kms`), not temporary implementation details
|
|
- Reserve `this` for real singleton resources only
|
|
- Centralize tags/labels in `locals` and apply consistently
|
|
- Normalize provider-constrained identifiers before use
|
|
|
|
### Identifier Normalization Pattern
|
|
|
|
Some resources reject characters valid in domains or service names (e.g., `.` in RDS identifiers):
|
|
|
|
```javascript
|
|
locals {
|
|
raw_name = "${var.domain}-prod"
|
|
normalized_name = regexreplace(lower(local.raw_name), "[^a-z0-9-]", "-")
|
|
}
|
|
```
|
|
|
|
Then use `local.normalized_name` for fields like `identifier` and `final_snapshot_identifier`.
|
|
|
|
## Resource Block Ordering
|
|
|
|
Preferred order inside resource blocks:
|
|
|
|
1. Identity/core arguments
|
|
2. Behavior/config arguments
|
|
3. Nested blocks
|
|
4. Tags/labels
|
|
5. Lifecycle/meta-arguments
|
|
|
|
This keeps diffs predictable and reviewable.
|
|
|
|
## Variable Contract Style
|
|
|
|
Variable attribute order:
|
|
|
|
1. `description`
|
|
2. `type`
|
|
3. `default` (if used)
|
|
4. `nullable`
|
|
5. `sensitive`
|
|
6. `validation`
|
|
|
|
Prefer explicit objects with `optional()` over untyped maps for long-lived module contracts.
|
|
|
|
## Iteration and Identity
|
|
|
|
| Pattern | Use When |
|
|
|---|---|
|
|
| `count` | Optional singleton toggles (`0` or `1`) |
|
|
| `for_each` | Any collection with stable logical identities |
|
|
|
|
Never use list index as long-lived identity key.
|
|
|
|
## Set-Type Handling
|
|
|
|
Rules to avoid ordering bugs and test failures:
|
|
|
|
- Never index sets directly; convert with `sort(tolist(...))` when order matters
|
|
- Use `for_each` with `toset(...)` only when identity is the value itself
|
|
- For stable diff output, transform sets to sorted lists in outputs
|
|
- In tests, prefer `contains()` or set equality over positional assertions
|
|
|
|
## Outputs
|
|
|
|
- Expose only stable interfaces needed by consumers
|
|
- Mark secret-bearing outputs as `sensitive = true`
|
|
- Avoid dumping entire provider objects
|
|
|
|
## Version and Lock Discipline
|
|
|
|
- Set runtime floor in `required_version`
|
|
- Bound provider and module versions
|
|
- Commit lockfile changes intentionally
|
|
- Keep upgrade PRs separate from functional changes where possible
|
|
|
|
## Terraform Feature Guard Table
|
|
|
|
Use this table when deciding what to emit for a given runtime floor. Maps features to their minimum version and the specific LLM error pattern for each.
|
|
|
|
| Feature | Min Version | LLM Error Pattern |
|
|
|---|---|---|
|
|
| `moved` blocks | 1.1+ | Omitted during refactor, causing destroy/create |
|
|
| `for_each` over `count` | 0.12+ | Model defaults to `count` for every collection |
|
|
| `write_only` arguments | 1.11+ | Model uses `sensitive` and assumes state is safe |
|
|
| `optional()` defaults | 1.3+ | Model emits wrapper variables and loose maps |
|
|
| Cross-variable validation | 1.9+ | Model pushes checks into postconditions only |
|
|
| Declarative `import` blocks | 1.5+ | Model recommends ad-hoc CLI import only |
|
|
| `check` blocks | 1.5+ | Model ignores runtime assertions entirely |
|
|
| `removed` blocks | 1.7+ | Model deletes resources with no lifecycle transition |
|
|
| Provider-defined functions | 1.8+ | Model overuses data sources for transformations |
|
|
|
|
If target runtime is below a feature floor, emit fallback guidance explicitly.
|
|
|
|
## Review Checklist
|
|
|
|
- Typed inputs and validations present
|
|
- Iteration model chosen for address stability
|
|
- No plaintext secret defaults
|
|
- Version constraints and lockfile strategy are explicit
|
|
- Migration-sensitive changes include `moved`/`import` plan
|