Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
finished implementation
  • Loading branch information
aslilac committed Aug 15, 2025
commit 60d81d19ef893d61bf6d24697bc1aa37077eca8f
2 changes: 1 addition & 1 deletion coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion coderd/database/queries/workspaces.sql
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@ SELECT * FROM workspaces WHERE template_id = $1 AND deleted = false;
-- name: GetWorkspaceACLByID :one
SELECT
group_acl as groups,
user_acl as user
user_acl as users
FROM
workspaces
WHERE
Expand Down
129 changes: 70 additions & 59 deletions coderd/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -2148,70 +2148,81 @@
workspace = httpmw.WorkspaceParam(r)
)

_, err := api.Database.GetWorkspaceACLByID(ctx, workspace.ID)
// Fetch the ACL data
acl, err := api.Database.GetWorkspaceACLByID(ctx, workspace.ID)

Check failure on line 2152 in coderd/workspaces.go

View workflow job for this annotation

GitHub Actions / lint

import-shadowing: The name 'acl' shadows an import name (revive)
if err != nil {
httpapi.InternalServerError(rw, err)
return
}

// userIDs := make([]uuid.UUID, 0, len(users))
// for _, user := range users {
// userIDs = append(userIDs, user.ID)
// }

// orgIDsByMemberIDsRows, err := api.Database.GetOrganizationIDsByMemberIDs(r.Context(), userIDs)
// if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
// httpapi.InternalServerError(rw, err)
// return
// }

// organizationIDsByUserID := map[uuid.UUID][]uuid.UUID{}
// for _, organizationIDsByMemberIDsRow := range orgIDsByMemberIDsRows {
// organizationIDsByUserID[organizationIDsByMemberIDsRow.UserID] = organizationIDsByMemberIDsRow.OrganizationIDs
// }

// groups := make([]codersdk.TemplateGroup, 0, len(dbGroups))
// for _, group := range dbGroups {
// var members []database.GroupMember

// // This is a bit of a hack. The caller might not have permission to do this,
// // but they can read the acl list if the function got this far. So we let
// // them read the group members.
// // We should probably at least return more truncated user data here.
// // nolint:gocritic
// members, err = api.Database.GetGroupMembersByGroupID(dbauthz.AsSystemRestricted(ctx), database.GetGroupMembersByGroupIDParams{
// GroupID: group.Group.ID,
// IncludeSystem: false,
// })
// if err != nil {
// httpapi.InternalServerError(rw, err)
// return
// }
// // nolint:gocritic
// memberCount, err := api.Database.GetGroupMembersCountByGroupID(dbauthz.AsSystemRestricted(ctx), database.GetGroupMembersCountByGroupIDParams{
// GroupID: group.Group.ID,
// IncludeSystem: false,
// })
// if err != nil {
// httpapi.InternalServerError(rw, err)
// return
// }
// groups = append(groups, codersdk.TemplateGroup{
// Group: db2sdk.Group(database.GetGroupsRow{
// Group: group.Group,
// OrganizationName: template.OrganizationName,
// OrganizationDisplayName: template.OrganizationDisplayName,
// }, members, int(memberCount)),
// Role: convertToTemplateRole(group.Actions),
// })
// }

// httpapi.Write(ctx, rw, http.StatusOK, codersdk.TemplateACL{
// Users: convertTemplateUsers(users, organizationIDsByUserID),
// Groups: groups,
// })

httpapi.Write(ctx, rw, http.StatusOK, codersdk.WorkspaceACL{})
// Fetch all of the users and their organization memberships
userIDs := make([]uuid.UUID, 0, len(acl.Users))
for userID, _ := range acl.Users {

Check failure on line 2160 in coderd/workspaces.go

View workflow job for this annotation

GitHub Actions / lint

range: should omit 2nd value from range; this loop is equivalent to `for userID := range ...` (revive)
userIDs = append(userIDs, uuid.MustParse(userID))
}
dbUsers, err := api.Database.GetUsersByIDs(ctx, userIDs)

Check failure on line 2163 in coderd/workspaces.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to err (ineffassign)

orgIDsByMemberIDsRows, err := api.Database.GetOrganizationIDsByMemberIDs(r.Context(), userIDs)
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
httpapi.InternalServerError(rw, err)
return
}
organizationIDsByUserID := map[uuid.UUID][]uuid.UUID{}
for _, organizationIDsByMemberIDsRow := range orgIDsByMemberIDsRows {
organizationIDsByUserID[organizationIDsByMemberIDsRow.UserID] = organizationIDsByMemberIDsRow.OrganizationIDs
}

// Convert the db types to the codersdk.WorkspaceUser type
users := make([]codersdk.WorkspaceUser, 0, len(dbUsers))
for _, it := range dbUsers {
users = append(users, codersdk.WorkspaceUser{
User: db2sdk.User(it, organizationIDsByUserID[it.ID]),
Role: convertToWorkspaceRole(acl.Users[it.ID.String()].Permissions),
})
}

// Fetch all of the groups
groupIDs := make([]uuid.UUID, 0, len(acl.Groups))
for groupID, _ := range acl.Groups {

Check failure on line 2186 in coderd/workspaces.go

View workflow job for this annotation

GitHub Actions / lint

range: should omit 2nd value from range; this loop is equivalent to `for groupID := range ...` (revive)
groupIDs = append(groupIDs, uuid.MustParse(groupID))
}
dbGroups, err := api.Database.GetGroups(ctx, database.GetGroupsParams{GroupIds: groupIDs})

Check failure on line 2189 in coderd/workspaces.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to err (ineffassign)

groups := make([]codersdk.WorkspaceGroup, 0, len(dbGroups))
for _, it := range dbGroups {
var members []database.GroupMember
// This is taken from the template ACL implementation, and is far from
// ideal. Usually, when we use the System context it's because we need to
// run some query that won't actually be exposed to the user. That is not
// the case here. This data goes directly to an unauthorized user. We are
// just straight up breaking security promises.
//
// Fine for now while behind the shared-workspaces experiment, but needs to
// be fixed before GA.
// For context see https://github.com/coder/coder/pull/19375
// nolint:gocritic
members, err = api.Database.GetGroupMembersByGroupID(dbauthz.AsSystemRestricted(ctx), database.GetGroupMembersByGroupIDParams{
GroupID: it.Group.ID,
IncludeSystem: false,
})
if err != nil {
httpapi.InternalServerError(rw, err)
return
}
groups = append(groups, codersdk.WorkspaceGroup{
Group: db2sdk.Group(database.GetGroupsRow{
Group: it.Group,
OrganizationName: it.OrganizationName,
OrganizationDisplayName: it.OrganizationDisplayName,
}, members, len(members)),
Role: convertToWorkspaceRole(acl.Groups[it.Group.ID.String()].Permissions),
})
}

httpapi.Write(ctx, rw, http.StatusOK, codersdk.WorkspaceACL{
Users: users,
Groups: groups,
})
}

// @Summary Update workspace ACL
Expand Down
92 changes: 0 additions & 92 deletions docs/reference/api/enterprise.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

92 changes: 92 additions & 0 deletions docs/reference/api/workspaces.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading