From 9edca92c74382dfc7450e978c8c7d9f19098c867 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Thu, 7 Aug 2025 16:19:00 +1000 Subject: [PATCH 1/5] fix: fix incorrect migration in constraint (#19212) --- .../000356_enforce_deadline_below_max_deadline.up.sql | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/coderd/database/migrations/000356_enforce_deadline_below_max_deadline.up.sql b/coderd/database/migrations/000356_enforce_deadline_below_max_deadline.up.sql index bcb3ab643521f..00c36ddd0b5dd 100644 --- a/coderd/database/migrations/000356_enforce_deadline_below_max_deadline.up.sql +++ b/coderd/database/migrations/000356_enforce_deadline_below_max_deadline.up.sql @@ -8,13 +8,15 @@ UPDATE SET deadline = max_deadline WHERE - deadline > max_deadline - AND max_deadline != '0001-01-01 00:00:00+00'; + (deadline = '0001-01-01 00:00:00+00'::timestamptz OR deadline > max_deadline) + AND max_deadline != '0001-01-01 00:00:00+00'::timestamptz; -- Add the new constraint. ALTER TABLE workspace_builds ADD CONSTRAINT workspace_builds_deadline_below_max_deadline CHECK ( + -- (deadline is not zero AND deadline <= max_deadline)... (deadline != '0001-01-01 00:00:00+00'::timestamptz AND deadline <= max_deadline) + -- UNLESS max_deadline is zero. OR max_deadline = '0001-01-01 00:00:00+00'::timestamptz ); From 99d75cc000a1689cd7ce88b3f36feaff6c15f24a Mon Sep 17 00:00:00 2001 From: Ethan <39577870+ethanndickson@users.noreply.github.com> Date: Thu, 7 Aug 2025 16:31:27 +1000 Subject: [PATCH 2/5] fix: use system context for querying workspaces when deleting users (#19211) Closes #19209. In `templates.go`, we do this to make sure we count ALL workspaces for a template before we try and delete that template: https://github.com/coder/coder/blob/dc598856e3be0926573dbbe2ec680e95a139093a/coderd/templates.go#L81-L99 However, we weren't doing the same when attempting to delete users, leading to the linked issue. We can solve the issue the same way as we do for templates. --- coderd/users.go | 5 ++++- coderd/users_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/coderd/users.go b/coderd/users.go index 7fbb8e7d04cdf..851c52d71188e 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -542,7 +542,10 @@ func (api *API) deleteUser(rw http.ResponseWriter, r *http.Request) { return } - workspaces, err := api.Database.GetWorkspaces(ctx, database.GetWorkspacesParams{ + // This query is ONLY done to get the workspace count, so we use a system + // context to return ALL workspaces. Not just workspaces the user can view. + // nolint:gocritic + workspaces, err := api.Database.GetWorkspaces(dbauthz.AsSystemRestricted(ctx), database.GetWorkspacesParams{ OwnerID: user.ID, }) if err != nil { diff --git a/coderd/users_test.go b/coderd/users_test.go index 9d695f37c9906..5928fc6486f51 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -377,6 +377,43 @@ func TestDeleteUser(t *testing.T) { require.ErrorAs(t, err, &apiErr, "should be a coderd error") require.Equal(t, http.StatusForbidden, apiErr.StatusCode(), "should be forbidden") }) + t.Run("CountCheckIncludesAllWorkspaces", func(t *testing.T) { + t.Parallel() + client, _ := coderdtest.NewWithProvisionerCloser(t, nil) + firstUser := coderdtest.CreateFirstUser(t, client) + + // Create a target user who will own a workspace + targetUserClient, targetUser := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID) + + // Create a User Admin who should not have permission to see the target user's workspace + userAdminClient, userAdmin := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID) + + // Grant User Admin role to the userAdmin + userAdmin, err := client.UpdateUserRoles(context.Background(), userAdmin.ID.String(), codersdk.UpdateRoles{ + Roles: []string{rbac.RoleUserAdmin().String()}, + }) + require.NoError(t, err) + + // Create a template and workspace owned by the target user + version := coderdtest.CreateTemplateVersion(t, client, firstUser.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, firstUser.OrganizationID, version.ID) + _ = coderdtest.CreateWorkspace(t, targetUserClient, template.ID) + + workspaces, err := userAdminClient.Workspaces(context.Background(), codersdk.WorkspaceFilter{ + Owner: targetUser.Username, + }) + require.NoError(t, err) + require.Len(t, workspaces.Workspaces, 0) + + // Attempt to delete the target user - this should fail because the + // user has a workspace not visible to the deleting user. + err = userAdminClient.DeleteUser(context.Background(), targetUser.ID) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusExpectationFailed, apiErr.StatusCode()) + require.Contains(t, apiErr.Message, "has workspaces") + }) } func TestNotifyUserStatusChanged(t *testing.T) { From 82d5a2076229614e599d3d71f2134a5d0c9bb311 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Thu, 7 Aug 2025 17:16:01 +1000 Subject: [PATCH 3/5] fix: fix flake in workspace TTL test caused by new constraint (#19213) --- coderd/workspaces_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 6d2a6e544ddd7..96381043db0ab 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -2922,10 +2922,11 @@ func TestWorkspaceUpdateTTL(t *testing.T) { dbJob, err := db.GetProvisionerJobByID(dbauthz.AsSystemRestricted(ctx), dbBuild.JobID) //nolint:gocritic // test require.NoError(t, err) require.True(t, dbJob.CompletedAt.Valid) + initialDeadline := dbJob.CompletedAt.Time.Add(deadline) expectedMaxDeadline := dbJob.CompletedAt.Time.Add(maxDeadline) err = db.UpdateWorkspaceBuildDeadlineByID(dbauthz.AsSystemRestricted(ctx), database.UpdateWorkspaceBuildDeadlineByIDParams{ //nolint:gocritic // test ID: build.ID, - Deadline: dbBuild.Deadline, + Deadline: initialDeadline, MaxDeadline: expectedMaxDeadline, UpdatedAt: dbtime.Now(), }) From 91780db1fe55c70e24335b603cb390bf05e019a1 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Thu, 7 Aug 2025 13:49:51 +0400 Subject: [PATCH 4/5] fix: upgrade to 1.24.6 to fix race in lib/pq queries (#19214) fixes: https://github.com/coder/internal/issues/731 THIS IS A SECURITY FIX upgrade to go 1.24.6 to avoid https://github.com/golang/go/issues/74831 (CVE-2025-47907) Also points to a new version of our lib/pq fork that worked around the Go issue, which should restore better performance. --- .github/actions/setup-go/action.yaml | 2 +- dogfood/coder/Dockerfile | 4 ++-- go.mod | 4 ++-- go.sum | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/actions/setup-go/action.yaml b/.github/actions/setup-go/action.yaml index a8a88621dda18..097a1b6cfd119 100644 --- a/.github/actions/setup-go/action.yaml +++ b/.github/actions/setup-go/action.yaml @@ -4,7 +4,7 @@ description: | inputs: version: description: "The Go version to use." - default: "1.24.4" + default: "1.24.6" use-preinstalled-go: description: "Whether to use preinstalled Go." default: "false" diff --git a/dogfood/coder/Dockerfile b/dogfood/coder/Dockerfile index 20fa93fef04d4..a16d414dfb26e 100644 --- a/dogfood/coder/Dockerfile +++ b/dogfood/coder/Dockerfile @@ -11,8 +11,8 @@ RUN cargo install jj-cli typos-cli watchexec-cli FROM ubuntu:jammy@sha256:0e5e4a57c2499249aafc3b40fcd541e9a456aab7296681a3994d631587203f97 AS go # Install Go manually, so that we can control the version -ARG GO_VERSION=1.24.4 -ARG GO_CHECKSUM="77e5da33bb72aeaef1ba4418b6fe511bc4d041873cbf82e5aa6318740df98717" +ARG GO_VERSION=1.24.6 +ARG GO_CHECKSUM="bbca37cc395c974ffa4893ee35819ad23ebb27426df87af92e93a9ec66ef8712" # Boring Go is needed to build FIPS-compliant binaries. RUN apt-get update && \ diff --git a/go.mod b/go.mod index be89bfcbb8747..19fbcff8f9a1c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/coder/coder/v2 -go 1.24.4 +go 1.24.6 // Required until a v3 of chroma is created to lazily initialize all XML files. // None of our dependencies seem to use the registries anyways, so this @@ -58,7 +58,7 @@ replace github.com/imulab/go-scim/pkg/v2 => github.com/coder/go-scim/pkg/v2 v2.0 // Adds support for a new Listener from a driver.Connector // This lets us use rotating authentication tokens for passwords in connection strings // which we use in the awsiamrds package. -replace github.com/lib/pq => github.com/coder/pq v1.10.5-0.20250630052411-a259f96b6102 +replace github.com/lib/pq => github.com/coder/pq v1.10.5-0.20250807075151-6ad9b0a25151 // Removes an init() function that causes terminal sequences to be printed to the web terminal when // used in conjunction with agent-exec. See https://github.com/coder/coder/pull/15817 diff --git a/go.sum b/go.sum index a4124c70ab7e9..d86aeff72cac0 100644 --- a/go.sum +++ b/go.sum @@ -916,8 +916,8 @@ github.com/coder/go-scim/pkg/v2 v2.0.0-20230221055123-1d63c1222136 h1:0RgB61LcNs github.com/coder/go-scim/pkg/v2 v2.0.0-20230221055123-1d63c1222136/go.mod h1:VkD1P761nykiq75dz+4iFqIQIZka189tx1BQLOp0Skc= github.com/coder/guts v1.5.0 h1:a94apf7xMf5jDdg1bIHzncbRiTn3+BvBZgrFSDbUnyI= github.com/coder/guts v1.5.0/go.mod h1:0Sbv5Kp83u1Nl7MIQiV2zmacJ3o02I341bkWkjWXSUQ= -github.com/coder/pq v1.10.5-0.20250630052411-a259f96b6102 h1:ahTJlTRmTogsubgRVGOUj40dg62WvqPQkzTQP7pyepI= -github.com/coder/pq v1.10.5-0.20250630052411-a259f96b6102/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/coder/pq v1.10.5-0.20250807075151-6ad9b0a25151 h1:YAxwg3lraGNRwoQ18H7R7n+wsCqNve7Brdvj0F1rDnU= +github.com/coder/pq v1.10.5-0.20250807075151-6ad9b0a25151/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx9n47SZOKOpgSE1bbJzlE4qPVs= github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0/go.mod h1:5UuS2Ts+nTToAMeOjNlnHFkPahrtDkmpydBen/3wgZc= github.com/coder/preview v1.0.3 h1:et0/frnLB68PPwsGaa1KAZQdBKBxNSqzMplYKsBpcNA= From 2851d9f3ea2750dca56f825a3e98095bfa0961c0 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 7 Aug 2025 13:37:58 +0200 Subject: [PATCH 5/5] fix: return empty array if no option multi-selected (#19224) Related: https://github.com/coder/coder/issues/19145 --- cli/cliui/select.go | 6 +++++- cli/cliui/select_test.go | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cli/cliui/select.go b/cli/cliui/select.go index b3222cbbf3a71..f609ca81c3e26 100644 --- a/cli/cliui/select.go +++ b/cli/cliui/select.go @@ -349,7 +349,11 @@ func RichMultiSelect(inv *serpent.Invocation, richOptions RichMultiSelectOptions } // Check selected option, convert descriptions (line) to values - var results []string + // + // The function must return an initialized empty array, since it is later marshaled + // into JSON. Otherwise, `var results []string` would be marshaled to "null". + // See: https://github.com/golang/go/issues/27589 + results := []string{} for _, sel := range selected { custom := true for i, option := range richOptions.Options { diff --git a/cli/cliui/select_test.go b/cli/cliui/select_test.go index 21fc4cb03c398..55ab81f50f01b 100644 --- a/cli/cliui/select_test.go +++ b/cli/cliui/select_test.go @@ -111,6 +111,17 @@ func TestRichMultiSelect(t *testing.T) { allowCustom: true, want: []string{"aaa", "bbb"}, }, + { + name: "NoOptionSelected", + options: []codersdk.TemplateVersionParameterOption{ + {Name: "AAA", Description: "This is AAA", Value: "aaa"}, + {Name: "BBB", Description: "This is BBB", Value: "bbb"}, + {Name: "CCC", Description: "This is CCC", Value: "ccc"}, + }, + defaults: []string{}, + allowCustom: false, + want: []string{}, + }, } for _, tt := range tests {