fix(coderd): actually wire the chat template allowlist into tools (#23626)

Problem: previously, the deployment-wide chat template allowlist was never actually wired in from `chatd.go`

- Extracts `parseChatTemplateAllowlist` into shared `coderd/util/xjson.ParseUUIDList`
- Adds `Server.chatTemplateAllowlist()` method that reads the allowlist from DB
- Passes `AllowedTemplateIDs` callback to `ListTemplates`, `ReadTemplate`, and `CreateWorkspace` tool constructors

> 🤖 Created by Coder Agents and reviewed by a human.
This commit is contained in:
Cian Johnston
2026-03-25 22:15:27 +00:00
committed by GitHub
parent dab4e6f0a4
commit 7a9d57cd87
5 changed files with 262 additions and 23 deletions
+35
View File
@@ -0,0 +1,35 @@
package xjson
import (
"encoding/json"
"strings"
"github.com/google/uuid"
"golang.org/x/xerrors"
)
// ParseUUIDList parses a JSON-encoded array of UUID strings
// (e.g. `["uuid1","uuid2"]`) and returns the corresponding
// slice of uuid.UUID values. An empty input (including
// whitespace-only) returns an empty (non-nil) slice.
func ParseUUIDList(raw string) ([]uuid.UUID, error) {
raw = strings.TrimSpace(raw)
if raw == "" {
return []uuid.UUID{}, nil
}
var strs []string
if err := json.Unmarshal([]byte(raw), &strs); err != nil {
return nil, xerrors.Errorf("unmarshal uuid list: %w", err)
}
ids := make([]uuid.UUID, 0, len(strs))
for _, s := range strs {
id, err := uuid.Parse(s)
if err != nil {
return nil, xerrors.Errorf("parse uuid %q: %w", s, err)
}
ids = append(ids, id)
}
return ids, nil
}
+70
View File
@@ -0,0 +1,70 @@
package xjson_test
import (
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/coderd/util/xjson"
)
func TestParseUUIDList(t *testing.T) {
t.Parallel()
a := uuid.MustParse("c7c6686d-a93c-4df2-bef9-5f837e9a33d5")
b := uuid.MustParse("8f3b3e0b-2c3f-46a5-a365-fd5b62bd8818")
tests := []struct {
name string
input string
want []uuid.UUID
wantErr string
}{
{
name: "EmptyString",
input: "",
want: []uuid.UUID{},
},
{
name: "JSONNull",
input: "null",
want: []uuid.UUID{},
},
{
name: "WhitespaceOnly",
input: " \n\t ",
want: []uuid.UUID{},
},
{
name: "ValidUUIDs",
input: `["c7c6686d-a93c-4df2-bef9-5f837e9a33d5","8f3b3e0b-2c3f-46a5-a365-fd5b62bd8818"]`,
want: []uuid.UUID{a, b},
},
{
name: "InvalidJSON",
input: "not json at all",
wantErr: "unmarshal uuid list",
},
{
name: "InvalidUUID",
input: `["not-a-uuid"]`,
wantErr: "parse uuid",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := xjson.ParseUUIDList(tt.input)
if tt.wantErr != "" {
require.Error(t, err)
require.Contains(t, err.Error(), tt.wantErr)
return
}
require.NoError(t, err)
require.NotNil(t, got)
require.Equal(t, tt.want, got)
})
}
}