baa-conductor

git clone 

commit
8809f1c
parent
f26dd00
author
im_wower
date
2026-03-29 02:01:36 +0800 CST
docs: add T-BUG-027 and T-BUG-028 for code review fixes

- T-BUG-027: SQL injection, D1 schema FK, daemon.stop() await, listener leaks
- T-BUG-028: sessions query missing conversation_id, ask timeout race condition

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2 files changed,  +281, -0
A tasks/T-BUG-027.md
+164, -0
  1@@ -0,0 +1,164 @@
  2+# Task T-BUG-027:修复安全和资源泄漏问题
  3+
  4+## 状态
  5+
  6+- 当前状态:`待开始`
  7+- 规模预估:`M`
  8+- 依赖任务:无
  9+- 建议执行者:`Claude`(涉及安全修复和 async 生命周期管理,需要理解多个模块的交互)
 10+
 11+## 直接给对话的提示词
 12+
 13+读 `/Users/george/code/baa-conductor/tasks/T-BUG-027.md` 任务文档,完成开发任务。
 14+
 15+## 当前基线
 16+
 17+- 仓库:`/Users/george/code/baa-conductor`
 18+- 分支基线:`main`
 19+- 提交:`f26dd00`
 20+
 21+## 分支与 worktree(强制)
 22+
 23+每个任务必须使用独立的分支和 worktree,禁止直接在 main 上修改,禁止多个任务共用同一个 worktree。
 24+
 25+- 分支名:`bug/security-and-resource-leaks`
 26+- worktree 路径:`/Users/george/code/baa-conductor-security-and-resource-leaks`
 27+
 28+开工步骤:
 29+
 30+1. `cd /Users/george/code/baa-conductor`
 31+2. `git worktree add ../baa-conductor-security-and-resource-leaks -b bug/security-and-resource-leaks main`
 32+3. `cd ../baa-conductor-security-and-resource-leaks`
 33+4. 在这个 worktree 目录里开发,不要回到主仓库目录
 34+
 35+完成后提交与推送(由执行者完成,不要合并):
 36+
 37+1. 在 worktree 里提交所有变更(包括更新后的任务文档)
 38+2. `git push -u origin bug/security-and-resource-leaks`
 39+
 40+## 目标
 41+
 42+修复代码审查发现的 5 个安全和资源泄漏问题。
 43+
 44+## 背景
 45+
 46+代码审查发现 d1-client sync-worker 有 SQL 注入风险、D1 schema 缺外键、claude-coded daemon 有资源泄漏(未 await stop、事件监听未清理、stderr 无错误处理)。
 47+
 48+## 涉及仓库
 49+
 50+- `/Users/george/code/baa-conductor`
 51+
 52+## 允许修改的目录
 53+
 54+- `/Users/george/code/baa-conductor/packages/d1-client/src/`
 55+- `/Users/george/code/baa-conductor/apps/claude-coded/src/`
 56+- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/index.ts`
 57+
 58+## 尽量不要修改
 59+
 60+- `/Users/george/code/baa-conductor/packages/artifact-db/`
 61+- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/local-api.ts`
 62+- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/instructions/`
 63+- `/Users/george/code/baa-conductor/plugins/`
 64+
 65+## 必须完成
 66+
 67+### 1. 修复 SQL 注入风险
 68+
 69+**文件**:`packages/d1-client/src/sync-worker.ts` 的 `buildSyncSql` 函数
 70+
 71+**问题**:表名和列名从 sync queue payload 直接拼接到 SQL,未做校验。
 72+
 73+**修复方案**:
 74+- 定义允许的表名白名单:`messages`、`executions`、`sessions`
 75+- 定义每张表允许的列名白名单(参照 artifact-db schema)
 76+- `buildSyncSql` 中校验 tableName 和所有 payload key 是否在白名单内,不在则拒绝并返回 null
 77+- 不要用正则校验列名,用显式白名单
 78+
 79+### 2. 修复 D1 schema 缺外键
 80+
 81+**文件**:`packages/d1-client/src/d1-setup.sql`
 82+
 83+**问题**:executions 表缺少 `FOREIGN KEY (message_id) REFERENCES messages(id)`,本地 artifact-db 有但 D1 没有。
 84+
 85+**修复方案**:
 86+- 在 d1-setup.sql 的 executions 表定义中加上 `FOREIGN KEY (message_id) REFERENCES messages(id)`
 87+- 确保与 `packages/artifact-db/src/schema.ts` 的 executions 表定义一致
 88+
 89+### 3. 修复 daemon.stop() 未 await
 90+
 91+**文件**:`apps/conductor-daemon/src/index.ts`
 92+
 93+**问题**:`start()` 错误处理和 `stop()` 方法中调 `daemon.stop()` 没有 await,可能留孤儿进程。
 94+
 95+**修复方案**:
 96+- `start()` 错误处理中的 `this.daemon.stop()` 改为 `await this.daemon.stop()`
 97+- `stop()` 方法中的 `this.daemon.stop()` 改为 `await this.daemon.stop()`
 98+
 99+### 4. 修复 stdio 事件监听未清理
100+
101+**文件**:`apps/claude-coded/src/stream-json-transport.ts`
102+
103+**问题**:`connect()` 注册了多个事件监听器(stdout data/end/error、stderr data、process error/exit),`close()` 只关了 stdin,重连会累积监听器。
104+
105+**修复方案**:
106+- 保存所有注册的监听器引用
107+- `close()` 中用 `off()` 移除所有监听器
108+- 或者改用 `once()` 对于一次性事件
109+
110+### 5. 修复 stderr 无错误处理
111+
112+**文件**:`apps/claude-coded/src/stream-json-transport.ts`
113+
114+**问题**:stderr 流没有注册 error handler,未捕获的 stderr 错误可能导致进程崩溃。
115+
116+**修复方案**:
117+- 给 stderr 注册 `error` 事件处理器,捕获并记录错误
118+- 同样需要在 `close()` 中清理
119+
120+## 需要特别注意
121+
122+- SQL 注入修复要用显式白名单,不要用正则(正则容易绕过)
123+- daemon.stop() 的 await 修复要注意不要引入死锁(stop 等待子进程退出,子进程可能等待 stdin 关闭)
124+- 事件监听清理要确保不会影响正常的连接/断开流程
125+- 所有开发必须在 worktree 中进行,不要在主仓库目录修改代码
126+
127+## 验收标准
128+
129+- `buildSyncSql` 对非白名单表名返回 null
130+- `buildSyncSql` 对非白名单列名过滤掉或返回 null
131+- `d1-setup.sql` 的 executions 表有外键约束
132+- conductor stop 时无孤儿进程
133+- claude-coded transport 重连不累积监听器
134+- stderr 错误不导致进程崩溃
135+- 所有现有测试通过
136+
137+## 推荐验证命令
138+
139+- `cd /Users/george/code/baa-conductor-security-and-resource-leaks && pnpm build`
140+- `cd /Users/george/code/baa-conductor-security-and-resource-leaks && pnpm test`
141+
142+## 执行记录
143+
144+> 以下内容由执行任务的 AI 填写,创建任务时留空。
145+
146+### 开始执行
147+
148+- 执行者:
149+- 开始时间:
150+- 状态变更:`待开始` → `进行中`
151+
152+### 完成摘要
153+
154+- 完成时间:
155+- 状态变更:`进行中` → `已完成`
156+- 修改了哪些文件:
157+- 核心实现思路:
158+- 跑了哪些测试:
159+
160+### 执行过程中遇到的问题
161+
162+> 记录执行过程中遇到的阻塞、环境问题、临时绕过方案等。合并时由合并者判断是否需要修复或建新任务。
163+
164+### 剩余风险
165+
A tasks/T-BUG-028.md
+117, -0
  1@@ -0,0 +1,117 @@
  2+# Task T-BUG-028:修复查询路由和 ask 超时逻辑问题
  3+
  4+## 状态
  5+
  6+- 当前状态:`待开始`
  7+- 规模预估:`S`
  8+- 依赖任务:无(与 T-BUG-027 可并行)
  9+- 建议执行者:`Claude`(需要理解 local-api 查询路由和 daemon ask 生命周期)
 10+
 11+## 直接给对话的提示词
 12+
 13+读 `/Users/george/code/baa-conductor/tasks/T-BUG-028.md` 任务文档,完成开发任务。
 14+
 15+## 当前基线
 16+
 17+- 仓库:`/Users/george/code/baa-conductor`
 18+- 分支基线:`main`
 19+- 提交:`f26dd00`
 20+
 21+## 分支与 worktree(强制)
 22+
 23+每个任务必须使用独立的分支和 worktree,禁止直接在 main 上修改,禁止多个任务共用同一个 worktree。
 24+
 25+- 分支名:`bug/query-routes-and-ask-timeout`
 26+- worktree 路径:`/Users/george/code/baa-conductor-query-routes-and-ask-timeout`
 27+
 28+开工步骤:
 29+
 30+1. `cd /Users/george/code/baa-conductor`
 31+2. `git worktree add ../baa-conductor-query-routes-and-ask-timeout -b bug/query-routes-and-ask-timeout main`
 32+3. `cd ../baa-conductor-query-routes-and-ask-timeout`
 33+4. 在这个 worktree 目录里开发,不要回到主仓库目录
 34+
 35+完成后提交与推送(由执行者完成,不要合并):
 36+
 37+1. 在 worktree 里提交所有变更(包括更新后的任务文档)
 38+2. `git push -u origin bug/query-routes-and-ask-timeout`
 39+
 40+## 目标
 41+
 42+修复 sessions 查询端点缺失 conversation_id 过滤,以及 claude-coded daemon ask 超时与正常完成的竞争条件。
 43+
 44+## 涉及仓库
 45+
 46+- `/Users/george/code/baa-conductor`
 47+
 48+## 允许修改的目录
 49+
 50+- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/local-api.ts` (sessions 查询路由)
 51+- `/Users/george/code/baa-conductor/apps/claude-coded/src/daemon.ts` (ask 超时逻辑)
 52+
 53+## 尽量不要修改
 54+
 55+- `/Users/george/code/baa-conductor/packages/`
 56+- `/Users/george/code/baa-conductor/plugins/`
 57+- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/instructions/`
 58+
 59+## 必须完成
 60+
 61+### 1. sessions 查询端点补 conversation_id 过滤
 62+
 63+**文件**:`apps/conductor-daemon/src/local-api.ts` 中 `handleArtifactSessionsList`
 64+
 65+**问题**:messages 和 executions 端点都支持 conversation_id 过滤,但 sessions 端点遗漏了。`store.listSessions()` 已支持 conversationId 参数但没被调用。
 66+
 67+**修复方案**:
 68+- 从 query 中读取 `conversation_id`(用现有的 `readOptionalQueryString`)
 69+- 传给 `store.listSessions({ platform, conversationId, limit, offset })`
 70+- 在响应的 `filters` 对象中加上 `conversation_id: conversationId ?? null`
 71+
 72+### 2. 修复 ask 超时与正常完成的竞争
 73+
 74+**文件**:`apps/claude-coded/src/daemon.ts` 中 ask/askStream 的超时逻辑
 75+
 76+**问题**:超时 timer 和正常 resolve 没互斥。如果正常完成后 timer 仍然触发,可能导致 `rejectPendingAsk` 在已完成的请求上执行。
 77+
 78+**修复方案**:
 79+- 正常完成时用 `clearTimeout(timer)` 取消超时计时器
 80+- 或用 `done` 标志位互斥,确保 timer 回调中检查 `done` 后 return
 81+- 确保 resolve 和 reject 不会双触发
 82+
 83+## 验收标准
 84+
 85+- `curl http://100.71.210.78:4317/v1/sessions?conversation_id=xxx` 能按 conversation_id 过滤
 86+- 响应的 filters 对象包含 `conversation_id` 字段
 87+- ask 正常完成后超时 timer 被取消,不会触发 reject
 88+- 所有现有测试通过
 89+
 90+## 推荐验证命令
 91+
 92+- `cd /Users/george/code/baa-conductor-query-routes-and-ask-timeout && pnpm build`
 93+- `cd /Users/george/code/baa-conductor-query-routes-and-ask-timeout && pnpm test`
 94+
 95+## 执行记录
 96+
 97+> 以下内容由执行任务的 AI 填写,创建任务时留空。
 98+
 99+### 开始执行
100+
101+- 执行者:
102+- 开始时间:
103+- 状态变更:`待开始` → `进行中`
104+
105+### 完成摘要
106+
107+- 完成时间:
108+- 状态变更:`进行中` → `已完成`
109+- 修改了哪些文件:
110+- 核心实现思路:
111+- 跑了哪些测试:
112+
113+### 执行过程中遇到的问题
114+
115+> 记录执行过程中遇到的阻塞、环境问题、临时绕过方案等。合并时由合并者判断是否需要修复或建新任务。
116+
117+### 剩余风险
118+