跳转到内容

Aira provider-off Cloudflare 发布与回滚 Runbook

状态:RC-3 protected cloud execution verified on 2026-09-05

适用范围:G0/G2/G3 的 provider-off Worker;不适用于真实模型入口

安全不变量:AIRA_REAL_PROVIDER_ENABLED=false,工具链不接受 provider API key

  1. 从干净、已提交的主线 checkout 执行;pnpm install --offline --frozen-lockfile 已通过。
  2. 使用专用 Cloudflare 账号/项目与最小权限 token,先运行 pnpm --dir apps/server run cloud:auth。
  3. 不把 secret 写入 .env、命令参数、聊天、Git、CI artifact 或文档。只在当前终端会话从密码管理器注入。
  4. 明确回滚负责人和预览域名;真实 provider key 不属于本 Runbook。

非 secret 配置:

  • AIRA_REAL_PROVIDER_ENABLED=false
  • AIRA_RELEASE_MANIFEST:要部署的密封候选 manifest.json;部署只读取同目录的 wrangler.json、 gateway/production-worker.js 和 web/
  • AIRA_GATEWAY_BASE_URL:候选自定义域名的 canonical HTTPS origin,当前为 https://aira3d.com
  • AIRA_GATEWAY_ALLOWED_ORIGINS_JSON:1–32 个 canonical HTTPS origin
  • AIRA_GATEWAY_MODEL_POLICIES_JSON:provider/model allowlist 与 nano-USD 上限;这只是拒绝策略,不启用 transport
  • AIRA_GATEWAY_MAINTENANCE:可选,只接受 false/true,缺省 false;决定本次部署是否打开维护窗口

平台 secret 共三项:

  • AIRA_GATEWAY_INVITATIONS_JSON:只含预哈希 credentialHash/principalHash,不含原始 invitation
  • AIRA_GATEWAY_CLIENT_IP_PEPPER
  • AIRA_GATEWAY_ADMIN_TOKEN_SHA256

费用告警 webhook 的 URL/token 是成对可选配置,等真实 provider 启用、确实可能产生费用时再设为必填; provider-off 发布不依赖它们。打开 provider 时还需要 DEEPSEEK_API_KEY。 wrangler.production.json 的 secrets.required 只列出当前 provider-off Worker 的三项必需名称; provider-on 与可选名称由部署操作的 secret 清单和收据列出。实际 secret 值由部署命令通过平台 secret store 设置。

本机烟测另需原始 AIRA_GATEWAY_ADMIN_TOKEN。它必须匹配已配置 digest,只用于 HTTPS admin smoke,不上传为 Worker secret。

终端窗口
pnpm --dir apps/server run cloud:auth
pnpm --dir apps/server run cloud:preflight
pnpm --dir apps/server run cloud:deploy-provider-off

preflight 和发布都会先校验候选全部文件哈希以及单 Worker 的 Gateway/Static Assets 配置。发布工具随后执行: 认证检查 → --strict --no-bundle 部署候选 → 三项 secret 通过 Wrangler stdin 整批轮换 → provider-off health/匿名 agent/匿名 admin/管理员读取与关闭烟测 → 查询最近版本。子进程环境只传 OS、 CLOUDFLARE_* 和 WRANGLER_* allowlist;所有 AIRA_* 与 provider 环境变量都不继承。

成功收据写到被 Git 忽略的 .deploy/aira-gateway-cloud-operations/。收据不含 secret,不自动晋级为正式证据; 须由上线负责人核对域名、commit、request ID、最近版本数和 Workers Logs 后再保存到受保护发布记录。

维护状态是运行态的一层覆盖,不是候选的属性:候选里 AIRA_MAINTENANCE 恒为 false(打包时断言), 窗口由会话变量 AIRA_GATEWAY_MAINTENANCE 在部署时以 --var 决定。同一候选可以开关窗口而不重新打包。

候选里有两份配置,只差一处路由:wrangler.json 的 run_worker_first 是 ["/api/*", "/health"], 静态资源不经过 Worker(免费、更快);wrangler.maintenance.json 为 true,把 Worker 放到全部请求前面, 否则开关对资源面根本不生效。两份都在 manifest 里逐字节哈希,打包时断言彼此只差这一项。 部署工具按同一个会话变量选配置,所以路由与开关不可能各说各话。窗口期的 Worker 调用按 Workers 请求计费, 这笔钱只在窗口开着时付。

窗口打开时,除 /health 与 /api/* 之外的全部请求返回 503 与 maintenance.html,带 Cache-Control: no-store 和 Retry-After: 300。整面拦截而不是只拦导航:放行 chunk 会让已打开的页面继续半可用,与“维护中”这句话不符。 /health 如实报告 maintenance 字段,监控据此区分窗口与故障;管理面保持可达,窗口期仍能操作 kill switch。 /api/step 不进窗口:本部署 provider-off,模型路由本就无法执行模型,而它的开关是 admin kill switch,一件事不挂两个开关。

打开窗口:

终端窗口
$env:AIRA_GATEWAY_MAINTENANCE = 'true'
pnpm --dir apps/server run cloud:preflight
pnpm --dir apps/server run cloud:deploy-provider-off

关闭窗口:把 AIRA_GATEWAY_MAINTENANCE 改为 false(或不设)后重跑同两条命令,候选不变。

部署 smoke 会读回 /health 的 maintenance、探测站点入口(开 503、关 200)并断言它与本次请求的状态一致; 不一致则部署失败且不产生 passed 收据。收据记录 maintenance。回滚到早于本开关的版本仍可校验: 那些版本不报告该字段,按无窗口处理。

窗口期的逐字节静态校验:

终端窗口
pnpm --dir apps/web run smoke:cloudflare-static -- https://aira3d.com <manifest 路径>

它先读 /health:窗口打开时改为校验 /、SPA fallback 路径与一个 assets/* 深路径都返回 503, 且字节等于 manifest 里的 maintenance.html,输出 status: "maintenance" 与 productVerified: false; 产品的逐字节校验必须等窗口关闭后再跑。

终端窗口
pnpm --dir apps/server run cloud:smoke-provider-off

该命令会把管理员开关再次写为 false,不会调用 provider。随后人工确认:

  1. Workers Logs 能按收据中的 request ID 查到结构化事件,且不含 invitation、admin token、原始 IP、intent 或请求体;
  2. 至少三个最近版本可见;
  3. Static Assets 的逐字节、WASM MIME、cache/compression、SPA fallback 与真实 Chrome 产品 smoke 另按 G3 执行。

在上述云证据完成前,G2/G3 和 L0 均不得标记 Done。

先从发布收据或 wrangler versions list 选择最近检查窗口内的明确 version ID,再执行:

终端窗口
pnpm --dir apps/server run cloud:rollback-provider-off -- --version <version-id>

工具先调用 admin kill switch 并读回 false,确认目标属于最近版本窗口后才执行非交互回滚,最后重跑 provider-off smoke。若 kill switch、目标检查、回滚或 smoke 任一步失败,命令失败且不生成 passed 收据。

在密码管理器生成新值,更新 invitation 预哈希或 admin digest,重新注入当前会话并执行完整 preflight + deploy。 旧 invitation 的撤销必须体现在新 allowlist 中。保留新旧两个可回滚版本,验证新凭据通过、旧凭据拒绝后, 再结束轮换窗口。

真实 provider key 可以提前写入 Cloudflare Secret Store,但 provider-off 发布不会读取或转发它;启用模型 仍需另一轮明确授权、匹配的费用策略和已配置的告警 webhook。

  • 不把 AIRA_REAL_PROVIDER_ENABLED 改为 true;
  • 不向本工具链加入 provider key、provider adapter 或真实模型 smoke;
  • 不使用未提交工作树发布;
  • 不因本地 verifier 通过而宣称 Cloudflare、Workers Logs 或回滚已实际通过;
  • 不在缺少用户再次明确授权时运行真实 provider Gate。