Files
cc-web/docs/gitea-workflow/DEPLOYMENT.md

9.0 KiB
Raw Permalink Blame History

Gitea Webhook Agent 部署与运维设计

本文是 PRD.mdARCHITECTURE.md 的运行手册。 它定义部署、凭据、恢复和故障处置边界Gitea 仍是唯一主交互入口cc-web 页面 只承担配置、镜像和运维控制。

1. 运行基线

MVP 采用单 Gitea 实例(instanceId=default)和专用 ccweb-bot。同仓库永远 串行,跨仓库允许并行,不设置全局并发上限。生产环境至少需要:

项目 基线
Node/Bun 使用项目锁定的运行时和已验收的单文件发布包;不要混用系统 Node
进程 一个 cc-web worker外部 Codex App Server 按会话复用
持久目录 WORKFLOW_DATA_ROOT(任务/审计/租约)与 WORKSPACE_ROOTGit 工作区)分离
网络 Gitea Webhook 入站、Gitea REST/MCP 出站、Codex App Server 本地 stdio/JSON-RPC
时间 主机启用 NTP持久化时间全部使用 UTC ISO-8601
访问 反向代理终止 TLSWebhook 路径只允许 POST 和受限请求体大小

建议为 worker、工作区和日志使用独立系统用户。WORKFLOW_DATA_ROOT 仅 worker 可读写,WORKSPACE_ROOT 不允许 Web 静态服务暴露,备份目录使用不同权限主体。

2. 配置与凭据

配置按“非敏感文件 → Secret 管理 → 线程级注入”分层。示例(值均为占位符):

CC_WEB_GITEA_HOST=https://gitea.example
CC_WEB_GITEA_INSTANCE_ID=default
CC_WEB_GITEA_BOT_LOGIN=ccweb-bot
GITEA_WEBHOOK_SECRET_FILE=/etc/ccweb/secrets/gitea-webhook
GITEA_BOT_TOKEN_FILE=/etc/ccweb/secrets/gitea-bot-token
CC_WEB_GITEA_WORKFLOW_STATE=/var/lib/ccweb/gitea-workflow/state.json
CC_WEB_GITEA_WORKSPACE_ROOT=/var/lib/ccweb/workspaces

cc-web 管理页对应接口为:

  • GET /api/gitea-workflow/config返回地址、Bot 用户名、工作区和凭据是否已配置;不会返回 Secret/Token。

  • PUT /api/gitea-workflow/config:保存上述配置,敏感字段写入受保护的运行配置;保存后立即更新当前进程的 Webhook、Git 和 gitea-mcp 线程配置,不要求重启 cc-web。

  • GET /api/gitea-workflow/overview/tasks/audit:状态镜像。

  • POST /api/gitea-workflow/control/pause|resume、仓库 enable|disable、任务 cancel|abort:需要 cc-web 登录 Bearer Token服务端自动记录操作来源和请求幂等 ID页面不要求用户填写审计字段。

  • 内部部署可以不配置 Webhook Secret配置后入口启用 HMAC-SHA256 验签。Bot Token 只在 gitea-mcp/REST 出站边界使用,不能把 Bot Token 当作 Webhook Secret。

  • Secret 文件权限为 0600、属主为 worker日志、审计、评论正文和 Git remote URL 禁止写入 Secret。审计只记录 secretRef/tokenRef 和不可逆指纹。

  • thread/start.config.mcp_servers.gitea.env 使用线程级 secret 引用或运行时 注入值;不能把某个来源会话 ID、Bot Token 或 Gitea Secret 放在长驻 app-server 的进程级全局环境中。

  • gitea-mcp 随 cc-web 源码/发布目录放在 bin/gitea-mcp,不需要为每个服务单独 安装。只有替换版本时才使用 CC_WEB_GITEA_MCP_COMMAND 指向本机绝对路径;可选的 CC_WEB_GITEA_MCP_STARTUP_TIMEOUT_MS 控制 initialize 预检超时(默认 8000ms 上限 30000ms。cc-web 发布流程不从网络自动下载或安装外部二进制。

  • 轮换 Secret 时先配置新值并验证签名,再撤销旧值;未配置 Secret 的内部入口应 由反向代理/网络白名单限制来源。Bot Token 更新后立即作用于后续 MCP 线程。

3. Webhook 与反向代理

Gitea 只向反向代理暴露的 HTTPS 路径发送 Webhook。代理应

  1. 严格保留原始请求 body 和 X-Gitea-SignatureX-Gitea-DeliveryX-Gitea-Event 头,不做 JSON 重排后再交给验签层。
  2. 限制方法为 POST、请求体大小建议 1 MiB和连接超时超限返回 413。
  3. 只将来自 Gitea 网段的请求转发到 worker不要在代理层伪造签名或 delivery。
  4. 配置了 Secret 时worker 验签失败返回 401解析失败返回 400首次入队返回 202重复 delivery/忽略事件返回 200。未配置 Secret 的内部入口仍需由代理 限制来源;持久化不可用时返回 503。
  5. 代理访问日志脱敏 Authorization、签名值和正文;保留 request ID 以便与 deliveryKey 关联。

验签必须针对 raw body 计算 HMAC-SHA256并使用常量时间比较。解析后的 mention 和仓库字段不能替代 raw body 验签;缺少 delivery header 时只能使用可靠 payload ID否则拒绝入队。

4. 启动、健康检查与发布

启动顺序固定为:

  1. 检查配置文件、Secret 文件权限、数据目录可写性和工作区根目录是否在允许 根下;禁止自动 reset --hardclean
  2. 打开持久 Store执行租约过期扫描和恢复扫描queued 重新入队, running/preparing/aborting 按架构规则转为带 interrupted_by_restartretry_wait,终态不重跑。
  3. 启动 Scheduler 和受控的 Codex App Server完成 initialize 后发送 initialized,再 best-effort 探测 goals 与 collaboration mode。
  4. 仅在健康检查通过后把 Webhook 代理切入当前 worker。

健康检查至少包含Store 读写探针、租约扫描完成、Gitea /api/v1/version 或 等价只读探针、Codex App Server initialize smoke以及线程级 gitea-mcp stdio initialize 预检。健康检查不得创建评论、修改仓库或打印凭据。

发布采用“先旁路验证、再切流”:在 staging 用回归 fixtures 和真实 Gitea 测试 仓库验证 HMAC、入队、MCP 配置与回帖确认;生产切换前确认旧 worker 已停止领取 新任务且租约已释放。回滚只切换到上一份已验收发布包和数据快照,不删除当前 工作区或审计。

5. 日常运维控制

操作 影响 约束
全局 pause 停止领取新任务,已运行任务继续 页面按钮直接执行,服务端记录操作
resume 恢复调度 先检查工作区和 Gitea 连通性
repo disable 拒绝该仓库新触发 不强杀运行中任务,保留历史
cancel queued 取消未启动任务 幂等;不得取消已领取任务
abort running 向 Codex App 请求取消 等待确认或超时后释放租约并审计
replay delivery 仅用于核对/恢复 先查 deliveryKey,禁止绕过去重直接执行

所有控制操作必须通过受保护的运维 API服务端生成操作记录和幂等 ID。API 不接受 任意 Git 命令、模型切换或 MCP 工具参数。

6. 监控与告警

结构化日志只输出关联 IDdeliveryKey、taskId、repoKey、sessionKey、threadId、 turnId、leaseId、errorCode。建议监控Webhook 401/400/503 比例、队列年龄、锁等待、 运行任务数量、retry_wait 数量、blocked_workspace 数量、MCP 握手失败、回帖确认 缺失和 REST 兜底次数。

以下情况应告警并暂停自动扩容:连续 HMAC 失败、同一 delivery payload hash 变化、租约频繁过期、回帖兜底连续失败、工作区出现未知 owner 或路径越界、 Bot Token/Secret 可能泄露。告警正文不得包含 Secret、完整评论正文或源码。

7. 备份、恢复与数据保留

  • 备份 Store 的任务、会话、turn、评论索引、控制面和 append-only 审计; webhook_deliveries 至少保留覆盖 Gitea 重试窗口的记录。
  • 工作区是可重建缓存,备份前先记录 repoKey、HEAD、dirty 状态;不要把 未提交用户修改静默覆盖或当成可恢复快照。
  • 恢复顺序:停止领取 → 恢复 Store → 校验版本/唯一键 → 执行租约恢复扫描 → 只读检查工作区 → 启动 Scheduler → 逐步 resume。恢复后优先核对 deliveryKey → taskId → turnId → commentId 链路,避免重复回帖。
  • 清理策略必须由管理员显式启用并保留审计;不得因磁盘告警直接删除运行中 任务、未确认评论或工作区。

8. 故障处置速查

症状 先查 安全动作
Webhook 全部 401 Secret 引用、raw body、代理头 暂停切流,验证单个 fixture不打印签名
任务堆积 pause、锁、并发槽位、租约 不手工改状态;修复后让恢复扫描接管
工作区 blocked git status、owner、锁文件 保留现场,管理员审查后再解除;禁止 reset/clean
App/MCP 不可达 initialize、stdio stderr、hostRef、gitea-mcp 可执行文件 命令缺失、进程启动失败、握手失败或超时均立即进入 failed 并发送一条 giteabot: 失败回执;修复后重新触发
MCP 成功但无评论 resource/task/turn 标记、Gitea 查询 只允许一次 reply_retry随后 REST 兜底
重启后重复执行 stateVersion、leaseId、终态记录 先 pause修复 Store/租约,再恢复;禁止批量重放

每次事故结束后导出关联审计、错误码、重试次数和最终评论 ID形成可复盘记录。