mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat(enterprise): implement organization "disable workspace sharing" option (#21376)
Adds a per-organization setting to disable workspace sharing. When enabled, all existing workspace ACLs in the organization are cleared and the workspace ACL mutation API endpoints return `403 Forbidden`. This complements the existing site-wide `--disable-workspace-sharing` flag by providing more granular control at the organization level. Closes https://github.com/coder/internal/issues/1073 (part 2) --------- Co-authored-by: Steven Masley <Emyrk@users.noreply.github.com>
This commit is contained in:
@@ -5266,7 +5266,66 @@ func TestDeleteWorkspaceACL(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// nolint:tparallel,paralleltest // Subtests modify package global.
|
||||
// `use`-role shares are granted `workspace:read` via the workspace RBAC ACL
|
||||
// list, so they should be able to read the ACL.
|
||||
//
|
||||
//nolint:tparallel,paralleltest // Test modifies a package global (rbac.workspaceACLDisabled).
|
||||
func TestWorkspaceReadCanListACL(t *testing.T) {
|
||||
// Be defensive by saving/restoring the modified package global.
|
||||
prevWorkspaceACLDisabled := rbac.WorkspaceACLDisabled()
|
||||
rbac.SetWorkspaceACLDisabled(false)
|
||||
t.Cleanup(func() { rbac.SetWorkspaceACLDisabled(prevWorkspaceACLDisabled) })
|
||||
|
||||
var (
|
||||
client, db = coderdtest.NewWithDatabase(t, &coderdtest.Options{
|
||||
DeploymentValues: coderdtest.DeploymentValues(t, func(dv *codersdk.DeploymentValues) {
|
||||
dv.Experiments = []string{string(codersdk.ExperimentWorkspaceSharing)}
|
||||
}),
|
||||
})
|
||||
admin = coderdtest.CreateFirstUser(t, client)
|
||||
workspaceOwnerClient, workspaceOwner = coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
|
||||
sharedUserClientA, sharedUserA = coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
|
||||
_, sharedUserB = coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
|
||||
sharedGroup = dbgen.Group(t, db, database.Group{OrganizationID: admin.OrganizationID})
|
||||
workspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: admin.OrganizationID,
|
||||
}).Do().Workspace
|
||||
)
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
err := workspaceOwnerClient.UpdateWorkspaceACL(ctx, workspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
UserRoles: map[string]codersdk.WorkspaceRole{
|
||||
sharedUserA.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
sharedUserB.ID.String(): codersdk.WorkspaceRoleAdmin,
|
||||
},
|
||||
GroupRoles: map[string]codersdk.WorkspaceRole{
|
||||
sharedGroup.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
acl, err := sharedUserClientA.WorkspaceACL(ctx, workspace.ID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, acl.Users, 2)
|
||||
require.Len(t, acl.Groups, 1)
|
||||
|
||||
gotRoles := make(map[uuid.UUID]codersdk.WorkspaceRole, len(acl.Users))
|
||||
for _, u := range acl.Users {
|
||||
gotRoles[u.ID] = u.Role
|
||||
}
|
||||
require.Equal(t, codersdk.WorkspaceRoleUse, gotRoles[sharedUserA.ID])
|
||||
require.Equal(t, codersdk.WorkspaceRoleAdmin, gotRoles[sharedUserB.ID])
|
||||
|
||||
gotGroupRoles := make(map[uuid.UUID]codersdk.WorkspaceRole, len(acl.Groups))
|
||||
for _, g := range acl.Groups {
|
||||
gotGroupRoles[g.ID] = g.Role
|
||||
}
|
||||
require.Equal(t, codersdk.WorkspaceRoleUse, gotGroupRoles[sharedGroup.ID])
|
||||
}
|
||||
|
||||
// nolint:tparallel,paralleltest // Subtests modify a package global (rbac.workspaceACLDisabled).
|
||||
func TestWorkspaceSharingDisabled(t *testing.T) {
|
||||
t.Run("CanAccessWhenEnabled", func(t *testing.T) {
|
||||
var (
|
||||
|
||||
Reference in New Issue
Block a user