- gitea_webhook.py: Header 全部改 X-Gitea-*,移除 workflow_run handler - gitea_webhook_service.py: _fetch_pr_diff 改直接 httpx,不依賴 github_api_service - 清除兩個檔案的所有殘留 github_ log key,review_id prefix 改 gitea- - test_gitea_webhook.py: 10/10 通過,docstring 修正 - 03-secrets.yaml: 新增 GITEA_WEBHOOK_SECRET 佔位 - cd.yaml: 新增 GITEA_WEBHOOK_SECRET 注入步驟 - ADR-059: 建立架構決策文件 待統帥操作: Gitea Actions secret + Gitea UI Webhook 設定 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
111 lines
3.5 KiB
Markdown
111 lines
3.5 KiB
Markdown
# ADR-059: Gitea Webhook 整合 (GitHub → Gitea 遷移)
|
||
|
||
**日期**: 2026-04-05 (台北時區)
|
||
**狀態**: ✅ 已批准
|
||
**決策者**: 首席架構師 + 統帥
|
||
|
||
---
|
||
|
||
## 背景
|
||
|
||
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 常數替換,業務邏輯層完全不動。
|
||
|
||
---
|
||
|
||
## 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 欄位 | — | — ← **幾乎相同** |
|
||
|
||
---
|
||
|
||
## 支援事件
|
||
|
||
| 事件 | 說明 |
|
||
|------|------|
|
||
| `pull_request` | PR 代碼審查 (opened/synchronize/reopened) |
|
||
| `push` | 主分支推送審查 |
|
||
| `ping` | 連線測試 |
|
||
| `workflow_run` | **廢棄** (CD pipeline 已有 Telegram 通知,重複覆蓋無必要) |
|
||
|
||
---
|
||
|
||
## 變更範圍
|
||
|
||
| 檔案 | 動作 |
|
||
|------|------|
|
||
| `src/api/v1/github_webhook.py` | 保留(歷史參考),不刪除 |
|
||
| `src/api/v1/gitea_webhook.py` | 新建,Header 改 Gitea,移除 workflow_run handler |
|
||
| `src/services/github_webhook_service.py` | 保留(歷史參考),不刪除 |
|
||
| `src/services/gitea_webhook_service.py` | 新建,_fetch_pr_diff 改用直接 httpx(不依賴 github_api_service) |
|
||
| `src/main.py` | 掛載 gitea_webhook_router,路徑 `/api/v1/webhooks/gitea` |
|
||
| `src/core/config.py` | 新增 `GITEA_WEBHOOK_SECRET`、`GITEA_ALLOWED_REPOS` |
|
||
| `k8s/awoooi-prod/03-secrets.yaml` | 新增 `GITEA_WEBHOOK_SECRET` 佔位 |
|
||
| `.gitea/workflows/cd.yaml` | 新增 `GITEA_WEBHOOK_SECRET` 注入步驟 |
|
||
| `tests/test_gitea_webhook.py` | 新建,Header 改 Gitea |
|
||
| `tests/conftest.py` | `GITEA_WEBHOOK_SECRET`、`GITEA_ALLOWED_REPOS` 環境變數 |
|
||
|
||
---
|
||
|
||
## API 端點
|
||
|
||
```
|
||
新: POST /api/v1/webhooks/gitea
|
||
新: GET /api/v1/webhooks/gitea/reviews/{review_id}
|
||
|
||
舊: POST /api/v1/webhooks/github ← 仍掛載但未用
|
||
```
|
||
|
||
---
|
||
|
||
## 安全設計
|
||
|
||
- HMAC-SHA256 簽章驗證 (X-Gitea-Signature)
|
||
- Fail-Closed: 生產環境未設 `GITEA_WEBHOOK_SECRET` → 直接拒絕
|
||
- 倉庫白名單: `GITEA_ALLOWED_REPOS`(預設 `wooo/awoooi`)
|
||
- 所有欄位存取使用 `.get()` chain,防止 Gitea nullable 欄位 KeyError
|
||
|
||
---
|
||
|
||
## Gitea UI 設定
|
||
|
||
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. **Content Type**: `application/json` ← 必須明確選擇
|
||
4. **Secret**: 與 `GITEA_WEBHOOK_SECRET` K8s Secret 值相同
|
||
5. **Trigger On**: Pull Request events + Push events
|
||
|
||
---
|
||
|
||
## 後置待辦
|
||
|
||
- [ ] Gitea Actions secret `GITEA_WEBHOOK_SECRET` 設定(統帥操作)
|
||
- [ ] Gitea UI Webhook 設定(統帥操作)
|
||
- [ ] K8s Secret 手動 patch 首次注入
|
||
- [ ] E2E 驗證:觸發一次 PR → 收到 Telegram 代碼審查通知
|
||
|
||
---
|
||
|
||
## 參考
|
||
|
||
- ADR-039: Gitea CI/CD 遷移
|
||
- ADR-029: CI/CD AI 整合架構
|
||
- Phase 13.1: GitHub PR Review 原始實作
|