mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add service_accounts workspace sharing mode (#23093)
Introduce a three-way workspace sharing setting (none, everyone, service_accounts) replacing the boolean workspace_sharing_disabled. In service_accounts mode, only service account-owned workspaces can be shared while regular members' share permissions are removed. Adds a new organization-service-account system role with per-org permissions reconciled alongside the existing organization-member system role. Related to: https://linear.app/codercom/issue/PLAT-28/feat-service-accounts-sharing-mode-and-rbac-role --------- Co-authored-by: Steven Masley <Emyrk@users.noreply.github.com> Co-authored-by: Kayla はな <mckayla@hey.com>
This commit is contained in:
co-authored by
Steven Masley
Kayla はな
parent
6b76e30321
commit
91ec0f1484
@@ -11035,7 +11035,7 @@ func (q *sqlQuerier) UpdateMemberRoles(ctx context.Context, arg UpdateMemberRole
|
||||
|
||||
const getDefaultOrganization = `-- name: GetDefaultOrganization :one
|
||||
SELECT
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, workspace_sharing_disabled
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, shareable_workspace_owners
|
||||
FROM
|
||||
organizations
|
||||
WHERE
|
||||
@@ -11057,14 +11057,14 @@ func (q *sqlQuerier) GetDefaultOrganization(ctx context.Context) (Organization,
|
||||
&i.DisplayName,
|
||||
&i.Icon,
|
||||
&i.Deleted,
|
||||
&i.WorkspaceSharingDisabled,
|
||||
&i.ShareableWorkspaceOwners,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getOrganizationByID = `-- name: GetOrganizationByID :one
|
||||
SELECT
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, workspace_sharing_disabled
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, shareable_workspace_owners
|
||||
FROM
|
||||
organizations
|
||||
WHERE
|
||||
@@ -11084,14 +11084,14 @@ func (q *sqlQuerier) GetOrganizationByID(ctx context.Context, id uuid.UUID) (Org
|
||||
&i.DisplayName,
|
||||
&i.Icon,
|
||||
&i.Deleted,
|
||||
&i.WorkspaceSharingDisabled,
|
||||
&i.ShareableWorkspaceOwners,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getOrganizationByName = `-- name: GetOrganizationByName :one
|
||||
SELECT
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, workspace_sharing_disabled
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, shareable_workspace_owners
|
||||
FROM
|
||||
organizations
|
||||
WHERE
|
||||
@@ -11120,7 +11120,7 @@ func (q *sqlQuerier) GetOrganizationByName(ctx context.Context, arg GetOrganizat
|
||||
&i.DisplayName,
|
||||
&i.Icon,
|
||||
&i.Deleted,
|
||||
&i.WorkspaceSharingDisabled,
|
||||
&i.ShareableWorkspaceOwners,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -11191,7 +11191,7 @@ func (q *sqlQuerier) GetOrganizationResourceCountByID(ctx context.Context, organ
|
||||
|
||||
const getOrganizations = `-- name: GetOrganizations :many
|
||||
SELECT
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, workspace_sharing_disabled
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, shareable_workspace_owners
|
||||
FROM
|
||||
organizations
|
||||
WHERE
|
||||
@@ -11235,7 +11235,7 @@ func (q *sqlQuerier) GetOrganizations(ctx context.Context, arg GetOrganizationsP
|
||||
&i.DisplayName,
|
||||
&i.Icon,
|
||||
&i.Deleted,
|
||||
&i.WorkspaceSharingDisabled,
|
||||
&i.ShareableWorkspaceOwners,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -11252,7 +11252,7 @@ func (q *sqlQuerier) GetOrganizations(ctx context.Context, arg GetOrganizationsP
|
||||
|
||||
const getOrganizationsByUserID = `-- name: GetOrganizationsByUserID :many
|
||||
SELECT
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, workspace_sharing_disabled
|
||||
id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, shareable_workspace_owners
|
||||
FROM
|
||||
organizations
|
||||
WHERE
|
||||
@@ -11297,7 +11297,7 @@ func (q *sqlQuerier) GetOrganizationsByUserID(ctx context.Context, arg GetOrgani
|
||||
&i.DisplayName,
|
||||
&i.Icon,
|
||||
&i.Deleted,
|
||||
&i.WorkspaceSharingDisabled,
|
||||
&i.ShareableWorkspaceOwners,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -11317,7 +11317,7 @@ INSERT INTO
|
||||
organizations (id, "name", display_name, description, icon, created_at, updated_at, is_default)
|
||||
VALUES
|
||||
-- If no organizations exist, and this is the first, make it the default.
|
||||
($1, $2, $3, $4, $5, $6, $7, (SELECT TRUE FROM organizations LIMIT 1) IS NULL) RETURNING id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, workspace_sharing_disabled
|
||||
($1, $2, $3, $4, $5, $6, $7, (SELECT TRUE FROM organizations LIMIT 1) IS NULL) RETURNING id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, shareable_workspace_owners
|
||||
`
|
||||
|
||||
type InsertOrganizationParams struct {
|
||||
@@ -11351,7 +11351,7 @@ func (q *sqlQuerier) InsertOrganization(ctx context.Context, arg InsertOrganizat
|
||||
&i.DisplayName,
|
||||
&i.Icon,
|
||||
&i.Deleted,
|
||||
&i.WorkspaceSharingDisabled,
|
||||
&i.ShareableWorkspaceOwners,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -11367,7 +11367,7 @@ SET
|
||||
icon = $5
|
||||
WHERE
|
||||
id = $6
|
||||
RETURNING id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, workspace_sharing_disabled
|
||||
RETURNING id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, shareable_workspace_owners
|
||||
`
|
||||
|
||||
type UpdateOrganizationParams struct {
|
||||
@@ -11399,7 +11399,7 @@ func (q *sqlQuerier) UpdateOrganization(ctx context.Context, arg UpdateOrganizat
|
||||
&i.DisplayName,
|
||||
&i.Icon,
|
||||
&i.Deleted,
|
||||
&i.WorkspaceSharingDisabled,
|
||||
&i.ShareableWorkspaceOwners,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -11428,21 +11428,21 @@ const updateOrganizationWorkspaceSharingSettings = `-- name: UpdateOrganizationW
|
||||
UPDATE
|
||||
organizations
|
||||
SET
|
||||
workspace_sharing_disabled = $1,
|
||||
shareable_workspace_owners = $1,
|
||||
updated_at = $2
|
||||
WHERE
|
||||
id = $3
|
||||
RETURNING id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, workspace_sharing_disabled
|
||||
RETURNING id, name, description, created_at, updated_at, is_default, display_name, icon, deleted, shareable_workspace_owners
|
||||
`
|
||||
|
||||
type UpdateOrganizationWorkspaceSharingSettingsParams struct {
|
||||
WorkspaceSharingDisabled bool `db:"workspace_sharing_disabled" json:"workspace_sharing_disabled"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
ShareableWorkspaceOwners ShareableWorkspaceOwners `db:"shareable_workspace_owners" json:"shareable_workspace_owners"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateOrganizationWorkspaceSharingSettings(ctx context.Context, arg UpdateOrganizationWorkspaceSharingSettingsParams) (Organization, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateOrganizationWorkspaceSharingSettings, arg.WorkspaceSharingDisabled, arg.UpdatedAt, arg.ID)
|
||||
row := q.db.QueryRowContext(ctx, updateOrganizationWorkspaceSharingSettings, arg.ShareableWorkspaceOwners, arg.UpdatedAt, arg.ID)
|
||||
var i Organization
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
@@ -11454,7 +11454,7 @@ func (q *sqlQuerier) UpdateOrganizationWorkspaceSharingSettings(ctx context.Cont
|
||||
&i.DisplayName,
|
||||
&i.Icon,
|
||||
&i.Deleted,
|
||||
&i.WorkspaceSharingDisabled,
|
||||
&i.ShareableWorkspaceOwners,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -19373,9 +19373,21 @@ SELECT
|
||||
array_agg(org_roles || ':' || organization_members.organization_id::text)
|
||||
FROM
|
||||
organization_members,
|
||||
-- All org_members get the organization-member role for their orgs
|
||||
-- All org members get an implied role for their orgs. Most members
|
||||
-- get organization-member, but service accounts will get
|
||||
-- organization-service-account instead. They're largely the same,
|
||||
-- but having them be distinct means we can allow configuring
|
||||
-- service-accounts to have slightly broader permissions–such as
|
||||
-- for workspace sharing.
|
||||
unnest(
|
||||
array_append(roles, 'organization-member')
|
||||
array_append(
|
||||
roles,
|
||||
CASE WHEN users.is_service_account THEN
|
||||
'organization-service-account'
|
||||
ELSE
|
||||
'organization-member'
|
||||
END
|
||||
)
|
||||
) AS org_roles
|
||||
WHERE
|
||||
user_id = users.id
|
||||
@@ -25466,10 +25478,21 @@ SET
|
||||
user_acl = '{}'::jsonb
|
||||
WHERE
|
||||
organization_id = $1
|
||||
AND (
|
||||
NOT $2::boolean
|
||||
OR owner_id NOT IN (
|
||||
SELECT id FROM users WHERE is_service_account = true
|
||||
)
|
||||
)
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) DeleteWorkspaceACLsByOrganization(ctx context.Context, organizationID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteWorkspaceACLsByOrganization, organizationID)
|
||||
type DeleteWorkspaceACLsByOrganizationParams struct {
|
||||
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
|
||||
ExcludeServiceAccounts bool `db:"exclude_service_accounts" json:"exclude_service_accounts"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) DeleteWorkspaceACLsByOrganization(ctx context.Context, arg DeleteWorkspaceACLsByOrganizationParams) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteWorkspaceACLsByOrganization, arg.OrganizationID, arg.ExcludeServiceAccounts)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user