In a Sentinel policy for HCP Terraform, what do the tfplan, tfstate and tfconfig imports each give you?
answer
- not one document, several
- what changes vs what exists
- the written HCL is its own input
- run metadata is a fourth import
- cost estimate lives outside the plan
basics
~20 stfplan gives the changes this run proposes, tfstate gives the resources the workspace already has, and tfconfig gives the configuration as written. They are three separate documents, so a rule reads whichever one answers its question.
solid answer
~40 sA policy check in a managed run is not handed "the Terraform code" as one blob. `tfplan/v2` carries this run's proposed changes — `resource_changes` with each address's `actions`, `before` and `after`, plus `planned_values` describing the intended end state. `tfstate/v2` carries what the workspace already contains, which is the only way to reason about resources this run does not touch. `tfconfig/v2` carries the configuration as written — resource and provider blocks, module calls, raw expressions — for rules about how the code is authored rather than what it resolves to. There is a fourth, `tfrun`, with workspace and organization metadata and, when cost estimation is enabled, the run's prior, proposed and delta monthly cost. Choosing the wrong document is the usual reason a rule silently checks nothing.
go deeper
Be ready to name the four inputs and say in one sentence what each is for. Interviewers mostly want to hear that the plan, the state and the configuration are separate documents rather than one bundle.
Expect to be asked which import answers a specific rule, and why the wrong choice makes a rule pass vacuously. Know the shape of resource_changes: address, actions, before, after.
Show that you pick the input deliberately and check the rule actually matched something. Be able to explain why a workspace-wide inventory rule needs state while a change-scoped rule does not.
Own the consequence: rules that depend on state or run metadata can only execute where those inputs exist, which constrains where your guardrails can be evaluated and who has to operate that decision point.
## The shape of a policy check inside a managed run In HCP Terraform and Terraform Enterprise a run moves through stages: plan, then cost estimation if it is enabled, then the policy check, then apply. The policy check sits between plan and apply, which means the engine is reasoning about a change that has been fully resolved but not yet executed. What matters for authoring is that the policy is not given a single document. Sentinel exposes the run's data through several **imports**, each a distinct view. ### `tfplan/v2` — what this run proposes The plan import is the workhorse. Its `resource_changes` collection is keyed by resource address (`aws_s3_bucket.data`, `module.net.aws_subnet.a[0]`) and each entry carries the resource's `type`, `name`, `mode` and `provider_name`, plus a `change` object holding: - `actions` — a list such as `["create"]`, `["update"]`, `["delete"]`, `["no-op"]`, or a delete and a create together when the resource is being replaced; - `before` — the attribute values recorded before this run; - `after` — the attribute values the run intends to produce. Alongside it, `planned_values` describes the whole intended end state of the workspace, and `variables` and `output_changes` cover inputs and outputs. Most rules of the form "nothing being created may sit outside our approved regions" are written against `resource_changes`. ### `tfstate/v2` — what already exists The state import exposes the resources currently recorded in the workspace, and the workspace outputs. This is the input you cannot substitute. `resource_changes` lists addresses the run is changing; a resource nobody is touching this run simply is not there. If the rule is "this workspace must not contain any resource outside the approved regions", including the ones created last year, only state can answer it. ### `tfconfig/v2` — what was written The configuration import exposes the source as authored: resource blocks and their raw expressions, provider blocks, variable and output declarations, module calls. Use it when the rule is about the *code*, not the resolved result — a provider block that hardcodes a region, a required variable someone inlined as a literal, a module call whose source is not what the platform team publishes. A plan cannot answer these because by plan time the expressions have been evaluated away. ### `tfrun` — the run itself `tfrun` carries metadata the platform owns rather than anything Terraform computed: the workspace and organization, and — where cost estimation is on — the run's `cost_estimate` with prior, proposed and delta monthly cost. A budget guardrail is expressible only because this import exists. ### Why the separation is the point The same English question gets different answers depending on which document you ask. "Is the region approved?" against `tfconfig` asks how the code is written; against `tfplan` it asks what this change will produce; against `tfstate` it asks what is standing right now. A rule that reads `planned_values` and concludes "no violations" may simply have been looking at a document where the offending resource never appears. Two boundaries are worth stating plainly, because new authors trip on both: 1. **The policy sees only these documents.** It cannot call a cloud API to look something up, cannot read another workspace, and cannot consult a previous run. 2. **These are Sentinel's names.** HCP Terraform can also evaluate OPA policy sets over the same run data; the split between plan, configuration, state and run metadata is a property of the platform, and the import names are a property of the framework. The practical habit to build is to decide, before writing a line, which document actually contains the fact your rule depends on — and then to check whether that document exists wherever you intend the rule to run.
- What does the tfrun import add that a plan file on its own does not carry?Data the platform produced rather than Terraform: the workspace and organization the run belongs to, and — when cost estimation is enabled — the run's prior, proposed and delta monthly cost. A rule that caps the cost increase of a single change, or that applies only to production workspaces, depends on that import existing.
- Why can't a rule about resources nobody is changing be answered from tfplan alone?Because `resource_changes` only lists addresses this run touches. A resource created six months ago and untouched today has no entry there, and `planned_values` will describe it only insofar as the plan reproduces the intended end state. Questions about the workspace's existing inventory belong to the state import.
- When would you read tfconfig instead of tfplan?When the rule is about how the code is written rather than what it evaluates to — a hardcoded credential-shaped literal, a provider block missing a required setting, a module call whose source is not an approved one. By plan time those expressions have been resolved, so the evidence you want is only in the configuration import.
The plan is the diff, the state is the file as it stands on disk, and the configuration is the source you wrote. A reviewer who is handed only one of the three will confidently miss things.
saying these in an interview costs you the question
- Assumes the plan already contains everything in state
- Treats the configuration and the plan as the same document
- Thinks a policy can call the cloud API to look values up
- Reads planned values and misses resources being destroyed
- Cannot say where a cost figure would come from