mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat(coderd/rbac): make organization-member a per-org system custom role (#21359)
Migrated the built-in organization-member role to DB storage so it can be customized per org. Closes https://github.com/coder/internal/issues/1073 (part 1)
This commit is contained in:
@@ -13,7 +13,10 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/db2sdk"
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtestutil"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/rbac/rolestore"
|
||||
"github.com/coder/coder/v2/coderd/util/ptr"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
|
||||
@@ -694,22 +697,75 @@ func TestGroup(t *testing.T) {
|
||||
t.Run("RegularUserReadGroup", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client, user := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureTemplateRBAC: 1,
|
||||
},
|
||||
}})
|
||||
client1, _ := coderdtest.CreateAnotherUser(t, client, user.OrganizationID)
|
||||
t.Run("WorkspaceSharingEnabled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
//nolint:gocritic // test setup
|
||||
group, err := client.CreateGroup(ctx, user.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "hi",
|
||||
client, user := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureTemplateRBAC: 1,
|
||||
},
|
||||
}})
|
||||
client1, _ := coderdtest.CreateAnotherUser(t, client, user.OrganizationID)
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
//nolint:gocritic // test setup
|
||||
group, err := client.CreateGroup(ctx, user.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "hi",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
ggroup, err := client1.Group(ctx, group.ID)
|
||||
require.NoError(t, err, "regular users can read groups unless workspace sharing is disabled")
|
||||
normalizeGroupMembers(&group)
|
||||
normalizeGroupMembers(&ggroup)
|
||||
require.Equal(t, group, ggroup)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client1.Group(ctx, group.ID)
|
||||
require.Error(t, err, "regular users cannot read groups")
|
||||
t.Run("WorkspaceSharingDisabled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, ps, sqlDB := dbtestutil.NewDBWithSQLDB(t)
|
||||
client, _, api, user := coderdenttest.NewWithAPI(t, &coderdenttest.Options{
|
||||
Options: &coderdtest.Options{
|
||||
Database: db,
|
||||
Pubsub: ps,
|
||||
},
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureTemplateRBAC: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
_, err := sqlDB.ExecContext(ctx, "UPDATE organizations SET workspace_sharing_disabled = true WHERE id = $1", user.OrganizationID)
|
||||
require.NoError(t, err)
|
||||
|
||||
//nolint:gocritic // ReconcileOrgMemberRole needs the system:update
|
||||
// permission that the test context doesn't have.
|
||||
sysCtx := dbauthz.AsSystemRestricted(ctx)
|
||||
_, _, err = rolestore.ReconcileOrgMemberRole(sysCtx, api.Database, database.CustomRole{
|
||||
Name: rbac.RoleOrgMember(),
|
||||
OrganizationID: uuid.NullUUID{
|
||||
UUID: user.OrganizationID,
|
||||
Valid: true,
|
||||
},
|
||||
}, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
client1, _ := coderdtest.CreateAnotherUser(t, client, user.OrganizationID)
|
||||
|
||||
//nolint:gocritic // test setup
|
||||
group, err := client.CreateGroup(ctx, user.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "hi",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client1.Group(ctx, group.ID)
|
||||
require.Error(t, err, "regular users cannot read groups when workspace sharing is disabled")
|
||||
cerr, ok := codersdk.AsError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusNotFound, cerr.StatusCode())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("FilterDeletedUsers", func(t *testing.T) {
|
||||
@@ -947,22 +1003,30 @@ func TestGroups(t *testing.T) {
|
||||
// Query from the user's perspective
|
||||
user5View, err := user5Client.Groups(ctx, codersdk.GroupArguments{})
|
||||
require.NoError(t, err)
|
||||
normalizeAllGroups(user5Groups)
|
||||
normalizeAllGroups(user5View)
|
||||
|
||||
// Everyone group and group 2
|
||||
require.Len(t, user5View, 2)
|
||||
// Org members can read all groups when workspace sharing is not
|
||||
// disabled, but group membership is limited to the requesting user.
|
||||
// TODO(geokat): add another test with workspace sharing disabled.
|
||||
require.Len(t, user5View, 3)
|
||||
user5ViewIDs := db2sdk.List(user5View, func(g codersdk.Group) uuid.UUID {
|
||||
return g.ID
|
||||
})
|
||||
|
||||
require.ElementsMatch(t, []uuid.UUID{
|
||||
everyoneGroup.ID,
|
||||
group1.ID,
|
||||
group2.ID,
|
||||
}, user5ViewIDs)
|
||||
for _, g := range user5View {
|
||||
// Only expect the 1 member, themselves
|
||||
require.Len(t, g.Members, 1)
|
||||
require.Equal(t, user5.ReducedUser.ID, g.Members[0].MinimalUser.ID)
|
||||
if g.ID == everyoneGroup.ID || g.ID == group2.ID {
|
||||
// Only expect the 1 member, themselves.
|
||||
require.Len(t, g.Members, 1)
|
||||
require.Equal(t, user5.ReducedUser.ID, g.Members[0].MinimalUser.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
require.Empty(t, g.Members)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,9 +12,12 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/audit"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/db2sdk"
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/rbac/rolestore"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
|
||||
@@ -265,6 +268,14 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var organization database.Organization
|
||||
err = api.Database.InTx(func(tx database.Store) error {
|
||||
// Serialize creation and reconciliation of the org-member
|
||||
// system role across coderd instances (e.g. during rolling
|
||||
// restarts).
|
||||
err := tx.AcquireLock(ctx, database.LockIDReconcileSystemRoles)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("acquire system roles reconciliation lock: %w", err)
|
||||
}
|
||||
|
||||
if req.DisplayName == "" {
|
||||
req.DisplayName = req.Name
|
||||
}
|
||||
@@ -281,6 +292,24 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create organization: %w", err)
|
||||
}
|
||||
|
||||
// Populate the placeholder system role(s) that the DB trigger
|
||||
// created for us.
|
||||
//nolint:gocritic // ReconcileOrgMemberRole needs the system:update
|
||||
// permission that user doesn't have.
|
||||
sysCtx := dbauthz.AsSystemRestricted(ctx)
|
||||
_, _, err = rolestore.ReconcileOrgMemberRole(sysCtx, tx, database.CustomRole{
|
||||
Name: rbac.RoleOrgMember(),
|
||||
OrganizationID: uuid.NullUUID{
|
||||
UUID: organizationID,
|
||||
Valid: true,
|
||||
},
|
||||
}, organization.WorkspaceSharingDisabled)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("reconcile organization-member role for organization %s: %w",
|
||||
organizationID, err)
|
||||
}
|
||||
|
||||
_, err = tx.InsertOrganizationMember(ctx, database.InsertOrganizationMemberParams{
|
||||
OrganizationID: organization.ID,
|
||||
UserID: apiKey.UserID,
|
||||
|
||||
@@ -65,6 +65,9 @@ func (api *API) postOrgRoles(rw http.ResponseWriter, r *http.Request) {
|
||||
SitePermissions: db2sdk.List(req.SitePermissions, sdkPermissionToDB),
|
||||
OrgPermissions: db2sdk.List(req.OrganizationPermissions, sdkPermissionToDB),
|
||||
UserPermissions: db2sdk.List(req.UserPermissions, sdkPermissionToDB),
|
||||
// Satisfy the linter (we don't support member permissions in non-system roles).
|
||||
MemberPermissions: database.CustomRolePermissions{},
|
||||
IsSystem: false,
|
||||
})
|
||||
if httpapi.Is404Error(err) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
@@ -82,15 +85,15 @@ func (api *API) postOrgRoles(rw http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(ctx, rw, http.StatusOK, db2sdk.Role(inserted))
|
||||
}
|
||||
|
||||
// patchRole will allow creating a custom organization role
|
||||
// putOrgRoles will allow updating a custom organization role
|
||||
//
|
||||
// @Summary Upsert a custom organization role
|
||||
// @ID upsert-a-custom-organization-role
|
||||
// @Summary Update a custom organization role
|
||||
// @ID update-a-custom-organization-role
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param organization path string true "Organization ID" format(uuid)
|
||||
// @Param request body codersdk.CustomRoleRequest true "Upsert role request"
|
||||
// @Param request body codersdk.CustomRoleRequest true "Update role request"
|
||||
// @Tags Members
|
||||
// @Success 200 {array} codersdk.Role
|
||||
// @Router /organizations/{organization}/members/roles [put]
|
||||
@@ -126,8 +129,9 @@ func (api *API) putOrgRoles(rw http.ResponseWriter, r *http.Request) {
|
||||
OrganizationID: organization.ID,
|
||||
},
|
||||
},
|
||||
ExcludeOrgRoles: false,
|
||||
OrganizationID: organization.ID,
|
||||
ExcludeOrgRoles: false,
|
||||
OrganizationID: organization.ID,
|
||||
IncludeSystemRoles: false,
|
||||
})
|
||||
// If it is a 404 (not found) error, ignore it.
|
||||
if err != nil && !httpapi.Is404Error(err) {
|
||||
@@ -153,6 +157,8 @@ func (api *API) putOrgRoles(rw http.ResponseWriter, r *http.Request) {
|
||||
SitePermissions: db2sdk.List(filterInvalidPermissions(req.SitePermissions), sdkPermissionToDB),
|
||||
OrgPermissions: db2sdk.List(filterInvalidPermissions(req.OrganizationPermissions), sdkPermissionToDB),
|
||||
UserPermissions: db2sdk.List(filterInvalidPermissions(req.UserPermissions), sdkPermissionToDB),
|
||||
// Satisfy the linter (we don't support member permissions in non-system roles).
|
||||
MemberPermissions: database.CustomRolePermissions{},
|
||||
})
|
||||
if httpapi.Is404Error(err) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
@@ -197,6 +203,12 @@ func (api *API) deleteOrgRole(rw http.ResponseWriter, r *http.Request) {
|
||||
defer commitAudit()
|
||||
|
||||
rolename := chi.URLParam(r, "roleName")
|
||||
|
||||
// Catch requests that try to delete system roles.
|
||||
if !validOrganizationRoleRequest(ctx, codersdk.CustomRoleRequest{Name: rolename}, rw) {
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := api.Database.CustomRoles(ctx, database.CustomRolesParams{
|
||||
LookupRoles: []database.NameOrganizationPair{
|
||||
{
|
||||
@@ -204,7 +216,8 @@ func (api *API) deleteOrgRole(rw http.ResponseWriter, r *http.Request) {
|
||||
OrganizationID: organization.ID,
|
||||
},
|
||||
},
|
||||
ExcludeOrgRoles: false,
|
||||
ExcludeOrgRoles: false,
|
||||
IncludeSystemRoles: false,
|
||||
// Linter requires all fields to be set. This field is not actually required.
|
||||
OrganizationID: organization.ID,
|
||||
})
|
||||
|
||||
@@ -256,6 +256,59 @@ func TestCustomOrganizationRole(t *testing.T) {
|
||||
require.ErrorContains(t, err, "not allowed to assign user permissions")
|
||||
})
|
||||
|
||||
// Attempt to add org member permissions, which is not allowed.
|
||||
t.Run("MemberPermissions", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
owner, first := coderdenttest.New(t, &coderdenttest.Options{
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureCustomRoles: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
role := templateAdminCustom(first.OrganizationID)
|
||||
role.Name = "test-role-member-perms"
|
||||
role.OrganizationMemberPermissions = []codersdk.Permission{
|
||||
{
|
||||
ResourceType: codersdk.ResourceWorkspace,
|
||||
Action: codersdk.ActionRead,
|
||||
},
|
||||
}
|
||||
|
||||
//nolint:gocritic // we want unrestricted permissions for the test
|
||||
_, err := owner.CreateOrganizationRole(ctx, role)
|
||||
var apiErr *codersdk.Error
|
||||
require.ErrorAs(t, err, &apiErr)
|
||||
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
||||
require.ErrorContains(t, err, "not allowed to assign organization member permissions for an organization role")
|
||||
})
|
||||
|
||||
// Attempt to delete a system role, which is not allowed.
|
||||
t.Run("DeleteSystemRole", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
owner, first := coderdenttest.New(t, &coderdenttest.Options{
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureCustomRoles: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
//nolint:gocritic // we want unrestricted permissions for the test
|
||||
err := owner.DeleteOrganizationRole(ctx, first.OrganizationID, rbac.RoleOrgMember())
|
||||
var apiErr *codersdk.Error
|
||||
require.ErrorAs(t, err, &apiErr)
|
||||
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
||||
require.ErrorContains(t, err, "Reserved role name")
|
||||
})
|
||||
|
||||
t.Run("NotFound", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
owner, first := coderdenttest.New(t, &coderdenttest.Options{
|
||||
|
||||
@@ -3639,41 +3639,45 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
dv := coderdtest.DeploymentValues(t)
|
||||
dv.Experiments = []string{string(codersdk.ExperimentWorkspaceSharing)}
|
||||
|
||||
var (
|
||||
client, db, orgOwner = coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
ownerClient, db, owner := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
},
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureTemplateRBAC: 1,
|
||||
},
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
codersdk.FeatureTemplateRBAC: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
_, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
|
||||
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
ctx = testutil.Context(t, testutil.WaitMedium)
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
group, err := client.CreateGroup(ctx, orgOwner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
workspaceOwnerClient, workspaceOwner := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.ScopedRoleOrgAuditor(owner.OrganizationID))
|
||||
|
||||
sharedWorkspace := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
|
||||
// Unshared workspace.
|
||||
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
group, err := ownerClient.CreateGroup(ctx, owner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "wibble",
|
||||
})
|
||||
require.NoError(t, err, "create group")
|
||||
|
||||
client.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
err = workspaceOwnerClient.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
GroupRoles: map[string]codersdk.WorkspaceRole{
|
||||
group.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err, "update workspace ACL")
|
||||
|
||||
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
workspaces, err := ownerClient.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
Shared: ptr.Ref(true),
|
||||
})
|
||||
require.NoError(t, err, "fetch workspaces")
|
||||
@@ -3688,7 +3692,7 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
dv.Experiments = []string{string(codersdk.ExperimentWorkspaceSharing)}
|
||||
|
||||
var (
|
||||
client, db, orgOwner = coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
ownerClient, db, owner = coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
},
|
||||
@@ -3698,25 +3702,26 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
_, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
|
||||
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
|
||||
workspaceOwnerClient, workspaceOwner = coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.ScopedRoleOrgAuditor(owner.OrganizationID))
|
||||
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
_, toShareWithUser = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID)
|
||||
_, toShareWithUser = coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID)
|
||||
ctx = testutil.Context(t, testutil.WaitMedium)
|
||||
)
|
||||
|
||||
group, err := client.CreateGroup(ctx, orgOwner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
group, err := ownerClient.CreateGroup(ctx, owner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "wibble",
|
||||
})
|
||||
require.NoError(t, err, "create group")
|
||||
|
||||
client.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
err = workspaceOwnerClient.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
UserRoles: map[string]codersdk.WorkspaceRole{
|
||||
toShareWithUser.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
},
|
||||
@@ -3724,8 +3729,9 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
group.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err, "update workspace ACL")
|
||||
|
||||
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
workspaces, err := ownerClient.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
Shared: ptr.Ref(true),
|
||||
})
|
||||
require.NoError(t, err, "fetch workspaces")
|
||||
@@ -3740,7 +3746,7 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
dv.Experiments = []string{string(codersdk.ExperimentWorkspaceSharing)}
|
||||
|
||||
var (
|
||||
client, db, orgOwner = coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
ownerClient, db, owner = coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
},
|
||||
@@ -3750,30 +3756,31 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
_, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
|
||||
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
workspaceOwnerClient, workspaceOwner = coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.ScopedRoleOrgAuditor(owner.OrganizationID))
|
||||
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
notSharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
ctx = testutil.Context(t, testutil.WaitMedium)
|
||||
)
|
||||
|
||||
group, err := client.CreateGroup(ctx, orgOwner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
group, err := ownerClient.CreateGroup(ctx, owner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "wibble",
|
||||
})
|
||||
require.NoError(t, err, "create group")
|
||||
|
||||
client.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
err = workspaceOwnerClient.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
GroupRoles: map[string]codersdk.WorkspaceRole{
|
||||
group.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err, "update workspace ACL")
|
||||
|
||||
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
workspaces, err := ownerClient.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
Shared: ptr.Ref(false),
|
||||
})
|
||||
require.NoError(t, err, "fetch workspaces")
|
||||
@@ -3788,7 +3795,7 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
dv.Experiments = []string{string(codersdk.ExperimentWorkspaceSharing)}
|
||||
|
||||
var (
|
||||
client, db, orgOwner = coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
ownerClient, db, owner = coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
},
|
||||
@@ -3798,30 +3805,30 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
_, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
|
||||
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
workspaceOwnerClient, workspaceOwner = coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.ScopedRoleOrgAuditor(owner.OrganizationID))
|
||||
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
ctx = testutil.Context(t, testutil.WaitMedium)
|
||||
)
|
||||
|
||||
group, err := client.CreateGroup(ctx, orgOwner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
group, err := ownerClient.CreateGroup(ctx, owner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "wibble",
|
||||
})
|
||||
require.NoError(t, err, "create group")
|
||||
err = client.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
err = workspaceOwnerClient.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
GroupRoles: map[string]codersdk.WorkspaceRole{
|
||||
group.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
workspaces, err := ownerClient.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
SharedWithGroup: group.ID.String(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -3836,7 +3843,7 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
dv.Experiments = []string{string(codersdk.ExperimentWorkspaceSharing)}
|
||||
|
||||
var (
|
||||
client, db, orgOwner = coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
ownerClient, db, owner = coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
},
|
||||
@@ -3846,44 +3853,44 @@ func TestWorkspacesFiltering(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
_, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
|
||||
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
workspaceOwnerClient, workspaceOwner = coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.ScopedRoleOrgAuditor(owner.OrganizationID))
|
||||
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
OrganizationID: orgOwner.OrganizationID,
|
||||
OrganizationID: owner.OrganizationID,
|
||||
}).Do().Workspace
|
||||
ctx = testutil.Context(t, testutil.WaitMedium)
|
||||
)
|
||||
|
||||
group, err := client.CreateGroup(ctx, orgOwner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
group, err := ownerClient.CreateGroup(ctx, owner.OrganizationID, codersdk.CreateGroupRequest{
|
||||
Name: "wibble",
|
||||
})
|
||||
require.NoError(t, err, "create group")
|
||||
err = client.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
err = workspaceOwnerClient.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
GroupRoles: map[string]codersdk.WorkspaceRole{
|
||||
group.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
workspacesByID, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
workspacesByID, err := ownerClient.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
SharedWithGroup: group.ID.String(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, workspacesByID.Count)
|
||||
require.Equal(t, sharedWorkspace.ID, workspacesByID.Workspaces[0].ID)
|
||||
|
||||
workspacesByName, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
workspacesByName, err := ownerClient.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
SharedWithGroup: group.Name,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, workspacesByName.Count)
|
||||
require.Equal(t, sharedWorkspace.ID, workspacesByName.Workspaces[0].ID)
|
||||
|
||||
workspacesByOrgAndName, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
workspacesByOrgAndName, err := ownerClient.Workspaces(ctx, codersdk.WorkspaceFilter{
|
||||
SharedWithGroup: fmt.Sprintf("coder/%s", group.Name),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -4535,7 +4542,7 @@ func TestWorkspacesSharedWith(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
_, workspaceOwner := coderdtest.CreateAnotherUser(t, client, user.OrganizationID)
|
||||
workspaceOwnerClient, workspaceOwner := coderdtest.CreateAnotherUser(t, client, user.OrganizationID)
|
||||
|
||||
workspace := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
@@ -4563,7 +4570,7 @@ func TestWorkspacesSharedWith(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Share workspace with user and group
|
||||
err = client.UpdateWorkspaceACL(ctx, workspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
err = workspaceOwnerClient.UpdateWorkspaceACL(ctx, workspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
UserRoles: map[string]codersdk.WorkspaceRole{
|
||||
sharedWithUser.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
},
|
||||
@@ -4623,7 +4630,7 @@ func TestWorkspacesSharedWith(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
_, workspaceOwner := coderdtest.CreateAnotherUser(t, client, user.OrganizationID)
|
||||
workspaceOwnerClient, workspaceOwner := coderdtest.CreateAnotherUser(t, client, user.OrganizationID)
|
||||
|
||||
workspace := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OwnerID: workspaceOwner.ID,
|
||||
@@ -4651,7 +4658,7 @@ func TestWorkspacesSharedWith(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Share workspace with user and group
|
||||
err = client.UpdateWorkspaceACL(ctx, workspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
err = workspaceOwnerClient.UpdateWorkspaceACL(ctx, workspace.ID, codersdk.UpdateWorkspaceACL{
|
||||
UserRoles: map[string]codersdk.WorkspaceRole{
|
||||
sharedWithUser.ID.String(): codersdk.WorkspaceRoleUse,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user