fix: render base variables into templates instead of tfvars (DEVEX-287) (#26436)

Part of the Template Builder wizard PR stack.

## Problem

The kubernetes base template used Terraform `variable` blocks and
`var.*` references for `use_kubeconfig` and `namespace`, but the
composed tar bundle never included a `.tfvars` file. This caused
`terraform plan` to fail with "required template variables need values:
namespace".

## Fix

Base templates now use Go template variables (`{{ .Variables.* }}`) just
like module templates do. Values are validated, HCL-quoted, and rendered
directly into the output HCL.

Also adds explicit "variable is required" validation to both
`mergeBaseVariables` and `mergeModuleVariables`, replacing the previous
reliance on `missingkey=error` at render time for clearer error
messages.

---
> [!NOTE]
> Generated by Coder Agents on behalf of @jeremyruppel
This commit is contained in:
Jeremy Ruppel
2026-06-23 11:26:38 -04:00
committed by GitHub
parent 2f6f8b9520
commit 7ea5d48296
7 changed files with 126 additions and 61 deletions
+19 -10
View File
@@ -55,9 +55,13 @@ func TestMergeModuleVariables(t *testing.T) {
},
}
requiredVars := map[string]string{
"required_no_default": "value",
}
t.Run("DefaultsApplied", func(t *testing.T) {
t.Parallel()
merged, err := mergeModuleVariables(manifest, nil)
merged, err := mergeModuleVariables(manifest, requiredVars)
require.NoError(t, err)
require.Equal(t, "13337", merged["port"])
require.Equal(t, "false", merged["enabled"])
@@ -65,7 +69,7 @@ func TestMergeModuleVariables(t *testing.T) {
t.Run("ComputedAndSensitiveSkipped", func(t *testing.T) {
t.Parallel()
merged, err := mergeModuleVariables(manifest, nil)
merged, err := mergeModuleVariables(manifest, requiredVars)
require.NoError(t, err)
require.NotContains(t, merged, "agent_id")
require.NotContains(t, merged, "api_key")
@@ -73,22 +77,24 @@ func TestMergeModuleVariables(t *testing.T) {
t.Run("NonRequiredWithoutDefaultGetsNull", func(t *testing.T) {
t.Parallel()
merged, err := mergeModuleVariables(manifest, nil)
merged, err := mergeModuleVariables(manifest, requiredVars)
require.NoError(t, err)
require.Equal(t, "null", merged["optional_no_default"])
})
t.Run("RequiredWithoutDefaultOmitted", func(t *testing.T) {
t.Run("RequiredWithoutDefaultIsRequired", func(t *testing.T) {
t.Parallel()
merged, err := mergeModuleVariables(manifest, nil)
require.NoError(t, err)
require.NotContains(t, merged, "required_no_default")
_, err := mergeModuleVariables(manifest, nil)
require.Error(t, err)
require.Contains(t, err.Error(), `variable "required_no_default"`)
require.Contains(t, err.Error(), "is required")
})
t.Run("CallerOverridesDefault", func(t *testing.T) {
t.Parallel()
merged, err := mergeModuleVariables(manifest, map[string]string{
"port": "9999",
"port": "9999",
"required_no_default": "value",
})
require.NoError(t, err)
require.Equal(t, "9999", merged["port"])
@@ -166,6 +172,7 @@ func TestMergeModuleVariables(t *testing.T) {
"port": "null",
"enabled": "null",
"optional_no_default": "null",
"required_no_default": "null",
})
require.NoError(t, err)
require.Equal(t, "null", merged["port"])
@@ -173,9 +180,11 @@ func TestMergeModuleVariables(t *testing.T) {
require.Equal(t, "null", merged["optional_no_default"])
})
t.Run("EmptyCallerVarsNoError", func(t *testing.T) {
t.Run("EmptyCallerVarsUsesDefaults", func(t *testing.T) {
t.Parallel()
merged, err := mergeModuleVariables(manifest, map[string]string{})
merged, err := mergeModuleVariables(manifest, map[string]string{
"required_no_default": "value",
})
require.NoError(t, err)
require.Equal(t, "13337", merged["port"])
})