From f6ad8d3215b176a34efc7459a497c6bd1d2430d4 Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Tue, 23 Sep 2025 12:20:58 -0400 Subject: [PATCH] actions: fix panic during query plan by not planning actions We don't need to plan any actions during query plan mode. Test stolen from DanielMSchmidt, thank you! --- .../terraform/context_plan_actions_test.go | 107 +++++++++++++++++- internal/terraform/graph_builder_plan.go | 7 +- internal/terraform/transform_action_plan.go | 4 +- 3 files changed, 113 insertions(+), 5 deletions(-) diff --git a/internal/terraform/context_plan_actions_test.go b/internal/terraform/context_plan_actions_test.go index 5707875b87..c82245b726 100644 --- a/internal/terraform/context_plan_actions_test.go +++ b/internal/terraform/context_plan_actions_test.go @@ -4,6 +4,7 @@ package terraform import ( + "maps" "path/filepath" "slices" "sort" @@ -144,7 +145,70 @@ action "test_action" "hello" {} } }, }, - + "query run": { + module: map[string]string{ + "main.tf": ` +action "test_action" "hello" {} +resource "test_object" "a" { + lifecycle { + action_trigger { + events = [before_create, after_update] + actions = [action.test_action.hello] + } + } +} +`, + "main.tfquery.hcl": ` +list "test_resource" "test1" { + provider = "test" + config { + filter = { + attr = "foo" + } + } +} +`, + }, + expectPlanActionCalled: false, + planOpts: &PlanOpts{ + Mode: plans.NormalMode, + Query: true, + }, + }, + "query run, action references resource": { + module: map[string]string{ + "main.tf": ` +action "test_action" "hello" { + config { + attr = resource.test_object.a + } +} +resource "test_object" "a" { + lifecycle { + action_trigger { + events = [before_create, after_update] + actions = [action.test_action.hello] + } + } +} +`, + "main.tfquery.hcl": ` +list "test_resource" "test1" { + provider = "test" + config { + filter = { + attr = "foo" + } + } +} +`, + }, + expectPlanActionCalled: false, + planOpts: &PlanOpts{ + Mode: plans.NormalMode, + Query: true, + }, + }, "invalid config": { module: map[string]string{ "main.tf": ` @@ -3269,6 +3333,47 @@ resource "test_object" "a" { }, }, }, + ListResourceTypes: map[string]providers.Schema{ + "test_resource": { + Body: &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "data": { + Type: cty.DynamicPseudoType, + Computed: true, + }, + }, + BlockTypes: map[string]*configschema.NestedBlock{ + "config": { + Block: configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "filter": { + Required: true, + NestedType: &configschema.Object{ + Nesting: configschema.NestingSingle, + Attributes: map[string]*configschema.Attribute{ + "attr": { + Type: cty.String, + Required: true, + }, + }, + }, + }, + }, + }, + Nesting: configschema.NestingSingle, + }, + }, + }, + }, + }, + }, + ListResourceFn: func(req providers.ListResourceRequest) providers.ListResourceResponse { + resp := []cty.Value{} + ret := req.Config.AsValueMap() + maps.Copy(ret, map[string]cty.Value{ + "data": cty.TupleVal(resp), + }) + return providers.ListResourceResponse{Result: cty.ObjectVal(ret)} }, } diff --git a/internal/terraform/graph_builder_plan.go b/internal/terraform/graph_builder_plan.go index 69776cff54..87a8dab985 100644 --- a/internal/terraform/graph_builder_plan.go +++ b/internal/terraform/graph_builder_plan.go @@ -174,9 +174,10 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer { }, &ActionPlanTransformer{ - Config: b.Config, - Operation: b.Operation, - Targets: b.ActionTargets, + Config: b.Config, + Operation: b.Operation, + Targets: b.ActionTargets, + queryPlanMode: b.queryPlan, }, // Add dynamic values diff --git a/internal/terraform/transform_action_plan.go b/internal/terraform/transform_action_plan.go index 752a8e9b2f..7f2fc8b4e2 100644 --- a/internal/terraform/transform_action_plan.go +++ b/internal/terraform/transform_action_plan.go @@ -16,10 +16,12 @@ type ActionPlanTransformer struct { Config *configs.Config Targets []addrs.Targetable Operation walkOperation + + queryPlanMode bool } func (t *ActionPlanTransformer) Transform(g *Graph) error { - if t.Operation != walkPlan { + if t.Operation != walkPlan || t.queryPlanMode { return nil }