8000 feat: enable agent connection reports by default, remove flag (cherry-pick #16778) by matifali · Pull Request #16809 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

feat: enable agent connection reports by default, remove flag (cherry-pick #16778) #16809

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
172e523
feat(agent): wire up agentssh server to allow exec into container (#1…
johnstcn Feb 26, 2025
38c0e8a
fix(agent/agentssh): ensure RSA key generation always produces valid …
ThomasK33 Feb 26, 2025
c5a265f
feat(cli): add experimental rpty command (#16700)
johnstcn Feb 26, 2025
a2cc1b8
fix: display premium banner on audit page when license inactive (#16713)
mtojek Feb 26, 2025
2971957
ci: also restart tagged provisioner deployment (#16716)
johnstcn Feb 26, 2025
f1b357d
feat: support session audit log (#16703)
BrunoQuaresma Feb 26, 2025
b94d2cb
fix(coderd): handle deletes and links for new agent/app audit resourc…
mafredri Feb 26, 2025
7c035a4
fix: remove provisioners from deployment sidebar (#16717)
BrunoQuaresma Feb 26, 2025
7cd6e9c
fix: return provisioners in desc order and add limit to cli (#16720)
mafredri Feb 26, 2025
5295902
docs: clarified prometheus integration behavior (#16724)
michaelvp411 Feb 26, 2025
1cb864b
fix: allow viewOrgRoles for custom roles page (#16722)
jaaydenh Feb 26, 2025
81ef9e9
docs: document new feature stages (#16719)
EdwardAngert Feb 26, 2025
2aa749a
chore(cli): fix test flake caused by agent connect race (#16725)
johnstcn Feb 26, 2025
6b69635
chore: warn user without permissions to view org members (#16721)
jaaydenh Feb 26, 2025
5cdc13b
docs: fix broken links in feature-stages (#16727)
EdwardAngert Feb 26, 2025
b3d6755
docs: copy edit early access section in feature-stages doc (#16730)
EdwardAngert Feb 27, 2025
95363c9
fix(enterprise/coderd): remove useless provisioner daemon id from req…
johnstcn Feb 27, 2025
6dd51f9
chore: test metricscache on postgres (#16711)
DanielleMaywood Feb 27, 2025
4ba5a8a
feat(agent): add connection reporting for SSH and reconnecting PTY (#…
mafredri Feb 27, 2025
cccdf1e
feat: implement WorkspaceCreationBan org role (#16686)
Emyrk Feb 27, 2025
464fccd
chore: create collapsible summary component (#16705)
jaaydenh Feb 27, 2025
bf5b002
fix: add org role read permissions to site wide template admins and a…
jaaydenh Feb 27, 2025
91a4a98
chore: add an unassign action for roles (#16728)
aslilac Feb 27, 2025
0ea0601
fix: handle undefined job while updating build progress (#16732)
mtojek Feb 27, 2025
7e33902
chore: use org-scoped roles for organization groups and members e2e t…
aslilac Feb 27, 2025
b23e05b
fix(vpn): fail early if wintun.dll is not present (#16707)
deansheather Feb 28, 2025
3997eee
chore: update tailscale (#16737)
deansheather Feb 28, 2025
64fec8b
feat: include winres metadata in Windows binaries (#16706)
deansheather Feb 28, 2025
ec44f06
feat(cli): allow SSH command to connect to running container (#16726)
johnstcn Feb 28, 2025
6889ad2
fix(agent/agentcontainers): remove empty warning if no containers exi…
johnstcn Feb 28, 2025
e27953d
fix(site): add a beta badge for presets (#16751)
SasSwart Feb 28, 2025
930816f
fix: locate Terraform entrypoint file (#16753)
mtojek Feb 28, 2025
4216e28
fix: editor: fallback to default entrypoint (#16757)
mtojek Feb 28, 2025
fc2815c
docs: fix anchor and repo links (#16555)
guspan-tanadi Mar 2, 2025
ca23abe
feat(provisioner): add support for workspace_owner_rbac_roles (#16407)
nxf5025 Mar 2, 2025
d0e2060
feat(agent): add second SSH listener on port 22 (#16627)
ThomasK33 Mar 3, 2025
c074f77
feat: add notifications inbox db (#16599)
defelmnq Mar 3, 2025
a5842e5
docs: document default GitHub OAuth2 configuration and device flow (#…
hugodutka Mar 3, 2025
9c5d496
docs: suggest disabling the default GitHub OAuth2 provider on k8s (#1…
hugodutka Mar 3, 2025
0f4f6bd
docs: describe default sign up behavior with GitHub (#16765)
hugodutka Mar 3, 2025
88f0131
fix: use dbtime in dbmem query to fix flake (#16773)
ethanndickson Mar 3, 2025
04c3396
refactor: replace `golang.org/x/exp/slices` with `slices` (#16772)
Juneezee Mar 3, 2025
ca23abc
chore(cli): fix test flake in TestSSH_Container/NotFound (#16771)
johnstcn Mar 3, 2025
7dc05cc
feat: enable agent connection reports by default, remove flag
mafredri Mar 3, 2025
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
feat: implement WorkspaceCreationBan org role (#16686)
Using negative permissions, this role prevents a user's ability to
create & delete a workspace within a given organization.

Workspaces are uniquely owned by an org and a user, so the org has to
supercede the user permission with a negative permission.

# Use case

Organizations must be able to restrict a member's ability to create a
workspace. This permission is implicitly granted (see
#16546 (comment)).

To revoke this permission, the solution chosen was to use negative
permissions in a built in role called `WorkspaceCreationBan`.

# Rational

Using negative permissions is new territory, and not ideal. However,
workspaces are in a unique position.

Workspaces have 2 owners. The organization and the user. To prevent
users from creating a workspace in another organization, an [implied
negative
permission](https://github.com/coder/coder/blob/36d9f5ddb3d98029fee07d004709e1e51022e979/coderd/rbac/policy.rego#L172-L192)
is used. So the truth table looks like: _how to read this table
[here](https://github.com/coder/coder/blob/36d9f5ddb3d98029fee07d004709e1e51022e979/coderd/rbac/README.md#roles)_

| Role (example)  | Site | Org  | User | Result |
|-----------------|------|------|------|--------|
| non-org-member  | \_   | N    | YN\_ | N      |
| user            | \_   | \_   | Y    | Y      |
| WorkspaceBan    | \_   | N    | Y    | Y      |
| unauthenticated | \_   | \_   | \_   | N      |


This new role, `WorkspaceCreationBan` is the same truth table condition
as if the user was not a member of the organization (when doing a
workspace create/delete). So this behavior **is not entirely new**.

<details>

<summary>How to do it without a negative permission</summary>

The alternate approach would be to remove the implied permission, and
grant it via and organization role. However this would add new behavior
that an organizational role has the ability to grant a user permissions
on their own resources?

It does not make sense for an org role to prevent user from changing
their profile information for example. So the only option is to create a
new truth table column for resources that are owned by both an
organization and a user.

| Role (example)  | Site | Org  |User+Org| User | Result |
|-----------------|------|------|--------|------|--------|
| non-org-member  | \_   | N    |  \_    | \_   | N      |
| user            | \_   | \_   |  \_    | \_   | N      |
| WorkspaceAllow  | \_   | \_   |   Y    | \_   | Y      |
| unauthenticated | \_   | \_   |  \_    | \_   | N      |

Now a user has no opinion on if they can create a workspace, which feels
a little wrong. A user should have the authority over what is theres.

There is fundamental _philosophical_ question of "Who does a workspace
belong to?". The user has some set of autonomy, yet it is the
organization that controls it's existence. A head scratcher 🤔

</details>

## Will we need more negative built in roles?

There are few resources that have shared ownership. Only
`ResourceOrganizationMember` and `ResourceGroupMember`. Since negative
permissions is intended to revoke access to a shared resource, then
**no.** **This is the only one we need**.

Classic resources like `ResourceTemplate` are entirely controlled by the
Organization permissions. And resources entirely in the user control
(like user profile) are only controlled by `User` permissions.


![Uploading Screenshot 2025-02-26 at 22.26.52.png…]()

---------

Co-authored-by: Jaayden Halko <jaayden.halko@gmail.com>
Co-authored-by: ケイラ <mckayla@hey.com>
  • Loading branch information
3 people authored Feb 27, 2025
commit cccdf1ecac805fd8b83ad2e05b8747968fc2f933
10 changes: 6 additions & 4 deletions coderd/httpapi/httpapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,13 @@ func ResourceNotFound(rw http.ResponseWriter) {
Write(context.Background(), rw, http.StatusNotFound, ResourceNotFoundResponse)
}

var ResourceForbiddenResponse = codersdk.Response{
Message: "Forbidden.",
Detail: "You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials.",
}

func Forbidden(rw http.ResponseWriter) {
Write(context.Background(), rw, http.StatusForbidden, codersdk.Response{
Message: "Forbidden.",
Detail: "You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials.",
})
Write(context.Background(), rw, http.StatusForbidden, ResourceForbiddenResponse)
}

func InternalServerError(rw http.ResponseWriter, err error) {
Expand Down
107 changes: 72 additions & 35 deletions coderd/rbac/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ const (
customSiteRole string = "custom-site-role"
customOrganizationRole string = "custom-organization-role"

orgAdmin string = "organization-admin"
orgMember string = "organization-member"
orgAuditor string = "organization-auditor"
orgUserAdmin string = "organization-user-admin"
orgTemplateAdmin string = "organization-template-admin"
orgAdmin string = "organization-admin"
orgMember string = "organization-member"
orgAuditor string = "organization-auditor"
orgUserAdmin string = "organization-user-admin"
orgTemplateAdmin string = "organization-template-admin"
orgWorkspaceCreationBan string = "organization-workspace-creation-ban"
)

func init() {
Expand Down Expand Up @@ -159,6 +160,10 @@ func RoleOrgTemplateAdmin() string {
return orgTemplateAdmin
}

func RoleOrgWorkspaceCreationBan() string {
return orgWorkspaceCreationBan
}

// ScopedRoleOrgAdmin is the org role with the organization ID
func ScopedRoleOrgAdmin(organizationID uuid.UUID) RoleIdentifier {
return RoleIdentifier{Name: RoleOrgAdmin(), OrganizationID: organizationID}
Expand All @@ -181,6 +186,10 @@ func ScopedRoleOrgTemplateAdmin(organizationID uuid.UUID) RoleIdentifier {
return RoleIdentifier{Name: RoleOrgTemplateAdmin(), OrganizationID: organizationID}
}

func ScopedRoleOrgWorkspaceCreationBan(organizationID uuid.UUID) RoleIdentifier {
return RoleIdentifier{Name: RoleOrgWorkspaceCreationBan(), OrganizationID: organizationID}
}

func allPermsExcept(excepts ...Objecter) []Permission {
resources := AllResources()
var perms []Permission
Expand Down Expand Up @@ -496,6 +505,31 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
User: []Permission{},
}
},
// orgWorkspaceCreationBan prevents creating & deleting workspaces. This
// overrides any permissions granted by the org or user level. It accomplishes
// this by using negative permissions.
orgWorkspaceCreationBan: func(organizationID uuid.UUID) Role {
return Role{
Identifier: RoleIdentifier{Name: orgWorkspaceCreationBan, OrganizationID: organizationID},
DisplayName: "Organization Workspace Creation Ban",
Site: []Permission{},
Org: map[string][]Permission{
organizationID.String(): {
{
Negate: true,
ResourceType: ResourceWorkspace.Type,
Action: policy.ActionCreate,
},
{
Negate: true,
ResourceType: ResourceWorkspace.Type,
Action: policy.ActionDelete,
},
},
},
User: []Permission{},
}
},
}
}

Expand All @@ -506,44 +540,47 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
// map[actor_role][assign_role]<can_assign>
var assignRoles = map[string]map[string]bool{
"system": {
owner: true,
auditor: true,
member: true,
orgAdmin: true,
orgMember: true,
orgAuditor: true,
orgUserAdmin: true,
orgTemplateAdmin: true,
templateAdmin: true,
userAdmin: true,
customSiteRole: true,
customOrganizationRole: true,
owner: true,
auditor: true,
member: true,
orgAdmin: true,
orgMember: true,
orgAuditor: true,
orgUserAdmin: true,
orgTemplateAdmin: true,
orgWorkspaceCreationBan: true,
templateAdmin: true,
userAdmin: true,
customSiteRole: true,
customOrganizationRole: true,
},
owner: {
owner: true,
auditor: true,
member: true,
orgAdmin: true,
orgMember: true,
orgAuditor: true,
orgUserAdmin: true,
orgTemplateAdmin: true,
templateAdmin: true,
userAdmin: true,
customSiteRole: true,
customOrganizationRole: true,
owner: true,
auditor: true,
member: true,
orgAdmin: true,
orgMember: true,
orgAuditor: true,
orgUserAdmin: true,
orgTemplateAdmin: true,
orgWorkspaceCreationBan: true,
templateAdmin: true,
userAdmin: true,
customSiteRole: true,
customOrganizationRole: true,
},
userAdmin: {
member: true,
orgMember: true,
},
orgAdmin: {
orgAdmin: true,
orgMember: true,
orgAuditor: true,
orgUserAdmin: true,
orgTemplateAdmin: true,
customOrganizationRole: true,
orgAdmin: true,
orgMember: true,
orgAuditor: true,
orgUserAdmin: true,
orgTemplateAdmin: true,
orgWorkspaceCreationBan: true,
customOrganizationRole: true,
},
orgUserAdmin: {
orgMember: true,
Expand Down
18 changes: 15 additions & 3 deletions coderd/rbac/roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ func TestRolePermissions(t *testing.T) {
// Subjects to user
memberMe := authSubject{Name: "member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember()}}}
orgMemberMe := authSubject{Name: "org_member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID)}}}
orgMemberMeBanWorkspace := authSubject{Name: "org_member_me_workspace_ban", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID), rbac.ScopedRoleOrgWorkspaceCreationBan(orgID)}}}
groupMemberMe := authSubject{Name: "group_member_me", Actor: rbac.Subject{ID: currentUser.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.ScopedRoleOrgMember(orgID)}, Groups: []string{groupID.String()}}}

owner := authSubject{Name: "owner", Actor: rbac.Subject{ID: adminID.String(), Roles: rbac.RoleIdentifiers{rbac.RoleMember(), rbac.RoleOwner()}}}
Expand Down Expand Up @@ -181,20 +182,30 @@ func TestRolePermissions(t *testing.T) {
Actions: []policy.Action{policy.ActionRead},
Resource: rbac.ResourceWorkspace.WithID(workspaceID).InOrg(orgID).WithOwner(currentUser.String()),
AuthorizeMap: map[bool][]hasAuthSubjects{
true: {owner, orgMemberMe, orgAdmin, templateAdmin, orgTemplateAdmin},
true: {owner, orgMemberMe, orgAdmin, templateAdmin, orgTemplateAdmin, orgMemberMeBanWorkspace},
false: {setOtherOrg, memberMe, userAdmin, orgAuditor, orgUserAdmin},
},
},
{
Name: "C_RDMyWorkspaceInOrg",
Name: "UpdateMyWorkspaceInOrg",
// When creating the WithID won't be set, but it does not change the result.
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
Actions: []policy.Action{policy.ActionUpdate},
Resource: rbac.ResourceWorkspace.WithID(workspaceID).InOrg(orgID).WithOwner(currentUser.String()),
AuthorizeMap: map[bool][]hasAuthSubjects{
true: {owner, orgMemberMe, orgAdmin},
false: {setOtherOrg, memberMe, userAdmin, templateAdmin, orgTemplateAdmin, orgUserAdmin, orgAuditor},
},
},
{
Name: "CreateDeleteMyWorkspaceInOrg",
// When creating the WithID won't be set, but it does not change the result.
Actions: []policy.Action{policy.ActionCreate, policy.ActionDelete},
Resource: rbac.ResourceWorkspace.WithID(workspaceID).InOrg(orgID).WithOwner(currentUser.String()),
AuthorizeMap: map[bool][]hasAuthSubjects{
true: {owner, orgMemberMe, orgAdmin},
false: {setOtherOrg, memberMe, userAdmin, templateAdmin, orgTemplateAdmin, orgUserAdmin, orgAuditor, orgMemberMeBanWorkspace},
},
},
{
Name: "MyWorkspaceInOrgExecution",
// When creating the WithID won't be set, but it does not change the result.
Expand Down Expand Up @@ -942,6 +953,7 @@ func TestListRoles(t *testing.T) {
fmt.Sprintf("organization-auditor:%s", orgID.String()),
fmt.Sprintf("organization-user-admin:%s", orgID.String()),
fmt.Sprintf("organization-template-admin:%s", orgID.String()),
fmt.Sprintf("organization-workspace-creation-ban:%s", orgID.String()),
},
orgRoleNames)
}
Expand Down
48 changes: 48 additions & 0 deletions coderd/workspaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,54 @@ func TestWorkspace(t *testing.T) {
require.Error(t, err, "create workspace with archived version")
require.ErrorContains(t, err, "Archived template versions cannot")
})

t.Run("WorkspaceBan", func(t *testing.T) {
t.Parallel()
owner, _, _ := coderdtest.NewWithAPI(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
first := coderdtest.CreateFirstUser(t, owner)

version := coderdtest.CreateTemplateVersion(t, owner, first.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJobCompleted(t, owner, version.ID)
template := coderdtest.CreateTemplate(t, owner, first.OrganizationID, version.ID)

goodClient, _ := coderdtest.CreateAnotherUser(t, owner, first.OrganizationID)

// When a user with workspace-creation-ban
client, user := coderdtest.CreateAnotherUser(t, owner, first.OrganizationID, rbac.ScopedRoleOrgWorkspaceCreationBan(first.OrganizationID))

// Ensure a similar user can create a workspace
coderdtest.CreateWorkspace(t, goodClient, template.ID)

ctx := testutil.Context(t, testutil.WaitLong)
// Then: Cannot create a workspace
_, err := client.CreateUserWorkspace(ctx, codersdk.Me, codersdk.CreateWorkspaceRequest{
TemplateID: template.ID,
TemplateVersionID: uuid.UUID{},
Name: "random",
})
require.Error(t, err)
var apiError *codersdk.Error
require.ErrorAs(t, err, &apiError)
require.Equal(t, http.StatusForbidden, apiError.StatusCode())

// When: workspace-ban use has a workspace
wrk, err := owner.CreateUserWorkspace(ctx, user.ID.String(), codersdk.CreateWorkspaceRequest{
TemplateID: template.ID,
TemplateVersionID: uuid.UUID{},
Name: "random",
})
require.NoError(t, err)
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, wrk.LatestBuild.ID)

// Then: They cannot delete said workspace
_, err = client.CreateWorkspaceBuild(ctx, wrk.ID, codersdk.CreateWorkspaceBuildRequest{
Transition: codersdk.WorkspaceTransitionDelete,
ProvisionerState: []byte{},
})
require.Error(t, err)
require.ErrorAs(t, err, &apiError)
require.Equal(t, http.StatusForbidden, apiError.StatusCode())
})
}

func TestResolveAutostart(t *testing.T) {
Expand Down
9 changes: 9 additions & 0 deletions coderd/wsbuilder/wsbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,15 @@ func (b *Builder) authorize(authFunc func(action policy.Action, object rbac.Obje
return BuildError{http.StatusBadRequest, msg, xerrors.New(msg)}
}
if !authFunc(action, b.workspace) {
if authFunc(policy.ActionRead, b.workspace) {
// If the user can read the workspace, but not delete/create/update. Show
// a more helpful error. They are allowed to know the workspace exists.
return BuildError{
Status: http.StatusForbidden,
Message: fmt.Sprintf("You do not have permission to %s this workspace.", action),
Wrapped: xerrors.New(httpapi.ResourceForbiddenResponse.Detail),
}
}
// We use the same wording as the httpapi to avoid leaking the existence of the workspace
return BuildError{http.StatusNotFound, httpapi.ResourceNotFoundResponse.Message, xerrors.New(httpapi.ResourceNotFoundResponse.Message)}
}
Expand Down
11 changes: 6 additions & 5 deletions codersdk/rbacroles.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ const (
RoleUserAdmin string = "user-admin"
RoleAuditor string = "auditor"

RoleOrganizationAdmin string = "organization-admin"
RoleOrganizationMember string = "organization-member"
RoleOrganizationAuditor string = "organization-auditor"
RoleOrganizationTemplateAdmin string = "organization-template-admin"
RoleOrganizationUserAdmin string = "organization-user-admin"
RoleOrganizationAdmin string = "organization-admin"
RoleOrganizationMember string = "organization-member"
RoleOrganizationAuditor string = "organization-auditor"
RoleOrganizationTemplateAdmin string = "organization-template-admin"
RoleOrganizationUserAdmin string = "organization-user-admin"
RoleOrganizationWorkspaceCreationBan string = "organization-workspace-creation-ban"
)
27 changes: 15 additions & 12 deletions enterprise/coderd/roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,11 @@ func TestListRoles(t *testing.T) {
return member.ListOrganizationRoles(ctx, owner.OrganizationID)
},
ExpectedRoles: convertRoles(map[rbac.RoleIdentifier]bool{
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: false,
{Name: codersdk.RoleOrganizationAuditor, OrganizationID: owner.OrganizationID}: false,
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: false,
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: false,
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: false,
{Name: codersdk.RoleOrganizationAuditor, OrganizationID: owner.OrganizationID}: false,
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: false,
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: false,
{Name: codersdk.RoleOrganizationWorkspaceCreationBan, OrganizationID: owner.OrganizationID}: false,
}),
},
{
Expand Down Expand Up @@ -473,10 +474,11 @@ func TestListRoles(t *testing.T) {
return orgAdmin.ListOrganizationRoles(ctx, owner.OrganizationID)
},
ExpectedRoles: convertRoles(map[rbac.RoleIdentifier]bool{
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationAuditor, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationAuditor, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationWorkspaceCreationBan, OrganizationID: owner.OrganizationID}: true,
}),
},
{
Expand Down Expand Up @@ -505,10 +507,11 @@ func TestListRoles(t *testing.T) {
return client.ListOrganizationRoles(ctx, owner.OrganizationID)
},
ExpectedRoles: convertRoles(map[rbac.RoleIdentifier]bool{
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationAuditor, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationAuditor, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: true,
{Name: codersdk.RoleOrganizationWorkspaceCreationBan, OrganizationID: owner.OrganizationID}: true,
}),
},
}
Expand Down
4 changes: 4 additions & 0 deletions site/src/api/typesGenerated.ts

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

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
MockOwnerRole,
MockSiteRoles,
MockUserAdminRole,
MockWorkspaceCreationBanRole,
} from "testHelpers/entities";
import { withDesktopViewport } from "testHelpers/storybook";
import { EditRolesButton } from "./EditRolesButton";
Expand Down Expand Up @@ -41,3 +42,14 @@ export const Loading: Story = {
await userEvent.click(canvas.getByRole("button"));
},
};

export const AdvancedOpen: Story = {
args: {
selectedRoleNames: new Set([MockWorkspaceCreationBanRole.name]),
roles: MockSiteRoles,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.click(canvas.getByRole("button"));
},
};
Loading
Loading
0