feat(webhook): ADR-059 GitHub → Gitea Webhook 遷移完成
- 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>
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
"""
|
||||
Phase 13.1: GitHub Webhook 整合測試
|
||||
ADR-059: Gitea Webhook 整合測試
|
||||
===================================
|
||||
測試 GitHub Webhook → OpenClaw AI 代碼審查整合
|
||||
測試 Gitea Webhook → OpenClaw AI 代碼審查整合
|
||||
|
||||
測試策略 (遵循 feedback_no_mock_testing.md):
|
||||
- 使用 ASGITransport 撞擊真實端點
|
||||
- 不使用 Mock,直接測試 HTTP 層
|
||||
- 驗證 HMAC 簽章邏輯
|
||||
- 驗證 HMAC 簽章邏輯 (X-Gitea-Signature)
|
||||
|
||||
🔴 IMPORTANT: 禁止 Mock 測試!
|
||||
"""
|
||||
@@ -20,14 +20,14 @@ import pytest
|
||||
from fastapi import FastAPI
|
||||
from httpx import ASGITransport
|
||||
|
||||
# 2026-04-05 Claude Code: 改用最小化 app,只掛載 github_webhook router
|
||||
# 2026-04-05 Claude Code: 改用最小化 app,只掛載 gitea_webhook router
|
||||
# 原 `from src.main import app` 會 import 整個應用,觸發 sqlalchemy.ext.asyncio
|
||||
# C extension (asyncpg.protocol.protocol) 在 CI runner 上 segfault (exit 139)
|
||||
# github_webhook router 的 import chain 不走 DB,可獨立測試
|
||||
from src.api.v1.github_webhook import router as github_webhook_router
|
||||
# gitea_webhook router 的 import chain 不走 DB,可獨立測試
|
||||
from src.api.v1.gitea_webhook import router as gitea_webhook_router
|
||||
|
||||
app = FastAPI()
|
||||
app.include_router(github_webhook_router, prefix="/api/v1")
|
||||
app.include_router(gitea_webhook_router, prefix="/api/v1")
|
||||
|
||||
# 環境變數設定已移至 conftest.py (解決 E402)
|
||||
|
||||
@@ -138,7 +138,7 @@ def ping_payload():
|
||||
|
||||
|
||||
def generate_signature(secret: str, body: bytes) -> str:
|
||||
"""生成 GitHub Webhook 簽章"""
|
||||
"""生成 Gitea Webhook 簽章 (X-Gitea-Signature)"""
|
||||
signature = hmac.new(
|
||||
secret.encode(),
|
||||
body,
|
||||
@@ -168,18 +168,18 @@ async def test_webhook_missing_signature(sample_pr_payload):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
# 故意不提供 X-Hub-Signature-256
|
||||
"X-Gitea-Event": "pull_request",
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
# 故意不提供 X-Gitea-Signature
|
||||
},
|
||||
)
|
||||
|
||||
# 在 dev 環境下,缺少 secret 但配置了 secret,應該要求簽章
|
||||
# 由於我們設定了 GITHUB_WEBHOOK_SECRET,缺少簽章應該返回 401
|
||||
# 由於我們設定了 GITEA_WEBHOOK_SECRET,缺少簽章應該返回 401
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
@@ -193,13 +193,13 @@ async def test_webhook_invalid_signature(sample_pr_payload):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
"X-Hub-Signature-256": "sha256=invalid_signature_here",
|
||||
"X-Gitea-Event": "pull_request",
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
"X-Gitea-Signature": "sha256=invalid_signature_here",
|
||||
},
|
||||
)
|
||||
|
||||
@@ -216,13 +216,13 @@ async def test_webhook_valid_signature(sample_pr_payload, webhook_secret):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
"X-Hub-Signature-256": signature,
|
||||
"X-Gitea-Event": "pull_request",
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
"X-Gitea-Signature": signature,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -274,13 +274,13 @@ async def test_webhook_repo_not_in_whitelist(webhook_secret):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
"X-Hub-Signature-256": signature,
|
||||
"X-Gitea-Event": "pull_request",
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
"X-Gitea-Signature": signature,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -304,13 +304,13 @@ async def test_webhook_ping_event(ping_payload, webhook_secret):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "ping",
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
"X-Hub-Signature-256": signature,
|
||||
"X-Gitea-Event": "ping",
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
"X-Gitea-Signature": signature,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -331,13 +331,13 @@ async def test_webhook_push_event(sample_push_payload, webhook_secret):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "push",
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
"X-Hub-Signature-256": signature,
|
||||
"X-Gitea-Event": "push",
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
"X-Gitea-Signature": signature,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -381,13 +381,13 @@ async def test_webhook_push_non_default_branch(webhook_secret):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "push",
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
"X-Hub-Signature-256": signature,
|
||||
"X-Gitea-Event": "push",
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
"X-Gitea-Signature": signature,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -419,13 +419,13 @@ async def test_webhook_unsupported_event(webhook_secret):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "star", # 不支援的事件
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
"X-Hub-Signature-256": signature,
|
||||
"X-Gitea-Event": "star", # 不支援的事件
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
"X-Gitea-Signature": signature,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -468,13 +468,13 @@ async def test_webhook_pr_unsupported_action(webhook_secret):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
"X-Hub-Signature-256": signature,
|
||||
"X-Gitea-Event": "pull_request",
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
"X-Gitea-Signature": signature,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -498,13 +498,13 @@ async def test_webhook_wrong_signature_format(sample_pr_payload):
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
response = await client.post(
|
||||
"/api/v1/webhooks/github",
|
||||
"/api/v1/webhooks/gitea",
|
||||
content=body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-GitHub-Delivery": "test-delivery-id",
|
||||
"X-Hub-Signature-256": "md5=wrong_format", # 錯誤格式
|
||||
"X-Gitea-Event": "pull_request",
|
||||
"X-Gitea-Delivery": "test-delivery-id",
|
||||
"X-Gitea-Signature": "md5=wrong_format", # 錯誤格式
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user