Associate: testing and validation — check blocks and policy layers
The exam asks whether you can enforce assumptions and verify behavior. Name each tool by what it stops.
<!-- hal:authoritative:yaml -->
The exam asks whether you can enforce assumptions and verify behavior. Name each tool by what it stops.
§I — Frame
09-05 Cert practiced terraform.workspace and Lab 13 prod guardrails. That material stays. Today the Associate and Pro-depth seat turns to testing and validation: variable validation, lifecycle preconditions and postconditions, check blocks, terraform test, and the policy layer that sits outside a single root module.
Lab 07 is the correction lab for the first four. Lab 29 deepens terraform test with multi-run setup and sharper asserts. Brikman Chapter 9 supplies the testing pyramid vocabulary: unit-ish checks, plan tests, integration tests, end-to-end tests.
Ops today implements the HCL on AWS resources. Dev asserts failures with terratest. Go parses plan JSON. Cert must say which instrument belongs on which exam question.
§II — Objective map: what stops what
Variable validation. Rejects illegal input values when variables are evaluated. Exam cue: validation block with condition and error_message. Scope: one variable. Cannot see other resources.
Lifecycle precondition. Rejects create or update when a condition on configuration or data is false. Exam cue: inside lifecycle on a resource or data source. Fails plan and apply for that node.
Lifecycle postcondition. Rejects after the provider returns self if an invariant is false. Exam cue: uses self. Apply may have already mutated the cloud.
Check block. Advisory assert at plan and apply. Exam cue: top-level check with assert. Does not replace organizational policy.
terraform test. Runs .tftest.hcl files with run blocks, optional command = plan|apply, variables, assert, and expect_failures. Exam cue: native tests next to the module.
Policy-as-code (Sentinel, OPA over plan JSON). Evaluates the planned change set for the workspace or pipeline. Exam cue: HCP Terraform policy sets; local Conftest/OPA; distinct from Custom Conditions.
§III — Lab 07 patterns you must recognize
Lab 07 starter already shows:
validationonenvironmentandname_prefix.preconditiononterraform_data.deploymentblocking prod +t3.micro.check "name_prefix_quality"requiring length >= 5.tests/basic.tftest.hclwith a happy plan and anexpect_failuresrun.
On the exam, map each snippet to the failure mode. If the question says "fail before provider create when environment is prod and instance is tiny," answer precondition (or validation if only one variable is involved). If the question says "warn but still apply when a naming convention is weak," answer check block. If the question says "automate that expectation in CI without Go," answer terraform test with expect_failures.
§IV — Lab 29 depth for Pro-shaped items
Lab 29 asks for multi-run flows: a setup run with command = apply, then later asserts across outputs. Pro-depth items favor:
- Ordered runs that share state inside the test file.
- Clear
asserterror_messagetext. - Setup/teardown thinking without leaving orphan resources in a shared cloud account.
You do not need to memorize every HCL attribute. You need to recognize that native tests can apply, assert, and apply again. Terratest remains valid; the exam also expects familiarity with first-party terraform test.
§V — Worked exam discriminators
Discriminator A. "Prevent a variable from accepting values outside an allowlist." → variable validation.
Discriminator B. "Prevent apply when two variables combine unsafely." → precondition (or a test that expects failure).
Discriminator C. "Ensure after apply that an instance has no public IP in prod." → postcondition on self.public_ip.
Discriminator D. "Flag short name prefixes without failing apply." → check block.
Discriminator E. "Block every workspace in the org from opening SSH to the world." → policy-as-code / SCP / admission control, not a single module check.
Discriminator F. "Prove the unsafe combination fails in CI using only Terraform CLI." → terraform test + expect_failures.
Write these six on a card. Most Associate items collapse into one of them.
§VI — Policy versus Custom Conditions
Custom Conditions travel with the module. They help authors and consumers of that module. They are invisible to stacks that never call the module.
Policy-as-code evaluates plans at the platform boundary. Sentinel on HCP Terraform can deny a plan after terraform plan succeeds locally. OPA can deny in GitHub Actions after terraform show -json. SCPs deny API calls even if Terraform would have applied.
Associate questions often ask which layer fits a vignette. If the vignette names one module author, prefer Custom Conditions. If it names a platform team and many workspaces, prefer policy sets. If it names an AWS account guardrail independent of Terraform, prefer SCP or IAM.
09-05 Cert already used a workspace precondition as a local guard. Today keep that as one tool among many, not the org-wide answer.
§VII — Plan testing in Brikman's frame
Brikman Plan testing (pp. 544-546) argues you can catch many mistakes by inspecting a plan without applying. Native checks and preconditions make some of those mistakes fail automatically. Plan JSON consumers (yesterday's Python census, today's Go parser) make the rest visible in PRs.
For the exam: plan testing is cheaper than full integration tests. Integration tests still matter when behavior only appears after create. Do not claim plan alone proves runtime health.
§VII.B — Sample vignette walkthroughs
Vignette 1. A module accepts environment as free text. Developers typo prd. Apply creates mistagged resources. Fix: variable validation with an allowlist. Optional: precondition if other variables must align after validation passes.
Vignette 2. A team wants prod to refuse public IPs even when a junior sets associate_public_ip_address = true. Fix: postcondition on self.public_ip, plus a precondition that rejects the associate flag when environment == "prod" so the API call never happens.
Vignette 3. Platform wants every plan scanned for open security groups across hundreds of workspaces. Fix: policy-as-code over plan JSON or HCP policy sets. A check block in one module cannot see the fleet.
Vignette 4. CI must prove the prod-micro combination fails without Go. Fix: terraform test run with expect_failures. Terratest is acceptable in real pipelines; the exam still wants you to recognize the native command.
Vignette 5. Naming guidelines prefer five-character prefixes but emergencies allow shorter names. Fix: check block for the guideline; do not use a precondition unless the org elevates the rule to mandatory.
§VII.C — Commands to keep muscle-fresh
terraform validate
terraform plan -var-file=prod-unsafe.tfvars
terraform test
terraform test -filter=tests/basic.tftest.hcl
terraform show -json tfplan.out > plan.json
Know what each exits on. validate does not run preconditions that need plan-time values from data sources in every case you expect; prefer plan for Custom Conditions. test runs the files. show -json feeds policy engines and today's Go parser.
§VII.D — Common trap answers
Trap: calling a check block a "hard prevent." It is advisory unless the platform treats warnings as failures.
Trap: saying variable validation can read other resources. It cannot.
Trap: saying postconditions run before the provider create. They run after self exists.
Trap: saying Sentinel replaces module preconditions. It complements them at another boundary.
Trap: saying workspaces are required for validation. Workspaces are orthogonal; 09-05 covered them.
§VIII — Study drill (self-check)
- Name the four HCL instruments in Lab 07 and one sentence each on failure behavior.
- Write an
expect_failuresrun for prod +t3.microfrom memory. - Explain why a check warning can still exit zero.
- Place Sentinel relative to precondition for a company-wide SSH ban.
- Contrast
terraform testwith terratest in one paragraph without declaring a winner.
Tap-to-reveal style answers belong in Maghrib quiz cards later. For now, speak the answers out loud against Lab 07 and Lab 29 READMEs.
§IX — Closing
Associate success here is taxonomy plus vignette mapping. Pro-depth success adds multi-run tests and honest limits of each layer. Implement the HCL in Ops. Prove failure in Dev. Parse JSON in Go. Keep policy for the platform.
§IX.B — Linking Ops, Dev, and Go without double-counting study time
Read Ops once for the AWS HCL shape. Skim Dev for how expect_failures becomes InitAndPlanE. Skim Go for how check warnings appear in JSON when plan succeeds. Your Cert drill is the taxonomy card in §V plus the five vignettes in §VII.B.
If time is short before an exam window, prioritize: (1) validation versus precondition versus check, (2) terraform test expect_failures, (3) policy-as-code versus module conditions. Terratest details are useful professionally and less frequent on Associate items.
§IX.C — Pro-depth extras worth one more pass
replace_triggered_byalready spent on 09-02; do not confuse it with postconditions.movedandimportblocks are state surgery; they are not validation.- HCP Terraform run tasks can call external scanners; treat them as policy-adjacent, not Custom Conditions.
- Sensitive outputs interact with plan JSON redaction; know that exams may ask what remains visible.
Write one paragraph that places Custom Conditions, terraform test, terratest, and Sentinel on a single timeline from terraform plan to merge. If the paragraph cannot stay coherent, the taxonomy is not yet solid.
Related
- Paired Ops: Archmagus-Stack/01-Earth-DevOps/Synthesis-Lessons/2026-09-08-terraform-check-blocks-preconditions-postconditions-on-aws-resources/lesson.md
- Paired Dev: Archmagus-Stack/Polyglot-Dev/Go/2026-09-08-terratest-asserting-check-block-failures-and-plan-tests/lesson.md
- Prior Cert (workspaces): Archmagus-Stack/Cert-Prep/HashiCorp/2026-09-05-terraform-workspaces-with-terraform-workspace-and-prod-guardrails/lesson.md
- Lab 07: Archmagus-Stack/Sovereign-Bootcamp/tfpro-labs/labs/07-validation-checks-tests-broken/README.md
- Lab 29: Archmagus-Stack/Sovereign-Bootcamp/tfpro-labs/labs/29-terraform-test-depth-broken/README.md