authorizeChatWorkspaceExec enforces the workspace-level permissions shared by the chat stream endpoints that proxy a live websocket into the workspace agent (currently /stream/git and /stream/desktop). The chat row only authorizes the chat owner, so callers also need exec-level access (ApplicationC
( rw http.ResponseWriter, r *http.Request, chat database.Chat, noWorkspaceMessage string, )
| 2254 | // |
| 2255 | //nolint:revive // HTTP handler writes to ResponseWriter. |
| 2256 | func (api *API) authorizeChatWorkspaceExec( |
| 2257 | rw http.ResponseWriter, |
| 2258 | r *http.Request, |
| 2259 | chat database.Chat, |
| 2260 | noWorkspaceMessage string, |
| 2261 | ) (database.Workspace, bool) { |
| 2262 | ctx := r.Context() |
| 2263 | |
| 2264 | if !chat.WorkspaceID.Valid { |
| 2265 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 2266 | Message: noWorkspaceMessage, |
| 2267 | }) |
| 2268 | return database.Workspace{}, false |
| 2269 | } |
| 2270 | |
| 2271 | workspace, err := api.Database.GetWorkspaceByID(ctx, chat.WorkspaceID.UUID) |
| 2272 | if httpapi.Is404Error(err) { |
| 2273 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 2274 | Message: codersdk.ChatGitWatchWorkspaceNotFoundMessage, |
| 2275 | }) |
| 2276 | return database.Workspace{}, false |
| 2277 | } |
| 2278 | if err != nil { |
| 2279 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 2280 | Message: "Internal error fetching chat workspace.", |
| 2281 | Detail: err.Error(), |
| 2282 | }) |
| 2283 | return database.Workspace{}, false |
| 2284 | } |
| 2285 | |
| 2286 | if !api.Authorize(r, policy.ActionApplicationConnect, workspace) && |
| 2287 | !api.Authorize(r, policy.ActionSSH, workspace) { |
| 2288 | httpapi.Forbidden(rw) |
| 2289 | return database.Workspace{}, false |
| 2290 | } |
| 2291 | |
| 2292 | return workspace, true |
| 2293 | } |
| 2294 | |
| 2295 | // EXPERIMENTAL: this endpoint is experimental and is subject to change. |
| 2296 | // |
no test coverage detected