
buzz Provider Wire 契约用录制式黄金夹具守护桌面端与 Kubernetes 提供方的 stdin/stdout 协议【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz本文基于仓库内 provider-wire 夹具目录说明 及 wire_fixtures.rs 测试套件撰写。导读buzz 桌面端desktop将受管 Agent 部署到 Kubernetes 时并不是直接调用库函数而是以子进程方式启动buzz-backend-kubernetes提供方provider通过stdin 送入一个 JSON 请求、从 stdout 读回一个 JSON 响应、并以退出码表达成败。这套一次进程、一个对象的线缆协议wire protocol规范中称为 §Provider Protocol横跨两个独立代码库谁来当裁判答案就是本文的主角crates/buzz-backend-kubernetes/tests/fixtures/provider-wire/下的黄金线缆夹具golden wire fixtures。读完本文你将掌握这套协议的请求/响应形态、夹具录制而非发明的治理规则、测试套件如何驱动真实二进制做端到端断言以及桌面端与提供方各自的责任边界。一、夹具目录是什么跨代码库的契约仲裁者crates/buzz-backend-kubernetes/tests/fixtures/provider-wire/ ├── README.md ├── deploy-full-launch.request.json # 桌面端最完整的发射载荷无静态响应 ├── deploy-no-owner.request.json # 无 owner 的拒绝响应 ├── deploy-no-owner.response.json ├── deploy-relay-mesh.request.json # relay-mesh 提供方的拒绝响应 ├── deploy-relay-mesh.response.json ├── deploy-relay-mesh-padded.request.json # 带空格的 relay-mesh 同样被拒 ├── deploy-relay-mesh-padded.response.json ├── deploy-tag-image.request.json # 非 digest 固定的镜像 tag拒绝 ├── deploy-tag-image.response.json └── info.request.json # 握手请求无静态响应按字段校验每个*.request.json是桌面端可能发射的请求每个配对的*.response.json是本提供方对它的精确响应。校验分工是双向的提供方一侧由 tests/wire_fixtures.rs 断言喂入请求 → 比对 stdout 与响应夹具桌面端一侧应自行断言它发射的载荷能被解析为对应请求README 明确要求 desktop 侧承担这一职责。协议本身的形态是一个进程只处理一次操作请求方每次 spawn 一个新的提供方进程[wire.rs](https://link.gitcode.com/i/ff7079fb43f3c0db05a10e61c07b0390)的注释说得非常直白——One process per operation: one JSON object in, one JSON object out。这个设计决定了后面很多看似过度设计的断言比如必须恰好一行输出都是在为这个形态兜底。二、让夹具有用而非装饰的三条军规README 用三条规则约束夹具的维护每一条背后都有一次真实事故规则一请求是录制的不是发明的一个没人发射的夹具测试的是一个不存在的契约。录制在这里有精确含义执行并转录——deploy-full-launch.request.json是桌面端真实代码路径build_launch_block→deploy_payload_json的输出而不是读代码推导出来的形状。为什么强调不是推导的因为推导正是这个夹具当初同时获得四个不可能值的根源README 记录了这次事故错误字段推导者写的内容真实发射方写的内容出处respond_to一个公钥字符串kebab-case 的RespondTo枚举序列化值桌面端managed_agents/types.rsallowlist / owner不符合规则的字符串通过validate_respond_to_allowlist64 位十六进制校验的值见下节并行度环境变量BUZZ_ACP_PARALLELISMBUZZ_ACP_AGENTS桌面端运行时写入README 引用的runtime.rs:729launch.env键凭空捏造来自resolve_effective_harness_descriptor的某一层桌面端 harness 解析也就是说任何人凭阅读代码推导一个请求都几乎必然写出提供方和桌面端双方都不会真正收发的东西。只有从真实发射路径转录下来的载荷才有资格成为契约样本。规则二提供方不巡逻这份文件桌面端必须自守关键在于提供方对大量字段是刻意漠视的respond_to在提供方眼里只是一个不透明的OptionString见 wire.rsallowlist 只是一个不透明的VecStringwire.rspolicy_env是一张任意 map。所以the_full_desktop_payload_is_accepted这个测试对发明数据和录制数据会一样高兴地通过——提供方无法证明这份文件是真话。真正的执法者是桌面端的整体对象相等测试whole-object equality test桌面端在自己的测试里现场构建载荷并与该文件逐字节比较。这一侧不写夹具就成了单边声明。配套的还有一个完整性守卫wire_fixtures.rs里对响应夹具目录做了一次 case 列表与磁盘扫描的比对见 wire_fixtures.rs——新增了一个.response.json却忘了加进测试数组套件会立刻报response fixtures and cases disagree。它能阻止 case 消失但正如 README 所说它无法告诉你某个 case 是假的。这就是录制纪律存在的意义。规则三响应在 key 排序重序列化之后字节级比较serde_json::Value在比较时对键序不敏感但夹具比较刻意先做key 排序后的重序列化再逐字节比较responses_match_their_fixtures中对 actual 与 expected 的assert_eq!。效果是一个字段改名或类型变化在这里立刻失败而不是在一个默默读到undefined的桌面端里延迟爆炸。这正是黄金夹具最值钱的地方——契约漂移在最靠近改动点的地方被拦下。三、夹具逐项解析每个请求/响应到底在守什么deploy-relay-mesh共享计算 Agent 不能进 Pod请求只带最小字段name、relay_url、private_key_nsec、auth_tag、provider: relay-mesh响应是{ok:false,error:deploy refused: this agent is configured for shared compute (relay-mesh), which runs on the relay rather than in a pod. Switch the agent to a local runtime before deploying it to Kubernetes.}relay-mesh是跑在 relay 上的共享计算运行时没有 Pod 可部署。实现上这个拒绝发生在请求反序列化之前main.rs的respond先把输入解析成裸serde_json::Value再调用refuse_relay_mesh见 main.rs原因注释写得很清楚——AgentPayload刻意不携带provider字段所以必须看线缆上的原始值才能做出这个判定。deploy-relay-mesh-padded relay-mesh 一样被拒同一个请求只是provider变成了带首尾空格的 relay-mesh 响应完全相同。refuse_relay_mesh在比较前先trim()——因为桌面端各层对 padding 的处理不一致有的层 trim、有的层不 trim一个共享了自己绕行路径的后卫不是后卫。这个夹具专门钉死带 padding 也必须被拒绝。deploy-no-owner没有 owner 就无法响应!shutdown请求没有auth_tag也没有launch.owner_pubkey响应是{ok:false,error:deploy refused: neither auth_tag nor launch.owner_pubkey resolved — without an owner the agent cannot honor !shutdown}对应实现是 env.rs 的!shutdown守卫无法把!shutdown指令路由给正确的操作者时拒绝部署本身就是一种安全行为。deploy-tag-image镜像必须 digest 固定请求里provider_config.image是ghcr.io/block/buzz-sprig:latest响应是{ok:false,error:provider_config.image \ghcr.io/block/buzz-sprig:latest\ is not digest-pinned: a tag is a mutable pointer, and this object runs with the agents private key. Use namesha256:64 hex chars}实现位于 image.rs。理由极具说服力这个对象携带着 Agent 的私钥运行镜像 tag 是可变的指针任何人推送同名 tag 就等于在编排一个持有私钥的恶意镜像。要求namesha256:64 hex chars是强制性的供应链安全基线config.rs的测试也印证了这一规则config.rs:343断言解析错误包含digest-pinned。deploy-full-launch桌面端最完整的发射载荷这是唯一没有静态响应夹具的 deploy 用例——因为它会真实触达集群结果依赖 kubeconfig。它的价值在于the_full_desktop_payload_is_accepted把桌面端最丰富的载荷喂进去断言它在解析层被完整接受失败必须发生在连接阶段而不是解析阶段。载荷中可见完整的三层结构顶层agent字段agent_command/agent_args、model、provider、relay_url、respond_to这里是allowlist、respond_to_allowlist两个 64 位十六进制公钥、parallelism、env_vars等agent.launch块command、args、env、policy_env含BUZZ_ACP_AGENTS、BUZZ_ACP_DISPLAY_NAME、BUZZ_ACP_MODEL、BUZZ_ACP_SESSION_POLICY等与owner_pubkeyprovider_confignamespace、imagedigest 固定形式、inactivity_seconds。info握手请求{op:info,request_id:req-1}——注意request_id被发送但永远不会出现在响应里详见下节。它没有静态响应文件因为info响应里含有一个每次调用随机生成的命名空间默认值黄金拷贝反而会让测试每次必挂所以 info_response_carries_the_contract_fields 改为按桌面端实际读取的字段断言ok true、protocol_version 1、name kubernetesconfig_schema.required [namespace, image]namespace默认值以buzz-agents-开头image默认值以ghcr.io/block/buzz-sprig:开头且包含sha256:。四、测试套件驱动真实二进制而不是进程内函数wire_fixtures.rs 的模块注释点明了整套测试的方法论这些测试驱动的是编译产物built binary通过真实管道通信而不是调用进程内函数。因为桌面端依赖的契约是stdin → stdout 一个 JSON 对象 → 退出码而进程内测试会跳过三件真正会坏的事进程什么都没写进程写了两个对象桌面端读取器会永远卡在第二个对象上通过退出码表达结果。run()辅助函数wire_fixtures.rs把请求写入子进程 stdin等待退出返回(stdout, 退出码)。一个值得注意的细节它强制设置了KUBECONFIG/nonexistent/kubeconfig-for-fixture-tests——一个必然失败的 kubeconfig 本身就是测试装置任何意外触达集群的夹具会在这里响亮地失败而不是悄悄依赖开发者当前指向的某个集群。四个测试各自在断言什么responses_match_their_fixtures对每个 case断言退出码为 0、stdout 恰好一行stdout.matches(\n).count() 1杜绝一次写了两个对象、响应与夹具在 key 排序重序列化后相等并执行目录扫描完整性守卫。info_response_carries_the_contract_fields如上节所述按字段校验而不是整字节比较规避随机生成的命名空间默认值。the_full_desktop_payload_is_accepted喂入完整载荷断言错误包含kubeconfig——它失败了因为没有集群但必须失败在连接这一步证明它已接受其上的每一个字段。the_respond_to_gate_matches_the_harness_acceptance_surface一组 pre-registered 的 respond-to 矩阵把deploy-full-launch.request.json作为基线每个 case 只改动被测字段用例respond_toallowlist预期是否到达集群allowlist []allowlist空列表否拒绝allowlist absentallowlist缺省否拒绝allowlist junkallowlist[beefcafe]否拒绝unparseable modenpub1abc—否拒绝padded mode allowlist —否拒绝allowlist two validallowlist两个 64-hex是owner-only junk listowner-only[beefcafe]是非 allowlist 模式不校验列表allowlist padded upperallowlist带空格大写 64-hex是trim 后合法nobody / anyonenobody/anyone—是判断是否到达集群的探针就是错误串里是否含kubeconfig连接失败还是deploy refused被门禁拒绝——正如注释所说kubeconfig 意味着门禁通过并到达了集群其他任何结果都意味着我们在写 Secret 之前就拒绝了。只断言ok: false的测试会在连接错误上照样通过从而什么都证明不了。五、协议实现的源码级剖析wire.rs 的刻意取舍wire.rs 定义了协议的两端类型处处体现只类型化本绑定真正消费的字段的原则Request是一个#[serde(tag op, rename_all lowercase)]的枚举Info/Deploy未知 op 走带内错误in-band error返回request_id刻意缺席于所有响应变体一次请求对应一次响应、一个进程没有需要关联的异步消息响应 schema 里也没有回显它的位置InfoResponse只有ok/name/version/protocol_version/description/config_schemaDeployResponse只有ok/agent_id。Serde 在进入时忽略它所以发送request_id的调用方依然被接受——类型化它只会造出一个没人读的字段AgentPayload只类型化relay_url、private_key_nsec、auth_tag、respond_to、respond_to_allowlist、env_vars、launch。name、model、provider、turn_timeout_seconds被刻意排除对象名由公钥推导而非显示名模型/提供方对已解析进launch块类型化它们会诱发规范禁止的提供方侧重映射LaunchBlock携带桌面端已解析好的command/args/env/policy_env/owner_pubkey其中env是烘焙 → 运行时元数据 → 定义 → 全局 → persona → agent六层合并的最终结果policy_env是可覆盖的行为默认值Response是#[serde(untagged)]枚举扁平序列化为{ok: true, …}——因为桌面端从顶层读取ok、error、agent_id。环境变量的三档优先级与门禁env.rs 的build_env把最终 Pod 环境按规范顺序写成三次赋值让后来者胜可见而非靠争论Tier 1launch.policy_env可覆盖行为默认值Tier 2launch.env有launch块时不再重新合并env_vars否则会复活桌面端已解析掉的层无launch块时回退到遗留字段env_varsTier 3权威层先清空再写入BUZZ_RELAY_URL、BUZZ_PRIVATE_KEY等——身份永远来自顶层载荷字段绝不来自env_vars。门禁validate_respond_to_gateenv.rs与buzz-acp自身的规则完全镜像连不对称性都照搬allowlist 只在 allowlist 模式下校验、其他模式仅告警。每条校验失败都有一个具体的为什么——模式不合法意味着 Pod 会参数解析失败、被替换、并在每次尝试后遗留一个 Secret只有后续部署的孤儿清扫才能回收见注释中ORPHAN_SECRET_MIN_AGE_SECS。桌面端侧对应的权威校验器是 types.rs 的validate_respond_to_allowlist逐条 trim、必须恰为 64 个十六进制字符、去重并归一化小写前端 UI 层RespondToField.tsx也明确指向这个 Rust 侧校验器作为唯一权威。六、桌面端如何发射这些请求agents_deploy.rs桌面端的发射路径集中在 agents_deploy.rsbuild_deploy_payloadL191-L248是完整装配先做spawn_key_refusal检查加载全局/persona/team 环境并逐层 mergeresolve_effective_config解析生效配置ensure_remote_provider_supported在桌面端就拒绝relay-mesh共享计算 Agent 不能远程部署因为 mesh 端点是桌面本地的然后resolve_effective_harness_descriptor解析 harness 描述符最后交给deploy_payload_json序列化build_launch_blockL161-L178与build_launch_block_for_policy负责产出launch块——这正是deploy-full-launch.request.json的来源deploy_payload_jsonL255 起是纯序列化的一半遗留顶层字段仅为展示/记账保留提供方实际执行的是解析好的launch块effective_parallelism与launch.policy_env[BUZZ_ACP_AGENTS]从同一个解析结果预计算避免两个数字对不上。这套桌面端预解析、提供方只执行的分工正是夹具规则二的根源提供方把大量字段当作不透明值所以契约的真实性必须由发射方桌面端用自己的整体相等测试来背书。七、边界与局限为什么成功部署不在静态夹具里README 在最后明确划清了边界deploy-*夹具只覆盖无需集群即可触达的响应——拒绝与畸形输入。一次成功的部署需要真实的 apiserver它由**一致性套件conformance suite**覆盖而不是静态夹具——因为静态夹具无法表达一个 Secret 被创建、Pod 被调度、启动被确认这类有状态结果。这也解释了目录里的微妙结构有deploy-full-launch.request.json却没有它的.response.json——这个 case 的响应是被解析层接受、在连接层失败是一种结构性的不可能。如果你想亲手验证这套契约流程是进入crates/buzz-backend-kubernetes先cargo build得到二进制再cargo test --test wire_fixtures运行上述四个测试夹具文件即协议样本桌面端侧则可参考其deploy_payload_json的既有单测如 agents_deploy.rs 起的序列化测试来补足发射侧整体相等的验证。结语provider-wire 夹具目录的独特之处在于它不是一份文档化的协议而是一组可执行的、双向约束的、记录了真实历史事故的契约样本。录制而非发明防的是想当然提供方不巡逻所以桌面端自守防的是单边声明key 排序后字节级比较防的是静默漂移。当你下次在两个代码库之间划一条 stdin/stdout 边界时这套黄金夹具 真实二进制测试 刻意的不对称守卫的组合是一个可以直接照搬的样板。【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考