Skip to content

feat(v3): 跨机上手链路 — auth issue / login --token / room invite / join 远程放宽#206

Open
raysonmeng wants to merge 2 commits into
feat/v3-web-dashboardfrom
feat/v3-xnet-onboarding
Open

feat(v3): 跨机上手链路 — auth issue / login --token / room invite / join 远程放宽#206
raysonmeng wants to merge 2 commits into
feat/v3-web-dashboardfrom
feat/v3-xnet-onboarding

Conversation

@raysonmeng

Copy link
Copy Markdown
Owner

背景 / Why

审计暴露的跨机 onboarding 大洞:broker 用自己的 storeStorePskIdentityProvider + getMembers)验 token 与成员,而边机 abg auth login 只在本机 store 自签——方向反了,边机 token 永远进不了 broker store → 4401。两边 store 物理隔离、零桥接。

The broker validates tokens & membership against its own store; an edge abg auth login self-signs only in the local store, so an edge token never authenticated against a remote broker (4401). This PR adds the missing cross-machine onboarding primitives.

改了什么 / What

  • abg auth issue --id --name(在 broker 机跑):在 broker store registerIdentity + issueToken + 打印 token 带外发不写本地 auth-token(token 是给别人的)。
  • abg auth login --token <PSK>(边机跑):把 broker 签发的 token 装进 <state>/auth-token(0600),不 register/issue;空 token 拒(fail-closed,避免静默关认证)。
  • abg auth login --id --name:legacy 本机自签(单机:同一 store 既签又验),保留不变。
  • abg room invite <roomId> <id> [--name] [--broker-url](broker 机):issueToken + addMember + 打印对方该跑的一条龙(export AGENTBRIDGE_BROKER_URL=… + abg auth login --token … + abg join …);caller 必须是成员(复用 §11.2 isMember 授权门);loopback 地址会告警提示换可路由地址。
  • abg join 远程房间放宽:本地无此房不再硬失败,只映射 cwd→roomagentId:null, local:false);不授予成员资格,成员制交 broker 在订阅时强制。
  • 连接卡 net-detect.ts:改用真实可跑命令(引导走 room invite)。
  • 评审修复:auth issue 补 token 积累诚实提示(与 invite 一致);removeRoomMember 补房间存在守卫(与 addRoomMember 对称)。

安全边界 / Security

  • auth issue / invite 复用 isMember 授权门;join 放宽只映射 cwd,broker 才是远程权威(subscribe/publish/投递/离线/补投全部对 broker store 校验,边机本地状态不被采信)。
  • 0700 目录锁(collab.db 存 raw PSK + PII)+ 0600 token;空 token 拒。
  • 存在性报错 oracle 仅对 collab.db 属主本机可见(他本就能直接读 db),不跨权限边界;broker 端对「房间不存在」与「非成员」返回一致 not a room member,跨网无存在性 oracle。

测试 / Tests

  • 单测:cli-auth / cli-room / net-detect 全绿;新增 invite 一条龙输出断言、远程 join 不授成员断言、remove 成员/房间守卫断言。
  • bun run check1863 pass / 0 fail,typecheck 干净,plugin-sync OK,版本对齐。
  • Cross-review:6 个独立 opus reviewer / 4 轮,最后两轮全 0 真实 issue 收敛。

诚实标注 / Honest scope

  • 本 PR 是协议+CLI 原语层。物理隔离多 store 的真·端到端证明(机器A 签发 → 机器B 装 token → join → 连 broker → 收到房间事件,绝不共享 store)作为紧接的下一步补上(不复用之前共享 store 的 §13 捷径)。
  • token 吊销(重复 issue/invite 旧 token 不自动失效)仍在 backlog(独立的 abg auth revoke + at-rest 哈希)。

🤖 Generated with Claude Code

rayson951005@gmail.com and others added 2 commits June 26, 2026 21:29
补齐审计抓出的跨机 onboarding 大洞(根因:边机 abg auth login 自签的 token 进不了 broker store → broker 验 token 用自己 store → 4401):

- `abg auth issue --id --name`(在 broker 机跑):在 broker store registerIdentity + issueToken + **打印 token 带外发**,**不写本地 auth-token**(token 是给别人的)
- `abg auth login --token <PSK>`(在边机跑):把 broker 签发的 token 装进 `<state>/auth-token`(0600),**不 register/issue**;空 token 拒
- `abg auth login --id --name`:legacy 本机自签(单机:同一 store 既签又验),保留不变
- `abg room invite <roomId> <id> [--name] [--broker-url]`(broker 机):issueToken + addMember + 打印对方该跑的一条龙(`abg auth login --token …` + `abg join …`);**caller 必须是成员**(复用 §11.2 isMember 授权门)
- `abg join` 远程房间放宽:本地无此房不再硬失败,只映射 cwd→room;成员制交 broker 订阅时强制(**不授予成员资格**)
- 连接卡 net-detect.ts:改用真实命令(引导用 room invite)
- cli.ts 路由 auth issue + room invite + printHelp

安全:auth issue/invite 复用 isMember 授权门;join 放宽只映射 cwd、broker 才是权威;0700 目录 + 0600 token;空 token 拒。
bun run check 1860 pass。

feat(v3): cross-machine onboarding — auth issue / login --token / room invite / remote join

Broker validates tokens against ITS store, so an edge self-signed token was never valid (4401).
Adds broker-side token issuance + edge-side install + one-shot room invite + remote-join relax.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rhWKm1VUSnEVxmjpYwNfc
物理隔离的两个 SqliteStore(机器A=broker+operator / 机器B=远程边机),驱动真实 CLI 原语
(inviteRoomMember 在 store A 签发+加成员 → installToken 边机装 token → joinRoom 远程只映射 cwd)
+ 真实边机入口 startRoomBridge,证明:唯一跨界的是 token 字符串,机器A publish 的完成事件
送达机器B;全程 store B 零房间/零成员、连 token 都解析不了(resolveToken→null),broker(store A)
是唯一权威。负向:边机本地自签 token(store C,不在 broker store A)被 broker 拒——复刻修复前根因。

2 个对抗式 opus reviewer 各自独立跑变异测试(连接前删 store A 里 bob 成员资格 / 换 store A 没签发的假
token → B 收 0 条),均判「诚实证明、非空过」、0 真实 issue。

test(v3): cross-machine onboarding multi-store E2E proof (T8)

Two physically separate SqliteStore files driving the real CLI primitives + the real edge entry
(startRoomBridge): only the token string crosses; machine B's store holds no room / no membership
and cannot even resolve the token (resolveToken→null) — the broker (store A) is the sole authority.
A completion published on machine A is delivered to machine B. Negative test reproduces the pre-fix
root cause (an edge self-signed token, never issued by the broker's store A, is rejected at 4401).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rhWKm1VUSnEVxmjpYwNfc
@raysonmeng

Copy link
Copy Markdown
Owner Author

T8 跨机 onboarding 多独立 store E2E 真测已落地(commit 2869fdd,本 PR 内)

PR 说明里「物理隔离多 store 的真·端到端证明作为下一步」现已补上:src/integration-test/xnet-onboarding.test.ts

  • 物理隔离两个 SqliteStore(机器A=broker+operator / 机器B=远程边机,不同临时目录、不同文件、无共享对象)。
  • 驱动真实 CLI 原语inviteRoomMember(store A 签发+加成员)→ installToken(边机装带外 token)→ joinRoom(远程只映射 cwd、不授成员);再经真实边机入口 startRoomBridge 连 broker。
  • 正向:唯一跨界的是 token 字符串;机器A publishCompletion 的 task_completed 送达机器B。全程断言 store B getRoom→nullgetMembers→[]resolveToken→null(B 的 store 对该 token 鉴权全盲),成员资格只活在 broker 的 store A。
  • 负向:边机本地自签 token(store C,不在 broker store A)被 broker 拒(4401)——复刻修复前根因。
  • 对抗 review:2 个独立 opus reviewer 各自跑变异测试(连接前从 store A 删 bob 成员 / 换 store A 没签发的假 token → B 收 0 条),均判「诚实证明、非空过」、0 真实 issue

bun run check:1865 pass / 0 fail。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant