Skip to content

Wire policy evaluation into Terraform core runtime#38516

Merged
dsa0x merged 19 commits into
mainfrom
policy-pr3-core-runtime
Jun 1, 2026
Merged

Wire policy evaluation into Terraform core runtime#38516
dsa0x merged 19 commits into
mainfrom
policy-pr3-core-runtime

Conversation

@dsa0x
Copy link
Copy Markdown
Member

@dsa0x dsa0x commented May 4, 2026

This is part of a stacked series to upstream the policy work in smaller, reviewable pieces:

This PR wires policy evaluation into Terraform core itself. It adds the runtime behavior for evaluating policy during graph execution, passes the relevant metadata and values into the policy engine, and records the resulting policy outcomes back onto the run so later layers can surface them.

This is the core of the stack. The main thing happening here is not CLI behavior yet, but rather defining where policy runs in the Terraform runtime, what objects get evaluated, and how those results are tracked.

Included here

  • policy evaluation during core graph/runtime execution
  • provider/resource runtime wiring
  • core tests covering policy behavior
  • supporting core/test plumbing needed to make that work

Target Release

1.16.x

Rollback Plan

  • If a change needs to be reverted, we will roll out an update to the code within 7 days.

Changes to Security Controls

Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain.

CHANGELOG entry

  • This change is user-facing and I added a changelog entry.
  • This change is not user-facing.

@dsa0x dsa0x added the no-changelog-needed Add this to your PR if the change does not require a changelog entry label May 4, 2026
@dsa0x dsa0x force-pushed the policy-pr3-core-runtime branch from ac6ebf9 to fb1a082 Compare May 15, 2026 12:13
@dsa0x dsa0x marked this pull request as ready for review May 18, 2026 09:52
@dsa0x dsa0x requested a review from a team as a code owner May 18, 2026 09:52
@dsa0x dsa0x force-pushed the policy-pr2-results-diags branch from c3a1b4b to f309492 Compare May 19, 2026 14:07
@dsa0x dsa0x requested review from a team as code owners May 19, 2026 14:07
@dsa0x dsa0x force-pushed the policy-pr2-results-diags branch 2 times, most recently from fabac57 to 7f791cd Compare May 21, 2026 11:43
@dsa0x dsa0x force-pushed the policy-pr3-core-runtime branch from e691a08 to a6d3871 Compare May 21, 2026 16:03
@dsa0x dsa0x changed the base branch from policy-pr2-results-diags to main May 22, 2026 13:56
@dsa0x dsa0x force-pushed the policy-pr3-core-runtime branch 4 times, most recently from 35ef0a8 to def6dde Compare May 26, 2026 12:37
@dsa0x dsa0x force-pushed the policy-pr3-core-runtime branch from 82875dc to d4ca814 Compare May 26, 2026 21:22
Copy link
Copy Markdown
Member

@SarahFrench SarahFrench left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still looking through this PR, and it's a lot easier after the meeting we had yesterday (thank you!). I'll continue looking but I figured I'd share an initial round of comments.

Comment thread internal/terraform/node_resource_abstract_instance.go Outdated
Comment thread internal/tfdiags/sourceless.go Outdated
Comment thread internal/plans/plan.go
Comment thread internal/dag/walk_test.go
Comment thread internal/terraform/context_apply.go
Comment thread internal/terraform/context_apply.go Outdated
@github-actions
Copy link
Copy Markdown
Contributor

The equivalence tests failed. Please investigate here.

@dsa0x dsa0x force-pushed the policy-pr3-core-runtime branch from 2676716 to 104673a Compare May 28, 2026 12:12
Co-authored-by: Sarah French <15078782+SarahFrench@users.noreply.github.com>
@dsa0x dsa0x force-pushed the policy-pr3-core-runtime branch from 104673a to 1e97ca1 Compare May 28, 2026 13:10
@dsa0x dsa0x requested a review from SarahFrench May 29, 2026 06:16
Copy link
Copy Markdown
Member

@SarahFrench SarahFrench left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still looking through, but here are some more comments 📝

Comment thread internal/terraform/graph_builder_apply.go
Comment thread internal/terraform/node_provider.go Outdated
Comment thread internal/terraform/node_provider_abstract.go Outdated
@dsa0x dsa0x force-pushed the policy-pr3-core-runtime branch from 2e848ac to acbabc3 Compare June 1, 2026 07:38
Copy link
Copy Markdown
Member

@SarahFrench SarahFrench left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved - I've looked through all the changes and have no further questions or feedback.

@dsa0x dsa0x merged commit 7d22d46 into main Jun 1, 2026
14 checks passed
@dsa0x dsa0x deleted the policy-pr3-core-runtime branch June 1, 2026 10:58
Copy link
Copy Markdown
Member

@austinvalle austinvalle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for the late review 😅 , left a few comments/questions

Comment thread internal/states/sync.go
addrs := s.state.allResourceInstanceObjectAddrs(func(objAddr addrs.AbsResourceInstanceObject) bool {
return objAddr.ResourceInstance.ConfigResource().Equal(addr)
})
s.lock.RUnlock()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this unlock meant to be deferred? Looks like we're accessing s.state after the mutex been unlocked 👀

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Thank you!.

Comment on lines +590 to +592
if policyGraph := ctx.PolicyGraph(); policyGraph != nil && !n.preDestroyRefresh {
policyGraph.Add(policyNodeFromChange(change))
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we expecting that data sources should also have a policy node added? It looks like they also use this writeChange method to plan 👀

diags = diags.Append(n.writeChange(ctx, change, ""))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. This never caused a problem because data source changes are denoted as Read, so we never send them for policy evaluation. However it does make sense to not have a node for them in the first place

Comment on lines +71 to +72
default:
return nil
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Is this switch statement meant to be exhaustive? If not, a log mentioning why we're skipping policy evaluation could be helpful for future debuggers 👀

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't exhaustive, as there are other actions that we do not care about. Adding a log here.

Comment on lines +53 to +55
if modCfg == nil {
return nil
}
Copy link
Copy Markdown
Member

@austinvalle austinvalle Jun 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Is this expected? Feels like it should either be a panic (internal implementation error) or a log (expected skip of policy evaluation) 🤔

readResp := provider.ReadDataSource(providers.ReadDataSourceRequest{
TypeName: target,
Config: configVal,
ProviderMeta: meta,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very interesting 👀 , was it specifically requested that we add provider meta here? I'm not 100% sure how it's being used today by the providers, but I believe the usage of it was more analytics then functional behavior of ReadDataSource (I also vaguely remember it being related to module usage, but here the context is the resource policy is using it, not the actual configuration... not sure if the distinction is important 🤔 )

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, meta only has to do with tracking module usage. If this config isn't coming directly from module usage, this probably shouldn't be used here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right.. I dont have much knowledge about the origins of that object in the request. However, this data source evaluation uses the same provider as the module of the current resource whose policy is being evaluated. So I am not sure it would be a bad idea when we send this meta and the provider translates it as part of the module usage.

Comment thread internal/terraform/policy.go
func getDataSourceForPolicyCallback(ctx EvalContext, provider providers.Interface, schema providers.GetProviderSchemaResponse, meta cty.Value) func(datasource string, attrs cty.Value) (cty.Value, error) {
return func(target string, attrs cty.Value) (cty.Value, error) {
if datasource, ok := schema.DataSources[target]; ok {
configVal, err := datasource.Body.CoerceValue(attrs)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would the config require CoerceValue? It looks like it's patching over a typing bug elsewhere.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The config here does not come from a parsed terraform configuration. It comes from the policy engine, which means it has not been validated, and is merely denoted as an object thus far. CoerceValue would allow us to validate it against the schema.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog-needed Add this to your PR if the change does not require a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants