Repository navigation
Conversation
f363fd2 to
44967f2
Compare
# 问题描述(复现步骤)
在知识库目录(MongoDataset type=folder)上配置协作者、生效范围选"所有子级"后,
后代知识库本身的权限正常,但知识库内的文件夹/文件(collection)始终没有该协作者。
复现:F(folder) → D(知识库,开启文件级权限) → CF(folder) → FILE;在 F 上给成员新增
manage,查询 resource_permissions,CF/FILE 仍只有 owner。(TD 2026082400078)
# 根因分析
1a. syncDatasetToCollections 入口用被改节点自身的 collectionPermissionEnabled 短路。
folder 类型永远不会开启文件级权限,于是整棵后代 collection 树被跳过。
1b. 调用顺序错误:collaborator 更新先写 dataset 树,再触发 collection 同步;同步时读到的
后代快照已是新值,diff 为空,提前返回。
1c. resumeInheritPermission 同样在写完 dataset 树后才读取 newEffectiveClbs,跨树 diff 丢失。
修复:
- syncDatasetToCollections 的开关判断下沉到每个 dataset:关闭态 dataset 跳过自身
collection,但继续遍历后代;folder 不再短路整棵树。
- collaborator 更新(pro)与 resumeInheritPermission 改为先同步 collection 再写 dataset
树;resume 在事务内按 merge(父级, 自身) 公式预计算 newEffectiveClbs。
# 测试
- packages/service test/support/permission/collection/controller.test.ts:含 TD 回归、
按 dataset 独立开关、变更前快照顺序契约
- prettier 检查通过
Co-Authored-By: Claude <noreply@anthropic.com>
44967f2 to
d82a520
Compare
c121914yu
left a comment
There was a problem hiding this comment.
基于 d82a520 重新审查:根目录移动相关实现和测试已移除,当前变更范围围绕目录权限下发,范围合理。仍有下列两项问题,其中 Pro 真实入口的调用顺序导致修复尚未闭环。
验证范围:使用此提交的原始 TypeScript 函数和内存数据库/鉴权桩复现新增、撤销、降权及无关分支扫描;恢复继承能够将权限同步到 collection 子树并保留子级额外授权;git diff --check 通过。未复跑 MongoDB/API 测试或全量测试。
建议补充真实 Pro 协作者更新入口的授权、撤销/降权回归,以及非根目录恢复继承后 collection 子树的回归用例。另请同步清理 PR 标题和正文测试说明中已移除的根目录移动内容。
| * 根级继承态 collection 从 oldEffectiveClbs 物化到 newEffectiveClbs,folder 递归同步子树。 | ||
| * 由 dataset 写路径(collaborator/move/resume)在同一事务内调用。幂等(diff 写入)。 | ||
| * | ||
| * 调用约束:必须在 dataset 树写入**之前**调用,`syncDatasetToCollections` 需要读到后代 |
There was a problem hiding this comment.
[P1] 补齐 Pro 真实入口的同步顺序修复
这里新增了“必须在 dataset 树写入之前调用”的约束,但本 PR 固定的 Pro 提交仍为 c089f2836158a39b37b88103801559e34c7eb1c0。该版本 admin/src/service/support/permission/controller.ts:109–123 仍先执行 updateResourceCollaborators(已更新 dataset 及其继承子树),再执行 onUpdated 中的 syncDatasetToCollections。此时读取到的后代 dataset 已是新快照,计算出的后代 old/new 权限相同,collection 同步会提前返回。
使用原始函数和内存仓储复现 F(folder) → D(开启文件级权限) → CF(folder) → FILE:新增 manage 后 D 获得权限,但 CF/FILE 没有;撤销后 CF/FILE 仍保留旧权限;manage 降为 read 后 D 已是 read,CF/FILE 仍为 manage。新增回归测试手动先调用 collection 同步再更新 dataset,未走真实 Pro 入口,因此测试通过仍无法验证生产链路。
请补齐 Pro 的调用顺序修改,并确保依赖版本包含该修复,同时通过真实协作者更新入口验证新增、撤销和降权。
There was a problem hiding this comment.
| const children = await MongoDataset.find( | ||
| { teamId, parentId: currentId }, | ||
| '_id parentId inheritPermission' | ||
| '_id parentId inheritPermission collectionPermissionEnabled' |
There was a problem hiding this comment.
[P2] 在收集阶段剪掉独立子树,并按层批量查询
删除顶部的关闭态短路后,关闭文件权限的 dataset folder 也会进入这段遍历。目前每个节点单独执行一次 MongoDataset.find,且 collectQueue 无条件加入所有子节点;inheritPermission=false 仅在后面的同步阶段跳过,其整棵独立子树仍被扫描并加载 ACL。
内存桩复现 F → I(inheritPermission=false) → 100 个后代时,虽然这些后代不受 F 的授权变化影响,仍触发 102 次目录查询,并将 101 个无关资源 ID 送入 ACL 查询。目录规模增大后,这些串行查询会拉长权限更新事务。
建议沿用 syncResourceTreePermissions 的按层 frontier/$in 查询方式,在收集阶段就停止独立权限分支;开启状态的判断仍按各 dataset 独立执行。
# 问题描述(复现步骤) syncDatasetToCollections 去掉顶部关闭态短路后,folder 入口会完整遍历后代: 每个节点单独执行一次 MongoDataset.find,且 inheritPermission=false 的独立子树 也被无条件收集,随后整批送入 ACL 查询。F → I(independent) → 100 个后代时, 产生 102 次目录查询和 101 个无关资源 ID 的 ACL 读取,全部发生在权限更新事务内, 串行往返会拉长事务。 # 根因分析 - 收集阶段是单节点 BFS,没有按层批量查询; - inheritPermission 只在同步阶段跳过,收集阶段未剪枝; - 同步阶段对每个节点扫描全量后代列表找直接子节点,复杂度 O(n²)。 修复: - 收集阶段改为 frontier + parentId $in 按层查询; - 继承态判断(shouldInheritResourcePermission)前移到收集阶段,独立分支不遍历、 不加载 ACL;collectionPermissionEnabled 仍按 dataset 独立判断,不参与剪枝; - 收集时建立父子邻接表,同步阶段按层下推,去掉全量扫描。 # 测试 - packages/service test/support/permission/collection/controller.test.ts:45/45 通过 (新增:独立子树不查询后代、不加载其 ACL) - projects/app test/api/core/dataset/resumeInheritPermission.test.ts、update.test.ts:25/25 通过 - prettier / eslint 通过 Co-Authored-By: Claude <noreply@anthropic.com>
问题描述(复现步骤)
根因分析
1a. syncDatasetToCollections 入口用被改节点自身的 collectionPermissionEnabled 短路。
folder 类型永远不会开启文件级权限,于是整棵后代 collection 树被跳过。
1b. 调用顺序错误:collaborator 更新先写 dataset 树,再触发 collection 同步;同步时读到的
后代快照已是新值,diff 为空,提前返回。
1c. resumeInheritPermission 同样在写完 dataset 树后才读取 newEffectiveClbs,跨树 diff 丢失。
修复:
测试