chatStartWorkspace starts a stopped workspace by creating a new build with the "start" transition. It mirrors chatCreateWorkspace but for the start path. Aliased as ChatStartWorkspace in coderd/export_test.go so external tests in the coderd_test package can drive the auto-update path end-to-end. Th
( ctx context.Context, ownerID uuid.UUID, workspaceID uuid.UUID, req codersdk.CreateWorkspaceBuildRequest, )
| 3855 | // end-to-end. The proper fix is to extract the request building into |
| 3856 | // a pure function; tracked in CODAGT-292. |
| 3857 | func (api *API) chatStartWorkspace( |
| 3858 | ctx context.Context, |
| 3859 | ownerID uuid.UUID, |
| 3860 | workspaceID uuid.UUID, |
| 3861 | req codersdk.CreateWorkspaceBuildRequest, |
| 3862 | ) (codersdk.WorkspaceBuild, error) { |
| 3863 | actor, _, err := httpmw.UserRBACSubject(ctx, api.Database, ownerID, rbac.ScopeAll) |
| 3864 | if err != nil { |
| 3865 | return codersdk.WorkspaceBuild{}, xerrors.Errorf("load user authorization: %w", err) |
| 3866 | } |
| 3867 | ctx = dbauthz.As(ctx, actor) |
| 3868 | |
| 3869 | workspace, err := api.Database.GetWorkspaceByID(ctx, workspaceID) |
| 3870 | if err != nil { |
| 3871 | return codersdk.WorkspaceBuild{}, xerrors.Errorf("get workspace: %w", err) |
| 3872 | } |
| 3873 | |
| 3874 | updatedToActiveVersion := false |
| 3875 | if req.Transition == codersdk.WorkspaceTransitionStart { |
| 3876 | template, err := api.Database.GetTemplateByID(ctx, workspace.TemplateID) |
| 3877 | if err != nil { |
| 3878 | return codersdk.WorkspaceBuild{}, xerrors.Errorf("get template: %w", err) |
| 3879 | } |
| 3880 | |
| 3881 | templateAccessControl := (*(api.AccessControlStore.Load())).GetTemplateAccessControl(template) |
| 3882 | if templateAccessControl.RequireActiveVersion { |
| 3883 | latestBuild, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspace.ID) |
| 3884 | if err != nil { |
| 3885 | return codersdk.WorkspaceBuild{}, xerrors.Errorf("get latest workspace build: %w", err) |
| 3886 | } |
| 3887 | |
| 3888 | updatedToActiveVersion = latestBuild.TemplateVersionID != template.ActiveVersionID |
| 3889 | req.TemplateVersionID = template.ActiveVersionID |
| 3890 | } |
| 3891 | } |
| 3892 | |
| 3893 | // Build a synthetic API key so postWorkspaceBuildsInternal can |
| 3894 | // record the correct initiator. |
| 3895 | syntheticKey := database.APIKey{ |
| 3896 | UserID: ownerID, |
| 3897 | } |
| 3898 | |
| 3899 | apiBuild, err := api.postWorkspaceBuildsInternal( |
| 3900 | ctx, |
| 3901 | syntheticKey, |
| 3902 | workspace, |
| 3903 | req, |
| 3904 | func(action policy.Action, object rbac.Objecter) bool { |
| 3905 | // Authorization is handled by dbauthz on the context. |
| 3906 | authErr := api.HTTPAuth.Authorizer.Authorize(ctx, actor, action, object.RBACObject()) |
| 3907 | return authErr == nil |
| 3908 | }, |
| 3909 | audit.WorkspaceBuildBaggage{}, |
| 3910 | ) |
| 3911 | if err != nil { |
| 3912 | if updatedToActiveVersion && isChatStartWorkspaceManualUpdateRequiredError(err) { |
| 3913 | const retryInstructions = "The workspace needs the template's active version before it can start. Use read_template with this workspace's template_id to inspect the active version's required parameters, then retry start_workspace with a parameters object that supplies any missing or changed values. If the correct value for a parameter is not obvious from its description or defaults, ask the user rather than guessing." |
| 3914 | if responder, ok := httperror.IsResponder(err); ok { |
nothing calls this directly
no test coverage detected