fix(aibox): batch I audit fixes - prompt write cap, light-subagent cancel propagation, atomic history writes

Remaining-item sweep (audit report §12):
- N9: cap prompt file writes (identity/soul/status, 10k chars) to bound
  persistent-injection surface
- F5: run_light_subagent switches to stream_chat + parent cancel_event
  (mid-stream interrupt); ExpressEmotionTool injects parent event
- Q4: busy_timeout=10s on mark_as_triggered (multi-process DB contention)
- Q5: malformed reminder_time tasks returned as due (were silently dropped
  by SQL-level string filter, which is now Python-side authoritative check)
- Q7b: load_conversation realpath prefix check (../ traversal defense)
- Q8: atomic JSON writes (tmp+os.replace) for index/current/archive
- F6: dedicated ws command executor for /new, /reload_prompts
- F9: --once hard-exit backstop after soft timeout
- PromptManager singleton lock; limit=0 semantics (None = no LIMIT)
This commit is contained in:
qing committed 2026-08-18 03:09:05 +00:00
1 parent 9fee9a1478
commit db54921066
6 files changed
+379 -23

No files matched your search

+22 -7
View File
@@ -402,11 +402,14 @@ class MemoDatabase:
# 如果传入了 before_time,使用它,否则使用当前时间
compare_time = before_time if before_time else now
# I 批(审计 2026-08-18):去掉 SQL 层 reminder_time <= ? 预过滤——
# 字符串比较会把格式异常的时间(如 "不是时间")静默排除在 SQL 层,
# Python 二次验证永远看不到它们(Q5:格式异常任务按到期返回)。
# 时间过滤改由下方 Python 解析做权威判断(本地小库全扫描可忽略)。
query = '''
SELECT * FROM memos
WHERE is_completed = 0
AND reminder_time IS NOT NULL
AND reminder_time <= ? -- 严格小于等于比较时间
AND (repeat_end_time IS NULL OR repeat_end_time >= ?)
'''
@@ -415,11 +418,13 @@ class MemoDatabase:
query += ' ORDER BY reminder_time ASC, priority DESC'
params = [compare_time, compare_time]
params = [compare_time]
if limit:
# I 批:limit=0 语义修正——此前 `if limit:` 使 0 等同"不限",
# 与 None=不限的惯例冲突;改为 None 才不加 LIMIT
if limit is not None:
query += ' LIMIT ?'
params.append(int(limit))
params.append(max(0, int(limit)))
cursor.execute(query, params)
@@ -440,7 +445,11 @@ class MemoDatabase:
# 调试日志
self.logger.debug(f"过滤掉未到期任务 #{memo['id']}: {memo['reminder_time']} > {compare_time}")
except (ValueError, TypeError) as e:
self.logger.warning(f"解析任务 #{memo['id']} 的提醒时间失败: {e}")
# I 批(审计 2026-08-18):格式异常此前被静默丢弃——
# 任务永不执行且用户无感知。改为按"到期"返回并告警,
# 至少保证任务被处理而非永久丢失
self.logger.warning(f"解析任务 #{memo['id']} 的提醒时间失败,按到期处理: {e}")
results.append(memo)
else:
# 没有提醒时间的任务不应该在待执行列表中
self.logger.warning(f"任务 #{memo['id']} 没有提醒时间,但被返回为待执行")
@@ -461,9 +470,11 @@ class MemoDatabase:
'''
params = []
if limit:
# I 批:limit=0 语义修正——此前 `if limit:` 使 0 等同"不限",
# 与 None=不限的惯例冲突;改为 None 才不加 LIMIT
if limit is not None:
query += ' LIMIT ?'
params.append(int(limit))
params.append(max(0, int(limit)))
cursor.execute(query, params)
@@ -525,6 +536,10 @@ class MemoDatabase:
with sqlite3.connect(self.db_path) as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
# I 批(审计 2026-08-18):多进程同库(CLI --memo-add + 服务调度)
# 写竞争时默认 5s 后直接报 database is locked——busy_timeout 让
# SQLite 等待锁释放(最长 10s)而不是立即失败
cursor.execute("PRAGMA busy_timeout = 10000")
cursor.execute("BEGIN IMMEDIATE")
try:
cursor.execute('SELECT * FROM memos WHERE id = ?', (memo_id,))