Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
11 changes: 11 additions & 0 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions coderd/searchquery/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ func Templates(ctx context.Context, db database.Store, actorID uuid.UUID, query
IDs: parser.UUIDs(values, []uuid.UUID{}, "ids"),
Deprecated: parser.NullableBoolean(values, sql.NullBool{}, "deprecated"),
HasAITask: parser.NullableBoolean(values, sql.NullBool{}, "has-ai-task"),
AgentsAllowed: parser.NullableBoolean(values, sql.NullBool{}, "agents-allowed"),
AuthorID: parser.UUID(values, uuid.Nil, "author_id"),
AuthorUsername: parser.String(values, "", "author"),
HasExternalAgent: parser.NullableBoolean(values, sql.NullBool{}, "has_external_agent"),
Expand Down
14 changes: 14 additions & 0 deletions coderd/searchquery/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,20 @@ func TestSearchTemplates(t *testing.T) {
},
},
},
{
Name: "AgentsAllowedTrue",
Query: "agents-allowed:true",
Expected: database.GetTemplatesWithFilterParams{
AgentsAllowed: sql.NullBool{Bool: true, Valid: true},
},
},
{
Name: "AgentsAllowedFalse",
Query: "agents-allowed:false",
Expected: database.GetTemplatesWithFilterParams{
AgentsAllowed: sql.NullBool{Bool: false, Valid: true},
},
},
{
Name: "MyTemplates",
Query: "author:me",
Expand Down
2 changes: 2 additions & 0 deletions coderd/telemetry/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,7 @@ func ConvertTemplate(dbTemplate database.Template) Template {
AutostopRequirementWeeks: dbTemplate.AutostopRequirementWeeks,
AutostartAllowedDays: codersdk.BitmapToWeekdays(dbTemplate.AutostartAllowedDays()),
RequireActiveVersion: dbTemplate.RequireActiveVersion,
AgentsAllowed: dbTemplate.AgentsAllowed,
Deprecated: dbTemplate.Deprecated != "",
UseClassicParameterFlow: ptr.Ref(dbTemplate.UseClassicParameterFlow),
}
Expand Down Expand Up @@ -1855,6 +1856,7 @@ type Template struct {
AutostopRequirementWeeks int64 `json:"autostop_requirement_weeks"`
AutostartAllowedDays []string `json:"autostart_allowed_days"`
RequireActiveVersion bool `json:"require_active_version"`
AgentsAllowed bool `json:"agents_allowed"`
Deprecated bool `json:"deprecated"`
UseClassicParameterFlow *bool `json:"use_classic_parameter_flow"`
}
Expand Down
18 changes: 18 additions & 0 deletions coderd/telemetry/telemetry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,24 @@ func TestMain(m *testing.M) {
goleak.VerifyTestMain(m, testutil.GoleakOptions...)
}

func TestConvertTemplateAgentsAllowed(t *testing.T) {
t.Parallel()

for _, tt := range []struct {
name string
allowed bool
}{
{name: "Allowed", allowed: true},
{name: "Disallowed", allowed: false},
} {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := telemetry.ConvertTemplate(database.Template{AgentsAllowed: tt.allowed})
require.Equal(t, tt.allowed, got.AgentsAllowed)
})
}
}

func TestTelemetry(t *testing.T) {
t.Parallel()
t.Run("Snapshot", func(t *testing.T) {
Expand Down
8 changes: 5 additions & 3 deletions coderd/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque

// Default is false as dynamic parameters are now the preferred approach.
useClassicParameterFlow := ptr.NilToDefault(createTemplate.UseClassicParameterFlow, false)
agentsAllowed := ptr.NilToDefault(createTemplate.AgentsAllowed, true)

// Make a temporary struct to represent the template. This is used for
// auditing if any of the following checks fail. It will be overwritten when
Expand All @@ -224,7 +225,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
Icon: createTemplate.Icon,
DisplayName: createTemplate.DisplayName,
UseClassicParameterFlow: useClassicParameterFlow,
AgentsAllowed: true,
AgentsAllowed: agentsAllowed,
}

_, err := api.Database.GetTemplateByOrganizationAndName(ctx, database.GetTemplateByOrganizationAndNameParams{
Expand Down Expand Up @@ -448,7 +449,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
MaxPortSharingLevel: maxPortShareLevel,
UseClassicParameterFlow: useClassicParameterFlow,
CorsBehavior: corsBehavior,
AgentsAllowed: true,
AgentsAllowed: agentsAllowed,
})
if err != nil {
return xerrors.Errorf("insert template: %s", err)
Expand Down Expand Up @@ -780,7 +781,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
UseClassicParameterFlow: resolved.useClassicTemplateFlow,
CorsBehavior: resolved.corsBehavior,
DisableModuleCache: resolved.disableModuleCache,
AgentsAllowed: template.AgentsAllowed,
AgentsAllowed: resolved.agentsAllowed,
})
if err != nil {
return xerrors.Errorf("update template metadata: %w", err)
Expand Down Expand Up @@ -1057,6 +1058,7 @@ func (api *API) convertTemplate(
UseClassicParameterFlow: template.UseClassicParameterFlow,
CORSBehavior: codersdk.CORSBehavior(template.CorsBehavior),
DisableModuleCache: template.DisableModuleCache,
AgentsAllowed: template.AgentsAllowed,
}
}

Expand Down
2 changes: 2 additions & 0 deletions coderd/templates_meta_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type templateMetaUpdate struct {
allowUserAutostart bool
allowUserAutostop bool
allowUserCancelWorkspaceJobs bool
agentsAllowed bool
requireActiveVersion bool
deprecationMessage string
useClassicTemplateFlow bool
Expand Down Expand Up @@ -81,6 +82,7 @@ func resolveTemplateMetaUpdate(
allowUserAutostart: ptr.NilToDefault(req.AllowUserAutostart, template.AllowUserAutostart),
allowUserAutostop: ptr.NilToDefault(req.AllowUserAutostop, template.AllowUserAutostop),
allowUserCancelWorkspaceJobs: ptr.NilToDefault(req.AllowUserCancelWorkspaceJobs, template.AllowUserCancelWorkspaceJobs),
agentsAllowed: ptr.NilToDefault(req.AgentsAllowed, template.AgentsAllowed),
Comment thread
ethanndickson marked this conversation as resolved.
requireActiveVersion: ptr.NilToDefault(req.RequireActiveVersion, template.RequireActiveVersion),
deprecationMessage: ptr.NilToDefault(req.DeprecationMessage, template.Deprecated),
useClassicTemplateFlow: ptr.NilToDefault(req.UseClassicParameterFlow, template.UseClassicParameterFlow),
Expand Down
9 changes: 9 additions & 0 deletions coderd/templates_meta_update_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func baselineTemplate() database.Template {
AllowUserAutostart: false,
AllowUserAutostop: false,
AllowUserCancelWorkspaceJobs: false,
AgentsAllowed: true,
RequireActiveVersion: true,
DefaultTTL: int64(60 * 60 * 1000 * 1000 * 1000), // 1 hour in ns
ActivityBump: int64(30 * 60 * 1000 * 1000 * 1000), // 30 minutes in ns
Expand Down Expand Up @@ -81,6 +82,7 @@ func baselineResolved() templateMetaUpdate {
allowUserAutostart: tpl.AllowUserAutostart,
allowUserAutostop: tpl.AllowUserAutostop,
allowUserCancelWorkspaceJobs: tpl.AllowUserCancelWorkspaceJobs,
agentsAllowed: tpl.AgentsAllowed,
requireActiveVersion: tpl.RequireActiveVersion,
deprecationMessage: tpl.Deprecated,
useClassicTemplateFlow: tpl.UseClassicParameterFlow,
Expand Down Expand Up @@ -225,6 +227,13 @@ func TestResolveTemplateMetaUpdate(t *testing.T) {
r.allowUserCancelWorkspaceJobs = true
}},
},
{
name: "AgentsAllowed",
req: codersdk.UpdateTemplateMeta{AgentsAllowed: ptr.Ref(false)},
expected: expected{override: func(r *templateMetaUpdate) {
r.agentsAllowed = false
}},
},
{
name: "FailureTTLMillis",
req: codersdk.UpdateTemplateMeta{FailureTTLMillis: ptr.Ref(int64(3_600_000))},
Expand Down
11 changes: 11 additions & 0 deletions coderd/templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ func TestPostTemplateByOrganization(t *testing.T) {
assert.Equal(t, expected.ActivityBumpMillis, got.ActivityBumpMillis)
assert.Equal(t, expected.TimeTilAutostopNotifyMillis, got.TimeTilAutostopNotifyMillis)
assert.Equal(t, expected.UseClassicParameterFlow, false) // Current default is false
assert.True(t, expected.AgentsAllowed)
assert.True(t, got.AgentsAllowed)

require.Len(t, auditor.AuditLogs(), 3)
assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs()[0].Action)
Expand Down Expand Up @@ -1007,6 +1009,7 @@ func TestPatchTemplateMeta(t *testing.T) {
ActivityBumpMillis: ptr.Ref(3 * time.Hour.Milliseconds()),
TimeTilAutostopNotifyMillis: ptr.Ref(5 * time.Minute.Milliseconds()),
AllowUserCancelWorkspaceJobs: ptr.Ref(false),
AgentsAllowed: ptr.Ref(false),
}
// It is unfortunate we need to sleep, but the test can fail if the
// updatedAt is too close together.
Expand All @@ -1025,6 +1028,7 @@ func TestPatchTemplateMeta(t *testing.T) {
assert.Equal(t, *req.ActivityBumpMillis, updated.ActivityBumpMillis)
assert.Equal(t, *req.TimeTilAutostopNotifyMillis, updated.TimeTilAutostopNotifyMillis)
assert.False(t, *req.AllowUserCancelWorkspaceJobs)
assert.False(t, updated.AgentsAllowed)

// Extra paranoid: did it _really_ happen?
updated, err = client.Template(ctx, template.ID)
Expand All @@ -1038,6 +1042,7 @@ func TestPatchTemplateMeta(t *testing.T) {
assert.Equal(t, *req.ActivityBumpMillis, updated.ActivityBumpMillis)
assert.Equal(t, *req.TimeTilAutostopNotifyMillis, updated.TimeTilAutostopNotifyMillis)
assert.False(t, *req.AllowUserCancelWorkspaceJobs)
assert.False(t, updated.AgentsAllowed)

require.Len(t, auditor.AuditLogs(), 5)
assert.Equal(t, database.AuditActionWrite, auditor.AuditLogs()[4].Action)
Expand Down Expand Up @@ -1960,6 +1965,7 @@ func TestPatchTemplateMeta(t *testing.T) {
ctr.Icon = "/icon/original.png"
ctr.DefaultTTLMillis = ptr.Ref((24 * time.Hour).Milliseconds())
ctr.AllowUserCancelWorkspaceJobs = ptr.Ref(true)
ctr.AgentsAllowed = ptr.Ref(false)
})

ctx := testutil.Context(t, testutil.WaitLong)
Expand All @@ -1975,6 +1981,7 @@ func TestPatchTemplateMeta(t *testing.T) {
assert.Equal(t, template.Icon, updated.Icon)
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
assert.Equal(t, template.AllowUserCancelWorkspaceJobs, updated.AllowUserCancelWorkspaceJobs)
assert.Equal(t, template.AgentsAllowed, updated.AgentsAllowed)
assert.Equal(t, template.RequireActiveVersion, updated.RequireActiveVersion)
})

Expand All @@ -1991,9 +1998,11 @@ func TestPatchTemplateMeta(t *testing.T) {
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
ctr.AllowUserCancelWorkspaceJobs = ptr.Ref(true)
ctr.AgentsAllowed = ptr.Ref(false)
ctr.DefaultTTLMillis = ptr.Ref((24 * time.Hour).Milliseconds())
})
require.True(t, template.AllowUserCancelWorkspaceJobs)
require.False(t, template.AgentsAllowed)
require.Equal(t, (24 * time.Hour).Milliseconds(), template.DefaultTTLMillis)

ctx := testutil.Context(t, testutil.WaitLong)
Expand All @@ -2006,6 +2015,7 @@ func TestPatchTemplateMeta(t *testing.T) {
})
require.NoError(t, err)
assert.Equal(t, newTTL, updated.DefaultTTLMillis)
assert.False(t, updated.AgentsAllowed, "omitted agents field must not be overwritten")
assert.True(t, updated.AllowUserCancelWorkspaceJobs, "omitted bool field must not be overwritten")

// Conversely, sending only AllowUserCancelWorkspaceJobs must not zero
Expand All @@ -2015,6 +2025,7 @@ func TestPatchTemplateMeta(t *testing.T) {
})
require.NoError(t, err)
assert.False(t, updated.AllowUserCancelWorkspaceJobs)
assert.False(t, updated.AgentsAllowed, "unrelated patch must preserve agents field")
assert.Equal(t, newTTL, updated.DefaultTTLMillis, "omitted int64 field must not be overwritten")
})
}
Expand Down
42 changes: 4 additions & 38 deletions coderd/x/chatd/chatd.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import (
coderdpubsub "github.com/coder/coder/v2/coderd/pubsub"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/coderd/util/xjson"
"github.com/coder/coder/v2/coderd/webpush"
"github.com/coder/coder/v2/coderd/workspacestats"
"github.com/coder/coder/v2/coderd/x/agenthooks/dispatch"
Expand Down Expand Up @@ -208,36 +207,6 @@ type Server struct {
chatHeartbeatInterval time.Duration
}

// chatTemplateAllowlist returns the deployment-wide template
// allowlist as a set of permitted template IDs. The callback
// signature matches what the chat tools expect. When the
// allowlist is empty or cannot be loaded the function returns
// nil, which the tools interpret as "all templates allowed".
func (p *Server) chatTemplateAllowlist() map[uuid.UUID]bool {
//nolint:gocritic // AsChatd provides narrowly-scoped daemon
// access for reading deployment config.
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
//nolint:gocritic // AsChatd provides narrowly-scoped read
// access to deployment config (the template allowlist).
ctx = dbauthz.AsChatd(ctx)
raw, err := p.db.GetChatTemplateAllowlist(ctx)
if err != nil {
p.logger.Warn(ctx, "failed to load chat template allowlist", slog.Error(err))
return nil
}
ids, err := xjson.ParseUUIDList(raw)
if err != nil {
p.logger.Warn(ctx, "failed to parse chat template allowlist", slog.Error(err))
return nil
}
m := make(map[uuid.UUID]bool, len(ids))
for _, id := range ids {
m[id] = true
}
return m
}

func (p *Server) loadAdvisorConfig(ctx context.Context, logger slog.Logger) codersdk.AdvisorConfig {
cfg, err := p.configCache.AdvisorConfig(ctx)
if err != nil {
Expand Down Expand Up @@ -3867,14 +3836,12 @@ func (p *Server) appendRootChatTools(

tools = append(tools,
chattool.ListTemplates(p.db, opts.chat.OrganizationID, chattool.ListTemplatesOptions{
OwnerID: opts.chat.OwnerID,
Logger: p.logger,
Clock: p.clock,
AllowedTemplateIDs: p.chatTemplateAllowlist,
OwnerID: opts.chat.OwnerID,
Logger: p.logger,
Clock: p.clock,
}),
chattool.ReadTemplate(p.db, opts.chat.OrganizationID, chattool.ReadTemplateOptions{
OwnerID: opts.chat.OwnerID,
AllowedTemplateIDs: p.chatTemplateAllowlist,
OwnerID: opts.chat.OwnerID,
}),
chattool.CreateWorkspace(p.db, opts.chat.OrganizationID, opts.chat.ID, chattool.CreateWorkspaceOptions{
OwnerID: opts.chat.OwnerID,
Expand All @@ -3884,7 +3851,6 @@ func (p *Server) appendRootChatTools(
WorkspaceMu: opts.workspaceMu,
OnChatUpdated: onChatUpdated,
Logger: p.logger,
AllowedTemplateIDs: p.chatTemplateAllowlist,
}),
chattool.StartWorkspace(p.db, opts.chat.ID, chattool.StartWorkspaceOptions{
OwnerID: opts.chat.OwnerID,
Expand Down
Loading
Loading