feat(cli): add --agents-allowed to template commands (#27517)

Relates to CODAGT-713

Depends on #27515

This adds `--agents-allowed` to `coder templates create` and `coder templates edit`. Template creation defaults the option to true, matching the per-template API and database default, while template editing only changes the value when the flag is explicitly supplied so unrelated edits preserve the existing setting.

The generated CLI help and reference documentation include the new option. #27518 updates the Coder Agents platform controls documentation to describe the completed per-template model.
This commit is contained in:
Ethan
2026-08-06 14:45:38 +10:00
committed by GitHub
parent 6c8a8647f6
commit 78b5a0f5a2
8 changed files with 165 additions and 0 deletions
+8
View File
@@ -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 create workspaces using this template.",
Default: "true",
Value: serpent.BoolOf(&agentsAllowed),
},
{
Flag: "private",
Description: "Disable the default behavior of granting template access to the 'everyone' group. " +
+51
View File
@@ -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)
+12
View File
@@ -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 create workspaces using this template.",
Default: "true",
Value: serpent.BoolOf(&agentsAllowed),
},
{
Flag: "allow-user-cancel-workspace-jobs",
Description: "Allow users to cancel in-progress workspace jobs.",
+70
View File
@@ -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})
+3
View File
@@ -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 create workspaces using 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
+3
View File
@@ -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 create workspaces using 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.