背景
#152(Wiki Transformations starter pack 在新 workspace 不可见)已按方案 A修复并合入 dev(commit 07d6f01b):7 个 starter pack 模板 workspace_id 置 NULL(全局),查询层 listForKb/listByWorkspace/findByName 加 OR workspace_id IS NULL。可见性问题确实修好了(已本地复测 WikiTransformationStarterPackGlobalE2ETest 4/4 绿)。
但 方案 A 把 starter pack 变成全局共享行后,带进来一个跨 workspace 的写/删问题:被描述为"只读共享",实际代码并非只读。
问题:全局模板可被任意 workspace 编辑/删除,且影响所有 workspace
WikiTransformationController.verifyTemplateWorkspace:
private void verifyTemplateWorkspace(WikiTransformationEntity t, Long workspaceId) {
long wsId = workspaceId != null ? workspaceId : 1L;
if (t.getWorkspaceId() != null && !t.getWorkspaceId().equals(wsId)) {
throw new MateClawException("err.common.wrong_workspace", 403, "...");
}
}
对 workspace_id IS NULL 的全局模板,t.getWorkspaceId() != null 为 false → 校验对所有 workspace 放行。而 PUT /{id}(update)与 DELETE /{id}(delete,门槛仅 @RequireWorkspaceRole("member"))都复用这同一个校验。
后果:
- 任意 workspace 的 member 都能编辑全局 starter pack,改动命中所有 workspace(单一共享行)。
- 任意 workspace 的 member 都能删除全局 starter pack,删除后对所有 workspace 消失。
- 删除不可恢复:V165 是一次性 Flyway 迁移,删掉不会重新播种。
即一个 workspace 的普通成员可以把开箱即用模板从全平台改坏或删除。
复现
- workspace B(≠1)的 member 登录
DELETE /api/v1/wiki/transformations/{starterPackId}(如 1000004001),带 X-Workspace-Id: B
- 返回 200,模板被删
- 任意其它 workspace(含 workspace 1)的 Transformations 列表里该模板消失,且无法恢复
建议修复
把 null-workspace 模板视为"系统所有、对所有 workspace 只读",在写路径拒绝改动全局模板。例如在 update/delete 入口(或专门的校验里)加:
if (t.getWorkspaceId() == null) {
throw new MateClawException("err.wiki.global_template_readonly", 403,
"Built-in global templates are read-only");
}
verifyTemplateWorkspace 当前的"放行"语义只适合读/应用(查看、apply 全局模板对所有 workspace 合理),不适合改/删。建议读写分离:读/apply 放行 null-workspace,改/删拒绝 null-workspace。
顺带:findByName 同名碰撞(🟢 minor)
findByName 现在是 workspace_id = ? OR workspace_id IS NULL + LIMIT 1,无确定性排序。若某 workspace 自建了与 starter pack 同名的模板,可能返回全局那条(修复前确定返回本地那条)。建议排序让 workspace-local 优先于 global(如 workspace_id 非空优先)。
关联
背景
#152(Wiki Transformations starter pack 在新 workspace 不可见)已按方案 A修复并合入
dev(commit07d6f01b):7 个 starter pack 模板workspace_id置 NULL(全局),查询层listForKb/listByWorkspace/findByName加OR workspace_id IS NULL。可见性问题确实修好了(已本地复测WikiTransformationStarterPackGlobalE2ETest4/4 绿)。但 方案 A 把 starter pack 变成全局共享行后,带进来一个跨 workspace 的写/删问题:被描述为"只读共享",实际代码并非只读。
问题:全局模板可被任意 workspace 编辑/删除,且影响所有 workspace
WikiTransformationController.verifyTemplateWorkspace:对
workspace_id IS NULL的全局模板,t.getWorkspaceId() != null为 false → 校验对所有 workspace 放行。而PUT /{id}(update)与DELETE /{id}(delete,门槛仅@RequireWorkspaceRole("member"))都复用这同一个校验。后果:
即一个 workspace 的普通成员可以把开箱即用模板从全平台改坏或删除。
复现
DELETE /api/v1/wiki/transformations/{starterPackId}(如1000004001),带X-Workspace-Id: B建议修复
把 null-workspace 模板视为"系统所有、对所有 workspace 只读",在写路径拒绝改动全局模板。例如在 update/delete 入口(或专门的校验里)加:
verifyTemplateWorkspace当前的"放行"语义只适合读/应用(查看、apply 全局模板对所有 workspace 合理),不适合改/删。建议读写分离:读/apply 放行 null-workspace,改/删拒绝 null-workspace。顺带:
findByName同名碰撞(🟢 minor)findByName现在是workspace_id = ? OR workspace_id IS NULL+LIMIT 1,无确定性排序。若某 workspace 自建了与 starter pack 同名的模板,可能返回全局那条(修复前确定返回本地那条)。建议排序让 workspace-local 优先于 global(如workspace_id非空优先)。关联
07d6f01bWikiTransformationStarterPackGlobalE2ETest4/4 绿(可见性已修)