Files
awoooi/docs/superpowers/plans/2026-04-05-gitea-webhook-migration.md
2026-04-05 14:22:29 +08:00

24 KiB
Raw Blame History

Gitea Webhook Migration Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 將 GitHub Webhook 整合Phase 13.1)遷移至 Gitea Webhook讓 Gitea PR/Push 事件能觸發 OpenClaw AI 代碼審查。

Architecture: 最少改動策略 — Gitea 與 GitHub 的 payload 欄位幾乎相同,差異只在 HTTP header 名稱。重命名檔案、替換 Header 常數、移除 workflow_run handler業務邏輯層OpenClaw 呼叫、Redis 儲存、Telegram 通知、Approval 建立)完全不動。

Tech Stack: FastAPI, Python 3.11, pytest-asyncio, httpx ASGITransport, K8s Secrets, Gitea Webhook


File Map

動作 路徑
新增 apps/api/src/api/v1/gitea_webhook.py
新增 apps/api/src/services/gitea_webhook_service.py
修改 apps/api/src/main.py
修改 apps/api/src/core/config.py
修改 k8s/awoooi-prod/03-secrets.yaml
修改 .gitea/workflows/cd.yaml
新增 apps/api/tests/test_gitea_webhook.py
修改 apps/api/tests/conftest.py
刪除 apps/api/src/api/v1/github_webhook.py
刪除 apps/api/src/services/github_webhook_service.py
刪除 apps/api/tests/test_github_webhook.py
新增 docs/adr/ADR-059-gitea-webhook-integration.md

Task 1: Config 層 — 替換 GITHUB_ → GITEA_ 環境變數

Files:

  • Modify: apps/api/src/core/config.py:490-505

  • Step 1: 讀取現有 config 確認位置

grep -n "GITHUB_WEBHOOK_SECRET\|GITHUB_ALLOWED_REPOS\|get_github_allowed" apps/api/src/core/config.py

Expected output 類似:

490:    GITHUB_WEBHOOK_SECRET: str = Field(
494:    GITHUB_ALLOWED_REPOS: str = Field(
501:        raw = self.GITHUB_ALLOWED_REPOS
  • Step 2: 替換 config.py 中的 GITHUB_ 欄位

apps/api/src/core/config.py 中這段:

    GITHUB_WEBHOOK_SECRET: str = Field(
        default="",
        description="GitHub Webhook secret for signature verification (X-Hub-Signature-256)",
    )
    GITHUB_ALLOWED_REPOS: str = Field(
        default="",
        description="Comma-separated list of allowed repositories (e.g., 'owner/repo1,owner/repo2')",
    )

    def get_github_allowed_repos(self) -> list[str]:
        """Parse comma-separated allowed repos to list"""
        raw = self.GITHUB_ALLOWED_REPOS
        if not raw or not raw.strip():
            return []
        return [repo.strip() for repo in raw.split(",") if repo.strip()]

改為:

    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')",
    )

    def get_gitea_allowed_repos(self) -> list[str]:
        """Parse comma-separated allowed repos to list"""
        # 2026-04-05 Claude Code (ADR-059): GitHub → Gitea webhook 遷移
        raw = self.GITEA_ALLOWED_REPOS
        if not raw or not raw.strip():
            return []
        return [repo.strip() for repo in raw.split(",") if repo.strip()]
  • Step 3: 驗證 config 語法正確
cd apps/api && python3.11 -c "from src.core.config import settings; print('GITEA_WEBHOOK_SECRET:', repr(settings.GITEA_WEBHOOK_SECRET)); print('GITEA_ALLOWED_REPOS:', repr(settings.GITEA_ALLOWED_REPOS))"

Expected:

GITEA_WEBHOOK_SECRET: ''
GITEA_ALLOWED_REPOS: 'wooo/awoooi'
  • Step 4: Commit
git add apps/api/src/core/config.py
git commit -m "refactor(config): GITHUB_WEBHOOK_SECRET → GITEA_WEBHOOK_SECRET (ADR-059)"

Task 2: Service 層 — 建立 gitea_webhook_service.py

Files:

  • Create: apps/api/src/services/gitea_webhook_service.py

這個 task 從 github_webhook_service.py 複製並修改:

  • class 名稱 GitHub*Gitea*

  • Redis key prefix github_review:gitea_review:

  • Telegram 訊息中 GITHUB CODE REVIEWGITEA CODE REVIEW

  • 移除 CIFailureDiagnosis class、_call_openclaw_ci_diagnosis()_send_ci_failure_telegram_alert()_create_ci_failure_approval()diagnose_ci_failure() 整個 method

  • 所有 payload 存取改用 .get() chain防禦性解析

  • Step 1: 複製並重命名

cp apps/api/src/services/github_webhook_service.py apps/api/src/services/gitea_webhook_service.py
  • Step 2: 批次替換 class/常數名稱
cd apps/api/src/services
# 替換 class 名稱和常數
sed -i \
  -e 's/GITHUB_REVIEW_TTL_SECONDS/GITEA_REVIEW_TTL_SECONDS/g' \
  -e 's/IGitHubReviewRepository/IGiteaReviewRepository/g' \
  -e 's/GitHubReviewRedisRepository/GiteaReviewRedisRepository/g' \
  -e 's/GitHubWebhookService/GiteaWebhookService/g' \
  -e 's/get_github_webhook_service/get_gitea_webhook_service/g' \
  -e 's/github_review:/gitea_review:/g' \
  -e 's/GITHUB CODE REVIEW/GITEA CODE REVIEW/g' \
  -e 's/github-webhook/gitea-webhook/g' \
  gitea_webhook_service.py
  • Step 3: 更新 config 存取settings.GITHUB_ → settings.GITEA_
sed -i \
  -e 's/settings\.GITHUB_WEBHOOK_SECRET/settings.GITEA_WEBHOOK_SECRET/g' \
  -e 's/settings\.GITHUB_ALLOWED_REPOS/settings.GITEA_ALLOWED_REPOS/g' \
  -e 's/settings\.get_github_allowed_repos/settings.get_gitea_allowed_repos/g' \
  apps/api/src/services/gitea_webhook_service.py
  • Step 4: 移除 CI 診斷相關程式碼

手動編輯 apps/api/src/services/gitea_webhook_service.py,刪除以下區塊:

  1. class CIFailureDiagnosis(BaseModel): 整個 class約 51-67 行附近)
  2. async def _call_openclaw_ci_diagnosis(self, ...) 整個 method約 268-320 行附近)
  3. async def _send_ci_failure_telegram_alert(self, ...) 整個 method約 448-548 行附近)
  4. async def _create_ci_failure_approval(self, ...) 整個 method約 633-719 行附近)
  5. async def diagnose_ci_failure(self, ...) 整個 method約 908-1042 行附近)

確認方式:

grep -n "ci_failure\|CIFailure\|diagnose_ci\|workflow_run" apps/api/src/services/gitea_webhook_service.py

Expected: 無輸出(全部移除)

  • Step 5: 更新檔案 docstring 和版本資訊

gitea_webhook_service.py 頂部 docstring 改為:

"""
AWOOOI API - Gitea Webhook Service
====================================
ADR-059: GitHub → Gitea Webhook 遷移

整合流程:
1. Gitea Webhook (PR/Push) → AWOOOI API
2. HMAC-SHA256 簽章驗證 (X-Gitea-Signature)
3. 解析 PR diff / Push commits
4. 呼叫 OpenClaw 進行 AI 代碼審查
5. 儲存審查結果到 Redis
6. 發送 Telegram 通知
7. (可選) 建立 Approval 等待人工確認

支援事件:
- pull_request: PR 代碼審查
- push: 主分支推送審查

版本: v1.0
最後修改: 2026-04-05 (台北時區)
修改者: Claude Code (ADR-059 GitHub → Gitea 遷移)
"""
  • Step 6: 審查所有 payload .get() 防禦性存取

搜尋所有直接 key access 並改為 .get() chain

grep -n 'payload\["' apps/api/src/services/gitea_webhook_service.py | head -20

對每個直接存取(payload["key"])改為 payload.get("key", default)。 重要位置包含:

  • review_pull_request() 中存取 pull_requestrepositorysender 欄位
  • review_push() 中存取 commitsrepositoryref 欄位

範例修改:

# ❌ 舊
repo_name = payload["repository"]["full_name"]

# ✅ 新
repo_name = payload.get("repository", {}).get("full_name", "")
  • Step 7: 語法驗證
cd apps/api && python3.11 -c "from src.services.gitea_webhook_service import get_gitea_webhook_service; print('✅ import OK')"

Expected: ✅ import OK

  • Step 8: Commit
git add apps/api/src/services/gitea_webhook_service.py
git commit -m "feat(service): 新增 GiteaWebhookService (ADR-059移除 CI 診斷)"

Task 3: Router 層 — 建立 gitea_webhook.py

Files:

  • Create: apps/api/src/api/v1/gitea_webhook.py

github_webhook.py 複製並修改:

  • Header 常數:X-GitHub-EventX-Gitea-EventX-Hub-Signature-256X-Gitea-Signature

  • Router prefix/webhooks/github/webhooks/gitea

  • 移除 handle_workflow_run() 和相關 Pydantic models (GitHubWorkflowRun, GitHubWorkflowJob)

  • 所有 GitHub* class → Gitea*

  • import 改為 gitea_webhook_service

  • Step 1: 複製並重命名

cp apps/api/src/api/v1/github_webhook.py apps/api/src/api/v1/gitea_webhook.py
  • Step 2: 批次替換 header 名稱和 class 名稱
sed -i \
  -e 's/X-GitHub-Event/X-Gitea-Event/g' \
  -e 's/X-Hub-Signature-256/X-Gitea-Signature/g' \
  -e 's/X-GitHub-Delivery/X-Gitea-Delivery/g' \
  -e 's/x_hub_signature_256/x_gitea_signature/g' \
  -e 's/x_github_event/x_gitea_event/g' \
  -e 's/x_github_delivery/x_gitea_delivery/g' \
  -e 's/GitHubUser/GiteaUser/g' \
  -e 's/GitHubRepository/GiteaRepository/g' \
  -e 's/GitHubPullRequest/GiteaPullRequest/g' \
  -e 's/GitHubCommit/GiteaCommit/g' \
  -e 's/GitHubWebhookPayload/GiteaWebhookPayload/g' \
  -e 's/GitHubWebhookResponse/GiteaWebhookResponse/g' \
  -e 's/GitHubSignatureError/GiteaSignatureError/g' \
  -e 's/verify_github_signature/verify_gitea_signature/g' \
  -e 's/verify_allowed_repo/verify_gitea_allowed_repo/g' \
  -e 's/github_webhook_service/gitea_webhook_service/g' \
  -e 's/get_github_webhook_service/get_gitea_webhook_service/g' \
  -e 's/GitHubWebhookService/GiteaWebhookService/g' \
  apps/api/src/api/v1/gitea_webhook.py
  • Step 3: 替換 router prefix 和 config 存取
sed -i \
  -e 's|prefix="/webhooks/github"|prefix="/webhooks/gitea"|g' \
  -e 's/tags=\["GitHub Webhook"\]/tags=["Gitea Webhook"]/g' \
  -e 's/settings\.GITHUB_WEBHOOK_SECRET/settings.GITEA_WEBHOOK_SECRET/g' \
  -e 's/settings\.get_github_allowed_repos/settings.get_gitea_allowed_repos/g' \
  apps/api/src/api/v1/gitea_webhook.py
  • Step 4: 移除 workflow_run 相關程式碼

手動編輯 apps/api/src/api/v1/gitea_webhook.py,刪除以下區塊:

  1. class GitHubWorkflowRun(BaseModel): 整個 class
  2. class GitHubWorkflowJob(BaseModel): 整個 class若存在
  3. async def handle_workflow_run(...) 整個 function
  4. 主 handler handle_gitea_webhook()workflow_run 的 dispatch branch
    elif event_type == "workflow_run":
        return await handle_workflow_run(payload)
    

確認移除:

grep -n "workflow_run\|WorkflowRun\|WorkflowJob" apps/api/src/api/v1/gitea_webhook.py

Expected: 無輸出

  • Step 5: 更新 docstring

gitea_webhook.py 頂部 docstring 改為:

"""
AWOOOI API - Gitea Webhook Handler
====================================
ADR-059: GitHub → Gitea Webhook 遷移

整合流程:
1. Gitea Webhook (PR/Push) → AWOOOI API
2. HMAC-SHA256 簽章驗證 (X-Gitea-Signature)
3. 解析 PR diff / Push commits
4. 呼叫 OpenClaw 進行 AI 代碼審查
5. 儲存審查結果到 Redis
6. 發送 Telegram 通知
7. (可選) 建立 Approval 等待人工確認

支援事件:
- pull_request: PR 代碼審查 (opened, synchronize, reopened)
- push: 主分支推送審查
- ping: 連線測試

安全要求:
- HMAC 簽章驗證 (X-Gitea-Signature)
- Webhook Secret 存放於 K8s Secret
- 倉庫白名單驗證

版本: v1.0
最後修改: 2026-04-05 (台北時區)
修改者: Claude Code (ADR-059 GitHub → Gitea 遷移)
"""
  • Step 6: 語法驗證
cd apps/api && python3.11 -c "from src.api.v1.gitea_webhook import router; print('✅ router OK, prefix:', router.prefix)"

Expected: ✅ router OK, prefix: /webhooks/gitea

  • Step 7: Commit
git add apps/api/src/api/v1/gitea_webhook.py
git commit -m "feat(api): 新增 gitea_webhook router (ADR-059Header 改 X-Gitea-*)"

Task 4: main.py — 替換掛載

Files:

  • Modify: apps/api/src/main.py:43,467

  • Step 1: 確認目前掛載位置

grep -n "github_webhook" apps/api/src/main.py

Expected:

43:    github_webhook as github_webhook_v1,  # Phase 13.1: GitHub → OpenClaw
467:    github_webhook_v1.router, prefix="/api/v1", tags=["GitHub Webhook"]
  • Step 2: 替換 import

將 main.py 第 42-44 行附近的:

from src.api.v1 import (
    github_webhook as github_webhook_v1,  # Phase 13.1: GitHub → OpenClaw
)

改為:

from src.api.v1 import (
    gitea_webhook as gitea_webhook_v1,  # ADR-059: Gitea → OpenClaw (GitHub → Gitea 遷移)
)
  • Step 3: 替換 router 掛載

將 main.py 中:

app.include_router(
    github_webhook_v1.router, prefix="/api/v1", tags=["GitHub Webhook"]
)

改為:

app.include_router(
    gitea_webhook_v1.router, prefix="/api/v1", tags=["Gitea Webhook"]
)
  • Step 4: 驗證 main.py 可 import
cd apps/api && MOCK_MODE=true python3.11 -c "
import os; os.environ['MOCK_MODE']='true'; os.environ['DATABASE_URL']='postgresql+asyncpg://x:x@localhost/x'
from src.main import app
routes = [r.path for r in app.routes if hasattr(r, 'path')]
gitea_routes = [r for r in routes if 'gitea' in r]
print('Gitea routes:', gitea_routes)
github_routes = [r for r in routes if 'github' in r and 'gitea' not in r]
print('Leftover GitHub routes:', github_routes)
"

Expected:

Gitea routes: ['/api/v1/webhooks/gitea', '/api/v1/webhooks/gitea/reviews/{review_id}']
Leftover GitHub routes: []
  • Step 5: Commit
git add apps/api/src/main.py
git commit -m "refactor(main): github_webhook → gitea_webhook router 掛載 (ADR-059)"

Task 5: Tests — 建立 test_gitea_webhook.py

Files:

  • Create: apps/api/tests/test_gitea_webhook.py

  • Modify: apps/api/tests/conftest.py

  • Step 1: 更新 conftest.py

apps/api/tests/conftest.py 中:

os.environ.setdefault("GITHUB_WEBHOOK_SECRET", "test-secret-key-12345")
os.environ.setdefault("GITHUB_ALLOWED_REPOS", "test-owner/test-repo,wooo-ai/awoooi")

改為:

os.environ.setdefault("GITEA_WEBHOOK_SECRET", "test-secret-key-12345")
os.environ.setdefault("GITEA_ALLOWED_REPOS", "test-owner/test-repo,wooo/awoooi")
  • Step 2: 建立 test_gitea_webhook.py
cp apps/api/tests/test_github_webhook.py apps/api/tests/test_gitea_webhook.py
  • Step 3: 批次替換 header 和 import
sed -i \
  -e 's/X-Hub-Signature-256/X-Gitea-Signature/g' \
  -e 's/X-GitHub-Event/X-Gitea-Event/g' \
  -e 's/X-GitHub-Delivery/X-Gitea-Delivery/g' \
  -e 's/from src\.api\.v1\.github_webhook import router as github_webhook_router/from src.api.v1.gitea_webhook import router as gitea_webhook_router/g' \
  -e 's/github_webhook_router/gitea_webhook_router/g' \
  -e 's|prefix="/api/v1"|prefix="/api/v1"|g' \
  apps/api/tests/test_gitea_webhook.py
  • Step 4: 更新 app 建立

test_gitea_webhook.py 找到:

from src.api.v1.gitea_webhook import router as gitea_webhook_router

app = FastAPI()
app.include_router(gitea_webhook_router, prefix="/api/v1")

確認這兩行正確sed 應已處理 import確認 include_router 使用 gitea_webhook_router)。

  • Step 5: 執行測試,確認全部通過
cd apps/api && source /opt/api-venv/bin/activate 2>/dev/null || python3.11 -m venv /tmp/test-venv && source /tmp/test-venv/bin/activate && pip install -q uv && uv pip install -q -e ".[dev]"
cd apps/api && python3.11 -m pytest tests/test_gitea_webhook.py -v

Expected: 8 tests PASSED

PASSED tests/test_gitea_webhook.py::test_webhook_missing_signature
PASSED tests/test_gitea_webhook.py::test_webhook_invalid_signature
PASSED tests/test_gitea_webhook.py::test_webhook_valid_signature
PASSED tests/test_gitea_webhook.py::test_webhook_repo_not_in_whitelist
PASSED tests/test_gitea_webhook.py::test_webhook_ping_event
PASSED tests/test_gitea_webhook.py::test_webhook_push_event
PASSED tests/test_gitea_webhook.py::test_webhook_push_non_default_branch
PASSED tests/test_gitea_webhook.py::test_webhook_unsupported_event
PASSED tests/test_gitea_webhook.py::test_webhook_pr_unsupported_action
  • Step 6: Commit
git add apps/api/tests/test_gitea_webhook.py apps/api/tests/conftest.py
git commit -m "test: test_gitea_webhook.py — 8 個測試覆蓋 HMAC/whitelist/events (ADR-059)"

Task 6: 清除舊 GitHub 檔案

Files:

  • Delete: apps/api/src/api/v1/github_webhook.py

  • Delete: apps/api/src/services/github_webhook_service.py

  • Delete: apps/api/tests/test_github_webhook.py

  • Step 1: 確認 github_webhook 已無 import

grep -rn "github_webhook" apps/api/src/ apps/api/tests/ --include="*.py" | grep -v "__pycache__"

Expected: 無輸出(所有 reference 都已在前面步驟移除)

  • Step 2: 刪除舊檔案
git rm apps/api/src/api/v1/github_webhook.py \
       apps/api/src/services/github_webhook_service.py \
       apps/api/tests/test_github_webhook.py
  • Step 3: 確認無孤兒 import
cd apps/api && python3.11 -c "from src.main import app; print('✅ main import OK')"

Expected: ✅ main import OK

  • Step 4: 執行完整測試確認無 regression
cd apps/api && python3.11 -m pytest tests/ -v --tb=short -x \
  --ignore=tests/integration \
  --ignore=tests/test_anomaly_counter.py \
  --ignore=tests/test_global_repair_cooldown.py \
  --ignore=tests/test_redis_multisig.py \
  --ignore=tests/test_model_regression.py \
  --ignore=tests/test_prompt_validation.py \
  2>&1 | tail -30

Expected: 全部 PASSED無 FAILED

  • Step 5: Commit
git commit -m "chore: 移除舊 GitHub Webhook 檔案 (github_webhook.py / service / test) — ADR-059"

Task 7: K8s Secrets + CD Pipeline

Files:

  • Modify: k8s/awoooi-prod/03-secrets.yaml

  • Modify: .gitea/workflows/cd.yaml

  • Step 1: 更新 03-secrets.yaml

k8s/awoooi-prod/03-secrets.yaml 找到 GITHUB_WEBHOOK_SECRET(若存在),改為 GITEA_WEBHOOK_SECRET: "CHANGE_ME"

若不存在,在適當位置新增:

  GITEA_WEBHOOK_SECRET: "CHANGE_ME"  # 2026-04-05 Claude Code (ADR-059): CD 自動注入

確認:

grep -n "GITEA_WEBHOOK_SECRET\|GITHUB_WEBHOOK_SECRET" k8s/awoooi-prod/03-secrets.yaml

Expected: 只看到 GITEA_WEBHOOK_SECRET,無 GITHUB_WEBHOOK_SECRET

  • Step 2: 更新 cd.yaml Inject K8s Secrets step

.gitea/workflows/cd.yamlInject K8s Secrets stepSECRETS heredoc 內),在現有注入區塊末尾(echo "✅ 所有 Secrets 注入完成" 之前)新增:

          # ADR-059: Gitea Webhook Secret (PR/Push → OpenClaw 代碼審查)
          if [ -n "${GITEA_WEBHOOK_SECRET}" ]; then
            sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
              {"op":"add","path":"/data/GITEA_WEBHOOK_SECRET","value":"'"$(echo -n "${GITEA_WEBHOOK_SECRET}" | base64 -w 0)"'"}
            ]' && echo "✅ GITEA_WEBHOOK_SECRET 已注入" || echo "⚠️ GITEA_WEBHOOK_SECRET patch 失敗"
          else
            echo "⚠️ GITEA_WEBHOOK_SECRET 未設定Gitea webhook 簽章驗證將跳過"
          fi

同時在 step 的 env: 區塊新增:

          GITEA_WEBHOOK_SECRET: ${{ secrets.GITEA_WEBHOOK_SECRET }}
  • Step 3: 驗證 cd.yaml YAML 語法
python3 -c "import yaml; yaml.safe_load(open('.gitea/workflows/cd.yaml')); print('✅ YAML OK')"

Expected: ✅ YAML OK

  • Step 4: Commit
git add k8s/awoooi-prod/03-secrets.yaml .gitea/workflows/cd.yaml
git commit -m "ops(k8s+cd): 新增 GITEA_WEBHOOK_SECRET 注入 (ADR-059)"

Task 8: ADR 文件

Files:

  • Create: docs/adr/ADR-059-gitea-webhook-integration.md

  • Step 1: 建立 ADR-059

cat > docs/adr/ADR-059-gitea-webhook-integration.md << 'EOF'
# ADR-059: Gitea Webhook 整合 (GitHub → Gitea 遷移)

**日期**: 2026-04-05 (台北時區)
**狀態**: 已採用 (Adopted)
**決策者**: 統帥 + Claude Code
**關聯**: ADR-039 (Gitea CI/CD 遷移), ADR-029 (CI/CD AI 整合架構)

---

## 背景

Phase 13.1 (ADR-029) 實作了 GitHub Webhook → OpenClaw AI 代碼審查整合。
但 ADR-039 已將 CI/CD 全面遷移至 GiteaGitHub 只剩唯讀備份。
`GITHUB_WEBHOOK_SECRET` 從未注入 K8s SecretsGitHub Webhook 功能處於死路狀態。

## 決策

將 GitHub Webhook 整合遷移至 Gitea Webhook。
廢棄 `workflow_run` CI 診斷功能CD pipeline 已有 Telegram 通知覆蓋,重複無必要)。

## 遷移策略

**最少改動策略 (Minimal Viable Change)**

Gitea 與 GitHub 的 webhook payload 欄位幾乎相同,差異只在 HTTP header 名稱:

| 項目 | GitHub (廢棄) | Gitea () |
|------|-------------|-----------|
| 事件 Header | `X-GitHub-Event` | `X-Gitea-Event` |
| 簽章 Header | `X-Hub-Signature-256` | `X-Gitea-Signature` |
| 簽章格式 | `sha256=<hex>` | `sha256=<hex>` (相同) |
| Payload 欄位 || 幾乎相同 |

業務邏輯層OpenClaw 呼叫、Redis 儲存、Telegram 通知、Approval 建立)完全不動。

## 支援事件

| 事件 | 狀態 |
|------|------|
| `pull_request` (opened/synchronize/reopened) | ✅ 遷移 |
| `push` (main/master) | ✅ 遷移 |
| `workflow_run` | ❌ 廢棄 |
| `ping` | ✅ 遷移 |

## 端點變更

舊: POST /api/v1/webhooks/github 新: POST /api/v1/webhooks/gitea


## 實作護欄

1. **防禦性 payload 解析**: 所有欄位存取使用 `.get()` chain
2. **Gitea UI Content-Type**: 必須選 `application/json`(非 `application/x-www-form-urlencoded`

## 後果

- Gitea PR/Push 事件可觸發 OpenClaw AI 代碼審查
- 移除 `workflow_run` CI 診斷(由 CD pipeline TG 通知替代)
- `GITHUB_WEBHOOK_SECRET` K8s Secret 廢棄,改用 `GITEA_WEBHOOK_SECRET`
EOF
  • Step 2: Commit
git add docs/adr/ADR-059-gitea-webhook-integration.md
git commit -m "docs(adr): ADR-059 Gitea Webhook 整合 (GitHub → Gitea 遷移)"

Task 9: Push 到 Gitea + 部署後手動設定

  • Step 1: Push
git push gitea main
  • Step 2: 確認 CI 通過

觀察 Gitea Actions。Run API Tests step 應包含 test_gitea_webhook.py 的 9 個測試全部 PASSED。

  • Step 3: 在 Gitea UI 設定 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 Actions Secret GITEA_WEBHOOK_SECRET 相同值
  6. Trigger On: Pull Request events + Push events
  7. Active: 勾選
  8. 點擊 "Test Delivery" 確認 ping 事件收到 202 回應
  • Step 4: 在 Gitea Actions 新增 Secret

http://192.168.0.110:3001/wooo/awoooi → Settings → Actions → Secrets → 新增:

  • Name: GITEA_WEBHOOK_SECRET
  • Value: (統帥決定,與 Gitea UI Webhook Secret 相同)

Self-Review

Spec coverage check:

Spec 要求 對應 Task
github_webhook.pygitea_webhook.py Task 3
github_webhook_service.pygitea_webhook_service.py Task 2
main.py 更新 import + 路徑 Task 4
config.py GITHUB_ → GITEA_ Task 1
03-secrets.yaml 更新 Task 7
cd.yaml 注入 GITEA_WEBHOOK_SECRET Task 7
conftest.py env var 更新 Task 5
test_gitea_webhook.py Task 5
舊 GitHub 檔案刪除 Task 6
ADR-059 Task 8
防禦性 .get() 解析 Task 2 Step 6
Content-Type 警告文件 Task 9 Step 3
Gitea UI 設定步驟 Task 9 Step 3

Placeholder scan: 無 TBD/TODO所有步驟含完整程式碼或指令。

Type consistency: GiteaWebhookServiceget_gitea_webhook_servicegitea_webhook_router 在 Task 2/3/4/5 命名一致。