feat(coderd/templatebuilder): validation extraction, static file bundling, Windows OS (#26633)

Extract validation helpers to a dedicated file, add static file bundling
for base templates, and add Windows OS support.

**Commit 1: Extract validation to `validate.go`**
Move `validateVariableValue`, `validateStringValue`,
`validateNumberValue`, `validateBoolValue`, `toHCLLiteral`, `hclQuote`,
and `isSimpleJSONValue` from `compose.go` into `validate.go`.
Corresponding tests move to `validate_internal_test.go`. This keeps
`compose.go` focused on the compose pipeline.

**Commit 2: Static file bundling**
Add `StaticFiles` field to `ComposeResult` and a `collectStaticFiles`
helper that walks the base template FS to collect non-template files
(e.g. cloud-init `.tftpl` inputs). `BundleTar` now writes these files
into the output archive in sorted order for deterministic output. This
fixes `aws-linux`, whose cloud-init files were embedded but never
included in the tar.

**Commit 3: Windows OS support**
Add `BaseOSWindows` constant and register `"windows"` in `validBaseOS`
so that base templates with `os="windows"` can be loaded and used for
module compatibility filtering.

> [!NOTE]
> This PR was authored by Coder Agents on behalf of @jeremyruppel.
This commit is contained in:
Jeremy Ruppel
2026-06-30 18:08:02 -04:00
committed by GitHub
parent 2ea0d5f8ef
commit 6f0b81cfbc
7 changed files with 512 additions and 325 deletions
@@ -250,4 +250,25 @@ func TestParseBasesFromFS(t *testing.T) {
require.NoError(t, err)
require.Equal(t, "", bases["nospec"].Manifest.OS)
})
t.Run("AcceptsWindowsOS", func(t *testing.T) {
t.Parallel()
fsys := fstest.MapFS{
"bases/winbox/base.json": &fstest.MapFile{
Data: []byte(`{"id": "winbox", "os": "windows"}`),
},
"bases/winbox/main.tf.tmpl": &fstest.MapFile{
Data: []byte(`resource "coder_agent" "main" {}`),
},
"bases/winbox/README.md": &fstest.MapFile{
Data: []byte("# Windows\n"),
},
}
bases, err := parseBasesFromFS(fsys)
require.NoError(t, err)
require.Equal(t, "windows", bases["winbox"].Manifest.OS)
require.Equal(t, BaseOSWindows, validBaseOS[bases["winbox"].Manifest.OS])
})
}