pilot: central webhook service (user-level Gitea webhook + AI-REVIEW gate)
- pilot/webhook_server.py: stdlib HTTP receiver. HMAC-verifies X-Gitea-Signature, gates on pull_request action + AI-REVIEW label, runs review_pr in a background thread (responds 202 immediately so Gitea's delivery timeout never fires). Accepts both GitHub-style (labeled/synchronize) and Gitea event-type-style (label_updated/synchronized) action names. - pilot/ai_review.py: extract review_pr() core so both the CI run() and the webhook server share one review path. run() is now an env-driven wrapper. - pilot/README-webhook.md: architecture, onboarding, one-time per-owner user-webhook setup, the Gitea 1.26.1 system-webhook bug, the SSRF ALLOWED_HOST_LIST change, K8s deploy + script-update recipe. - README.md + design doc: note the webhook service as the preferred delivery path (partially reverses 'central webhook = non-goal', pilot only). Gitea 1.26.1 system webhooks broken (POST /admin/hooks -> 201 but never persists); user-level webhooks (one per repo-owner) are the working fallback. Gitea SSRF allow-list blocks in-cluster webhook targets by default; required a scoped [webhook] ALLOWED_HOST_LIST addition + gitea restart. E2E verified 2026-08-17: pragent-bot reviewed gitea_admin/pragent PR #2 and masi/portfolio PR #3 via the webhook service (glm-5.2:cloud). Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+38
-14
@@ -187,33 +187,57 @@ def _need(name: str) -> str:
|
||||
return v
|
||||
|
||||
|
||||
def run() -> int:
|
||||
api = _need("GITEA_API")
|
||||
repo = _need("GITEA_REPOSITORY")
|
||||
index = _need("PR_INDEX")
|
||||
token = _need("PRAGENT_BOT_TOKEN")
|
||||
ollama_url = _need("OLLAMA_URL")
|
||||
model = _need("OLLAMA_MODEL")
|
||||
title = os.environ.get("PR_TITLE", "")
|
||||
body = os.environ.get("PR_BODY", "")
|
||||
sha = os.environ.get("PRAGENT_SHA", "")
|
||||
max_tokens = int(os.environ.get("OLLAMA_MAX_TOKENS", "6000"))
|
||||
max_chars = int(os.environ.get("DIFF_MAX_CHARS", "150000"))
|
||||
def review_pr(
|
||||
api: str,
|
||||
repo: str,
|
||||
index: str,
|
||||
title: str,
|
||||
body: str,
|
||||
sha: str,
|
||||
token: str,
|
||||
ollama_url: str,
|
||||
model: str,
|
||||
max_tokens: int = 6000,
|
||||
max_chars: int = 150000,
|
||||
) -> bool:
|
||||
"""Run one review and post it as a PR comment.
|
||||
|
||||
Returns True on success, False on failure (failure note is posted when
|
||||
possible). Never raises — fail-open by design. Both the CI `run()` entry
|
||||
point and the central webhook server call this.
|
||||
"""
|
||||
try:
|
||||
diff, truncated, _orig = fetch_pr_diff(api, repo, index, token, max_chars)
|
||||
diff, _truncated, _orig = fetch_pr_diff(api, repo, index, token, max_chars)
|
||||
if not diff.strip():
|
||||
post_review(api, repo, index, token, format_review_body("No diff content to review.", model, sha))
|
||||
return 0
|
||||
return True
|
||||
user_prompt = build_user_prompt(title, body, diff)
|
||||
findings = call_model(ollama_url, model, SYSTEM_PROMPT, user_prompt, max_tokens)
|
||||
post_review(api, repo, index, token, format_review_body(findings, model, sha))
|
||||
return True
|
||||
except Exception as e: # fail-open
|
||||
try:
|
||||
post_review(api, repo, index, token, format_review_body(f"⚠️ AI review failed: {e}", model, sha))
|
||||
except Exception as e2:
|
||||
print(f"pragent: could not post failure note: {e2}", file=sys.stderr)
|
||||
print(f"pragent: review failed: {e}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
|
||||
def run() -> int:
|
||||
review_pr(
|
||||
api=_need("GITEA_API"),
|
||||
repo=_need("GITEA_REPOSITORY"),
|
||||
index=_need("PR_INDEX"),
|
||||
title=os.environ.get("PR_TITLE", ""),
|
||||
body=os.environ.get("PR_BODY", ""),
|
||||
sha=os.environ.get("PRAGENT_SHA", ""),
|
||||
token=_need("PRAGENT_BOT_TOKEN"),
|
||||
ollama_url=_need("OLLAMA_URL"),
|
||||
model=_need("OLLAMA_MODEL"),
|
||||
max_tokens=int(os.environ.get("OLLAMA_MAX_TOKENS", "6000")),
|
||||
max_chars=int(os.environ.get("DIFF_MAX_CHARS", "150000")),
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user