• ## 起因
    
    integration 测试里 `process.env.API_KEYS = 'test-api-key-123'` 是死代码:
    生产读的是 OPEN_API_KEYS(config.js:31),而这个测试文件里 API_KEYS 只出现
    这一次赋值,没有任何 /api/open/* 请求、没有任何 key 相关断言。已删。
    
    (更正上一轮的判断:它不是「为了错误的原因而绿」——它什么都没测,
    所以也谈不上错。两个缺陷互相抵消成了无害。)
    
    ## 为什么错名字能活这么久
    
    api-key-auth.test.js 原有 7 条用例**全在测 extractApiKey**(怎么从 header/query
    取出字符串),而做鉴权决定的 requireApiKey 一条都没有。OPEN_API_KEYS 那条分支
    从来没被执行过 —— 没有测试执行过的路径,喂给它什么名字都不会有人知道。
    
    补 4 条(拦/放两侧各两条):无 key → 401「需要 key」/ key 无效 → 401「key 不对」/
    命中系统 key 列表 → 放行且挂 req.apiKey / 命中用户 api_key → 放行且挂 req.user。
    
    ## 补完当场抓到一个真缺陷(这一条才是重点)
    
    requireApiKey 把 findByApiKey 返回的**原始数据库行**挂上 req.user,带着
    password_hash。JWT 那条路(jwt-auth.extractUser)一直是过 toPublicUser 才挂的 ——
    两条鉴权路径行为不一致,而 req.user 是 handler 唯一的身份来源。
    
    当前没有实际泄漏(open-api 的 handler 只读 req.user?.id / ?.email,
    没有哪个把整个对象回给调用方),但将来任何一个 res.json({ user: req.user })
    都会把 bcrypt 哈希发给外部 API 调用方。改成过 toPublicUser。
    
    顺带确认 requireApiKey 本身是 fail-closed 的:无 key 401;key 既不匹配用户
    api_key 也不在配置列表 401。OPEN_API_KEYS 为空只是让系统级 key 全部失效,
    不放开任何东西 —— 所以那个错名字不构成安全漏洞。
    
    ## 验证
    
    862 全绿(85 文件)。4 处变异逐一精确变红后逐字还原。
    
    其中 T3 值得记:第一版「无 key → 401」只断言状态码,而把 if (!key) 改成
    if (false) 之后测试仍全绿 —— 因为纵深防御,key=null 会落到第二道门照样 401。
    两者的区别在**文案**(「需要 key」vs「key 不对」),而我在另一条用例的注释里
    自己写了「两种失败要分得开」却没断言它。补上文案断言后 T3 才真的变红。
    只断言状态码的鉴权测试基本都有这个盲区。
    
    数据核查:跑完全套后共享 users.sqlite 的 sha256 不变、用户数仍为 1
    (新用例用 USERS_DB_PATH 打到 /tmp —— 这个覆盖口是上一轮刚补的,
    在它存在之前这组用例会往共享生产库里插测试用户)。
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    yibo authored
     
    Browse File »

  • - Agent as Micro-Container: each agent lives in data/agents/{id}/ with full encapsulation
    - Persona vs Capability split: agent.md (identity) + .claude/skills/main_skill/SKILL.md (workflow)
    - Conversations co-located: data/agents/{id}/conversations/ replaces global dir
    - Meta Skills renamed: meta_hunt, meta_digest, meta_creator, meta_evolving, meta_benchmark, meta_research
    - Dynamic Hot-Reload: AgentManager.getAgentConfig() falls back to filesystem scan
    - Parallel Sub-Agent orchestration via Promise.all with multi-terminal UI
    - Removed SQLite dependency, global skills/ directory, and legacy conversations/
    - Full architecture docs: 18-local-filesystem-first-agent-encapsulation.md
    yibo authored
     
    Browse File »