fix(read)!: 读信只认会话 —— 删掉「同工作区」那道闸门
用户订正:「是应该发到对应 session 的信,因为 agent 多 session 架构,不同 session 的
记忆是隔离的。你之前那个修法简直荒谬」
我把两条轴混在一起了:**工作区**决定 cwd/沙箱/线索可见面,**会话**决定记忆与收件箱。
原先 AgentMayReadSession 判「参与过 + 同工作区」,两头都错:
· 太松:同工作区内、我参与过的**别的会话**也放行 —— 会话之间记忆隔离,读别的会话
就是绕过隔离(用户上午的要求本就是"不同 session 不同收件箱");
· 太严:我在 A 工作区的上下文里读不到**自己刚发起**、落在 B 工作区那条会话。
zcode 撞上这条,403 文案还写着 cross-workspace ⇒ 它推断出"那五位 agent 不存在"。
新判据两句:① target 必须就是 scope(我当前那条会话);② 我参与过 target(防伪造
session_id)。scope==nil 保持迁移期放行(五家桥实测都带 session_id)。
403 文案换成「这封信不在你当前所在的那条会话里:每个会话各有各的收件箱(会话之间的
记忆是隔离的)。你当前在会话 <id>。要读它,就在它那条会话里读 —— 每封来信都会把 worker
唤醒到它自己那条会话上」。报"我在哪"安全,目标会话在哪不报。
判据:workspace_scope_test 的该用例改名并重写为五条形态(自己那条会话放行 / 同工作区
另一条会话拒 / 别的工作区会话拒 / 伪造 session_id 拒 / 未声明 scope 迁移期放行)。
生产实测:① 200 ② 403 not-your-session(新文案)③ 403(伪造)。
This commit is contained in:
@ -48,60 +48,76 @@ func sessionIn(t *testing.T, agent, ws, title string) uuid.UUID {
|
||||
return id
|
||||
}
|
||||
|
||||
func TestAgentMayReadSessionIsWorkspaceScoped(t *testing.T) {
|
||||
func TestAgentMayReadSessionIsSessionScoped(t *testing.T) {
|
||||
setupTestDB(t)
|
||||
ctx := context.Background()
|
||||
const agent = "pi"
|
||||
const wsA = "/home/program/agentmail"
|
||||
const wsB = "/home/program/TrueAgent"
|
||||
|
||||
scope := sessionIn(t, agent, wsA, "我在 A 干活")
|
||||
sameWS := sessionIn(t, agent, wsA, "A 的另一条线索")
|
||||
scope := sessionIn(t, agent, wsA, "我当前在 A 的这条会话里")
|
||||
sameWS := sessionIn(t, agent, wsA, "A 的同工作区、但另一条线索")
|
||||
otherWS := sessionIn(t, agent, wsB, "B 的线索")
|
||||
alien := sessionIn(t, "someone-else", wsA, "与我无关的线索")
|
||||
|
||||
// ① 同工作区 → 放行。少了这条,判据"永远拒绝"也能绿。
|
||||
ok, reason, err := AgentMayReadSession(ctx, agent, &scope, sameWS)
|
||||
// ① 就是我当前这条会话 → 放行。少了这条,判据"永远拒绝"也能绿。
|
||||
ok, reason, err := AgentMayReadSession(ctx, agent, &scope, scope)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("同工作区的会话必须能读,却被拒(reason=%q)", reason)
|
||||
t.Fatalf("自己当前这条会话必须能读,却被拒(reason=%q)", reason)
|
||||
}
|
||||
|
||||
// ② 跨工作区 → 拒,且原因要说清是工作区不对(不是"没参与过")。
|
||||
// ② 同工作区的**另一条**会话 → 拒。★ 2026-09-15 用户订正:
|
||||
// 会话是记忆隔离的单位,"不同 session 不同收件箱" —— 旧判据在这里是放行的
|
||||
// (它只看工作区),那等于绕过会话隔离。
|
||||
ok, reason, err = AgentMayReadSession(ctx, agent, &scope, sameWS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ok {
|
||||
t.Fatal("★ 同工作区但不同会话必须拒 —— 会话之间记忆隔离,读别的会话就是绕过它")
|
||||
}
|
||||
if reason != "not-your-session" {
|
||||
t.Fatalf("拒绝原因应是 not-your-session(实际 %q)", reason)
|
||||
}
|
||||
|
||||
// ③ 别的会话(工作区也不同)→ 拒,且**不再**用工作区的名义解释
|
||||
// (工作区是 cwd/沙箱那条轴的事;zcode 2026-09-15 正是被那句 cross-workspace
|
||||
// 误导,推断出"那些 agent 不存在")。
|
||||
ok, reason, err = AgentMayReadSession(ctx, agent, &scope, otherWS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ok {
|
||||
t.Fatal("★ 跨工作区必须拒 —— 用户报的就是这个(TrueAgent 的 worker 读到 agentmail 的线索)")
|
||||
t.Fatal("别的会话必须拒")
|
||||
}
|
||||
if reason != "cross-workspace" {
|
||||
t.Fatalf("拒绝原因应是 cross-workspace(实际 %q):分不清原因,调用方就没法自查", reason)
|
||||
if reason != "not-your-session" {
|
||||
t.Fatalf("拒绝原因应是 not-your-session(实际 %q)—— 别拿工作区当理由", reason)
|
||||
}
|
||||
|
||||
// ③ 没参与过的会话 → 拒,且原因是 not-participant(两道闸门要能分开)。
|
||||
ok, reason, err = AgentMayReadSession(ctx, agent, &scope, alien)
|
||||
// ④ 伪造 session_id:声明 target 就是自己所在会话,但并没参与过 → 拒。
|
||||
ok, reason, err = AgentMayReadSession(ctx, "pi-not-in-it", &alien, alien)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ok {
|
||||
t.Fatal("没参与过的会话必须拒")
|
||||
t.Fatal("没参与过的会话必须拒(防伪造 session_id)")
|
||||
}
|
||||
if reason != "not-participant" {
|
||||
t.Fatalf("拒绝原因应是 not-participant(实际 %q)", reason)
|
||||
}
|
||||
|
||||
// ④ 未声明 scope = 旧语义放行。**这是迁移期的妥协,不是正确行为**:
|
||||
// 尚未接线的桥会走这条路,所以它必须有判据守着 —— 哪天要收紧成"拒",
|
||||
// 这条测试会红,逼人去看还有谁没接线(服务端同时也记警告日志)。
|
||||
// ⑤ 未声明当前会话 = 迁移期旧语义放行。**这是妥协不是正确行为**:
|
||||
// 尚未接线的桥走这条路,所以它必须有判据守着 —— 哪天收紧成"拒",
|
||||
// 这条会红,逼人去看还有谁没接线。
|
||||
ok, _, err = AgentMayReadSession(ctx, agent, nil, otherWS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatal("未声明 scope 时是旧语义(放行)—— 要收紧请连这条判据一起改")
|
||||
t.Fatal("未声明 scope 时应保持旧语义放行(迁移期妥协,收紧要显式改这条判据)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user