- 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
+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+
+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+