Skip to content

refactor: extract organization-workspace-access role#25929

Merged
Emyrk merged 1 commit into
mainfrom
gateway-accounts/extract-workspace-access
Jun 5, 2026
Merged

refactor: extract organization-workspace-access role#25929
Emyrk merged 1 commit into
mainfrom
gateway-accounts/extract-workspace-access

Conversation

@Emyrk

@Emyrk Emyrk commented Jun 1, 2026

Copy link
Copy Markdown
Member

Refs PLAT-217.

Extracts an organization-workspace-access role so workspace elevation can be split off the organization-member floor without changing behavior.

  • New role holds the workspace-side resources currently granted by organization-member.
  • The MinimumImplicitMember floor preserves the existing behavior until feat(coderd): gate org-member workspace elevation behind experiment #26027 shrinks it.
  • Prebuilds orchestrator inserts memberships via dbauthz.AsSystemRestricted and no longer needs OrganizationMember or AssignOrgRole grants.
Agent context
  • coderd/rbac/roles.go: OrgWorkspaceAccessMemberPerms() grants Workspace, WorkspaceDormant, File (Create+Read), ProvisionerDaemon (Create+Read), and Task. Deliberate omissions (Template, Group, WorkspaceProxy, etc.) are documented inline.
  • coderd/rbac/roles_test.go: orgWorkspaceAccessUser is added to requiredSubjects. UserProvisionerDaemons is split into UserProvisionerDaemonsCreate and UserProvisionerDaemonsUpdateDelete because the new role grants Create+Read only and the test framework requires uniform pass/fail per case.
  • codersdk/rbacroles.go: exposes RoleOrganizationWorkspaceAccess.
  • enterprise/coderd/prebuilds/membership.go: InsertOrganizationMember runs under dbauthz.AsSystemRestricted. The orchestrator never acts with the elevation role; the membership row only exists so prebuilt workspaces have a valid owner.
  • coderd/database/dbauthz/dbauthz.go: drops the now-dead OrganizationMember and AssignOrgRole permissions from the prebuilds-orchestrator role and the orchestrator's entry in assignRoles.

Coder Agents on behalf of @Emyrk.

@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch from 665e852 to 39cfee3 Compare June 1, 2026 20:23
@Emyrk Emyrk force-pushed the gateway-accounts/enumerate-org-member branch from 3aa1a66 to 79be71f Compare June 1, 2026 20:39
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch from 39cfee3 to c23f308 Compare June 1, 2026 20:44
@Emyrk Emyrk force-pushed the gateway-accounts/enumerate-org-member branch from 79be71f to 989d98f Compare June 1, 2026 21:03
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch from c23f308 to a75eca2 Compare June 1, 2026 21:04
@Emyrk Emyrk force-pushed the gateway-accounts/enumerate-org-member branch from 989d98f to 5253fe8 Compare June 2, 2026 13:20
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch 2 times, most recently from 23745e1 to 8dc7f14 Compare June 2, 2026 14:13
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go Outdated
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch from 8dc7f14 to e62737a Compare June 2, 2026 14:28
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch from e62737a to 6aef7c0 Compare June 2, 2026 14:44
@Emyrk Emyrk changed the title refactor(coderd/rbac): extract organization-workspace-access role refactor: extract organization-workspace-access role Jun 2, 2026
Comment thread coderd/rbac/roles.go Outdated
Comment on lines +686 to +702
// orgWorkspaceAccess grants the workspace-operations
// capabilities org members need to use their workspaces.
// See OrgWorkspaceAccessMemberPerms for the perm set.
orgWorkspaceAccess: func(organizationID uuid.UUID) Role {
return Role{
Identifier: RoleIdentifier{Name: orgWorkspaceAccess, OrganizationID: organizationID},
DisplayName: "Organization Workspace Access",
Site: []Permission{},
User: []Permission{},
ByOrgID: map[string]OrgPermissions{
organizationID.String(): {
Org: []Permission{},
Member: OrgWorkspaceAccessMemberPerms(),
},
},
}
},

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This role will be viewable once this merges. Even though it's a subset of member today.

Hiding it until the split feels like a lot of work for what will likely ship in the same release.

And regardless, having it available early could be useful to configure before the split is adopted. As the split will have to be some opt-in behavior.

Emyrk added a commit that referenced this pull request Jun 2, 2026
…Accounts

Adds the column that drives per-org Gateway Accounts behavior. Effective
roles for an org member at request time are now the union of
organization_members.roles and organizations.default_org_member_roles,
so changes to the org default propagate to every member on the next
request. The deployment-wide default is
'organization-workspace-access', matching today's effective behavior.

The PATCH organization handler accepts the new field but rejects
deviations from the deployment default unless the
minimum-implicit-member experiment is enabled. The experiment constant
ships in this PR so the write-gating has something to check; the floor
shrink behavior lands in a follow-up.

Refs #25936. Stacks on #25929.
Emyrk added a commit that referenced this pull request Jun 2, 2026
…Accounts

Adds the column that drives per-org Gateway Accounts behavior. Effective
roles for an org member at request time are now the union of
organization_members.roles and organizations.default_org_member_roles,
so changes to the org default propagate to every member on the next
request. The deployment-wide default is
'organization-workspace-access', matching today's effective behavior.

The PATCH organization handler accepts the new field but rejects
deviations from the deployment default unless the
minimum-implicit-member experiment is enabled. The experiment constant
ships in this PR so the write-gating has something to check; the floor
shrink behavior lands in a follow-up.

Refs #25936. Stacks on #25929.
Emyrk added a commit that referenced this pull request Jun 2, 2026
…Accounts

Adds the column that drives per-org Gateway Accounts behavior. Effective
roles for an org member at request time are now the union of
organization_members.roles and organizations.default_org_member_roles,
so changes to the org default propagate to every member on the next
request. The deployment-wide default is
'organization-workspace-access', matching today's effective behavior.

The PATCH organization handler accepts the new field but rejects
deviations from the deployment default unless the
minimum-implicit-member experiment is enabled. The experiment constant
ships in this PR so the write-gating has something to check; the floor
shrink behavior lands in a follow-up.

Refs #25936. Stacks on #25929.
Emyrk added a commit that referenced this pull request Jun 2, 2026
…Accounts

Adds the column that drives per-org Gateway Accounts behavior. Effective
roles for an org member at request time are now the union of
organization_members.roles and organizations.default_org_member_roles,
so changes to the org default propagate to every member on the next
request. The deployment-wide default is
'organization-workspace-access', matching today's effective behavior.

The PATCH organization handler accepts the new field but rejects
deviations from the deployment default unless the
minimum-implicit-member experiment is enabled. The experiment constant
ships in this PR so the write-gating has something to check; the floor
shrink behavior lands in a follow-up.

Refs #25936. Stacks on #25929.
Emyrk added a commit that referenced this pull request Jun 2, 2026
…Accounts

Adds the column that drives per-org Gateway Accounts behavior. Effective
roles for an org member at request time are now the union of
organization_members.roles and organizations.default_org_member_roles,
so changes to the org default propagate to every member on the next
request. The deployment-wide default is
'organization-workspace-access', matching today's effective behavior.

The PATCH organization handler accepts the new field but rejects
deviations from the deployment default unless the
minimum-implicit-member experiment is enabled. The experiment constant
ships in this PR so the write-gating has something to check; the floor
shrink behavior lands in a follow-up.

Refs #25936. Stacks on #25929.
@Emyrk Emyrk changed the base branch from gateway-accounts/enumerate-org-member to graphite-base/25929 June 3, 2026 13:14
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch from 6aef7c0 to fb33230 Compare June 3, 2026 13:14
@Emyrk Emyrk force-pushed the graphite-base/25929 branch from 5253fe8 to f1ebc42 Compare June 3, 2026 13:14
@graphite-app graphite-app Bot changed the base branch from graphite-base/25929 to main June 3, 2026 13:15
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch 2 times, most recently from eafa7f5 to 0d366d9 Compare June 3, 2026 13:58
@Emyrk Emyrk changed the title refactor: extract organization-workspace-access role refactor: split organization-member role Jun 3, 2026
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch from 0d366d9 to fa7e9f9 Compare June 3, 2026 14:56
@Emyrk

Emyrk commented Jun 3, 2026

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Chat: Review in progress | View chat
Requested: 2026-06-03 16:26 UTC by @Emyrk

deep-review v0.6.1 | Round 1 | b9c3eea..fa7e9f9

Last posted: Round 1, 10 findings (1 P2, 3 P3, 1 P4, 3 Nit, 2 Note), COMMENT. Review

Finding inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P4 Open coderd/rbac/roles.go:212 ScopedRoleOrgWorkspaceAccess has zero callers R1 Netero Yes
CRF-2 P2 Open PR description GroupMember.read listed under Elevation but code places it in Floor R1 Netero Note, Mafu-san P2 Yes
CRF-3 P3 Open coderd/rbac/roles.go:1153 Floor perm maps duplicated between OrgMemberPermissions and OrgServiceAccountPermissions R1 Kurapika P3, Luffy P3, Meruem P3, Robin P3, Ryosuke P3, Razor P3, Zoro P3 Yes
CRF-4 P3 Open coderd/rbac/roles.go:223 Dormant workspace comment misnames excluded actions and omits Share R1 Leorio P3, Razor P3 Yes
CRF-5 P3 Open coderd/rbac/roles.go:685 Standalone orgWorkspaceAccess role has no authorization test subject R1 Bisky P3, Chopper P3, Knov P3 Yes
CRF-6 Nit Open coderd/rbac/roles.go:682 Several comments restate what code shows; pattern across 9 of 21 comments R1 Gon P2 Yes
CRF-7 Nit Open coderd/rbac/roles.go:216 Doc comment understates OrgWorkspaceAccessMemberPerms blast radius (3 callers) R1 Mafuuu Nit Yes
CRF-8 Nit Open commit message Commit scope coderd/rbac doesn't contain all changed files R1 Leorio Nit Yes
CRF-9 Note Open coderd/rbac/roles.go:694 Standalone role grants ActionShare without negate; safe via orgMember co-assignment R1 Hisoka P3, Knov Note, Mafuuu Note, Meruem Note, Razor Note Yes
CRF-10 Note Open coderd/rbac/roles.go:788 prebuildsOrchestrator cannot assign orgWorkspaceAccess (safe today, needed for split) R1 Kite Note, Zoro Note Yes

Round log

Round 1

Panel (19 reviewers: bisky, chopper, ging-go, gon, hisoka, kite, knov, kurapika, leorio, luffy, mafu-san, mafuuu, melody, meruem, pariston, razor, robin, ryosuke, zoro). Netero first pass clean (1 P4, 1 Note). Panel: 1 P2, 3 P3, 3 Nit, 2 Note. CRF-1 not posted (P4, pre-panel). Reviewed against b9c3eea..fa7e9f9.

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean role extraction. OrgWorkspaceAccessMemberPerms() is defined once and consumed by all three callers (standalone role, OrgMemberPermissions, OrgServiceAccountPermissions). Permission equivalence verified: slices.Concat(elevation, floor) produces the same 42 permissions across 12 resource types as the pre-refactor flat memberPerms. Assignment matrix correctly expanded for system, owner, userAdmin, orgAdmin, orgUserAdmin. All RBAC tests pass.

1 P2, 3 P3, 3 Nit, 2 Note.

"Just a function that returns permissions. That's it. That's the whole feature." Luffy

PS. Commit scope coderd/rbac doesn't contain all changed files (codersdk/rbacroles.go, enterprise/coderd/roles_test.go). Per project convention, omit the scope for cross-cutting changes.

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/rbac/roles.go
Comment thread coderd/rbac/roles.go
Comment thread coderd/rbac/roles.go
Comment thread coderd/rbac/roles.go
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go
Comment thread coderd/rbac/roles.go Outdated
Comment thread coderd/rbac/roles.go
Comment thread codersdk/rbacroles.go
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch 2 times, most recently from e9a3bd8 to 15e4f90 Compare June 3, 2026 21:08
@Emyrk Emyrk changed the title refactor: split organization-member role refactor: extract organization-workspace-access role Jun 3, 2026
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch 2 times, most recently from 32809ee to ecdc5f1 Compare June 3, 2026 21:43
@linear-code

linear-code Bot commented Jun 3, 2026

Copy link
Copy Markdown

PLAT-217

Comment on lines -535 to -543
// Should be able to add the prebuilds system user as a member to any organization that needs prebuilds.
rbac.ResourceOrganizationMember.Type: {
policy.ActionRead,
policy.ActionCreate,
},
// Needs to be able to assign roles to the system user in order to make it a member of an organization.
rbac.ResourceAssignOrgRole.Type: {
policy.ActionAssign,
},

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unfortunate, but with default roles, we need to escalate to the System context when making the prebuild user.

Comment thread coderd/rbac/roles.go
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch from ecdc5f1 to b7ec31f Compare June 3, 2026 21:56
@Emyrk Emyrk marked this pull request as ready for review June 3, 2026 21:56
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch 3 times, most recently from c746ace to eeadd81 Compare June 3, 2026 22:29
@Emyrk Emyrk requested a review from geokat June 4, 2026 14:40
Comment thread enterprise/coderd/prebuilds/membership.go
Comment thread coderd/rbac/roles.go
Introduce the organization-workspace-access role and split the member
and service-account perms into a floor plus an elevation set. The
elevation lives in the new OrgWorkspaceAccessMemberPerms helper and is
mirrored onto the new role; both OrgMemberPermissions and
OrgServiceAccountPermissions compose floor + elevation today, so this
PR is behavior-preserving.

A future PR will gate the elevation on the minimum-implicit-member
experiment so a user without organization-workspace-access has only
the floor. Org admins, owners, user admins, and the system role can
assign the new role.

The helper carries the same "Intentionally omitted at Member scope"
rationale as the prior enumeration so that owner-less resources (e.g.
ResourceTemplate, ResourceWorkspaceProxy) are not re-added by mistake.

TestRolePermissions adds an org_workspace_access subject to
requiredSubjects so the role's coverage is asserted in every test
case. This catches accidental Org/Member swaps in the role wiring
(e.g. attaching the perm set to Org instead of Member).

The prebuilds membership reconciler now wraps its InsertOrganizationMember
call with dbauthz.AsSystemRestricted instead of relying on the
AsPrebuildsOrchestrator context. The prebuilds system user does not
log in or act with its assigned roles; the membership row only exists
so prebuilt workspaces have a valid owner. Routing the assignment
check through the system actor keeps the call working when the
experiment splits workspace ops off organization-member, and removes
the dependency on prebuildsOrchestrator's assignable role map.
@Emyrk Emyrk force-pushed the gateway-accounts/extract-workspace-access branch from eeadd81 to 010e350 Compare June 5, 2026 14:19
@Emyrk Emyrk enabled auto-merge (squash) June 5, 2026 15:30
@Emyrk Emyrk merged commit bec2115 into main Jun 5, 2026
30 of 32 checks passed
@Emyrk Emyrk deleted the gateway-accounts/extract-workspace-access branch June 5, 2026 15:30
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants