fix(cli): proactively use active template version when require_active_version is set (#22033)

Fixes #22030

## Problem

When a template has `require_active_version = true` and a workspace is
outdated, the web UI always shows "Update and start" as the **only**
button (for all users including admins), but `coder start` starts with
the old version. For admins, this silently succeeds on the stale
version. For non-admins, it goes through a clunky 403→retry path. This
also affects the VS Code extension, which calls `coder start --yes`
under the hood.

## Root Cause

`buildWorkspaceStartRequest()` in `cli/start.go` checks
`workspace.AutomaticUpdates == "always"` but ignores
`workspace.TemplateRequireActiveVersion`. The server-side autostart
already ORs both settings together:

```go
// coderd/autobuild/lifecycle_executor.go
func useActiveVersion(opts, ws) bool {
    return opts.RequireActiveVersion || ws.AutomaticUpdates == "always"
}
```

The CLI was missing the `RequireActiveVersion` check.

## Fix

Add `workspace.TemplateRequireActiveVersion` to the existing OR
condition:

```go
// Before:
if workspace.AutomaticUpdates == codersdk.AutomaticUpdatesAlways || action == WorkspaceUpdate {

// After:
if workspace.AutomaticUpdates == codersdk.AutomaticUpdatesAlways || workspace.TemplateRequireActiveVersion || action == WorkspaceUpdate {
```

Now `coder start` and `coder restart` proactively use the active
template version when `require_active_version` is set, matching the web
UI and server autostart behavior. The 403→retry fallback remains as a
safety net but is no longer the primary path for any user.

## Testing

Updated `enterprise/cli/start_test.go` — all user types (owner, template
admin, ACL admin, group ACL admin, member) now expect the active version
when `require_active_version` is set, and verify the 403→retry message
does NOT appear.
This commit is contained in:
Garrett Delfosse
2026-02-24 19:51:48 -05:00
committed by GitHub
parent 119d436071
commit 6c16794173
2 changed files with 16 additions and 19 deletions
+1 -1
View File
@@ -120,7 +120,7 @@ func (r *RootCmd) start() *serpent.Command {
func buildWorkspaceStartRequest(inv *serpent.Invocation, client *codersdk.Client, workspace codersdk.Workspace, parameterFlags workspaceParameterFlags, buildFlags buildFlags, action WorkspaceCLIAction) (codersdk.CreateWorkspaceBuildRequest, error) {
version := workspace.LatestBuild.TemplateVersionID
if workspace.AutomaticUpdates == codersdk.AutomaticUpdatesAlways || action == WorkspaceUpdate {
if workspace.AutomaticUpdates == codersdk.AutomaticUpdatesAlways || workspace.TemplateRequireActiveVersion || action == WorkspaceUpdate {
version = workspace.TemplateActiveVersionID
if version != workspace.LatestBuild.TemplateVersionID {
action = WorkspaceUpdate
+15 -18
View File
@@ -86,30 +86,32 @@ func TestStart(t *testing.T) {
ExpectedVersion uuid.UUID
}
// All users should be updated to the active version when
// require_active_version is set, matching web UI behavior.
cases := []testcase{
{
Name: "OwnerUnchanged",
Name: "OwnerUpdates",
Client: ownerClient,
WorkspaceOwner: owner.UserID,
ExpectedVersion: oldVersion.ID,
ExpectedVersion: activeVersion.ID,
},
{
Name: "TemplateAdminUnchanged",
Name: "TemplateAdminUpdates",
Client: templateAdminClient,
WorkspaceOwner: templateAdmin.ID,
ExpectedVersion: oldVersion.ID,
ExpectedVersion: activeVersion.ID,
},
{
Name: "TemplateACLAdminUnchanged",
Name: "TemplateACLAdminUpdates",
Client: templateACLAdminClient,
WorkspaceOwner: templateACLAdmin.ID,
ExpectedVersion: oldVersion.ID,
ExpectedVersion: activeVersion.ID,
},
{
Name: "TemplateGroupACLAdminUnchanged",
Name: "TemplateGroupACLAdminUpdates",
Client: templateGroupACLAdminClient,
WorkspaceOwner: templateGroupACLAdmin.ID,
ExpectedVersion: oldVersion.ID,
ExpectedVersion: activeVersion.ID,
},
{
Name: "MemberUpdates",
@@ -156,16 +158,11 @@ func TestStart(t *testing.T) {
ws = coderdtest.MustWorkspace(t, c.Client, ws.ID)
require.Equal(t, c.ExpectedVersion, ws.LatestBuild.TemplateVersionID)
if initialTemplateVersion == ws.LatestBuild.TemplateVersionID {
return
}
if cmd == "start" {
require.Contains(t, buf.String(), "Unable to start the workspace with the template version from the last build")
}
if cmd == "restart" {
require.Contains(t, buf.String(), "Unable to restart the workspace with the template version from the last build")
// The CLI should proactively use the active version
// without hitting the 403→retry path.
if initialTemplateVersion != ws.LatestBuild.TemplateVersionID {
require.NotContains(t, buf.String(), "Unable to start the workspace with the template version from the last build")
require.NotContains(t, buf.String(), "Unable to restart the workspace with the template version from the last build")
}
})
}