Skip to content

Commit ec8828c

Browse files
committed
fix: Multiple builds using the incorrect agent token
This was an issue with our in-memory database that caused newer builds to return an outdated agent, which would then be rejected. A test case has been added to ensure this can't happen again!
1 parent 52271ff commit ec8828c

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

coderd/database/databasefake/databasefake.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,9 @@ func (q *fakeQuerier) GetWorkspaceAgentByAuthToken(_ context.Context, authToken
626626
q.mutex.RLock()
627627
defer q.mutex.RUnlock()
628628

629-
for _, agent := range q.provisionerJobAgent {
629+
// The schema sorts this by created at, so we iterate the array backwards.
630+
for i := len(q.provisionerJobAgent) - 1; i >= 0; i-- {
631+
agent := q.provisionerJobAgent[i]
630632
if agent.AuthToken.String() == authToken.String() {
631633
return agent, nil
632634
}
@@ -990,7 +992,7 @@ func (q *fakeQuerier) InsertProvisionerJob(_ context.Context, arg database.Inser
990992
return job, nil
991993
}
992994

993-
func (q *fakeQuerier) InsertWorkspaceAgent(_ context.Context, arg database.InsertWorkspaceAgentParams) (database.WorkspaceAgent, error) {
995+
func (q *fakeQuerier) InsertWorkspaceAgent(ctx context.Context, arg database.InsertWorkspaceAgentParams) (database.WorkspaceAgent, error) {
994996
q.mutex.Lock()
995997
defer q.mutex.Unlock()
996998

coderd/workspacebuilds_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@ import (
66
"testing"
77
"time"
88

9+
"cdr.dev/slog/sloggers/slogtest"
10+
"github.com/google/uuid"
911
"github.com/stretchr/testify/require"
1012

13+
"github.com/coder/coder/agent"
1114
"github.com/coder/coder/coderd/coderdtest"
15+
"github.com/coder/coder/coderd/database"
1216
"github.com/coder/coder/codersdk"
17+
"github.com/coder/coder/peer"
1318
"github.com/coder/coder/provisioner/echo"
1419
"github.com/coder/coder/provisionersdk/proto"
1520
)
@@ -115,6 +120,56 @@ func TestWorkspaceBuildResources(t *testing.T) {
115120
require.Equal(t, "example", resources[0].Type)
116121
require.Len(t, resources[0].Agents, 1)
117122
})
123+
t.Run("MultipleBuilds", func(t *testing.T) {
124+
// This ensures that the latest agent can connect through multiple builds.
125+
// Agents won't always have new authentication tokens on rebuild, because
126+
// infrastructure as code won't always recreate the resource.
127+
t.Parallel()
128+
client := coderdtest.New(t, nil)
129+
user := coderdtest.CreateFirstUser(t, client)
130+
coderdtest.NewProvisionerDaemon(t, client)
131+
authToken := uuid.NewString()
132+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
133+
Parse: echo.ParseComplete,
134+
Provision: []*proto.Provision_Response{{
135+
Type: &proto.Provision_Response_Complete{
136+
Complete: &proto.Provision_Complete{
137+
Resources: []*proto.Resource{{
138+
Name: "some",
139+
Type: "example",
140+
Agents: []*proto.Agent{{
141+
Id: "something",
142+
Auth: &proto.Agent_Token{
143+
Token: authToken,
144+
},
145+
}},
146+
}},
147+
},
148+
},
149+
}},
150+
})
151+
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
152+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
153+
workspace := coderdtest.CreateWorkspace(t, client, codersdk.Me, template.ID)
154+
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
155+
build, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
156+
TemplateVersionID: template.ActiveVersionID,
157+
Transition: database.WorkspaceTransitionStart,
158+
DryRun: false,
159+
})
160+
require.NoError(t, err)
161+
coderdtest.AwaitWorkspaceBuildJob(t, client, build.ID)
162+
163+
agentClient := codersdk.New(client.URL)
164+
agentClient.SessionToken = authToken
165+
agentCloser := agent.New(agentClient.ListenWorkspaceAgent, &peer.ConnOptions{
166+
Logger: slogtest.Make(t, nil),
167+
})
168+
t.Cleanup(func() {
169+
_ = agentCloser.Close()
170+
})
171+
coderdtest.AwaitWorkspaceAgents(t, client, build.ID)
172+
})
118173
}
119174

120175
func TestWorkspaceBuildLogs(t *testing.T) {

0 commit comments

Comments
 (0)