From a73b640c875fbfad303087397e118fe4053d95ca Mon Sep 17 00:00:00 2001 From: matevip Date: Tue, 28 Apr 2026 23:40:21 +0800 Subject: [PATCH] fix(workspace): scope default workspace backfill to admins only Restart-time backfill in WorkspaceSchemaMigration was inserting every existing user into the default workspace and copying mate_user.role ('user'/'admin') into mate_workspace_member.role, whose valid domain is {owner, admin, member, viewer}. Result: non-admin users assigned to other workspaces were silently re-attached to the default workspace with role='user', failing roleLevel() lookup and 403'ing on Agents. - Filter the INSERT on u.role = 'admin' and hard-code the membership role to 'owner', removing the role-domain mismatch and the workspace-isolation violation in one change. - Add V60__fix_invalid_workspace_member_roles.sql (h2 + mysql) to drop already-corrupted default-workspace rows for users who have a valid membership elsewhere, and downgrade the orphan rows to 'member' so those users aren't locked out entirely. Refs https://github.com/matevip/mateclaw/issues/29 --- .../core/config/WorkspaceSchemaMigration.java | 11 ++++---- ...60__fix_invalid_workspace_member_roles.sql | 26 +++++++++++++++++++ ...60__fix_invalid_workspace_member_roles.sql | 26 +++++++++++++++++++ 3 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 mateclaw-server/src/main/resources/db/migration/h2/V60__fix_invalid_workspace_member_roles.sql create mode 100644 mateclaw-server/src/main/resources/db/migration/mysql/V60__fix_invalid_workspace_member_roles.sql diff --git a/mateclaw-server/src/main/java/vip/mate/workspace/core/config/WorkspaceSchemaMigration.java b/mateclaw-server/src/main/java/vip/mate/workspace/core/config/WorkspaceSchemaMigration.java index 35547b86..cb57ef16 100644 --- a/mateclaw-server/src/main/java/vip/mate/workspace/core/config/WorkspaceSchemaMigration.java +++ b/mateclaw-server/src/main/java/vip/mate/workspace/core/config/WorkspaceSchemaMigration.java @@ -60,26 +60,27 @@ public class WorkspaceSchemaMigration implements ApplicationRunner { } /** - * 确保所有现有用户都是默认工作区的成员 + * Ensure all admin users have an owner-role membership in the default workspace. + * Non-admin users must be added explicitly via WorkspaceController.addMember. */ private void ensureDefaultWorkspaceMembership() { try { - // 查找不在默认工作区中的用户 int inserted = jdbcTemplate.update(""" INSERT INTO mate_workspace_member (id, workspace_id, user_id, role, create_time, update_time, deleted) - SELECT u.id, 1, u.id, CASE WHEN u.role = 'admin' THEN 'owner' ELSE u.role END, NOW(), NOW(), 0 + SELECT u.id, 1, u.id, 'owner', NOW(), NOW(), 0 FROM mate_user u WHERE u.deleted = 0 + AND u.role = 'admin' AND NOT EXISTS ( SELECT 1 FROM mate_workspace_member wm WHERE wm.workspace_id = 1 AND wm.user_id = u.id AND wm.deleted = 0 ) """); if (inserted > 0) { - log.info("Added {} existing user(s) to default workspace", inserted); + log.info("Added {} admin user(s) as owner of default workspace", inserted); } } catch (DataAccessException e) { - log.debug("Skipping default workspace membership init: {}", e.getMessage()); + log.debug("Skipping default workspace admin membership init: {}", e.getMessage()); } } } diff --git a/mateclaw-server/src/main/resources/db/migration/h2/V60__fix_invalid_workspace_member_roles.sql b/mateclaw-server/src/main/resources/db/migration/h2/V60__fix_invalid_workspace_member_roles.sql new file mode 100644 index 00000000..c569cdb1 --- /dev/null +++ b/mateclaw-server/src/main/resources/db/migration/h2/V60__fix_invalid_workspace_member_roles.sql @@ -0,0 +1,26 @@ +-- RFC-076: clean up invalid workspace_member rows produced by the legacy +-- WorkspaceSchemaMigration.ensureDefaultWorkspaceMembership() insert +-- (issue: https://github.com/matevip/mateclaw/issues/29). + +-- 1) For users who already have a valid membership in another workspace, +-- drop their illegal default-workspace membership. +DELETE FROM mate_workspace_member +WHERE workspace_id = 1 + AND deleted = 0 + AND role NOT IN ('owner', 'admin', 'member', 'viewer') + AND user_id IN ( + SELECT user_id FROM ( + SELECT user_id FROM mate_workspace_member + WHERE workspace_id <> 1 + AND deleted = 0 + AND role IN ('owner', 'admin', 'member', 'viewer') + ) t + ); + +-- 2) For orphans whose only membership is the illegal default one, +-- normalize the role to 'member' so they don't get locked out entirely. +UPDATE mate_workspace_member +SET role = 'member', update_time = NOW() +WHERE workspace_id = 1 + AND deleted = 0 + AND role NOT IN ('owner', 'admin', 'member', 'viewer'); diff --git a/mateclaw-server/src/main/resources/db/migration/mysql/V60__fix_invalid_workspace_member_roles.sql b/mateclaw-server/src/main/resources/db/migration/mysql/V60__fix_invalid_workspace_member_roles.sql new file mode 100644 index 00000000..c569cdb1 --- /dev/null +++ b/mateclaw-server/src/main/resources/db/migration/mysql/V60__fix_invalid_workspace_member_roles.sql @@ -0,0 +1,26 @@ +-- RFC-076: clean up invalid workspace_member rows produced by the legacy +-- WorkspaceSchemaMigration.ensureDefaultWorkspaceMembership() insert +-- (issue: https://github.com/matevip/mateclaw/issues/29). + +-- 1) For users who already have a valid membership in another workspace, +-- drop their illegal default-workspace membership. +DELETE FROM mate_workspace_member +WHERE workspace_id = 1 + AND deleted = 0 + AND role NOT IN ('owner', 'admin', 'member', 'viewer') + AND user_id IN ( + SELECT user_id FROM ( + SELECT user_id FROM mate_workspace_member + WHERE workspace_id <> 1 + AND deleted = 0 + AND role IN ('owner', 'admin', 'member', 'viewer') + ) t + ); + +-- 2) For orphans whose only membership is the illegal default one, +-- normalize the role to 'member' so they don't get locked out entirely. +UPDATE mate_workspace_member +SET role = 'member', update_time = NOW() +WHERE workspace_id = 1 + AND deleted = 0 + AND role NOT IN ('owner', 'admin', 'member', 'viewer');