從 GitHub Webhook (Phase 13.1) 遷移至 Gitea Webhook 最少改動策略:Header 常數替換,業務邏輯層不動 廢棄 workflow_run CI 診斷(CD pipeline 已有 TG 通知覆蓋) 整合首席架構師護欄:防禦性 payload 解析 + Content-Type 設定 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.0 KiB
Gitea Webhook 整合設計規格
日期: 2026-04-05 (台北時區)
作者: Claude Code + 首席架構師 Review
狀態: 已批准,待實作
ADR: ADR-059 (待建立)
關聯: ADR-039 (Gitea CI/CD 遷移), ADR-029 (CI/CD AI 整合架構)
背景
Phase 13.1 實作了 GitHub Webhook → OpenClaw AI 代碼審查整合,但:
- CI/CD 已於 ADR-039 全面遷移至 Gitea,GitHub 只剩唯讀備份
GITHUB_WEBHOOK_SECRET從未注入 K8s Secrets,功能實際上處於死路狀態- 代碼審查的觸發源應改為 Gitea(實際開發倉庫)
決策:遷移至 Gitea Webhook,廢棄 GitHub Webhook 整合。
設計原則
最少改動策略 (Minimal Viable Change)
Gitea 與 GitHub 的 webhook payload 欄位幾乎相同,差異只在 HTTP header 名稱。 因此策略是:重命名 + Header 常數替換,業務邏輯層(OpenClaw 呼叫、Redis 儲存、Telegram 通知、Approval 建立)完全不動。
Header 差異對照
| 項目 | GitHub (廢棄) | Gitea (新) |
|---|---|---|
| 事件類型 Header | X-GitHub-Event |
X-Gitea-Event |
| 簽章 Header | X-Hub-Signature-256 |
X-Gitea-Signature |
| 投遞 ID Header | X-GitHub-Delivery |
X-Gitea-Delivery |
| 簽章格式 | sha256=<hex> |
sha256=<hex> ← 相同 |
| Payload 欄位 | — | — ← 幾乎相同 |
Gitea 會同時送出
X-GitHub-Event相容 header,但我們應讀取原生的X-Gitea-Event, 語意清晰,未來不依賴相容層。
遷移範圍
支援事件
| 事件 | GitHub (舊) | Gitea (新) | 說明 |
|---|---|---|---|
pull_request |
✅ | ✅ 遷移 | PR 代碼審查 |
push |
✅ | ✅ 遷移 | 主分支推送審查 |
workflow_run |
✅ | ❌ 廢棄 | CD pipeline 已有 TG 通知,重複覆蓋無必要 |
ping |
✅ | ✅ 遷移 | 連線測試 |
檔案變更清單
| 檔案 | 動作 | 說明 |
|---|---|---|
src/api/v1/github_webhook.py |
重命名 → gitea_webhook.py |
Header 常數改 Gitea,移除 workflow_run handler |
src/services/github_webhook_service.py |
重命名 → gitea_webhook_service.py |
移除 diagnose_ci_failure(),class 改名 |
src/main.py |
修改 | 更新 import,掛載路徑改 /webhooks/gitea |
src/core/config.py |
修改 | GITHUB_WEBHOOK_SECRET → GITEA_WEBHOOK_SECRET,GITHUB_ALLOWED_REPOS → GITEA_ALLOWED_REPOS |
k8s/awoooi-prod/03-secrets.yaml |
修改 | 新增 GITEA_WEBHOOK_SECRET,移除 GITHUB_WEBHOOK_SECRET |
tests/conftest.py |
修改 | 更新 env var 名稱 |
tests/test_github_webhook.py |
重命名 → test_gitea_webhook.py |
Header 常數改 Gitea |
docs/adr/ADR-059-gitea-webhook-integration.md |
新增 | 決策記錄 |
API 端點
舊: POST /api/v1/webhooks/github
新: POST /api/v1/webhooks/gitea
舊: GET /api/v1/webhooks/github/reviews/{review_id}
新: GET /api/v1/webhooks/gitea/reviews/{review_id}
Config 變更
# 舊 (廢棄)
GITHUB_WEBHOOK_SECRET: str = Field(default="")
GITHUB_ALLOWED_REPOS: str = Field(default="")
# 新
GITEA_WEBHOOK_SECRET: str = Field(
default="",
description="Gitea Webhook secret for HMAC-SHA256 signature verification (X-Gitea-Signature)",
)
GITEA_ALLOWED_REPOS: str = Field(
default="wooo/awoooi",
description="Comma-separated list of allowed Gitea repositories (e.g., 'wooo/awoooi')",
)
防禦性 Payload 解析(首席架構師護欄 #1)
Gitea 部分欄位為 nullable 或可能缺失。所有欄位存取使用 .get() chain,禁止直接 key access:
# ❌ 禁止
repo_name = payload["repository"]["full_name"]
# ✅ 正確
repo_name = payload.get("repository", {}).get("full_name", "")
pr_number = payload.get("pull_request", {}).get("number", 0)
head_sha = payload.get("pull_request", {}).get("head", {}).get("sha", "")
現有 github_webhook_service.py 中已部分採用此模式,遷移時需全面審查確認。
Gitea UI 設定步驟(首席架構師護欄 #2)
部署完成後在 Gitea 設定 Webhook:
- 進入
http://192.168.0.110:3001/wooo/awoooi→ Settings → Webhooks → Add Webhook → Gitea - Target URL:
https://awoooi.wooo.work/api/v1/webhooks/gitea - HTTP Method: POST
- Content Type:
application/json← 必須明確選擇,否則 FastAPI 無法解析 - Secret: 與
GITEA_WEBHOOK_SECRETK8s Secret 值相同 - Trigger On: Pull Request events + Push events
- Active: 勾選
⚠️ Content-Type 若選
application/x-www-form-urlencoded,FastAPI 的Request.json()將無法解析,導致所有 webhook 請求失敗。
簽章驗證邏輯
驗證邏輯與 GitHub 完全相同,只需更換 header 名稱:
# 舊 header
x_hub_signature_256: str | None = Header(default=None, alias="X-Hub-Signature-256")
# 新 header
x_gitea_signature: str | None = Header(default=None, alias="X-Gitea-Signature")
HMAC-SHA256 計算方式不變:sha256=<hmac_sha256(secret, body).hexdigest()>
K8s Secrets 注入
k8s/awoooi-prod/03-secrets.yaml 新增:
GITEA_WEBHOOK_SECRET: "CHANGE_ME" # CD 自動注入
cd.yaml 的 Inject K8s Secrets step 需新增注入:
kubectl patch secret awoooi-secrets \
--patch "{\"stringData\": {\"GITEA_WEBHOOK_SECRET\": \"${{ secrets.GITEA_WEBHOOK_SECRET }}\"}}"
Gitea Actions secrets 需新增 GITEA_WEBHOOK_SECRET。
測試策略
test_gitea_webhook.py 複用現有 8 個測試案例,更新:
- Header 名稱:
X-Hub-Signature-256→X-Gitea-Signature、X-GitHub-Event→X-Gitea-Event - Router import:
from src.api.v1.gitea_webhook import router as gitea_webhook_router conftest.py:GITHUB_WEBHOOK_SECRET→GITEA_WEBHOOK_SECRET、GITHUB_ALLOWED_REPOS→GITEA_ALLOWED_REPOS
不在此 Scope
- Gitea 端實際 webhook secret 的生成與管理(統帥決定)
workflow_run等值替代方案(未來 Phase 規劃)- GitHub mirror repo 的 webhook 設定清除(可手動處理)