sub2api 网关接入:每用户独立账号 + 任务注入 + 网关可配置

- cloud/sub2api.py:管理 API 客户端(管理员登录/token 刷新/
  建用户/以用户发 key/删用户/查组/网关模型目录)+ 幂等开通
  ensure_user_gateway_key(入库失败尽力清理孤儿 key 与账号)
- worker:网关门(sub2api 时按 created_by 幂等开通,失败任务
  直接 failed;协调员子任务跟父任务属主)+ 默认模型走网关
  目录首个;三条执行路径(Local popen/同步、Docker 同步)注
  入任务级 env 与 --model-provider;NO_PROXY 追加网关 host
- host.py:--model-provider,sub2api 时以 -c 注入 provider 表
  (不改租户 config.toml);未配 SUB2API_BASE_URL 时 loud fail
- sandbox:Local/Docker 执行器传 --model-provider 与任务 env;
  docker 密钥只传名(-e SUB2API_API_KEY),值由 CLI 子进程
  环境提供,绝不进 argv;runner 不支持 env 时 loud fail
- server:OAuth 建号 best-effort 开通;/relay/models 走调用者
  自己的网关模型目录;init_db 补 user_gateway_keys 表
- 测试:新单测 11 个;全量 cloud 679(4 跳过)、host 65、
  deploy 19 全过
- 诚实边界:真模型调用实弹需上游账号挂组后才做;切流前
  xcmapi 保持现网
This commit is contained in:
host committed 2026-10-27 17:22:54 +08:00
1 parent 437684902a
commit ec47328d3c
7 files changed
+996 -54

No files matched your search

+40
View File
@@ -1017,6 +1017,46 @@ interrupted 且终态任务 cancel 返回 400、心跳后 sweep 不扫刚心跳
否则会把 `/admin/sweep`、`/admin/backup` 也暴露到公网),
否则公网页面调配额接口会落到 28080 而不是控制面。
## sub2api 网关(每用户独立网关账号)
- 开关:`CLOUD_GATEWAY`(默认 `xcmapi`;设为 `sub2api` 即切流)。
切流前 xcmapi 保持现网;切流本身只是改环境变量 + 重启服务,
不动任务数据。`SUB2API_BASE_URL`(网关 origin,如
`http://172.17.0.1:28084`,桥接 IP 供宿主与容器同达)、
`SUB2API_ADMIN_EMAIL` / `SUB2API_ADMIN_PASSWORD`(系统管理员
账号)、`SUB2API_GROUP_NAME`(默认 `codex-system`;或用
`SUB2API_GROUP_ID` 直接指定组 id)是开通必需的配置。
- 开通:OAuth 建号时 best-effort 调管理 API 开通(失败记
`sub2api_provision_failed` 审计,建号本身不失败);任务开跑
前 worker 按 `created_by` 幂等开通(`user_gateway_keys` 表:
user_id → sub2api_user_id、api_key、refresh_token),失败则
任务直接 failed,绝不跑错网关。协调员子任务无 created_by 时
跟父任务属主走。key 明文存 PG,与 GitHub App 私钥同一信任
边界(库只在宿主 loopback 可达);at-rest 加密是后续项。
- 注入:worker 在三条执行路径(Local popen、Local 同步、Docker
同步)都注入任务级 env:`SUB2API_API_KEY`(属主的 key)、
`SUB2API_BASE_URL`,并把网关 host 追加进 NO_PROXY(否则
codex 经 egress 代理访问内网网关会被挡)。host.py 以 `-c`
注入 provider(`model_provider=sub2api` + provider 表,不改
任何租户的 `config.toml`,多网关任务同项目并发互不干扰),
未配 `SUB2API_BASE_URL` 时 loud fail。#86 的 shell exclude
模式已覆盖 `*_KEY`,agent shell 看不到该 key。
- Docker 密钥通道:`SUB2API_API_KEY` 在 docker 命令里只传名
(`-e SUB2API_API_KEY`),值由 docker CLI 子进程环境提供
(`_docker_cli_env`),绝不进 argv(ps/docker inspect 可见
argv);runner 不支持 env 时 loud fail。其它 extra_env 仍按
`-e NAME=VALUE`(非密钥变量)。
- 模型目录:`/relay/models` 在 sub2api 下返回调用者自己的网关
模型(key 绑定的组决定);无 key 时返回空列表 +
`provisioning: pending`,不在页面加载时悄悄开通。任务未指定
模型时:`CLOUD_SUB2API_DEFAULT_MODEL` 优先,否则取该用户
网关模型首个;组里无模型时任务 failed( loud fail,不拿
xcmapi 的模型名去撞网关)。sub2api 模型目前无价目表,成本
走无价 token 上限那道护栏(见上节),报表记 unpriced。
- 诚实边界:本批只做到“网关可配置 + 任务注入 + 模型目录走
网关”;真模型调用实弹需上游账号挂到组里后才做(切流前置
条件),fallback 模型名在 sub2api 下须配网关侧的名字。
## 运维批(本轮新增:部署、恢复演练、监控、心跳、多用户验证)
细则在 `deploy/README.md`,这里只记代码侧的接口与默认值: