Skip to content

v1.4.1 — 协议桥加固 · 台账可删 · 前端有了第一层测试

Choose a tag to compare

@hellobs hellobs released this 04 Oct 09:29
· 77 commits to main since this release

v1.4.1 — 协议桥加固 · 台账可删 · 前端有了第一层自动化测试

v1.4.0 之后的第四轮体检结清。两个安全修复 + 一个数据治理功能 + 前端从零到有的测试层。

⚠️ 安全修复(建议尽快升级)

协议桥跨站可烧额度

/bridge 整条豁免在 CSRF 中间件之外(mavis 是服务端进程,发不出 UI 头),原先指望
"只监听本机 + 凭据不落盘"兜底。实测这条兜底不成立:桥转发前不看任何来源,而浏览器
text/plain POST 是 CORS 简单请求(不发预检、也发不出自定义头),跨站 POST 能带着
x-api-key 打到上游 —— 即跨站成本放大。

修法:桥内自己再判一层来源。纵深防御口径 —— 豁免前缀不该等于零校验。

  • 无来源(Origin / Referer 都没有)放行:mavis 用 httpx 调桥本就不带 Origin,这是它的自然形态
  • 带了但非本机 / 非 dev 源 → 403,且在碰上游之前就拒
  • 白名单:127.0.0.1 / localhost / ::1 + 本地 dev 源

回归手段(0 消耗,可直接重跑):scripts/bridge_probe.py、tests/test_bridge_origin.py。

桥在非 anthropic 形态下拒不服务(第三道门)

上一条修完后还剩一个残余面:形态不是 anthropic 时 mavis 走直连、根本不经过桥,但本机脚本
仍可以拿桥当跳板去烧额度
。现在桥自己先看一眼"我是不是生效中的那条上游路径",
不是就 503 拒不受理。

判据用 upstream.current().kind == "anthropic" —— 与 mavis_base_url() 同一条件,
所以不会误伤正常流程(mavis 只在 anthropic 形态下才指向 /bridge/v1)。
/bridge/healthz 新增 serving 字段,可以直接看桥在不在路径上。

回归:tests/test_bridge_serving.py(5 例,含"切回 anthropic 立刻恢复 200"这条防修复过头的)。

🗑 台账会话可删

以前只能增不能删 —— 打过的记录会一直躺在本地 SQLite 里。现在服务状态页有「⑦ 本机台账会话」
列表(最近 20 条:辩题 · 立场 · 时间)+ 逐条删除。

  • 后端 DELETE /api/session/{id},store.delete_session 一个事务级联清
    turns / cards / suggestions / feedback / citation_reports
  • 删的正好是当前会话时,前端状态一并清(sessionId / ledger / conflicts / autoCite)——
    否则界面挂着一个后端已不存在的 id,导出与两道检测全打 404
  • 删除态锁住整张表(防并发二次删除),分析进行中不许删

🔑 密钥默认不存本机

明文密钥躺进浏览器 localStorage 该由一次显式决定触发,不该由"顺手点了保存"带来。
现在默认不存,勾「记住密钥到本机」才存。三条规则:不传 = 不存 / 勾了没重填 = 沿用 /
传了以传的为准。

顺带咬出一个真 bug:toPatch() 原先无条件带 api_key: saved.api_key,一份"没记住密钥"
的配置照旧送去 = 传空串 = 清空后端内存里那把(api_key=None 才是"不动")。
症状是刚点完应用就显示「密钥未设置」。现在空密钥整个字段不提交。

🧪 前端第一次有自动化测试

  • 纯函数层29 例:upstreamStore / liveStateStore / adopt.cardFor(vitest 3.2.4——
    5.x 的 peer 要 vite 6+,与本仓库 vite 5 冲突)
  • 组件级 20 例(jsdom + testing-library):会话列表 / 删除态 / 密钥勾选字节级断言 /
    「点一次 = N 次上游调用」文案 / 「应用」时空密钥不带字段

写完做了变异检验:改坏实现看用例会不会红 —— 两条都精准命中单点
(去掉 rememberKey 判断 → 只有「不勾就保存」红;去掉删除锁 → 只有「删除中…锁全表」红)。
做法写进了 CONTRIBUTING §3。

🧾 界面把代价和限制说在按钮旁边

  • ⑤ 顶部:「上游只驻留后端内存,重启后会回到 .env 的初值 —— 用前请先确认一次」
  • 提交按钮下方:「点一次 = N 路并行 = N 次上游调用,超时的那几路照样计费;探测与核验不计费」
  • README 新增「第一次开机:五步」(中英双语)

✅ 回归

后端 pytest 314 passed(非沙箱前台)· 前端 vitest run 49 passed · tsc --noEmit 0 错 ·
vite build 通过 · bridge_probe.py 10/10 PASS · npm audit --omit=dev 0 漏洞
(全量 4 条告警全在 dev 工具链,vite 已是 5.x 终点 5.4.21,清零要整条升 6/7)。

⚠️ 本版仍未覆盖的(不藏着)

真实云端端到端一次都没跑过。 全部验证都打在假上游或本机模型上,真实网关 + 真实模型的
协议桥转译、五路真并发延迟分布、真实错误形态仍是空白。已知这是唯一用零消耗手段补不上的洞,
下一个版本处理。

引用核验的 MATCH_LOW=0.45 阈值也只在本地语料 + 手工构造的声称上验过,真实模型引述的
误报率未知(同上个原因:本地模型几乎不引法条,触发不了比对)。口径见决策日志 §16 续六。


本文档不含任何凭据。所有密钥只从环境变量读取。