AskaEth
770a83c3fb
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(gateway,security): WS 上行帧角色门 + 握手回放仅 owner/admin(design/11 §7.2)
主人 2026-10-03 拍板"这一类要收紧"后,补齐 §7.1 下行门之外的两处同类缺口:
viewer 是只读监控档,却能通过 WS 拿到内容、甚至发起写入。
A. 握手 history 回放仅 owner/admin(ws_history.go)
连接建立时回放主会话最近 50 条消息正文,此前对任意角色照发 ⇒ viewer 一连上就
拿走主人对话内容。门放在 hub.replayHistory 的第一行 —— 它是唯一发出 history 帧的
函数,将来多一个调用者也绕不过去。
B. 上行 JSON 帧按角色授权(ws_route.go,fail-closed)
此前 route 完全没有角色检查。现在 route 的第一条语句即:非 owner/admin → 回定向
{type:"error",data:{code:"forbidden"}} 并 return,因此"不广播、不驱动模型、不落库、
不返回任何内容"是结构性的,而不是每个 handler 各自记得检查。写成默认拒而非黑名单 ——
chat / interrupt / subagent_ask / task_output_query / voice_input / mode_switch 以及
将来任何新帧都自动被拒。协议级帧(ping/pong/close)由 gorilla 在 ReadMessage 内处理,
不受影响(已实测:被拒后 ping→pong 正常、close 后服务端注销连接)。
被修掉的真实越权:viewer 发 chat 会真的驱动模型并把消息落库;subagent_ask /
task_output_query 的定向应答会绕过 §7.1 下行门,把子代理上下文/任务输出回给 viewer。
契约:Docs/api-client.md → v0.49(对 viewer 收紧;owner/admin 逐帧形状不变)
验证:go build/vet 绿;go test ./... = 58 包 ok / 0 FAIL;-race ./internal/services/gateway/...
ok;linux/amd64 + darwin/arm64 交叉编译绿;新测试 -count=3 稳定。
真 httptest WS + 真 JWT 逐帧实测:viewer 收不到 history 回放、上行一律定向 forbidden
且 runner 计数 = 0 / 落库 = 0;owner 侧 chat 驱动 runner = 1 且落库 2 条。
变异验证:① 去掉 A 的门 → viewer 收到 {"type":"history",...,"content":"主人的私密提问"},FAIL;
② 去掉 B 的门 → viewer 帧驱动 runner 1 次并落库 2 条、且直接收到 subagent_event / task_output,
FAIL。均已还原;且撤掉 B 时 A 的测试仍独立 PASS(两把门不互相代偿)。
遗留(如实登记):非 JSON 的上行字节不经过 route 的角色门(零副作用:不带 type、不触发
handler、不落库);admin 上行未单独测一格(与 owner 共用同一分支)。
2026-10-03 22:02:16 +08:00
..
2026-10-03 21:06:22 +08:00
2026-09-07 18:19:31 +08:00
2026-09-07 18:19:31 +08:00
2026-10-03 18:26:27 +08:00
2026-10-03 18:00:01 +08:00
2026-09-08 02:53:01 +08:00
2026-09-08 02:53:01 +08:00
2026-09-09 00:08:29 +08:00
2026-09-08 23:20:12 +08:00
2026-09-08 23:20:12 +08:00
2026-09-09 00:08:29 +08:00
2026-09-07 13:57:36 +08:00
2026-09-08 21:45:00 +08:00
2026-09-07 16:21:49 +08:00
2026-10-03 21:06:22 +08:00
2026-09-09 00:08:29 +08:00
2026-10-03 18:26:27 +08:00
2026-09-09 00:08:29 +08:00
2026-10-03 19:54:22 +08:00
2026-10-03 20:40:44 +08:00
2026-10-03 20:12:29 +08:00
2026-10-03 20:22:31 +08:00
2026-10-03 20:40:44 +08:00
2026-09-08 06:48:15 +08:00
2026-09-08 21:23:12 +08:00
2026-09-07 05:13:36 +08:00
2026-09-08 21:45:00 +08:00
2026-09-08 21:45:00 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 20:40:44 +08:00
2026-09-30 11:58:49 +08:00
2026-10-03 21:50:29 +08:00
2026-09-07 16:01:47 +08:00
2026-10-03 21:39:03 +08:00
2026-10-03 19:27:25 +08:00
2026-09-08 21:49:12 +08:00
2026-10-03 20:12:29 +08:00
2026-09-08 21:17:26 +08:00
2026-09-08 23:59:13 +08:00
2026-10-03 21:24:51 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 21:24:51 +08:00
2026-10-03 20:12:29 +08:00
2026-10-03 16:55:22 +08:00
2026-10-03 16:55:22 +08:00
2026-09-08 21:24:36 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 19:27:25 +08:00
2026-09-30 09:03:16 +08:00
2026-09-06 21:02:46 +08:00
2026-10-03 19:27:25 +08:00
2026-10-03 15:22:03 +08:00
2026-10-03 21:38:59 +08:00
2026-10-03 21:38:59 +08:00
2026-09-06 21:02:46 +08:00
2026-10-03 15:22:03 +08:00
2026-10-03 21:24:51 +08:00
2026-10-03 20:40:44 +08:00
2026-09-07 19:43:48 +08:00
2026-09-07 19:43:48 +08:00
2026-10-03 19:27:25 +08:00
2026-10-03 20:40:44 +08:00
2026-10-03 19:27:25 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 21:01:33 +08:00
2026-10-03 20:30:38 +08:00
2026-10-03 21:01:33 +08:00
2026-10-03 20:12:29 +08:00
2026-10-03 16:47:55 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 20:12:29 +08:00
2026-10-03 21:01:33 +08:00
2026-09-06 20:40:49 +08:00
2026-09-08 21:36:03 +08:00
2026-09-08 21:36:03 +08:00
2026-10-03 22:02:16 +08:00
2026-10-03 20:12:29 +08:00
2026-09-06 16:31:28 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 22:02:16 +08:00
2026-10-03 15:19:57 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 15:19:57 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 21:50:29 +08:00
2026-10-03 22:02:16 +08:00
2026-10-03 22:02:16 +08:00