Loading the skills library…
Write, test, or convert Terraform Policy files (.policy.hcl, .policytest.hcl, Sentinel→tfpolicy). Triggers: policy.hcl, policytest, convert sentinel, tfpolicy, write a policy.
npx skills add hashicorp/agent-skills --skill terraform-policyInstalls from the source repository, including any supporting files.
Downloads contain the instructions shown here. Use the install command for the complete skill.
UTILITY SKILL — INVOKES: tfpolicy-author | tfpolicy-test
.policy.hcl policy from a description or requirement.sentinel policy to Terraform Policy.policytest.hcl test fileBefore giving authoring or testing instructions, check the installed tfpolicy CLI version and tailor guidance accordingly. This skill maintains guidance for the two most recent minor lines, 0.4.x and 0.5.x. The 0.3.x bullet below is baseline guidance that applies to every supported line. When a new minor ships, drop the oldest line and add the new one. Inline notes for versions earlier than 0.3.0 are retained only for older CLIs.
0.3.x (baseline), include a top-level policy { required_providers { ... } } block when authoring .policy.hcl files containing resource or provider policies. It is mandatory for tfpolicy validate; version-range validation is best effort, and wildcard targets such as resource_policy "*" are not schema-validated. Every mock resource {} block in .policytest.hcl files must declare attrs or prior_attrs; if both evaluate to empty, the test case is skipped (provider {} and module {} mocks are unaffected) (see tfpolicy-test). tfpolicy test reuses the target .policy.hcl's existing top-level policy { required_providers { ... } } block (there is no separate .policytest.hcl-level declaration) to validate provider, resource, and data-source policies and core::getdatasource()/core::getresources() arguments against resolved provider schemas before any test runs, failing the whole run on a schema mismatch (see ). and are available — prefer them over the list-comprehension workaround (see ). and are available to resource, provider, and module policies; Stack fields are empty strings outside Stack evaluations on 0.3.x and 0.4.x ( on 0.5.x+, see below). On 0.3.x only, the operation does not exist: resource policies evaluate only resources that the run creates, updates, or deletes, and the default is .core::alltrue(list)core::anytrue(list)core::length()meta.tfe_stackmeta.tfe_workspace.tagsnullno-opoperations["create", "update"]0.4.x or newer, all 0.3.x guidance still applies except the operations default, plus the no-op operation, which evaluates resources that the run leaves unchanged (the entire state). operations accepts "create", "update", "delete", and "no-op". For policies that do not reference prior_attrs, the default operations is now ["create", "update", "no-op"], so omitting it evaluates every resource in state. Use operations = ["create", "update"] to evaluate only changed resources. no-op exposes the existing values through attrs, and prior_attrs is unavailable. delete cannot be combined with create or no-op (["update", "delete"] is valid), and prior_attrs policies must set operations explicitly. Attrs-only policies (no prior_attrs) calling core::getresources whose operations omit no-op load with a warning; do not add no-op to a prior_attrs policy, which fails validation. In tests, set meta.operation = "no-op" explicitly because it is never inferred (see tfpolicy-author and tfpolicy-test).0.5.x or newer, all 0.4.x guidance still applies, with two changes. (1) Absent meta attributes are exposed as null instead of an empty string: meta.alias (no alias), meta.version (no version specified, including modules), and meta.tfe_stack.deployment_group / deployment_name / stack_name (workspace evaluations or not set). meta.tfe_workspace.tags is still an empty map. Passing null to a function such as core::semverconstraint, or interpolating it into a string such as error_message, fails, and && does not short-circuit, so guard with a conditional: meta.version != null ? core::semverconstraint(meta.version, ">= 2.0.0") : false. Equality checks are null-safe (meta.alias == "secondary" is false when there is no alias), but checks like meta.tfe_stack.stack_name == "" no longer match (use == null). (2) prior_attrs is rejected at parse time in provider_policy and module_policy blocks; it is valid only in resource_policy (update and delete operations). Use attrs. for provider attributes (see tfpolicy-author).0.3.x, 0.4.x, and 0.5.x paths..tftest.hcl files for Terraform modules — use terraform-testterraform-style-guide| Task | Sub-skill |
|---|---|
Write or convert a .policy.hcl policy | tfpolicy-author |
Write or debug a .policytest.hcl test | tfpolicy-test |
npx skills add hashicorp/agent-skills/terraform/terraform-policy/skills/tfpolicy-author
npx skills add hashicorp/agent-skills/terraform/terraform-policy/skills/tfpolicy-test
# terraform-policy
**UTILITY SKILL** — INVOKES: [tfpolicy-author](references/tfpolicy-author.md) | [tfpolicy-test](references/tfpolicy-test.md)
## USE FOR:
- Writing a new `.policy.hcl` policy from a description or requirement
- Converting a `.sentinel` policy to Terraform Policy
- Writing or debugging a `.policytest.hcl` test file
- Migrating a Sentinel policy library to Terraform Policy
Before giving authoring or testing instructions, check the installed `tfpolicy` CLI version and tailor guidance accordingly. This skill maintains guidance for the two most recent minor lines, `0.4.x` and `0.5.x`. The `0.3.x` bullet below is baseline guidance that applies to every supported line. When a new minor ships, drop the oldest line and add the new one. Inline notes for versions earlier than `0.3.0` are retained only for older CLIs.
- If the CLI is `0.3.x` (baseline), include a top-level `policy { required_providers { ... } }` block when authoring `.policy.hcl` files containing resource or provider policies. It is mandatory for `tfpolicy validate`; version-range validation is best effort, and wildcard targets such as `resource_policy "*"` are not schema-validated. Every mock `resource {}` block in `.policytest.hcl` files must declare `attrs` or `prior_attrs`; if both evaluate to empty, the test case is skipped (`provider {}` and `module {}` mocks are unaffected) (see [tfpolicy-test](references/tfpolicy-test.md#every-resource--mock-must-declare-a-non-empty-state-block-tfpolicy-030)). `tfpolicy test` reuses the target `.policy.hcl`'s existing top-level `policy { required_providers { ... } }` block (there is no separate `.policytest.hcl`-level declaration) to validate provider, resource, and data-source policies and `core::getdatasource()`/`core::getresources()` arguments against resolved provider schemas before any test runs, failing the whole run on a schema mismatch (see [tfpolicy-test](references/tfpolicy-test.md#test-execution-behavior)). `core::alltrue(list)` and `core::anytrue(list)` are available — prefer them over the `core::length()` list-comprehension workaround (see [tfpolicy-author](references/tfpolicy-author.md#core-functions--common-idioms)). `meta.tfe_stack` and `meta.tfe_workspace.tags` are available to resource, provider, and module policies; Stack fields are empty strings outside Stack evaluations on 0.3.x and 0.4.x (`null` on 0.5.x+, see below). On 0.3.x only, the `no-op` operation does not exist: resource policies evaluate only resources that the run creates, updates, or deletes, and the default `operations` is `["create", "update"]`.
- If the CLI is `0.4.x` or newer, all `0.3.x` guidance still applies except the `operations` default, plus the `no-op` operation, which evaluates resources that the run leaves unchanged (the entire state). `operations` accepts `"create"`, `"update"`, `"delete"`, and `"no-op"`. For policies that do not reference `prior_attrs`, the default `operations` is now `["create", "update", "no-op"]`, so omitting it evaluates every resource in state. Use `operations = ["create", "update"]` to evaluate only changed resources. `no-op` exposes the existing values through `attrs`, and `prior_attrs` is unavailable. `delete` cannot be combined with `create` or `no-op` (`["update", "delete"]` is valid), and `prior_attrs` policies must set `operations` explicitly. Attrs-only policies (no `prior_attrs`) calling `core::getresources` whose `operations` omit `no-op` load with a warning; do not add `no-op` to a `prior_attrs` policy, which fails validation. In tests, set `meta.operation = "no-op"` explicitly because it is never inferred (see [tfpolicy-author](references/tfpolicy-author.md#operation-scoping-and-prior_attrs) and [tfpolicy-test](references/tfpolicy-test.md#testing-operation-aware-policies)).
- If the CLI is `0.5.x` or newer, all `0.4.x` guidance still applies, with two changes. (1) Absent `meta` attributes are exposed as `null` instead of an empty string: `meta.alias` (no alias), `meta.version` (no version specified, including modules), and `meta.tfe_stack.deployment_group` / `deployment_name` / `stack_name` (workspace evaluations or not set). `meta.tfe_workspace.tags` is still an empty map. Passing `null` to a function such as `core::semverconstraint`, or interpolating it into a string such as `error_message`, fails, and `&&` does not short-circuit, so guard with a conditional: `meta.version != null ? core::semverconstraint(meta.version, ">= 2.0.0") : false`. Equality checks are null-safe (`meta.alias == "secondary"` is `false` when there is no alias), but checks like `meta.tfe_stack.stack_name == ""` no longer match (use `== null`). (2) `prior_attrs` is rejected at parse time in `provider_policy` and `module_policy` blocks; it is valid only in `resource_policy` (update and delete operations). Use `attrs.` for provider attributes (see [tfpolicy-author](references/tfpolicy-author.md#meta-attributes-nullable-on-050)).
- If the CLI version is unknown, ask the user to check it first or provide guidance that clearly distinguishes the `0.3.x`, `0.4.x`, and `0.5.x` paths.
## DO NOT USE FOR:
- Writing `.tftest.hcl` files for Terraform modules — use `terraform-test`
- General Terraform HCL authoring — use `terraform-style-guide`
## Routing
| Task | Sub-skill |
|------|-----------|
| Write or convert a `.policy.hcl` policy | [tfpolicy-author](references/tfpolicy-author.md) |
| Write or debug a `.policytest.hcl` test | [tfpolicy-test](references/tfpolicy-test.md) |
## Examples
- "Block EC2 instances without encryption" → [tfpolicy-author](references/tfpolicy-author.md)
- "Convert this Sentinel policy to tfpolicy" → [tfpolicy-author](references/tfpolicy-author.md)
- "Write a policytest for my EBS policy" → [tfpolicy-test](references/tfpolicy-test.md)
## Troubleshooting
- **Wrong skill triggered?** Load the sub-skill directly from the routing table above.
```bash
npx skills add hashicorp/agent-skills/terraform/terraform-policy/skills/tfpolicy-author
npx skills add hashicorp/agent-skills/terraform/terraform-policy/skills/tfpolicy-test
```