Skip to content

Commit 4e34c89

Browse files
committed
fix(coderd/provisionerdserver): ensure that SidebarAppID is a known workspace app
1 parent 84b852b commit 4e34c89

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

coderd/provisionerdserver/provisionerdserver.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,6 +1943,17 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
19431943
}
19441944
}
19451945

1946+
var knownAppIDs []string
1947+
for _, res := range jobType.WorkspaceBuild.Resources {
1948+
for _, agt := range res.Agents {
1949+
for _, app := range agt.Apps {
1950+
if app.Id == "" {
1951+
continue
1952+
}
1953+
knownAppIDs = append(knownAppIDs, app.Id)
1954+
}
1955+
}
1956+
}
19461957
var sidebarAppID uuid.NullUUID
19471958
hasAITask := len(jobType.WorkspaceBuild.AiTasks) == 1
19481959
if hasAITask {
@@ -1959,18 +1970,33 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
19591970
sidebarAppID = uuid.NullUUID{UUID: id, Valid: true}
19601971
}
19611972

1973+
// NOTE(Cian): If stopping a workspace build, we must ensure that the
1974+
// SidebarAppID corresponds to an extant coder_app. If it does not, the
1975+
// build will fail with a foreign key constraint violation as workspace_builds.ai_task_sidebar_app_id
1976+
// references coder_apps.id.
1977+
// Unfortunately, this behavior will result in the workspace build being
1978+
// 'silently' not configured as an AI task except for a warning in the logs.
1979+
// Ideally, we should also accept an app slug as these are less likely to change.
1980+
if sidebarAppID.Valid && !slices.Contains(knownAppIDs, sidebarAppID.UUID.String()) {
1981+
s.Logger.Warn(ctx, "workspace build has unknown sidebar app ID",
1982+
slog.F("workspace_build_id", workspaceBuild.ID),
1983+
slog.F("sidebar_app_id", sidebarAppID),
1984+
slog.F("known_app_ids", knownAppIDs),
1985+
)
1986+
sidebarAppID = uuid.NullUUID{}
1987+
hasAITask = false
1988+
}
19621989
// Regardless of whether there is an AI task or not, update the field to indicate one way or the other since it
19631990
// always defaults to nil. ONLY if has_ai_task=true MUST ai_task_sidebar_app_id be set.
1964-
err = db.UpdateWorkspaceBuildAITaskByID(ctx, database.UpdateWorkspaceBuildAITaskByIDParams{
1991+
if err = db.UpdateWorkspaceBuildAITaskByID(ctx, database.UpdateWorkspaceBuildAITaskByIDParams{
19651992
ID: workspaceBuild.ID,
19661993
HasAITask: sql.NullBool{
19671994
Bool: hasAITask,
19681995
Valid: true,
19691996
},
19701997
SidebarAppID: sidebarAppID,
19711998
UpdatedAt: now,
1972-
})
1973-
if err != nil {
1999+
}); err != nil {
19742000
return xerrors.Errorf("update workspace build ai tasks flag: %w", err)
19752001
}
19762002

coderd/provisionerdserver/provisionerdserver_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,6 +2794,20 @@ func TestCompleteJob(t *testing.T) {
27942794
},
27952795
expected: true,
27962796
},
2797+
{
2798+
name: "non-existing app",
2799+
input: &proto.CompletedJob_WorkspaceBuild{
2800+
AiTasks: []*sdkproto.AITask{
2801+
{
2802+
Id: uuid.NewString(),
2803+
SidebarApp: &sdkproto.AITaskSidebarApp{
2804+
Id: uuid.NewString(), // Non-existing app ID.
2805+
},
2806+
},
2807+
},
2808+
},
2809+
expected: false,
2810+
},
27972811
} {
27982812
t.Run(tc.name, func(t *testing.T) {
27992813
t.Parallel()

0 commit comments

Comments
 (0)