# Pathrule Pattern: Terraform / IaC (1.0.0)
# ::pathrule:package:terraform-iac

### [RULE] Remote state with native locking only  (path: /infra)
<!-- scope: project | priority: medium | advisory -->

State lives in a remote backend with locking, encryption, and versioning. Never local, never unlocked.

- Configure the `s3` backend with `use_lockfile = true` (GA since Terraform 1.11); do not add a `dynamodb_table` lock, that path is deprecated.
- Enable bucket versioning and SSE-KMS (`encrypt = true` plus a customer-managed `kms_key_id`) so state is recoverable and encrypted at rest.
- Give each environment its own state `key` and isolated IAM access; never share one state file across `dev`, `staging`, and `prod`.
- Never commit `terraform.tfstate` or `*.tfstate.backup`; treat state as a secret and keep it out of git.

---

### [RULE] Plan-gated, OIDC-authenticated CI  (path: /.github/workflows)
<!-- scope: folder | priority: high | strict -->

The pipeline runs `terraform plan`, saves it as an artifact, and applies that exact plan after approval.

- Use `terraform plan -out=tfplan` then `terraform apply tfplan`; never re-plan at apply time, the applied change must match what was reviewed.
- Authenticate to the cloud with short-lived OIDC tokens (GitHub Actions `id-token: write`), never long-lived static access keys in secrets.
- Scope the apply role to least privilege, and prefer a read-only identity for `plan` and a separate write identity for `apply`.
- Gate `apply` on a manual approval or protected environment so a human signs off on the plan before infrastructure changes.

---

### [MEMORY] Module and provider versioning conventions  (path: /infra/modules)

Reusable infrastructure is composed from versioned modules with pinned providers.

- Pin every provider in `required_providers` with `~>` constraints and commit `.terraform.lock.hcl` so every run and teammate resolves identical versions.
- Set `required_version` to the supported Terraform line (1.15.x as of mid-2026; 1.13 is EOL); bump deliberately, not implicitly.
- Source registry and git modules with an explicit `version` or pinned `?ref=` tag, never a floating `main` branch.
- Keep modules small and single-purpose with typed `variables.tf`, `outputs.tf`, and a README; root modules in `/infra/environments` only wire modules together.

---

### [MEMORY] Secrets and tagging conventions  (path: /infra)

Sensitive values never land in state, and every resource carries a consistent tag set.

- Use write-only arguments (e.g. `password_wo` with `password_wo_version`) and `ephemeral` resources/values (Terraform 1.11+) for passwords and tokens so they never persist to state or plan files.
- Source secrets at apply time from a secrets manager (AWS Secrets Manager / SSM Parameter Store) data sources; do not hardcode them in `*.tfvars` or commit them.
- Apply a baseline tag set via the AWS provider `default_tags` block: `Environment`, `Owner`, `ManagedBy = "terraform"`, and `CostCenter`.
- Mark sensitive outputs and variables `sensitive = true`, and remember that flag hides values from logs but does not encrypt or remove them from state.

---

### [SKILL] terraform-iac-review  (path: /)

---
name: terraform-iac-review
description: Pre-merge review checklist for Terraform / IaC changes covering remote state, locking, versioning, secrets, tagging, and plan-gated CI. Use before merging any Terraform PR.
---

# Terraform / IaC review

- [ ] Remote `s3` backend configured with `use_lockfile = true`, no deprecated DynamoDB lock
- [ ] State bucket has versioning enabled and SSE-KMS encryption (`encrypt = true` + `kms_key_id`)
- [ ] Each environment uses an isolated state `key`; no state files committed to git
- [ ] `required_version` and all `required_providers` are pinned; `.terraform.lock.hcl` is committed
- [ ] Modules sourced with an explicit `version` or pinned `?ref=`, never a floating branch
- [ ] No secrets in `*.tfvars`, code, or state; write-only / ephemeral args used for passwords and tokens
- [ ] Sensitive variables and outputs marked `sensitive = true`
- [ ] `default_tags` applies the baseline tag set (`Environment`, `Owner`, `ManagedBy`, `CostCenter`)
- [ ] CI runs `terraform plan -out=tfplan` and applies that exact artifact after approval
- [ ] Cloud auth uses short-lived OIDC tokens with a least-privilege role, no static keys
- [ ] `terraform validate` and `terraform fmt -check` pass; a security scan (tfsec/Checkov/Trivy) is clean
