From 46cbd84580b3456a9e2a8dff800fed8953affae6 Mon Sep 17 00:00:00 2001 From: Nick Fagerlund Date: Tue, 9 Dec 2025 22:50:26 +0000 Subject: [PATCH 1/2] backport of commit 116646ac85c83603f2f15cd201e4bfcdd90480f6 --- internal/configs/source_bundle_parser.go | 26 ++++++++++++++++++- .../internal/stackeval/planning_test.go | 23 +++++----------- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/internal/configs/source_bundle_parser.go b/internal/configs/source_bundle_parser.go index edac0cf014ff..092f40296ce0 100644 --- a/internal/configs/source_bundle_parser.go +++ b/internal/configs/source_bundle_parser.go @@ -67,7 +67,31 @@ func (p *SourceBundleParser) LoadConfigDir(source sourceaddrs.FinalSource) (*Mod }) return nil, diags } - mod.SourceDir = sourceDir + + // The result of sources.LocalPathForSource is an absolute path, but we + // don't actually want to pass an absolute path for a module's SourceDir; + // doing so will cause the value of `path.module` in Terraform configs to + // differ across plans and applies, since tfc-agent performs plans and + // applies in temporary directories. Instead, we try to resolve a relative + // path from Terraform's working directory, which should always be a + // reasonable SourceDir value. + workDir, err := os.Getwd() + if err != nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Cannot resolve working directory", + Detail: fmt.Sprintf("Failed to resolve current working directory: %s. This is a bug in Terraform - please report it.", err), + }) + } + relativeSourceDir, err := filepath.Rel(workDir, sourceDir) + if err != nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Cannot resolve relative path", + Detail: fmt.Sprintf("Failed to resolve relative path to module directory: %s. This is a bug in Terraform - please report it.", err), + }) + } + mod.SourceDir = relativeSourceDir return mod, diags } diff --git a/internal/stacks/stackruntime/internal/stackeval/planning_test.go b/internal/stacks/stackruntime/internal/stackeval/planning_test.go index e032d6f0fd86..ac669fb7fc3d 100644 --- a/internal/stacks/stackruntime/internal/stackeval/planning_test.go +++ b/internal/stacks/stackruntime/internal/stackeval/planning_test.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "os" - "path/filepath" "strings" "testing" "time" @@ -852,17 +851,9 @@ func TestPlanning_PathValues(t *testing.T) { t.Fatalf("failed to get current working directory: %s", err) } - normalizePath := func(path string) string { - rel, err := filepath.Rel(cwd, path) - if err != nil { - t.Errorf("rel(%s,%s): %s", cwd, path, err) - return path - } - return rel - } - + // path.cwd should be absolute and all others should be relative, as per documentation. expected := map[string]string{ - "cwd": ".", + "cwd": cwd, "root": "testdata/sourcebundle/planning/path_values/module", // this is the root module of the component "module": "testdata/sourcebundle/planning/path_values/module", // this is the root module "child_root": "testdata/sourcebundle/planning/path_values/module", // should be the same for all modules @@ -870,11 +861,11 @@ func TestPlanning_PathValues(t *testing.T) { } actual := map[string]string{ - "cwd": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "cwd"}].AsString()), - "root": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "root"}].AsString()), - "module": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "module"}].AsString()), - "child_root": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "child_root"}].AsString()), - "child_module": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "child_module"}].AsString()), + "cwd": component.PlannedOutputValues[addrs.OutputValue{Name: "cwd"}].AsString(), + "root": component.PlannedOutputValues[addrs.OutputValue{Name: "root"}].AsString(), + "module": component.PlannedOutputValues[addrs.OutputValue{Name: "module"}].AsString(), + "child_root": component.PlannedOutputValues[addrs.OutputValue{Name: "child_root"}].AsString(), + "child_module": component.PlannedOutputValues[addrs.OutputValue{Name: "child_module"}].AsString(), } if cmp.Diff(expected, actual) != "" { From 2d7dfadd7ec3c95e9baf73b9f93e090973556393 Mon Sep 17 00:00:00 2001 From: Nick Fagerlund Date: Tue, 9 Dec 2025 15:13:06 -0800 Subject: [PATCH 2/2] I think this is how the changelog thing works? --- .changes/v1.14/BUG FIXES-20251209-230000.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changes/v1.14/BUG FIXES-20251209-230000.yaml diff --git a/.changes/v1.14/BUG FIXES-20251209-230000.yaml b/.changes/v1.14/BUG FIXES-20251209-230000.yaml new file mode 100644 index 000000000000..d378f24610f7 --- /dev/null +++ b/.changes/v1.14/BUG FIXES-20251209-230000.yaml @@ -0,0 +1,5 @@ +kind: BUG FIXES +body: 'stacks: change absolute paths in path.module/path.root to be relative, as documented' +time: 2025-12-09T23:00:00.316597+00:00 +custom: + Issue: "37982"