Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/v1.12/BUG FIXES-20250331-150802.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: BUG FIXES
body: Import references should not be able to reference the import target
time: 2025-03-31T15:08:02.156881+02:00
custom:
Issue: "36672"
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.

This should point to the PR, not the issue

43 changes: 43 additions & 0 deletions internal/terraform/context_apply2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2188,6 +2188,49 @@ import {
}
}

// https://github.com/hashicorp/terraform/issues/36672
func TestContext2Apply_importSelfReference(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
resource "test_resource" "a" {
count = 2
}

import {
# the block references the same resource it is importing into
for_each = { for _, v in test_resource.a : v => v }
to = test_resource.a[each.key]
id = concat("importable-", each.key)
}
`,
})

p := testProvider("test")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})
_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
Mode: plans.NormalMode,
})

if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}

found := false
for _, diag := range diags {
if diag.Severity() == tfdiags.Error && diag.Description().Summary == "Invalid import block" {
found = true
break
}
}
if !found {
t.Fatalf("expected diag with summary 'Invalid import block', but got %s", diags.Err())
}
}

func TestContext2Apply_destroySkipsVariableValidations(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
Expand Down
19 changes: 18 additions & 1 deletion internal/terraform/transform_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func (t *ConfigTransformer) transform(g *Graph, config *configs.Config) error {
func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) error {
path := config.Path
module := config.Module
var diags tfdiags.Diagnostics
log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path)

var allResources []*configs.Resource
Expand Down Expand Up @@ -171,6 +172,21 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er
importTargets: imports,
}

// If a resource is the target of an import block, the import block
// must not reference that resource, except in the "to" attribute.
for _, ref := range abstract.ImportReferences() {
if addr, ok := ref.Subject.(addrs.Resource); ok {
if addr.Equal(relAddr) {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid import block",
Detail: "The import block can only reference the resource to be imported in the 'to' attribute.",
Subject: ref.SourceRange.ToHCL().Ptr(),
})
}
}
}

var node dag.Vertex = abstract
if f := t.Concrete; f != nil {
node = f(abstract)
Expand Down Expand Up @@ -199,7 +215,8 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er

g.Add(node)
}
return nil

return diags.Err()
}

// validateImportTargets ensures that the import target module exists in the
Expand Down