Skip to content

Feat/agent access - #310

Merged
21335464876 merged 4 commits into
devfrom
feat/agent-access
Oct 17, 2026
Merged

21335464876 merged 4 commits into
devfrom
feat/agent-access

Conversation

@SkylistqAq

Copy link
Copy Markdown
Collaborator

No description provided.

SkylistqAq and others added 4 commits October 17, 2026 15:59
- 新模块 agent-access:持久连接凭证(agent_connections,token 仅存 sha256)、
  幂等提交存储(agent_submissions,(connectionId, clientSubmissionId) 唯一,
  重放返回 duplicate)、调试事件(agent_access_events,每连接留 200 条)
- 对外 MCP 端点 POST /v1/mcp/agents:Bearer 连接 token 自鉴权(auth 豁免全局
  bearer)、会话重启自愈、工具按连接能力过滤;复用 channel-mcp 的
  ExchangeTransport(加 export 共享,不复制)
- 九工具面:list_rooms/search/fetch/read_file/get_rules/get_status/
  register_file/submit/submit_status;状态语义 ok/empty/no_permission/
  source_lost/parse_failed/stale/duplicate/pending_review;搜索命中带
  conversation_id+message_id 与 everroom:// URI(与 fetch 解析方案一致)
- 产物入库走 files 管线(sourceKind=agent-generated,CAS 去重);
  候选 pending_review 暂存,待第 6 章三路治理接入
- 连接页 REST /v1/agent-access/*:连接 CRUD/自检/示例查询/安装代写生成
  (agentskills 六字段 SKILL.md + 各工具配置片段)
- preSerialization 脱敏对连接签发/轮换/安装三端点豁免(对齐
  runtime-config/secrets 先例;否则 token 被改写为 [REDACTED])
- 迁移 0081 手写(drizzle-kit generate 因 0048 快照损坏不可用,仓库惯例)
- 测试 13 用例:单元/交换层 7 + 真引导服务器 HTTP 层 6;typecheck 过

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- GatewaySupervisor 新增 portProvider:固定端口设置(dataDir/
  agent-access-settings.json,损坏回退默认)使外部工具的 MCP 配置在
  网关重启后持续有效;页面提供应用与一键重启
- AgentAccessGatewayBridge(Diary 桥模式)+ 14 个 agent-access:* IPC
  通道 + preload agentAccess API + shared/agent-access.ts 共享 DTO;
  处理器提前到 gateway start 前注册(否则冷启动 IPC 排 servicesReady
  队列超时,连接列表须手动触发才出现)
- AgentConnectionsPage(导航「执行」组):连接列表/新建(Room 多选+能力
  勾选+回写位置)/暂停恢复/换 token(一次性展示+复制走主进程
  system-clipboard)/自检(发现/搜索/精读/回写)/示例查询/调试面板
  (提交+调用记录);加载 15s 超时兜底防无限转圈
- AgentAccessInstaller 安装落盘:Claude Code/Cursor 自动合并
  mcpServers.everroom(先备份、损坏 JSON 不写、只动自己的键)、Codex
  技能落盘+TOML 手动片段(token 已替换)、无机制宿主仅片段;安装时
  无 token 自动换发;卸载干净移除
- UI 复用项目资产:PageHeader/secondary-button/全局表单配方(对齐
  AgentSchedulesPage 与 source-connect-form),危险色统一 #b5493a
- 测试 11 用例(安装器 6/设置存储 3/导航 2);typecheck 与
  electron-vite build 过

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- docs/notes/everroom-agent-access-research.md:四路调研合成(网关现状/
  领域模型/MCP+Skills 规范生态/竞品),PRD 第 7 章逐条映射
- docs/design/agent-access-mcp-skills.zh-CN.md:大任务门禁文档——目标/
  架构红线自查/接口设计(表/工具面/状态语义/安装代写)/测试计划/
  分阶段与真机验证清单

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查总结

本 PR 新增外部 Agent 访问能力(持久连接 token + /v1/mcp/agents MCP 端点 + 桌面连接页/安装代写)。整体设计扎实:token 只存 sha256、明文仅创建/轮换返回一次、REST 走全局 bearer、MCP 端点以连接 token 自鉴权、读路径按 roomIds 过滤且有较完整的测试覆盖(鉴权豁免、暂停即时失效、幂等重放都测到了)。但写路径存在一处授权范围绕过,建议修复后再合入。

阻塞问题

1. everroom_submit 的 result_text 条目可绕过 Room 范围校验,向未授权 Room 写入(授权绕过)

apps/gateway/src/modules/agent-access/service.ts:359-362 中,processItem 的范围校验只对 artifact_file 生效:

const roomId = item.roomId ?? connection.scopes.writebackRoomId ?? null;
if (item.kind === "artifact_file" && roomId && !this.roomAllowed(connection, roomId)) {
  return { ...base, status: "rejected", error: "room_out_of_scope" };
}

而 result_text 的 schema 明确允许调用方携带任意 roomId(apps/gateway/src/modules/agent-access/tools-write.ts:46-53、types.ts:103)。复现路径:持有一个仅授权 roomIds: ["room-a"]、writebackRoomId: null 的连接 token 的外部 Agent,提交 { kind: "result_text", title: "x", content: "# x", roomId: "room-b" } —— 文件会以 roomId=room-b、pipelines.room: true 入库(见 create-server.ts 中 agentAccessImportArtifact),并返回 everroom://open/file/... 深链,即写入了连接未被授权的 Room。

同文件 artifact_file 分支与 everroom_register_file(tools-write.ts:130-135)都做了同样的范围校验,可确认这是遗漏而非设计意图。影响:对外暴露的 MCP 写端点的授权被扩大(例如被提示注入的外部 Agent 可向用户未授权的 Room 写内容)。建议去掉 item.kind === "artifact_file" && 条件对两类条目统一校验,并补一条「result_text 携带越界 roomId 应 rejected」的测试(现有 apps/gateway/tests/agent-access.test.ts:351-394 未覆盖该场景)。

建议修复(非阻塞)

2. writebackRoomId 未校验在授权 Room 范围内

  • apps/gateway/src/modules/agent-access/routes.ts:38-50(parseScopes)创建/更新时不校验 writebackRoomId ∈ roomIds;
  • 桌面表单 apps/desktop/src/renderer/src/components/pages/AgentConnectionCreateForm.tsx:152-158 在「仅选定 Room」模式下,回写下拉仍列出全部 Room。

修复问题 1 后,越界的 writebackRoomId 会导致所有回写条目被拒(与 UI 预期不一致);建议网关侧校验,表单只列选定 Room。

3. 已吊销/暂停的连接仍可换取安装代写内容

apps/gateway/src/modules/agent-access/service.ts:165-169 的 verifyTokenMatch 不检查 status,routes.ts:270-287 对 revoked 连接仍会返回含明文 token 的安装计划。该端点虽有全局 bearer 保护,影响有限,但建议非 active 连接直接 403/404,与 MCP 端点行为一致。

4. 含 token 的配置文件权限与备份残留

apps/desktop/src/main/agent-access/installer.ts:92 新建 ~/.claude.json、~/.cursor/mcp.json(内含 Bearer token)使用默认 0644 权限,多用户机器上其他本地用户可读,建议新建文件用 0600。另外 ${path}.everroom-backup-${Date.now()} 备份会无限累积(重新安装后备份里也含 token),可考虑只保留最近一份。

小问题 / 备注

  • apps/gateway/src/modules/agent-access/tools-read.ts:527:非 "all" 范围的记忆检索只取前 10 个 Room(roomIds.slice(0, 10)),超出部分静默漏检;建议在工具描述中注明或改为分页/上限提示。
  • apps/gateway/src/modules/agent-access/routes.ts:218-223:每次自检都以 selftest-${Date.now()} 新建一条 submission(citation)永久落库,调试数据会随自检持续膨胀;可考虑复用固定 submissionId(利用幂等重放)。
  • apps/gateway/src/modules/agent-access/mcp-routes.ts:5-7:body schema 只接受单个 JSON-RPC 对象,批量数组会得到普通 400(非 JSON-RPC 错误形状);发送 batch 的旧版 MCP 客户端会不兼容。
  • apps/gateway/src/modules/agent-access/mcp-routes.ts:49-56:DELETE /v1/mcp/agents 对无效 token 也返回 204,与 POST 的 401 不一致(且 closeSession 内的 verifyBearer 会顺带刷新 lastSeenAt)。
  • apps/gateway/src/modules/agent-access/install.ts:27-29:连接名未转义直接写入 SKILL.md 的 YAML frontmatter(name 仅限长度、未限字符),含换行/--- 的名称会破坏 frontmatter;建议过滤控制字符。
  • apps/gateway/drizzle/meta/_journal.json 丢失文件末尾换行(不影响解析),建议恢复以减少 diff 噪音。

值得肯定

  • 凭证管理规范:sha256 落库 + 唯一索引、前缀展示、明文一次性返回;
  • 读路径每个 fetch 目标都做 roomInScope 校验,搜索 roomIds 下推到 SQL 条件;
  • 测试真引导整服务器覆盖鉴权豁免与迁移(0081),桌面 installer 对损坏 JSON 的保守处理也有测试。

此 PR 修改了高风险文件,需要人工批准,不会自动合并。

  • apps/gateway/drizzle/0081_agent_access.sql
  • apps/gateway/drizzle/meta/_journal.json

@21335464876
21335464876 merged commit 7d66e67 into dev Oct 17, 2026
3 of 4 checks passed
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.

2 participants