• 起因是一个看起来无害的问题:<repo>/data/users.sqlite 为什么是 0 字节。
    答案是没人用它——user-db 走三级上跳落在仓库外的 ~lemonAI/data(跨兄弟仓库
    共享的平台数据,与 skill-db / benchmark-db 一致;仓库内 data/ 放 graph/companies/
    devloop 这类租户数据)。那个空文件是遗留,已删。
    
    顺着查下去发现三处同型缺陷,形态都是「产生 → 传递 → 落库 → 读回」漏掉读回,
    而且是最有欺骗性的一种:测试设了隔离用的 env,没有人读,于是数据全写进
    **共享的生产库**,测试照样全绿,afterAll 删的 /tmp 文件从来没被创建过、清理还“成功”。
    
    1) USERS_DB_PATH 压根不存在
       user-db.test.js 只能直写共享用户库(注释老实写着 "uses hardcoded
       data/users.sqlite"),afterAll 是空的、拿「邮箱按 UUID 唯一所以不会撞」
       当成了不用清理的理由。不撞是真的,不堆积是假的:357 个用户里 356 个是夹具。
       加 USERS_DB_PATH 覆盖口(口径同 graph-db 的 GRAPH_DB_PATH),测试改为
       先设 env 再清 require.cache 再 require(DB_PATH 是加载时求值的常量,
       顺序错了照样静默失效),afterAll 真删库文件。
    
    2) BENCHMARK_DB_PATH 有人设、没人读
       benchmark-db.test.js:13 与 integration/api-routes.test.js:43 都在设它,
       而 benchmark-db.js 那一行不读 → 共享 benchmark 库攒了 342 行
       skill_name=benchmark_test。补上读取后,两个测试文件一行不改就真隔离了
       (日志里 Initialized SQLite at /tmp/... 第一次是真的)。
    
    3) SKILLS_DIR 是写错的变量名
       config.js:13 读的是 SKILLS_CODE_DIR,所以 skillsCodeDir 一直指向那个
       2.7 万条的真实共享 skills 目录。两个测试文件的变量名改正。
    
    新增 guard server/tests/unit/test-isolation-env.test.js:
    测试赋值过的**路径类** env(_DIR/_PATH/_ROOT 结尾)必须有生产读者。
    只管路径类是刻意的——那是会造成静默数据污染的地方,而 HOME(os.homedir 间接读)、
    JWT_SECRET、PORT 这类天然不在范围内,不需要维护会腐烂的白名单。
    顺带钉住「共享 data 在仓库外」这个有意的分层,免得被“修”回仓库内。
    guard 第一版把自己文档注释里的举例当成真赋值、自己判红了,所以两侧都先剥注释——
    凡是静态扫源码的检查都要先想清楚该量的是代码还是文本。
    
    数据清理:共享 ~lemonAI/data/users.sqlite 删掉 358 行夹具
    (不是 356——修好之前又跑了两轮测试,每轮 +2,正好印证泄漏一直活跃),
    删前备份 + 计数闭合校验(保留行 + 匹配行 == 总数才动手),
    删后真人 bboonnee@gmail.com 完好,总数 1。
    
    验证:854 全绿(84 文件)。跑完全套后 users / benchmark_logs / skills
    三个共享库的 sha256 逐位不变——修好之前这不可能。
    3 处变异逐一精确变红(去掉任一 env 读取、把变量名改回错的)后逐字还原。
    
    未动:JWT_SECRET / API_KEYS 生产侧无读者或名字不符(config.js 读 OPEN_API_KEYS),
    不造成数据污染,另报;共享 benchmark 库那 342 行夹具未清,等确认。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »