Hedronite · Cert Lesson · Cert-Prep / HashiCorp · Tue 2026-09-08

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.

Lesson Class: Cert (Terraform Associate 003 / Pro-depth)
Facet: validation · Custom Conditions · terraform test · policy
Rebalance: After workspaces 09-05 · replace_triggered_by 09-02
Paired Ops: AWS check blocks
Grounding: Lab 07 · Lab 29 · Brikman Ch.9
Taxonomy
Six discriminators on one card.
Native test
expect_failures without Go.
Policy
Fleet gates sit outside one module.
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:

  1. validation on environment and name_prefix.
  2. precondition on terraform_data.deployment blocking prod + t3.micro.
  3. check "name_prefix_quality" requiring length >= 5.
  4. tests/basic.tftest.hcl with a happy plan and an expect_failures run.

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:

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)

  1. Name the four HCL instruments in Lab 07 and one sentence each on failure behavior.
  2. Write an expect_failures run for prod + t3.micro from memory.
  3. Explain why a check warning can still exit zero.
  4. Place Sentinel relative to precondition for a company-wide SSH ban.
  5. Contrast terraform test with 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

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