
Cua Sandbox 周期实时 Fleet E2E 工作流设计从云端沙箱冒烟到持久化池的自动化验证体系【免费下载链接】cuaScale computer-use 2.0 with open-source drivers, cross-OS fleets, and benchmarks for training, evaluation, and data generation.项目地址: https://gitcode.com/GitHub_Trending/cua/cua导读本文剖析 cua 仓库中cua-sandbox的周期实时 Fleet E2E 设计见 设计文档该方案通过 GitHub Actions 每 15 分钟对生产环境https://run.cua.ai执行真实的沙箱供给、guest 访问与 claim-only 清理验证并以双 lane仓库源码与已发布包覆盖两种套件ephemeral 与持久化 pool。读完本文你将掌握这套「实时冒烟 持久化资源治理 Alertmanager 告警 契约测试防回归」的 CI 体系如何设计、如何落地以及其底层 SDK 调用链与清理语义。一、为什么需要周期实时 E2E问题背景与设计目标问题单元测试无法证明生产链路可用cua-sandbox仓库对 Fleet 资源生成已有较为完整的单元与契约覆盖但普通的 PR CI 无法证明SDK 能否真的通过https://run.cua.ai供给一个真实沙箱、能否连通 guest 内的 computer-server、能否在结束时移除自己创建的资源。这三步恰好是用户使用Sandbox.ephemeral()时的完整旅程任何一环在真实基础设施上出问题本地 mock 测试都感知不到。仓库此前曾存在.github/workflows/periodic-test-linux-cloud-vm.yml每 15 分钟跑一次 Linux 云 VM 冒烟使用仓库 secret 并在失败时通知 Alertmanager。该工作流已于 2026 年 7 月 10 日作为遗留的 cloud VM 测试被移除。本文描述的periodic-cua-sandbox-live.yml正是它的替代者保留快速检测与运维告警能力但转向验证当前 Fleet-backed 的公开 SDK 契约。Goals目标设计文档明确了以下目标每 15 分钟针对生产基础设施执行一次 Fleet-backed 的Sandbox.ephemeral()在同一节奏下从预置的持久化 Fleet poolwarm 池与 scale-to-zero 池执行 claim同时测试当前仓库main源码与最新发布的cua-sandbox包相关变更合并到main后立即执行源码 lane验证 guest 访问、生成的 Fleet 端口配置、以及「仅清理 claim」的持久化资源回收通过 Alertmanager 告警并携带足够的 lane 与版本上下文用于故障分诊防止失败或已被取代的运行累积实时基础设施。Non-Goals非目标该工作流不是PR 必检项没有单独的 nightly 或全生命周期测试套件不测试快照、fork、Android、Windows 或多区域实时冒烟不测试server_port5000直到固定镜像在 5000 端口提供 computer-server 的/cmdAPI 为止非默认端口传播仍以既有契约测试为准不使用遗留的/api/keysAPI 或 namespace-scoped key。设计上刻意收窄范围实时冒烟只回答「公开 SDK 能否在生产上工作」其余深水区交给专门的测试矩阵避免把 CI 变成脆弱的全功能验证场。二、触发模型与 Lane 矩阵工作流文件 periodic-cua-sandbox-live.yml 定义了三个触发器schedulecron 为7/15 * * * *保留原工作流的:07、:22、:37、:52节奏每小时第 7/22/37/52 分钟push仅限main分支且只在这些路径变更时触发libs/python/cua-sandbox/**libs/python/cua-fleet/**.github/workflows/periodic-cua-sandbox-live.yml.github/scripts/tests/test_periodic_cua_sandbox_live.pyworkflow_dispatch手动触发接受laneboth/main-source/published-package、suiteboth/ephemeral/pool以及仅手动可用的force_failure布尔。双 lane 模型lane安装方式验证对象main-sourceuv pip install -e libs/python/cua-sandboxeditable 安装仓库当前main源码published-packageuv pip install --upgrade cua-sandbox拉取已发布 wheel最新发布的包两个 job 均以if: github.repository trycua/cua守卫。这意味着fork 即使同步了main或启用了 schedule也永远不会运行实时冒烟不会在凭据预检上失败更不会向公共 Alertmanager 端点投递 fork 起源的PeriodicCuaSandboxLiveE2EFailed告警。矩阵生成与契约化执行preparejob 通过一段 shell 脚本生成 JSON lane-and-suite 矩阵push只选择main-source×ephemeralschedule两个 lane × 两个 suite 全量workflow_dispatch按请求的 lane/suite 组合选择。关键细节该矩阵脚本不是直接在 Actions 里靠fromJSON拼出来就完事而是被契约测试提取出来在 bash 中真实执行使用临时GITHUB_OUTPUT并解析输出的 JSON因此任何「把 push 改成跑 both」或「忽略手动选择」的回归都会直接让 CI 失败——矩阵逻辑本身就是被测对象。完整断言见 test_periodic_cua_sandbox_live.py 中的test_prepare_matrix_selects_lanes_and_suites_for_each_trigger它覆盖 push/schedule/manual 下 11 种输入组合的期望矩阵。并发契约只取消旧调度不打断手动与 push矩阵 job 使用fail-fast: false并采用事件-lane-suite 三级分组的并发契约concurrency: group: periodic-cua-sandbox-live-${{ github.event_name }}-${{ matrix.lane }}-${{ matrix.suite }} cancel-in-progress: ${{ github.event_name schedule }}语义新的 schedule 只能取消同一 lane 与同一 suite的更早 schedulepush 与手动运行使用独立分组允许跑完。这避免了两类事故——多个调度互相叠加资源以及手动调试运行被调度任务误杀。三、安装隔离让「源码 lane」和「发布包 lane」真正各测各的两条 lane 安装完包之后都执行Prepare isolated live test suite步骤把tests/__init__.py和tests/live/*.py复制进一个临时目录CUA_LIVE_E2E_TEST_ROOT然后运行PYTHONPATH$CUA_LIVE_E2E_TEST_ROOT python -m pytest -q -s \ $CUA_LIVE_E2E_TEST_ROOT/tests/live/test_fleet_ephemeral.py关键点checkout 出的包根目录不在测试路径上。因此源码 lane 通过其 editable install 生效而发布包 lane 只能从 site-packages 导入cua_sandbox。这正是隔离的目的发布包 lane 必须证明「用户装到的 wheel」能用而不是悄悄回退到仓库源码。这一隔离语义还有专门的契约测试守护test_isolated_suite_cannot_import_checkout_cua_sandbox构造一个伪装成已安装 wheel 的目录用PYTHONPATH指向隔离套件目录与伪装安装目录断言import cua_sandbox解析到的模块来源不位于libs/python/cua-sandbox之下。版本与来源追溯checkout 后Record checked out source SHA用git rev-parse HEAD发布CUA_LIVE_E2E_SOURCE_SHAenv 与 step output 双写实时摘要、受控失败摘要、Alertmanager 注解统一使用该实际 checkout 的 SHA而不是触发事件的 SHA两者在 schedule 触发时不同混用会导致告警无法定位真实提交摘要中记录已解析的cua_sandbox模块来源module_origins.cua_sandbox指向cua_sandbox.__file__的绝对路径与cua-sandbox、cua-fleet两个包的安装版本。四、认证与密钥处理最小暴露面Fleet 认证只使用两个 masked 的 GitHub Actions secretsCUA_CLIENT_ID与CUA_CLIENT_SECRET配合CUA_FLEET_BASE_URLhttps://run.cua.ai。凭据预检防止「静默跳过」污染监控在 checkout、安装、pytest 之前Check Fleet OAuth credentials步骤检查两个 secret 是否为空为空立即exit 1。这一步很关键实时测试本身是 opt-in 的没有 OAuth 环境变量时 pytest 会 skip见下文。如果不做预检凭据缺失时工作流会「成功」生产监控就会被测试的 skip 语义静默穿透——预检把「配置缺失」从测试失败提升为工作流失败。step-scoped 凭据CUA_CLIENT_ID/CUA_CLIENT_SECRET只出现在两个步骤的env中Check Fleet OAuth credentialsRun live Fleet smoke/Run live Fleet pool smokecheckout、setup、包安装、复制测试套件等步骤都不继承任一 secret。契约测试用test_live_job_security_and_execution_structure精确断言livejob 的顶层env不含CUA_CLIENT_ID、CUA_CLIENT_SECRET、CUA_API_KEY且包含这两个 secret 的步骤恰好是上述三个OAuth 凭据步骤 两个实时运行步骤。设计文档同时明确任何凭据值、访问令牌或 authorization header 都不会写入日志或上传工件工作流不创建临时 user key。五、实时场景ephemeral 套件稳定的实时场景位于 test_fleet_ephemeral.pyopt-in 设计pytest.mark.skipif(not has_oauth_credentials(), ...)——只有配置了 OAuth 环境时才运行普通本地与 PR 测试保持无凭据状态。命名空间策略schedule 与 push 使用可复用的 DNS-safe 命名空间手动 ephemeral 运行使用run-unique命名空间。工作流设置cua-live-${{ matrix.lane }}-${{ github.event_name workflow_dispatch github.run_id || github.event_name }}分别得到schedule、push、或manual含 run_id三种命名空间。测试侧会校验命名空间必须以cua-live-开头、长度 ≤ 63、符合 DNS-1123 label 正则否则直接抛ValueError。供给参数与固定镜像使用确切的 certified 镜像pin 到 digest隔离 SDK/Fleet 回归与镜像 tag 漂移public.ecr.aws/k5j5w0x5/cua-ubuntu-24.04sha256:80fff8a40f217a460cef7a60161adb3899eabd02c3451f18926b84d1f81b8da2通过公开 SDK 供给参数如下参数值含义cpu4分配的 vCPU 数memory_mb4096内存MBserver_port8000computer-server 服务端口time_to_start900等待启动的最大秒数request_timeout60请求超时秒telemetry_enabledFalse关闭遥测这些参数直接对应 sandbox.py 中Sandbox.ephemeral()的签名server_port: int 8000为默认值time_to_start、request_timeout均可选。断言清单在 sandbox 上下文活跃期间测试按顺序验证每条都写入摘要便于事后审计sandbox 名称非空且绑定到预期命名空间claim/pool 名称等于请求的 namespace生成的 Fleet template 暴露名为server的 Service且targetPort8000生成的 readiness probe 使用tcpSocket.port8000sandbox.screen.size()恰好返回1024x768截图以 PNG 签名\x89PNG\r\n\x1a\n开头且载荷超过 1000 字节sandbox.shell.run(uname -s)成功且输出Linux。关于 2、3 两条 template 断言设计文档特别说明其刻意为之guest 的 screen/shell 成功只证明连通性而 template 断言证明公开的server_port输入真正到达了实时基础设施——而不是碰巧命中某个无关默认值或陈旧资源。template 契约断言实现在 fleet_e2e_support.py 的assert_template_contract中从template.spec.vm_template找到名为server的 service 校验target_port再把 readiness probe 序列化为 JSON 校验tcpSocket.port。附加签名 URL 生命周期CUA_LIVE_E2E_SIGNED_URLStrue当工作流设置CUA_LIVE_E2E_SIGNED_URLS: true当前工作流默认开启时测试额外验证创建签名 URLsandbox.services.create_signed_url(server, labelperiodic-live-e2e, expires_in_seconds300)断言 namespace/service/label 正确且revoked_at为None列表查询list_signed_urls()能找到该 URL 且未撤销撤销revoke_signed_url()后再次列表断言revoked_at非空。这覆盖了「创建 → 列出 → 撤销」的完整生命周期防止签名 URL 在 sandbox 退出后泄漏。六、清理与泄漏检测claim-only 语义为什么不能「显式删除」Fleet 的 reconciliation 会刻意保留每个专属 namespace、pool 与 template。若测试在退出时用名字去 delete namespace/pool/template会与 reconciliation 产生竞态删除后又被重建或删到别人正在用的资源。因此设计铁律是测试与工作流从不显式删除namespace、pool 或 template契约测试也断言工作流与测试文件中不存在cleanup_namespace、delete_namespace、delete_pool、wait_namespace_absent等字样。清理流程每次供给尝试后都会执行在Sandbox.ephemeral()退出后监控逻辑monitor对每一次供给尝试执行 claim-only 清理验证——包括 context 在产出 sandbox 之前就失败的情况保留原始场景异常若有轮询直到 claims 消失wait_claims_absent180 秒超时5 秒间隔404 视为已消失收集脱敏后的资源清单collect_resource_inventorytemplates / pools / claims 三个列表供给成功的情况下要求清单恰好为空templates/pools/claims 全空且 zero claimsyield 前失败的场景保留诊断清单但不强加该不变量。实现细节test_fleet_ephemeral.py 的finally块用claims_absent is False触发claim_leak失败、用「清单 ≠ 期望空清单」触发unexpected_inventory失败且提供最多 180 秒的收敛等待每 5 秒重查以容忍 reconciliation 的异步收敛。清理错误会与主异常一并上报cleanup_error/cleanup_secondary_errors/context_exit_error区分记录。七、持久化 Pool 套件warm 池与 scale-to-zero 池ephemeral套件无法覆盖「跨运行存活并发放 claim 的 pool」这一消费路径因此设计了pool套件仅 schedule 与 workflow_dispatch 运行push 保持只跑 ephemeral。测试文件为 test_fleet_pool_persistent.py。每个 lane 与事件类各拥有两个持久 pool 命名空间cua-live-pool-warm-lane-event-class cua-live-pool-cold-lane-event-class手动触发时 event-class 归一化为manual不使用 run_id——因为 pool 必须跨运行存活。观察 → 幂等 reconcile → claim → claim-only release每次运行的四步节奏观察先用Pool.get(namespace)读取记录pool_pre_existed、spec_replicas_before、ready_replicas_beforeapply用Pool.apply以同样的固定镜像 digest、cpu4、memory_mb4096幂等 reconcile——缺失则 bootstrap漂移则修复永不删除claimSandbox.ephemeral(pool..., name...)claim 名固定为 namespace因此中断运行的 claim 会被下一次运行接管并释放release退出 context 执行 claim-only 释放pool 与 template 必须继续存在。403 即 404Fleet 的授权先行语义fleet_e2e_support.py中的is_pool_missing_error注释揭示了关键语义Fleet 在存在性检查之前先评估 RBAC因此在尚未创建的 namespace 里读 pool 返回的是 403 而不是 404。观察步骤把两种状态都当作「未预存在」与 SDK 的 reconcile 语义保持一致而真正的访问拒绝会在Pool.apply处以规范的PoolAccessDenied指导失败——403/404 被归为「池不存在」只影响观察记录不会吞掉真实权限问题。warm 与 cold 两种模式模式配置行为warmreplicas1调度 claim 绑定到已在运行的 sandbox释放后该 sandbox 回收回池coldWarmPoolAutoscaling(min_pool_size0, initial_pool_size0, max_pool_size1)scale-to-zeroclaim 触发 autoscaler 按需冷启动容量cold 模式用 autoscaling 而非replicas0来表达 scale-to-zero是因为**Pool.apply拒绝小于 1 的replicas**——由 KEDA 拥有spec.replicas并衰减到零。测试代码中cold_autoscaling()的注释与工作流契约测试断言WarmPoolAutoscaling(min_pool_size0, initial_pool_size0, max_pool_size1)字符串存在都锁定了这一点。释放后的不变量与 SLA释放后监控轮询直到 claims 消失并要求 reconciled 清单恰好包含以 namespace 命名的 pool 与 template、zero claims——这是 ephemeral 套件「空清单」不变量的持久化镜像。释放后的 replica 计数仅作为遥测记录spec_replicas_after/ready_replicas_after因为 warm 池回收与 autoscaler 衰减由服务端控制。warm 模式额外断言仅当 pool 预存在且至少有一个 ready replica 时claim 获取时间必须 300 秒WARM_BIND_SLA_SECONDSbootstrap 运行只记录耗时、不强制 SLA——避免把「首建冷启动」误判为「预热绑定失败」。八、诊断与工件实时测试始终写入一份脱敏的 JSON 摘要summary.json/summary-pool-mode.json包含lane、source SHA、已安装的包版本、解析出的cua_sandbox模块来源namespace 与资源名断言耗时provision/apply/claim/cleanup 各阶段秒数screen 与 shell 观测结果screen.width/height、shell.stdout等claim-only 清理结果claims_absent与持久化 reconciled 资源persistent_resources各类错误分类primary_error、cleanup_error、context_exit_error、close_error、summary_error。脱敏在 fleet_e2e_support.py 的_redact_summary实现递归将键名匹配api_key/authorization/password/secret/token等敏感模式的值替换为redacted。仅失败时上传工件只在失败时工作流上传摘要与相关诊断保留 7 天- name: Upload failure diagnostics if: failure() uses: actions/upload-artifact65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 with: name: cua-sandbox-live-${{ matrix.lane }}-${{ matrix.suite }}-${{ github.run_id }}-${{ github.run_attempt }} path: /tmp/cua-live-e2e if-no-files-found: warn retention-days: 7工件名包含 lane、suite、run_id、run_attempt保证并发矩阵 job 上传互不冲突。受控失败把告警链路本身变成可测的手动触发时勾选force_failureWrite controlled failure diagnostics先生成包含ControlledFailure的脱敏summary.json内容含 lane/suite/namespace/source_shaControlled alert test failure执行exit 1使工作流失败失败路径随即触发「仅失败时上传工件」与 Alertmanager 告警。设计文档特别指出这样 failure-only 的工件路径本身就是可被认证的certifiable——你可以安全地演练告警与工件流程而不必真的破坏生产环境。版本记录步骤用tee -a $GITHUB_OUTPUT同时打印并发布sandbox/fleet输出供 Alertmanager payload 使用且从不读取自己的 step outputs契约测试断言steps.versions.outputs不出现在该步骤自身脚本中防止自引用死循环。九、Alertmanager 告警lane 与 suite 粒度的分诊每个 lane 都有一个if: failure()的通知步骤POST 到https://am.cua.ai/api/v2/alerts告警名PeriodicCuaSandboxLiveE2EFailed标签值severitycriticalservicecua-sandboxjobperiodic-cua-sandbox-livelanemain-source或published-packagesuiteephemeral或poolannotations 包含失败运行的 GitHub Actions 链接、source SHA 或已装包版本${{ steps.source_sha.outputs.source_sha }}与${{ steps.versions.outputs.sandbox }}、固定镜像 digest、以及工作流仪表盘链接。设计文档明确不得包含凭据或可能带 header 的原始授权失败信息。lane/suite 两个标签让 Alertmanager 能对重复失败分组而不会把「源码回归」与「发布包失败」合并也不会把「ephemeral 供给失败」与「持久化池 claim 失败」合并——这是分诊效率的关键设计。十、工作流契约覆盖把设计文档变成可执行断言仓库侧契约测试 test_periodic_cua_sandbox_live.py 使用yaml.BaseLoader解析工作流保留on键为字符串逐项断言触发器、路径过滤、两个 job 的上游仓库 fork 守卫实际执行的 prepare 矩阵、checkout refpush 用github.sha其余用github.refevent-lane-suite 并发分组与cancel-in-progress语义凭据预检、复制套件隔离PYTHONPATH指向测试根而非仓库包根版本输出处理tee -a $GITHUB_OUTPUT、不自读输出受控失败诊断、failure-only 工件retention-days: 7、含 run_attempt 的命名Alertmanager 标签与 annotations且source_sha来自 step output 而非github.sha所有 action 使用 40 位完整 SHA pin正则^[^][0-9a-f]{40}$工作流与测试文件中不存在任何显式删除调用。其中test_docs_describe_the_remediated_workflow还反向验证文档与实现一致设计文档与实施计划docs/superpowers/plans/2026-08-09-periodic-cua-sandbox-live-e2e.md必须包含一组 required 契约短语同时不得包含旧方案的残留措辞如「Emergency namespace cleanup」「namespace leak」「automatic namespace cleanup」等——直接防止回归到「显式删 namespace」的错误设计。Scripts CI 在pyyaml安装后于工作流变更时运行这套契约测试。十一、发布步骤与成功标准Rollout 顺序设计文档给出的七步添加实时测试、工作流与契约测试schedule 暂时禁用或加守卫手动 dispatchmain-source验证断言、诊断与完整的 claim-only 清理手动 dispatchpublished-package验证安装的 release 与清理行为每个 lane 手动 dispatchpool套件两次第一次 bootstrap 两个持久池pool_pre_existed为 false第二次证明 warm claim 绑定到预置容量并记录 cold scale-to-zero 遥测在不暴露 secret 的前提下演练 Alertmanager payload然后解决测试告警启用7/15 * * * *调度观察两个 lane 连续至少两次成功的调度运行后才算 rollout 完成。Success Criteria两个 lane 都带着固定 Duo 镜像在生产 Fleet 基础设施上通过main的相关合并立即获得源码 lane 结果每个调度间隔两个 lane 都启动新调度只能取消同 lane 更旧的调度push 与手动运行照常完成端口、屏幕、截图、shell 断言全部经由公开 SDK正常运行只保留命名的持久 pool/template 且无 claim失败供给记录只读的 claim 与清单诊断且不删除资源pool 套件从跨运行存活的持久池 claim 并释放回去warm 池绑定预置容量受控失败产生一条可行动的、lane/suite 特定的 Alertmanager 告警与脱敏失败工件。十二、实时证据治理命名空间生命周期小结作为全篇收束设计文档以「Live Evidence Remediation」总结了这套治理模型schedule/push 用可复用命名空间cua-live-lane-schedule、cua-live-lane-push避免资源无限累积手动 ephemeral 用 per-run 命名空间cua-live-lane-run-id避免陈旧所有权碰撞持久池命名空间刻意跨运行存活cua-live-pool-warm/cold-lane-event-classpool 与 template 由 Fleet reconciliation 持久化event-lane-suite 并发分组串行化每个确定性 claim 的使用只有 schedule 能取消同 lane/suite 的更早 scheduleSandbox.ephemeral()的验证以 claim-only 清理收尾退出后轮询至 claims 消失记录持久化 reconciled 资源要求恰好是命名的 pool/template 且 zero claims永不显式删除namespace、pool 或 template。这套「用可复用资源减少基础设施累积、用并发分组消除竞态、用 claim-only 清理避免与 reconciliation 打架、用契约测试锁死设计意图」的组合拳构成了 cua-sandbox 在真实云环境上的可信度底线。对于任何维护云上资源供给型 SDK 的团队这个模式都值得作为「生产冒烟 资源治理」的参考模板直接借鉴。延伸阅读设计文档原文docs/superpowers/specs/2026-08-09-periodic-cua-sandbox-live-e2e-design.md工作流实现.github/workflows/periodic-cua-sandbox-live.ymlephemeral 实时测试libs/python/cua-sandbox/tests/live/test_fleet_ephemeral.py持久化池实时测试libs/python/cua-sandbox/tests/live/test_fleet_pool_persistent.py共享支持库Fleet 客户端、脱敏、清单收集libs/python/cua-sandbox/tests/live/fleet_e2e_support.py工作流契约测试.github/scripts/tests/test_periodic_cua_sandbox_live.pySDKSandbox.ephemeral实现libs/python/cua-sandbox/cua_sandbox/sandbox.pySDKPool.get/Pool.apply实现libs/python/cua-sandbox/cua_sandbox/pool.py【免费下载链接】cuaScale computer-use 2.0 with open-source drivers, cross-OS fleets, and benchmarks for training, evaluation, and data generation.项目地址: https://gitcode.com/GitHub_Trending/cua/cua创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考