# 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 代碼審查整合,但: 1. CI/CD 已於 ADR-039 全面遷移至 Gitea,GitHub 只剩唯讀備份 2. `GITHUB_WEBHOOK_SECRET` 從未注入 K8s Secrets,功能實際上處於死路狀態 3. 代碼審查的觸發源應改為 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=` | `sha256=` ← **相同** | | 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 變更 ```python # 舊 (廢棄) 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: ```python # ❌ 禁止 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: 1. 進入 `http://192.168.0.110:3001/wooo/awoooi` → Settings → Webhooks → Add Webhook → Gitea 2. **Target URL**: `https://awoooi.wooo.work/api/v1/webhooks/gitea` 3. **HTTP Method**: POST 4. **Content Type**: `application/json` ← **必須明確選擇,否則 FastAPI 無法解析** 5. **Secret**: 與 `GITEA_WEBHOOK_SECRET` K8s Secret 值相同 6. **Trigger On**: Pull Request events + Push events 7. **Active**: 勾選 > ⚠️ Content-Type 若選 `application/x-www-form-urlencoded`,FastAPI 的 `Request.json()` > 將無法解析,導致所有 webhook 請求失敗。 --- ## 簽章驗證邏輯 驗證邏輯與 GitHub 完全相同,只需更換 header 名稱: ```python # 舊 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=` --- ## K8s Secrets 注入 `k8s/awoooi-prod/03-secrets.yaml` 新增: ```yaml GITEA_WEBHOOK_SECRET: "CHANGE_ME" # CD 自動注入 ``` `cd.yaml` 的 `Inject K8s Secrets` step 需新增注入: ```bash 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 個測試案例,更新: 1. Header 名稱:`X-Hub-Signature-256` → `X-Gitea-Signature`、`X-GitHub-Event` → `X-Gitea-Event` 2. Router import:`from src.api.v1.gitea_webhook import router as gitea_webhook_router` 3. `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 設定清除(可手動處理)