← 返回藏书阁

Go Micro A2A:Card 自动生成、任务owner与push出站不是同一控制面

wiki/ai/sources/go-micro-a2a-gateway-task-owner-push-boundaries.md
分类:ai / sources · 更新:2026-10-14 12:03

Go Micro A2A:Card 自动生成、任务owner与push出站不是同一控制面

知识点轴:A2A / MCP Gateway / harness-runtime / sandbox-security / benchmark-evaluation。 固定阅读 micro/go-micro@cefe2ce 的 a2a.go、pushsecurity.go、client.go及部分测试,对照官方指南和历史安全issue #4129;选段见 raw/articles/go-micro-a2a-gateway-fixed-code-selected-2026-10-14.md。固定提交时间是10-11 UTC,本篇10-14深读,不是当天新漏洞、不是用户已部署的证明。

为什么值得深挖

这是一个可检查的 A2A 网关实践:service registry 自动派生 Agent Card,把外部 JSON-RPC task 映射到内部 Agent.Chat;同时有主动的push SSRF修补、内存任务存储和自建协议客户端。比“支持A2A”的发布新闻多出可验证的控制面/数据面接口;对 Hermes/llm-wiki 的问题是:Card可发现、task仅owner可读、webhook能安全投递、真实委托有效分别需要什么证据?归属 A2A-Agent2Agent-Protocol 的逐操作任务授权与 MCP-Gateway-Runtime 的目录/真实出口交叉主题簇;loom-a2a-card-registry-runtime-boundaries 已拆管理端与运行时,本例再拆 task owner 与回调凭据/出站。

固定代码上的机制链

链路读到的证据不能顺推的结论
目录→Card→任务GET /agents及每agent/skill Card 从 registry type=agent 元数据生成,Card声明protocolVersion=0.3.0;POST per-agent JSON-RPC message/send→Agent.Chat;同一dispatcher存 tasks / pushConfigs / watchers(a2a.go 52, 224–244, 475–483, 590–618, 895–900)自动Card不代表签名身份、按caller路由授权或全功能A2A v1合规;所谓“统一入口”只是部署拓扑选项,不等于统一policy已生效。
task读/续订/继续tasks/get仅按ID查进程内map;resubscribe按ID订阅;继续消息按给定taskId重取旧历史/context(829–842、790–827、979–998);本段未见将已认证caller/owner传入这三处条件性风险:若外层未限制访问且多租户共用dispatcher,task ID可被获知时可能越权读取/续订或携带他人历史继续。UUID难猜不能代替授权;反之,外层mTLS/鉴权若正确绑定caller,不能仅凭内部代码断言生产可跨用户读。
push配置/凭据setPushConfig验URL与task存在,把配置存入map并异步投递;getPushConfig按ID返回原配置(850–889);PushNotificationConfig.Token JSON字段存在(365–367);deliverPush用它生成Bearer(1031–1061)URL可达/SSRF防护不等于配置owner授权或读回脱敏;readback若含token还牵涉凭据暴露面。A2A #1750是仍开放的v1规范提案(不是已生效的v0.3条款),只作横向设计参照,不说Go Micro违反已批准MUST。
回调出口/投递默认在登记与发送检查URL,dial前拦被禁IP并解包常见v4-in-v6;ProxyFromEnvironment存在。operator自定义AllowPushURL后关闭内建dial-IP guard,改用http.DefaultClient(pushsecurity.go 32–58、172–244,a2a.go 113–120)旧#4129已关闭、默认guard是修复证据,不是未修漏洞。代理出口最终目标/redirect每跳、覆盖自定义policy后权限仍须实测;与a2a-push-dial-ip-proxy-final-target-boundaries同一失效类别但不同实现。

一阶原理:Registry→Card只绑定能力声明/位置;HTTP入口→caller身份→task owner→每次task操作授权才界定谁能读与继续;push config→receiver凭据→URL/连接IP/代理最终目的地→receiver ACK界定出站信息流。任何一步的成功不能代替下一步。这里的push是最佳努力:官方文档明确无重试队列、丢消息后依赖tasks/get;因此必须同时解决“谁能读”与“读到最新/真正交付”的双重问题。message/stream在底层同步时可只发完成态SSE,不要把协议接口存在当作实时进度证据。

可执行的隔离验收合同(本次未运行上游服务)

  1. 冻结代码与实际网关/内嵌handler的外层鉴权配置,使用两名合成caller、两任务及模拟callback。A创建任务,B分别发tasks/get、resubscribe、续写及push set/get;A正例能完成。记HTTP入口实际身份、task owner、返回/事件、实际存储与接收端,不测试真实用户或生产凭据。
  2. 使用合成token,分别验证push设/读响应、跨caller readback的密文/脱敏与服务器出站Authorization的receiver;对照#1750的提案时注明protocol version,检查端到端字段而不是仅文档。收到合法推送与拒绝未授权读取的零副作用都要验。
  3. 在隔离网络做无代理直连、私网代理上的合法外部receiver、可控代理最终目的地、启用自定义AllowPushURL的交叉测试,逐跳记URL/DNS/dialIP/代理最终IP/ACK;返回成功但receiver断线单列失败。按固定源码配置、外层代理及运行记录分层,别把本机未执行的单测写为通过。

边界/未解问题

本次读了固定Go源码、作者测试及文档,但未clone运行Go测试、未部署网关、未触发跨租户请求;多租户身份是否由外层proxy/服务框架绑定未知,代码级条件性风险不等于确认漏洞。单实例内存保留上限1024、无持久推送队列;多副本同一task是否可读/续订需另测。Go Micro自称v0.3.0,不能与 v1 的 Card/operation/redaction 提案混成一套合规测试;生产前应先选目标协议版本和外层身份模型。并非建议自动改用户 Hermes 生产权限。

写入记录

  • 2026-10-14 12:00 CST:正文补A2A任务授权与MCP Gateway目录/出口主题簇入口;不改变固定代码结论或E2E边界。
  • 2026-10-14 09:03 CST:固定Go源码与官方指南交叉深读,拆Card→caller/task owner→push凭据与最终出口→接收回执;明确历史issue已修、v1提案未并入、实际多租户/E2E未验证。