Repository navigation
fix(audit): collection - #8070
shortlight5980 wants to merge 3 commits into
Conversation
shortlight5980
commented
Oct 21, 2026
| 审计操作 | 触发场景 | 日志文案 |
|---|---|---|
| 创建集合 | 手动新建集合或文件夹、文本 / 链接 / 文件 / 图片集导入、备份与模板导入、新建知识库时附带文件 | 【张三】在产品手册/技术文档中创建了【文件】【API 设计.pdf】 |
| 更新集合属性 | 集合改名、移动到其他目录、启用或禁用 | 【张三】将【产品手册】中【API 设计.pdf】的【名称】从【旧名称】调整为【新名称】 |
| 导出集合内容 | 导出集合内的问答数据 | 【张三】导出了【产品手册】中【API 设计.pdf】的集合内容 |
| 同步集合 | 对链接集合、API 文件集合执行同步 | 【张三】同步了【产品手册】中【API 设计.pdf】 |
| 添加集合标签 | 单个或批量给集合打标签 | 【张三】为【产品手册】中【API 设计.pdf】添加了标签【已审核】 |
| 移除集合标签 | 单个或批量移除集合的标签 | 【张三】移除了【产品手册】中【API 设计.pdf】的标签【已审核】 |
Coverage Report
File CoverageNo changed files found. |
|
✅ Admin Preview Image Ready! 🕒 Time: 2026-10-26 14:13:54 (UTC+8) |
|
✅ Build and publish successful - Preview fastgpt Image: 🕒 Time: 2026-10-26 14:17:35 (UTC+8) |
|
基于提交 1. [P1] 新审计事件会导致团队审计列表读取失败Mongo 审计 schema 已接入 同一文件的筛选入参、 2. [P2] 属性审计新增的翻译 key 会被清理脚本误删collection/update.ts:155 等位置直接保存 3. [P2] 批量标签审计未核对每个集合的实际变化pro/admin/src/pages/api/core/dataset/tag/batchSetCollectionTags.ts:59 对全部请求集合记录同一组标签名称。使用真实 controller、模拟数据库读写复现:集合原本没有该标签,移除前后 4. [P2] 同步返回失败时仍记录“已同步”collection/sync.ts:33 在 风格、验证与合并事项
需要明确的语义:审计记录“操作尝试”还是“成功变更”?若覆盖失败或无实际变化的请求,应补充结果字段和对应文案。 |
8ba19ca to
ff652af
Compare
Resloved |
7a911d6 to
b08d341
Compare
|
先 rebase 这个吧 |
c3d2204 to
a4d7525
Compare
c121914yu
left a comment
There was a problem hiding this comment.
Codex 自动审查:fix(audit): collection
重要发现
-
[P2,必须修复] 更新审计使用事务外的旧快照,可能漏掉真实状态变更。 主仓库
collection/update.ts:242–258。collection来自事务前的鉴权查询,事务内按_id写入后仍以这份快照判断是否变化。例如两个请求都读到forbid=false,A 先提交禁用,B 随后提交forbid=false恢复启用;B 将请求值与过期的false比较,得到空差异并跳过日志。最终集合已启用,审计却只留下禁用事件。旧实现每次更新都会留一条日志,本次新增的无变化过滤引入了这个漏记窗口。已用原 handler 与原差异函数做可控交错复现。建议在写入事务内读取旧值、计算差异并返回最终成功事务的审计快照,提交后再落日志,同时覆盖并发与事务重试。 -
[P2,必须修复] 标签选择入口按客户端列表推导审计,会记录并未发生的标签移除。 固定 pro
2816b01e6639edd9d8edf602c1b379511960fee4的admin/src/pages/api/core/dataset/tag/addToCollections.ts:71–85。collectionsToAddTag/collectionsToRemoveTag只由请求中的新旧 ID 列表计算,addTagToCollections没有返回数据库实际差异,路由却直接为这些 ID 写日志。成功移除后重试同一请求,或客户端旧列表已过期时,数据库中本来就没有标签,也会新增一条“移除了标签”的事件;原 handler 和原 service 的隔离执行已确认此行为。它也与本 PR 另两个标签入口“只记录实际变化”的处理不一致。建议让该 service 也从事务内旧值与实际写入值返回逐集合差异,再据此生成审计,补充重复提交与过期列表覆盖。此问题位于 pro 内部,因此只写入总报告,不伪造主仓库行级定位。
需求变更
为集合创建、改名/移动/启停、内容导出、同步、标签增删补充团队审计。创建、更新由旧枚举切换到 dataset.collection.* 事件,旧映射保留用于历史日志;一次属性更新按改名、位置、状态分别记录。恢复集合权限继承改用独立事件,并保存知识库、集合、继承来源名称。
关键实现路径
- 集合创建及各种文件、文本、链接、图片、备份/模板导入入口,在创建完成后写审计;
createWithFiles在事务成功后按文件写集合日志。audit/collection.ts统一对象类型、位置与属性差异,collection/paths.ts从原 API 提取祖先查询并补充环检测。 collection/update.ts协调鉴权、移动/状态级联事务和变更日志;export.ts在游标结束或错误路径用一次性开关记录;sync.ts在同步返回后记录操作,包含sameRaw/failed返回结果。- 公开集合更新接口与 pro 的单集合、批量标签设置共用
audit/utils.ts的差异函数,在事务内比较规范化前后标签值,提交后按集合记录;标签选择入口存在上面的差异缺口。日志最终由addAuditLog(s)写入operationLogs,团队列表通过共享事件全集校验,前端专用 processor 保留名称、URL、标签和路径原值,只翻译展示标签。
影响范围与越界判断
合理扩散。 主仓库 36 个文件以及 pro 8 个文件的实际 diff 均围绕集合审计、共享事件展示和局部验证展开。祖先路径提取供 API 与审计复用,共享标签差异函数服务于公开更新接口和 pro 的逐集合审计,审计常量合并至 metadata.ts 后所有 TypeScript 引用已同步;未发现应拆出的独立功能或部署配置变更。没有改变工作流、计费或外部 API 请求结构;标签单集合设置新增事务边界,批量路径跳过相同内容的写入。
代码质量
属性差异作为独立函数、路径查询带环检测、日志写入在业务提交后执行、失败记录由公共审计工具兜底,职责总体清楚。主要风险是上面两处旧快照与实际写入不一致;应统一使用事务内实际差异,避免不同入口采用不同审计口径。创建、更新旧事件的枚举和展示映射仍保留。
代码风格一致性
沿用 parseApiInput、现有鉴权、mongoSessionRun 和审计工具,新增核心函数有职责与边界注释。非阻塞建议: processDatasetCollectionSpecific 新增 t(metadata.objectType/changeItem/oldValue/newValue),与本次审查技能要求的静态 literal key 形式不一致,建议对有限展示字段使用显式映射。目前相关已知 key 在服务端已有静态 i18nT('...') 引用,四种语言的新增 19 个 key 与插值变量均一致,未发现当前文案缺失。
测试与验证缺口
实际执行:最新快照 12 个局部测试文件、157 项测试全部通过,使用仓库的 pnpm test <指定文件...> 入口,关闭覆盖率、单 worker、按 workspace 顺序运行:
- service:
audit/collection.test.ts、audit/config.test.ts,26 项通过。 - app:集合 update、paths、resumeInheritPermission、create/fileSourceLifecycle,以及前端 dataset/audit、processors/index,58 项通过。覆盖属性与公开标签审计、无变化跳过、权限拒绝、继承来源缺失、路径环检测、文件清理和名称/URL 展示。
- 固定 pro:标签 controller、batchSetCollectionTags、setCollectionTags、团队 audit list,73 项通过。覆盖实际标签差异、规范化、写入失败回滚、旧格式兼容与列表事件校验。
另外执行: 对最新快照的原 handler、原属性差异函数和原标签 service 做 Node 隔离验证(替换鉴权、数据库、事务依赖)。并发交错探针得到 finalForbid=false 且仅有 disable 日志;标签缺席的重复移除探针得到 tags=[] 却新增 dataset.collection.tag.remove 日志。这是代码分支的隔离复现,不等价于真实 Mongo 并发回归测试;现有局部测试没有覆盖这两条异常路径。
发布前 CI 状态:两项镜像构建及 global、web、workflow-core/cli 测试通过;app、service、pro 测试仍在运行。CI 状态与本次审查结论分别记录。
完整阅读主仓库 merge-base 到 head 的 diff,以及 pro 两端 gitlink 的真实 diff、提交和调用方;检查了创建持久化/队列边界、集合鉴权与状态级联、审计存储/列表/前端消费。git diff --check 在两仓库均通过。未运行全量测试、完整类型检查或浏览器端验证;流式导出和同步的完整异常路径未做端到端验证。
需要作者确认的问题
无阻碍定位上述缺陷的需求歧义。
审查结论
needs_changes。两项 P2 审计准确性问题需要修复;本次提交的是 COMMENT Review,不执行批准、请求修改或代码修复。
- 主仓库 head:
a4d7525a4eaed4347f8dfb574124f2f3658dfc35 - 实际 base 分支:
main;获取时 base:5b5cabb9786189ae29850cb8250300ad59e3da3f - merge-base:
749809070b75278e11a1576a8ef05ca90acb2d08 - pro:
b2a36080f37af4582c09f4ca1ea36bc85cf3c01d→2816b01e6639edd9d8edf602c1b379511960fee4,指针发生变化;两端代码均可获取,head 已核对检出且递归子模块无缺失。 - 审查与验证 worktree:
/Users/yjl/.codex/experiments/pr-review-client-probe/worktrees/pr-8070-53391933eb8d/tmp/pr-8070-latest。任务开始时复用宿主准备的父目录;PR 随后更新,因此在同一指定目录内建立新 detached worktree,原检出及用户主工作区保持原样。依赖锁文件未变化,复用父目录已安装依赖;两个独立快照均保留供复核。
Signed-off-by: shortlight5980 <lijunwei5980@163.com>
a4d7525 to
4702d8d
Compare
c121914yu
left a comment
There was a problem hiding this comment.
Codex 自动审查:fix(audit): collection
重要发现
-
[P2] 新增快照查询阻止系统 root 更新其他团队的集合。 update.ts:152 将鉴权返回的操作者
teamId用于集合查询,但authDatasetCollection/authDatasetCollectionMove明确允许系统 root 跨团队访问,且仍返回 root 当前团队的teamId。root 修改其他团队已有集合的名称、状态或位置时,鉴权通过后会在这里查不到集合并返回fileNotFound。旧实现使用已鉴权的集合执行更新,没有这道错误的团队过滤。应按已鉴权资源的collection.teamId读取事务快照,保留 root 旁路与租户边界,并补充跨团队 root 回归覆盖。 -
[P2] 外链导出被错误归到发布者本人名下。 export.ts:132–140 对普通导出与外链引用导出统一使用
tmbId写成员审计。但外链分支的 authChatTargetCrud 返回tmbId = outLinkConfig.tmbId(发布者),实际访客在uid中;需登录外链的uid还是已验证的访客成员 ID。当前导出代码丢弃uid/authType,新日志既没有访客身份,也只写exportScope: chat_quote。pro 审计列表再按该tmbId填充metadata.name,最终会显示成发布者下载了文件。此前该入口没有这条审计,新增加的错误归因会影响下载追溯。应区分资源归属身份与操作人,需登录外链记录验证过的访客,匿名外链明确记录访客来源/标识,避免显示为发布者操作。
需求变更
为集合创建、改名/移动/启停、导出、同步、标签增删及恢复权限继承补齐团队审计。创建覆盖手动集合/文件夹、文件、文本、链接、图片集、备份、模板和新建知识库附带文件;一次属性更新按实际变更逐条记录,标签按每个集合的实际差异记录。旧的创建/更新事件继续保留供历史日志展示。
关键实现路径
- 主应用创建入口 → 集合创建服务成功提交 →
getCollectionAuditLocation展开父目录 →addAuditLog(s)写入operationLogs。 collection/update→ 事务内重新读取集合、解析标签、计算属性及标签差异 → 提交成功后写审计;回滚不留日志,重试只采用最终成功的差异。路径查询从 API 提取到 service,并加入 session 透传和环检测。- pro 三个标签入口 → 单集合/批量标签 controller → 共享
diffCollectionTags→ 事务成功后按集合写日志;规范化、重复提交、选项顺序和裁剪均有对应处理。 - 共享事件枚举/展示映射 → pro 团队审计列表 schema 和筛选 → 主应用专用 metadata processor / 四语言文案。名称、路径及标签原值保留,状态与类型按当前语言显示。
影响范围与越界判断
事件注册、service 差异计算、各创建入口、pro 标签写入及前端展示属于合理扩散。agentLoopCore/boundary.test.ts 放宽指定 helper 的直接导入与集合审计没有直接关系,属于可疑越界的独立测试维护,建议在 PR 中解释关联或拆分;未发现该测试调整改变运行时行为。其余未发现大范围整理或依赖升级。
代码质量
事务内生成差异、事务外记录审计的职责清楚;标签值先规范化再比较,查询展示名称失败回退 ID,路径成环时终止,均有明确边界。必须修复的问题是上面的 root 回归与外链操作人错误;不能仅凭新增测试通过认定这两条未覆盖路径正确。
代码风格一致性
API 请求边界沿用 parseApiInput,共享逻辑从实际定义模块导入,新增复杂分支有职责说明。非阻塞建议:processDatasetCollectionSpecific 新增 t(metadata.objectType/changeItem/oldValue/newValue) 动态 key 调用,与现行静态字面量 key 规则不一致;建议有限枚举采用静态映射。当前 key 另有后端 i18nT('literal') 标记,四种语言新增项和插值一致,本次未发现实际翻译缺失。
测试与验证缺口
实际执行结果:
- 为独立 worktree 安装依赖,并完成 SDK 与 workflow 包构建。按受影响范围串行运行 service 3 个文件 / 31 项、主应用 9 个文件 / 77 项、pro 5 个文件 / 83 项,合计 17 个文件、191 项全部通过。
- 另用真实 Mongo 事务及 API 调用补做临时回归:系统 root 尝试改名其他团队的集合,实际返回
code: 500, error: fileNotFound,应成功的断言失败,证实发现 1。验证文件已移除,业务代码未改动。 - 对固定版本
authChatTargetCrud与导出 handler 做独立 Node 探针(仅将数据库、外链验证及审计写入等外部依赖替换为可控实现):访客 UID 与发布者不同,完成导出后审计仍只保存发布者tmbId,访客 UID 完全未进入记录,证实发现 2。这是调用链复现,并非真实外链浏览器端到端测试。
完整审阅主仓库 merge-base 到 head 的 37 个文件,以及 pro 两个 gitlink 之间的 9 个文件和调用链。主仓库与 pro 的 git diff --check 均通过;四语言各新增 19 个 key,插值集合一致。未运行全量测试、浏览器端到端验证或外部对象存储/爬虫的真实集成。
需要作者确认的问题
请明确匿名外链下载的审计身份展示约定;无论采用何种展示方式,都应区分访客与发布者本人。工作流边界测试调整与本需求的关联也建议补充说明。
审查结论
needs_changes:存在上述两个需要修复的问题。CI 在读取时全部成功,该状态独立于本次代码审查结论。
- 主仓库 head:
d3516d2cff294fa6b8072ed8dd07c3775d290ef5 - merge-base:
5fdc8d17e0d40b161a6aa54897d85d9b87cbcba5(目标分支main) - pro:
b2a36080f37af4582c09f4ca1ea36bc85cf3c01d→08e2f72052df109a88898592d99eca39519736a4,已审阅实际差异。 - worktree:
/Users/yjl/.codex/experiments/pr-review-client-probe/worktrees/pr-8070-36837731b836;复用宿主快照,保留目录,未修改业务代码。
| tagChanges: ReturnType<typeof diffCollectionTags>; | ||
| } = await mongoSessionRun(async (session) => { | ||
| // 所有变更共用事务内旧快照;重试时重新读取,避免并发操作导致漏记或沿用已回滚的差异。 | ||
| const previousCollection = await MongoDatasetCollection.findOne({ _id: id, teamId }, null, { |
There was a problem hiding this comment.
Codex 自动审查 · [P2] 按资源团队读取 root 已鉴权的快照
这里的 teamId 是鉴权返回的操作者当前团队。authDatasetCollection 和移动鉴权都允许系统 root 跨团队访问,却不会把这个字段改成资源团队,因此 root 更新其他团队集合时,会在鉴权通过后被这条新增查询挡成 fileNotFound;旧版本可以完成该更新。建议使用已鉴权集合的 collection.teamId 读取事务快照,并覆盖 root 与资源团队不一致的请求。
| auditFinished = true; | ||
| void addAuditLog({ | ||
| teamId: String(userTeamId), | ||
| tmbId, |
There was a problem hiding this comment.
Codex 自动审查 · [P2] 外链导出不要归因到发布者本人
此入口也接受外链引用导出。authChatTargetCrud 的外链分支将发布者 outLinkConfig.tmbId 返回为 tmbId,实际访客在 uid 中(需登录外链时是已验证的访客成员 ID)。这里把前者写为成员审计且丢掉访客身份,pro 列表又按它补操作人名称,导致访客下载显示成发布者本人下载。请区分访客身份与发布归属:已登录外链使用验证过的访客,匿名外链保留访客来源/标识并明确展示,避免错误成员归因。