Repository navigation
fix(workspaces): sharing lends no more than the sharer holds; restore archived workspaces - #550
Merged
Merged
Conversation
…sharing-limits e2e)
# Conflicts: # apps/web/src/frontend/features/workspaces/index.ts # docs/testing/TEST_IDS.md
…ipts capped too - effectiveMemberRole / cappedRole: every read of a member's role goes through the ceiling. Workspace scripts read the raw stored role, so a colleague stored as editor in a viewer's personal workspace could still save and delete its scripts; the admin list counted them as owners. - requireWorkspacePermission + assertRoleGrantable replace the copies in the directory and invite services. - workspaceGrantCeiling in @foxschema/shared: the dialog offers what the server accepts, from the same rule. - Settings dialog builds its role options once and registers Escape once. - e2e: apiCall / signInAs / browserAs helpers in helpers/accounts.ts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # docs/testing/TEST_IDS.md
A colleague stored as owner of a viewer's personal workspace is a viewer there, but the list sorted by the stored role and put them first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: 7146b014-311c-4104-b553-9c25b35cebe2) |
Contributor
Test IDsAdded (2)
|
This was referenced Oct 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this fixes
Sharing a personal workspace could lend more than its account holds (security). Everyone manages the members of their own workspace, whatever their role there. So a viewer account could invite a colleague as owner. The colleague then had DDL, DML, GRANT and schema migrate on the viewer's saved connections — credentials an admin handed out for reading.
Now:
workspaceRoleCeiling). Every read of a member's role goes through it (effectiveMemberRole/cappedRole), including rows stored before this rule or by an older build. That covers the session's permissions, the workspace list, the members list, the admin list of owners, and workspace scripts. Scripts read the raw role, so a capped colleague could still save and delete them.assertRoleGrantable). This applies to inviting and to changing a member's role, on the server. The settings dialog offers only those roles and says why (workspaceGrantCeilingin@foxschema/shared, the same rule on both sides).requireWorkspacePermission) replaces the copies in the directory and invite services.Archived workspaces can come back. Archiving promised its data is kept, but nothing could restore it. Admins now get Restore in Access control → Workspaces (
POST /workspaces/:id/restore).Escape closes the workspace settings dialog. The listener is registered once and calls the latest
onClose.Smaller:
helpers/accounts.ts(apiCall,signInAs,browserAs).Tests
Every fix was tested both ways: the test fails without the fix and passes with it.
workspace-role-ceiling.test.ts: invite and raise refused above the ceiling, the ceiling follows the account role, a stored-above-ceiling role acts at the ceiling everywhere (permissions, list, members order, scripts, admin owners), and the capped member cannot manage members.WorkspaceSettingsDialog.test.tsx: the roles on offer per account and workspace, Escape, and Escape after a re-render.workspaces-sharing-limits.test.ts(new) plusworkspaces.test.ts: 10/10 pass against this branch's servers.eslint ., security lint: clean.code-cell-executetiming test. It is not touched here, it flakes under machine load, and it failed a different case when re-run alone.Follow-ups (not in this PR)
useDismissablehook.api()copies.🤖 Generated with Claude Code
Note
High Risk
Changes authorization for workspace invites, member roles, and effective permissions (including scripts), plus a new admin restore path—security-sensitive workspace and access-control behavior.
Overview
Closes a workspace sharing privilege-escalation hole: in personal workspaces, members can no longer invite or promote others above what the sharer’s account role allows. The server now caps effective roles on every read (
effectiveMemberRole/cappedRole) and rejects over-grants on invites and member updates (assertRoleGrantable), with shared helpers (workspaceGrantCeiling,workspaceRoleAtMost) mirrored in Workspace settings (disabled role options +workspace-invite-ceilingcopy).Admins can restore archived workspaces via
POST /workspaces/:id/restoreand a Restore control in Access control → Workspaces (archived rows show Restore instead of join/open/members/archive).Smaller UX: Escape dismisses the workspace rail menu and settings dialog. E2E adds
helpers/accounts.tsandworkspaces-sharing-limits.test.ts, wired into the workspaces suite inrun-all.mjs.Reviewed by Cursor Bugbot for commit c530b2a. Bugbot is set up for automated code reviews on this repo. Configure here.