Repository navigation
v1.3.6 — 进程身份、凭据边界与跨进程互斥
v1.3.6 — 进程身份、凭据边界与跨进程互斥
针对 v1.3.5 独立审计(50 项行为缺陷,13 项带隔离实测,commit e0e4364)逐条处置:40 项行为缺陷已修,8 项按审计自身的说明归入"已知未结"(见文末),1 项(F07 发布签名)只能由证书账号闭合。
桌面壳不再被假服务骗到(F01)
- 旧实现把"端口上有人回 HTTP/1.x 200"当成工作台,会把 API token 交给占位进程。现在 Electron 与 Tauri 都向新增的免鉴权
GET /api/identify?n=<hex>发一次性随机 nonce,要求x-piwb-proof = HMAC-SHA256(API_TOKEN, nonce);Tauri 侧手写 HMAC(sha2)+ 常数时间比较,3 秒读超时保留。scripts/ui-contract-probe.mjs增加该项的运行时断言。
凭据只在信任域内流转(F02–F04、F17–F19、F32、F38)
- "不含密钥"导出写明范围并真正执行:manifest 带
scope/scopeNote,config.json/settings.json以脱敏副本入包,baseUrl的 userinfo 与凭据类查询值一并剥离,恢复前对 provider 行做形状校验。 - MCP 哨兵不再跟着改掉的命令走:
***环境/参数只在 command + args 身份一致时还原;配置文件改为mkdir后先暂存再替换。 - 只写 key 字段在所有出现处都脱敏(
scrubUrlCreds/scrubArgSecrets/maskApiKeys),被掩码的models.json往返不再摧毁已存baseUrl。 - key 冷却绑定凭据的 env 名,而不是数组下标(
provider#env:NAME)——换序/移动过的 key 不再冷却错误的槽位;字面 key 供应商keyEnvsFor返回[];nextInChain拒绝models.json里不存在的 provider/model,不再把它当免密供应商。 - 损坏配置留证进
corrupt-backups/,最多 3 份、0600。 - Windows 凭据文件 ACL 不再只保护 token(F08):服务端与备份模块写入的每个凭据文件都按当前用户收紧 DACL(
icacls /inheritance:r /grant:r <user>:F)——token、config.json、models.json、mcp.json、routing.json、cron.json、settings.json、model-meta.json,以及导出的 zip、恢复快照与恢复临时文件。POSIX 的 0600 本来就是对的,Windows 之前等于没设。
日志脱敏如实说明范围(F05、F06)
- cron 单次运行日志创建即 0600(F05)。
docs/TROUBLESHOOTING.md不再暗示"日志已脱敏":明确列出会替换的模式,以及不会替换的秘密(其它格式 key、Cookie 值、URL 查询串 token、子进程 stderr),并要求提交前人工确认(F06)。
Cron:单写者 + 诚实的窗口(F09–F16)
- 跨进程单写者:每个任务一把锁文件(
openSync('wx')、0600、30 分钟后可接管、bootReset 清扫),两个服务实例不再跑同一个任务(F09/F10)。 - daily 当天窗口只在 spawn 成功后消费:spawn 抛错、key/model 冷却都改为延期而不是烧掉当天(F11–F13)。
- settle 记录本次实际使用的 provider/model/key 身份,
__keyIdx从子进程环境剥离(F14)。 - 运行中的任务可以取消:停用/删除任务会终止其子进程;
settleWatch在close永不到达时兜底终结;日志 fd 0600(F15/F16/F05)。
界面不再展示乐观假象(F20–F22、F40–F45)
- WS open 解析生效模型(默认模型 + 停用供应商门禁)并固定路由 key env;跨供应商
set_model会重启该 tab 的 pi 并上报pi-restarted(F20/F21)。 - 用过工具的那一轮不再自动重发——副作用重复前必须由用户确认(F22)。
set_model未被确认时模型 chip 回滚(F41);goal 对话框先回答等待中的 modal 再替换(F42);goals/主题/供应商/技能/cron 与高级 JSON 编辑器都检查后端回执并在失败时回滚(F43/F40);结构化 API 错误按错误渲染,不再显示成"空文件"/"没有会话"/"今日 0"(F44);附件在发送前做尺寸门禁,不再因超过 8 MiB WS 帧而清空草稿并断连(F45)。
读取器与账本不再丢数据(F23–F31、F34)
- Codex 导入保留真实的重复轮次(合并不同轮次的去重已移除);pi/Claude 导入保留原始时间戳与工具错误语义;各会话解析器的头部读取补齐 null 守卫(F23/F24/F29/F30)。
- 会话导出默认按活动分支(
?all=1导出全部分支),中途失败回包带可见错误块而不是静默截断的 200,无内容时降级为文本说明而不是空文件(F25/F28)。 - Claude 账本按
message.idlast-wins(旧实现 first-wins 会丢掉最终 usage);会话树上报windowed;readJsonl返回{items, truncated},用量/账本暴露cappedFiles/truncatedFiles(F26/F27/F31)。 saveModelMeta改为 tmp+rename(F34)。
开发一致性与文档(F49)
- README 代码围栏修正;README.en 补齐它缺的 prepare-runtime + embed-token 流程;
prepare-runtime.mjs拷贝data/,开发环境 KB 不再静默为空。
验证
lint 0、测试 40/40、路由扫描 47 PASS、探针(ws / failover / ui / chat / contract)全 PASS;契约测试 23 → 39 项:新增 16 条锁定本轮修复(env 名 key 身份、字面 key 供应商、回退链校验、daily 窗口延期、导出分支与空transcript、错误形状渲染),ui-contract-probe.mjs 增加 F01 挑战应答检查。CI 8 job 全绿后从 CI 产物发布(5 件资产 + SBOM + SHA256SUMS.txt,逐件校验 artifact digest 与条目名)。
已知未结(按审计原文的口径):F07 发布签名(等证书账号——hash 清单能查损坏,不能认证恶意发布)、F33 恢复的崩溃安全事务日志、F35 Tauri 子服务监督/自动重启、F36 启动校验失败后自动从可信 ZIP 重建 runtime、F46 侧栏重绘引起全会话重扫、F47 长期运行资源全生命周期预算、F48 键盘/辅助技术路径与 modal 语义、F50 安装器级实机验收与供应链深度(action 摘要固定、Node 校验和签名、SBOM 分层、Windows/macOS 安装器冒烟)。