From e7a06acd5104857dc925a4ff163b72779ec0ab71 Mon Sep 17 00:00:00 2001 From: Ethan Dickson Date: Tue, 14 Jul 2026 05:35:28 +0000 Subject: [PATCH 1/2] feat(cli): add --agents-allowed to template commands --- cli/templatecreate.go | 8 +++ cli/templatecreate_test.go | 51 ++++++++++++++ cli/templateedit.go | 12 ++++ cli/templateedit_test.go | 70 +++++++++++++++++++ .../coder_templates_create_--help.golden | 3 + .../coder_templates_edit_--help.golden | 3 + docs/reference/cli/templates_create.md | 9 +++ docs/reference/cli/templates_edit.md | 9 +++ 8 files changed, 165 insertions(+) diff --git a/cli/templatecreate.go b/cli/templatecreate.go index d1bc545181f..3da9ef9767d 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -21,6 +21,7 @@ func (r *RootCmd) templateCreate() *serpent.Command { provisionerTags []string variablesFile string commandLineVariables []string + agentsAllowed bool disableEveryone bool requireActiveVersion bool @@ -159,6 +160,7 @@ func (r *RootCmd) templateCreate() *serpent.Command { TimeTilDormantAutoDeleteMillis: ptr.Ref(dormancyAutoDeletion.Milliseconds()), DisableEveryoneGroupAccess: disableEveryone, RequireActiveVersion: requireActiveVersion, + AgentsAllowed: &agentsAllowed, } template, err := client.CreateTemplate(inv.Context(), organization.ID, createReq) @@ -179,6 +181,12 @@ func (r *RootCmd) templateCreate() *serpent.Command { }, } cmd.Options = serpent.OptionSet{ + { + Flag: "agents-allowed", + Description: "Allow Coder Agents to use this template.", + Default: "true", + Value: serpent.BoolOf(&agentsAllowed), + }, { Flag: "private", Description: "Disable the default behavior of granting template access to the 'everyone' group. " + diff --git a/cli/templatecreate_test.go b/cli/templatecreate_test.go index cb744800430..36c9eff055f 100644 --- a/cli/templatecreate_test.go +++ b/cli/templatecreate_test.go @@ -12,6 +12,7 @@ import ( "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" + "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/provisioner/echo" "github.com/coder/coder/v2/provisionersdk/proto" "github.com/coder/coder/v2/testutil" @@ -58,6 +59,56 @@ func TestCliTemplateCreate(t *testing.T) { } } }) + t.Run("AgentsAllowed", func(t *testing.T) { + t.Parallel() + + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + owner := coderdtest.CreateFirstUser(t, client) + templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin()) + + for _, tt := range []struct { + name string + flag string + agentsAllowed bool + }{ + { + name: "DefaultTrue", + agentsAllowed: true, + }, + { + name: "False", + flag: "--agents-allowed=false", + agentsAllowed: false, + }, + } { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + templateName := coderdtest.RandomUsername(t) + source := clitest.CreateTemplateVersionSource(t, completeWithAgent()) + args := []string{ + "templates", + "create", + templateName, + "--yes", + "--directory", source, + "--test.provisioner", string(database.ProvisionerTypeEcho), + } + if tt.flag != "" { + args = append(args, tt.flag) + } + inv, root := clitest.New(t, args...) + clitest.SetupConfig(t, templateAdmin, root) + + require.NoError(t, inv.Run()) + + template, err := client.TemplateByName(t.Context(), owner.OrganizationID, templateName) + require.NoError(t, err) + require.Equal(t, tt.agentsAllowed, template.AgentsAllowed) + }) + } + }) + t.Run("CreateNoLockfile", func(t *testing.T) { t.Parallel() logger := testutil.Logger(t) diff --git a/cli/templateedit.go b/cli/templateedit.go index e25da3462c3..113ebd63034 100644 --- a/cli/templateedit.go +++ b/cli/templateedit.go @@ -33,6 +33,7 @@ func (r *RootCmd) templateEdit() *serpent.Command { allowUserCancelWorkspaceJobs bool allowUserAutostart bool allowUserAutostop bool + agentsAllowed bool requireActiveVersion bool deprecationMessage string disableEveryone bool @@ -142,6 +143,10 @@ func (r *RootCmd) templateEdit() *serpent.Command { dormancyAutoDeletion = time.Duration(template.TimeTilDormantAutoDeleteMillis) * time.Millisecond } + if !userSetOption(inv, "agents-allowed") { + agentsAllowed = template.AgentsAllowed + } + if !userSetOption(inv, "require-active-version") { requireActiveVersion = template.RequireActiveVersion } @@ -199,6 +204,7 @@ func (r *RootCmd) templateEdit() *serpent.Command { AllowUserCancelWorkspaceJobs: &allowUserCancelWorkspaceJobs, AllowUserAutostart: &allowUserAutostart, AllowUserAutostop: &allowUserAutostop, + AgentsAllowed: &agentsAllowed, RequireActiveVersion: &requireActiveVersion, DeprecationMessage: deprecated, DisableEveryoneGroupAccess: &disableEveryoneGroup, @@ -292,6 +298,12 @@ func (r *RootCmd) templateEdit() *serpent.Command { Default: "0h", Value: serpent.DurationOf(&dormancyAutoDeletion), }, + { + Flag: "agents-allowed", + Description: "Allow Coder Agents to use this template.", + Default: "true", + Value: serpent.BoolOf(&agentsAllowed), + }, { Flag: "allow-user-cancel-workspace-jobs", Description: "Allow users to cancel in-progress workspace jobs.", diff --git a/cli/templateedit_test.go b/cli/templateedit_test.go index d6c8af82b0f..3acc6513daf 100644 --- a/cli/templateedit_test.go +++ b/cli/templateedit_test.go @@ -115,6 +115,76 @@ func TestTemplateEdit(t *testing.T) { assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis) assert.Equal(t, template.AllowUserCancelWorkspaceJobs, updated.AllowUserCancelWorkspaceJobs) }) + t.Run("AgentsAllowed", func(t *testing.T) { + t.Parallel() + + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + owner := coderdtest.CreateFirstUser(t, client) + templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin()) + + for _, tt := range []struct { + name string + initialAgentsAllowed bool + flag string + description string + wantAgentsAllowed bool + }{ + { + name: "ExplicitTrue", + initialAgentsAllowed: false, + flag: "--agents-allowed=true", + wantAgentsAllowed: true, + }, + { + name: "ExplicitFalse", + initialAgentsAllowed: true, + flag: "--agents-allowed=false", + wantAgentsAllowed: false, + }, + { + name: "OmittedPreservesTrue", + initialAgentsAllowed: true, + description: "updated description", + wantAgentsAllowed: true, + }, + { + name: "OmittedPreservesFalse", + initialAgentsAllowed: false, + description: "updated description", + wantAgentsAllowed: false, + }, + } { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) + _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(req *codersdk.CreateTemplateRequest) { + req.AgentsAllowed = &tt.initialAgentsAllowed + }) + + cmdArgs := []string{"templates", "edit", template.Name} + if tt.flag != "" { + cmdArgs = append(cmdArgs, tt.flag) + } + if tt.description != "" { + cmdArgs = append(cmdArgs, "--description", tt.description) + } + inv, root := clitest.New(t, cmdArgs...) + clitest.SetupConfig(t, templateAdmin, root) + + require.NoError(t, inv.Run()) + + updated, err := client.Template(t.Context(), template.ID) + require.NoError(t, err) + require.Equal(t, tt.wantAgentsAllowed, updated.AgentsAllowed) + if tt.description != "" { + require.Equal(t, tt.description, updated.Description) + } + }) + } + }) + t.Run("InvalidDisplayName", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) diff --git a/cli/testdata/coder_templates_create_--help.golden b/cli/testdata/coder_templates_create_--help.golden index c0370d93d21..2b6e2fab53d 100644 --- a/cli/testdata/coder_templates_create_--help.golden +++ b/cli/testdata/coder_templates_create_--help.golden @@ -10,6 +10,9 @@ OPTIONS: -O, --org string, $CODER_ORGANIZATION Select which organization (uuid or name) to use. + --agents-allowed bool (default: true) + Allow Coder Agents to use this template. + --default-ttl duration (default: 24h) Specify a default TTL for workspaces created from this template. It is the default time before shutdown - workspaces created from this diff --git a/cli/testdata/coder_templates_edit_--help.golden b/cli/testdata/coder_templates_edit_--help.golden index 73760dadfcb..e9c3f33e41f 100644 --- a/cli/testdata/coder_templates_edit_--help.golden +++ b/cli/testdata/coder_templates_edit_--help.golden @@ -14,6 +14,9 @@ OPTIONS: template will have their shutdown time bumped by this value when activity is detected. Maps to "Activity bump" in the UI. + --agents-allowed bool (default: true) + Allow Coder Agents to use this template. + --allow-user-autostart bool (default: true) Allow users to configure autostart for workspaces on this template. This can only be disabled in enterprise. diff --git a/docs/reference/cli/templates_create.md b/docs/reference/cli/templates_create.md index 3f46f3e759f..51ce1ba338b 100644 --- a/docs/reference/cli/templates_create.md +++ b/docs/reference/cli/templates_create.md @@ -11,6 +11,15 @@ coder templates create [flags] [name] ## Options +### --agents-allowed + +| | | +|---------|-------------------| +| Type | bool | +| Default | true | + +Allow Coder Agents to use this template. + ### --private | | | diff --git a/docs/reference/cli/templates_edit.md b/docs/reference/cli/templates_edit.md index 5e9fe477050..fdb5c622c30 100644 --- a/docs/reference/cli/templates_edit.md +++ b/docs/reference/cli/templates_edit.md @@ -126,6 +126,15 @@ Specify a duration workspaces may be inactive prior to being moved to the dorman Specify a duration workspaces may be in the dormant state prior to being deleted. This licensed feature's default is 0h (off). Maps to "Dormancy Auto-Deletion" in the UI. +### --agents-allowed + +| | | +|---------|-------------------| +| Type | bool | +| Default | true | + +Allow Coder Agents to use this template. + ### --allow-user-cancel-workspace-jobs | | | From e45e100b887b5be0d93e1e8b0092fc66b3d1344a Mon Sep 17 00:00:00 2001 From: Ethan Dickson Date: Wed, 5 Aug 2026 08:11:46 +0000 Subject: [PATCH 2/2] review --- cli/templatecreate.go | 2 +- cli/templateedit.go | 2 +- cli/testdata/coder_templates_create_--help.golden | 2 +- cli/testdata/coder_templates_edit_--help.golden | 2 +- docs/reference/cli/templates_create.md | 2 +- docs/reference/cli/templates_edit.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cli/templatecreate.go b/cli/templatecreate.go index 3da9ef9767d..62ba06dde16 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -183,7 +183,7 @@ func (r *RootCmd) templateCreate() *serpent.Command { cmd.Options = serpent.OptionSet{ { Flag: "agents-allowed", - Description: "Allow Coder Agents to use this template.", + Description: "Allow Coder Agents to create workspaces using this template.", Default: "true", Value: serpent.BoolOf(&agentsAllowed), }, diff --git a/cli/templateedit.go b/cli/templateedit.go index 113ebd63034..751bb633040 100644 --- a/cli/templateedit.go +++ b/cli/templateedit.go @@ -300,7 +300,7 @@ func (r *RootCmd) templateEdit() *serpent.Command { }, { Flag: "agents-allowed", - Description: "Allow Coder Agents to use this template.", + Description: "Allow Coder Agents to create workspaces using this template.", Default: "true", Value: serpent.BoolOf(&agentsAllowed), }, diff --git a/cli/testdata/coder_templates_create_--help.golden b/cli/testdata/coder_templates_create_--help.golden index 2b6e2fab53d..7ef71d7d1cf 100644 --- a/cli/testdata/coder_templates_create_--help.golden +++ b/cli/testdata/coder_templates_create_--help.golden @@ -11,7 +11,7 @@ OPTIONS: Select which organization (uuid or name) to use. --agents-allowed bool (default: true) - Allow Coder Agents to use this template. + Allow Coder Agents to create workspaces using this template. --default-ttl duration (default: 24h) Specify a default TTL for workspaces created from this template. It is diff --git a/cli/testdata/coder_templates_edit_--help.golden b/cli/testdata/coder_templates_edit_--help.golden index e9c3f33e41f..972437a8e8c 100644 --- a/cli/testdata/coder_templates_edit_--help.golden +++ b/cli/testdata/coder_templates_edit_--help.golden @@ -15,7 +15,7 @@ OPTIONS: activity is detected. Maps to "Activity bump" in the UI. --agents-allowed bool (default: true) - Allow Coder Agents to use this template. + Allow Coder Agents to create workspaces using this template. --allow-user-autostart bool (default: true) Allow users to configure autostart for workspaces on this template. diff --git a/docs/reference/cli/templates_create.md b/docs/reference/cli/templates_create.md index 51ce1ba338b..a3bba84d924 100644 --- a/docs/reference/cli/templates_create.md +++ b/docs/reference/cli/templates_create.md @@ -18,7 +18,7 @@ coder templates create [flags] [name] | Type | bool | | Default | true | -Allow Coder Agents to use this template. +Allow Coder Agents to create workspaces using this template. ### --private diff --git a/docs/reference/cli/templates_edit.md b/docs/reference/cli/templates_edit.md index fdb5c622c30..2e472d1600e 100644 --- a/docs/reference/cli/templates_edit.md +++ b/docs/reference/cli/templates_edit.md @@ -133,7 +133,7 @@ Specify a duration workspaces may be in the dormant state prior to being deleted | Type | bool | | Default | true | -Allow Coder Agents to use this template. +Allow Coder Agents to create workspaces using this template. ### --allow-user-cancel-workspace-jobs