feat: add sharing info to /workspaces endpoint (#21049)

closes: https://github.com/coder/internal/issues/858

Similar to https://github.com/coder/coder/pull/19375, this one uses
system permissions for fetching actual user and group data.

Modifies the `workspaces_expanded` view to fetch the required data; this way it's made available to all code paths that make use of it.  

Also fixes a bug in a test helper function that can result in `null` being saved to the DB for `user_acl` or `group_acl` and break tests; a defensive check constraint that prevents this is worth a PR, e.g:

`ALTER TABLE workspaces
   ADD CONSTRAINT group_acl_is_object CHECK (jsonb_typeof(group_acl) = 'object');`

Also adds missing  `OwnerName` in `ConvertWorkspaceRows`.
This commit is contained in:
George K
2025-12-15 08:42:08 -08:00
committed by GitHub
parent 7ecfd1aa07
commit 103967ed02
22 changed files with 838 additions and 92 deletions
+17 -1
View File
@@ -73,7 +73,8 @@ type Workspace struct {
// and IsPrebuild returns false.
IsPrebuild bool `json:"is_prebuild"`
// TaskID, if set, indicates that the workspace is relevant to the given codersdk.Task.
TaskID uuid.NullUUID `json:"task_id,omitempty"`
TaskID uuid.NullUUID `json:"task_id,omitempty"`
SharedWith []SharedWorkspaceActor `json:"shared_with,omitempty"`
}
func (w Workspace) FullName() string {
@@ -695,6 +696,14 @@ type WorkspaceUser struct {
Role WorkspaceRole `json:"role" enums:"admin,use"`
}
type SharedWorkspaceActor struct {
ID uuid.UUID `json:"id" format:"uuid"`
ActorType SharedWorkspaceActorType `json:"actor_type" enums:"group,user"`
Name string `json:"name"`
AvatarURL string `json:"avatar_url,omitempty" format:"uri"`
Roles []WorkspaceRole `json:"roles"`
}
type WorkspaceRole string
const (
@@ -703,6 +712,13 @@ const (
WorkspaceRoleDeleted WorkspaceRole = ""
)
type SharedWorkspaceActorType string
const (
SharedWorkspaceActorTypeGroup SharedWorkspaceActorType = "group"
SharedWorkspaceActorTypeUser SharedWorkspaceActorType = "user"
)
func (c *Client) WorkspaceACL(ctx context.Context, workspaceID uuid.UUID) (WorkspaceACL, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/acl", workspaceID), nil)
if err != nil {