chore: 删除退役的旧 JWT 密钥,同步过时引用并记录登录接口决策

1. 删除 config/jwt/jwt-private.pem 与 jwt-public.pem(旧密钥,配置已不再指向)。
   删除后复跑全量门禁以确认没有残留依赖:ruff 通过、unit+contract 447 passed、
   acceptance_check --production 7 PASS、demo_agent_e2e 9/9 PASS。
2. 修掉 4 处引用旧密钥路径的地方(它们会在删除密钥后直接失败或误导接入方):
   - tests/unit/core/test_security.py 的三处硬编码路径改为单一常量 DEV_KEY_DIR,
     否则删除旧密钥后该测试会因读不到文件而失败;
   - tools/demo_agent_e2e.py 的 docstring 前置条件;
   - docs/09 的配置示例;docs/19 的手工自签说明(改为指向配置项与
     tools/generate_jwt_keys.py)。
3. docs/21 记录旧密钥已删除,并注明删除后已复跑验证无残留引用。
4. docs/19 未解决项新增第 5 条:无登录接口属于**有意识的推迟**(等业务 Agent 开发阶段
   结束后再补),写明补的时候只需动签发侧、验签侧与身份解析侧都不需要改,
   并附上当前私钥边界的实测结论(无法伪造不存在的用户、无法使用已禁用账号)。
This commit is contained in:
2026-09-10 18:18:00 +08:00
parent c32d3dbd06
commit 2c5ef35d18
5 changed files with 22 additions and 8 deletions
@@ -141,8 +141,9 @@ D:\conda\envs\jr_py313\python.exe tools\demo_agent_e2e.py
D:\conda\envs\jr_py313\python.exe C:\Users\...\e2e_run_check.py --label 手工验证
```
单条链路的手工命令(客户身份 9001,JWT 用 `config/jwt/jwt-private.pem` 按 RS256 自签,
参考 `tools/acceptance_check.py::token()`):
单条链路的手工命令(客户身份 9001,JWT 用配置项 `JWT_PRIVATE_KEY_PATH` 指向的私钥按 RS256 自签,
参考 `tools/acceptance_check.py::token()`)。还没有密钥就先跑一次
`python tools/generate_jwt_keys.py --out-dir config/jwt/dev`(详见 `docs/21-JWT密钥管理与轮换.md`):
```text
POST /api/v1/agent-runs
@@ -218,3 +219,11 @@ D:\conda\envs\jr_py313\python.exe tools\demo_agent_e2e.py
(`reviews`/`activations`/`archivals`)且运行期读取生效(见 3.1)。
4. **`docs/05` §9.5 未收录 `agent-intent-configs` 的 `GET` 详情路径**:该接口实际存在(用于获取
`If-Match` 所需的 ETag),但权威接口文档未列出,属文档待补项。
5. **没有登录接口(已决定推迟,不是遗漏)**:当前没有"账号密码换令牌"的接口,令牌由外部按
RS256 用私钥自签(见 `docs/21-JWT密钥管理与轮换.md`)。**决定:等业务 Agent 开发阶段
结束后再补**。补的时候只需动签发侧(新增 `POST /auth/login`:校验密码 → 用私钥签令牌),
验签侧 `JwtAuthenticator` 与身份解析侧 `IdentityService` 都不需要改。
代价与约束:开发阶段凡拿到私钥者都能以 `9001/9002/9003` 身份调用(实测**无法**伪造不存在的
用户、**无法**使用已禁用账号,边界是"签名有效 + 用户存在且启用"),因此私钥按 `docs/21`
第 7 节的红线管理;同时业务代码必须始终只从 `RequestContext` 取身份,否则后补登录接口会
从"增量"变成"翻遍所有业务代码"。