Nhận xét PR GitHub tự động với Webhooks
Hướng dẫn này hướng dẫn bạn cách kết nối Hermes Agent với GitHub để nó tự động tìm nạp điểm khác biệt của yêu cầu kéo, phân tích các thay đổi về mã và đăng nhận xét — được kích hoạt bởi sự kiện webhook mà không cần lời nhắc thủ công.
Khi PR được mở hoặc cập nhật, GitHub sẽ gửi webhook POST tới phiên bản Hermes của bạn. Hermes chạy tác nhân với lời nhắc hướng dẫn tác nhân truy xuất điểm khác biệt thông qua
gh CLI và phản hồi được đăng trở lại chuỗi PR.
Nếu bạn không có URL công khai hoặc chỉ muốn bắt đầu nhanh chóng, hãy xem Build a GitHub PR Review Agent - sử dụng công việc định kỳ để thăm dò PR theo lịch trình, hoạt động sau NAT và tường lửa.
Để biết thông tin tham khảo đầy đủ về nền tảng webhook (tất cả các tùy chọn cấu hình, loại phân phối, đăng ký động, mô hình bảo mật), hãy xem Webhooks.
Tải trọng webhook chứa dữ liệu do kẻ tấn công kiểm soát — Tiêu đề PR, thông báo cam kết và mô tả có thể chứa các hướng dẫn độc hại. Khi điểm cuối webhook của bạn tiếp xúc với Internet, hãy chạy cổng trong môi trường hộp cát (Docker, chương trình phụ trợ SSH). Xem security section bên dưới.
Điều kiện tiên quyết
- Đã cài đặt và chạy Hermes Agent ( `Hermes gateway
)
- XPROTECTX14XPROTECTX CLI được cài đặt và xác thực trên máy chủ cổng ( `gh auth login
)
- URL có thể truy cập công khai cho phiên bản Hermes của bạn (xem Local testing with ngrok nếu chạy cục bộ)
- Quyền truy cập của quản trị viên vào kho GitHub (bắt buộc để quản lý webhook)
Bước 1 — Kích hoạt nền tảng webhook
Thêm phần sau vào
~/.Hermes/config.yaml ` của bạn:
platforms:
webhook:
enabled: true
extra:
port: 8644 # default; change if another service occupies this port
rate_limit: 30 # max requests per minute per route (not a global cap)
routes:
GitHub-pr-review:
secret: "your-webhook-secret-here" # must match the GitHub webhook secret exactly
events:
- pull_request
# The agent is instructed to fetch the actual diff before reviewing.
# \{number} and \{repository.full_name} are resolved from the GitHub payload.
prompt: |
A pull request event was received (action: \{action}).
PR #\{number}: \{pull_request.title}
Author: \{pull_request.user.login}
Branch: \{pull_request.head.ref} → \{pull_request.base.ref}
Description: \{pull_request.body}
URL: \{pull_request.html_url}
If the action is "closed" or "labeled", stop here and do not post a comment.
Otherwise:
1. Run: gh pr diff \{number} --repo \{repository.full_name}
2. Review the code changes for correctness, security issues, and clarity.
3. Write a concise, actionable review comment and post it.
deliver: GitHub_comment
deliver_extra:
repo: "\{repository.full_name}"
pr_number: "\{number}"
`
``**Các trường chính:**
| Lĩnh vực | Mô tả |
|---|---|
|
`secret
` (cấp tuyến đường) | Bí mật HMAC cho tuyến đường này. Quay trở lại
`extra.secret
` toàn cầu nếu bị bỏ qua. |
|
`events
` | Danh sách các giá trị tiêu đề
`X-GitHub-Event
` được chấp nhận. Danh sách trống = chấp nhận tất cả. |
|
`prompt
` | Bản mẫu;
\{field}
` và
\{nested.field}
` giải quyết từ tải trọng GitHub. |
|
`deliver
` |
`GitHub_comment
` đăng bài qua
`gh pr comment
.
`log
` chỉ ghi vào nhật ký cổng. |
|
`deliver_extra.repo
` | Giải quyết ví dụ:
`org/repo
` khỏi tải trọng. |
|
`deliver_extra.pr_number
` | Phân giải thành số PR từ tải trọng. |
:::note[The payload does not contain code]
Tải trọng webhook GitHub bao gồm siêu dữ liệu PR (tiêu đề, mô tả, tên chi nhánh, URL) nhưng **không phải khác biệt**. Lời nhắc ở trên hướng dẫn tác nhân chạy
`gh pr diff
` để tìm nạp các thay đổi thực tế. Công cụ
`terminal
` được bao gồm trong bộ công cụ
`Hermes-webhook
` mặc định, do đó không cần cấu hình bổ sung.
:::
---
## Bước 2 - Khởi động cổng
``` bash
Hermes gateway
`
``Bạn nên xem:
`
[webhook] Listening on 0.0.0.0:8644 — routes: GitHub-pr-review
`
``Xác minh nó đang chạy:
`bash
curl http://localhost:8644/health
# \{"status": "ok", "platform": "webhook"}
`
---
## Bước 3 - Đăng ký webhook trên GitHub
1. Đi tới kho lưu trữ của bạn → **Cài đặt** → **Webhooks** → **Thêm webhook**
2. Điền vào:
- **URL tải trọng:**
`https://your-public-url.example.com/webhooks/GitHub-pr-review
- **Loại nội dung:**
`application/JSON
- **Bí mật:** cùng giá trị bạn đặt cho
`secret
` trong cấu hình tuyến đường
- **Sự kiện nào?** → Chọn từng sự kiện → chọn **Kéo yêu cầu**
3. Nhấp vào **Thêm webhook**
GitHub sẽ ngay lập tức gửi sự kiện
`ping
` để xác nhận kết nối. Nó được bỏ qua một cách an toàn —
`ping
` không có trong danh sách
`events
` của bạn — và trả về
\{"status": "ignored", "event": "ping"}
. Nó chỉ được ghi ở cấp độ GỠ LỖI, vì vậy nó sẽ không xuất hiện trong bảng điều khiển ở cấp độ nhật ký mặc định.
---
## Bước 4 - Mở PR thử nghiệm
Tạo một nhánh, thực hiện thay đổi và mở PR. Trong vòng 30–90 giây (tùy thuộc vào quy mô và kiểu PR), Hermes nên đăng bình luận đánh giá.
Để theo dõi tiến trình của đại lý trong thời gian thực:
``` bash
tail -f "$\{Hermes_HOME:-$HOME/.Hermes}/logs/gateway.log"
`
---
## Thử nghiệm cục bộ với ngrok
Nếu Hermes đang chạy trên máy tính xách tay của bạn, hãy sử dụng [ngrok](https://ngrok.com/) để hiển thị nó:
`bash
ngrok http 8644
`
``Sao chép URL
`https://...ngrok-free.app
` và sử dụng nó làm URL tải trọng GitHub của bạn. Ở cấp ngrok miễn phí, URL thay đổi mỗi khi ngrok khởi động lại — cập nhật webhook GitHub của bạn mỗi phiên. Tài khoản ngrok trả phí sẽ có được miền tĩnh.
Bạn có thể kiểm tra trực tiếp tuyến đường tĩnh bằng
`curl
- không cần tài khoản GitHub hoặc PR thực sự.:::tip Use XPROTECTX43XPROTECTX when testing locally
Thay đổi
`deliver: GitHub_comment
` thành
`deliver: log
` trong cấu hình của bạn trong khi thử nghiệm. Nếu không, tác nhân sẽ cố gắng đăng nhận xét lên kho lưu trữ
`org/repo#99
` giả mạo trong tải trọng thử nghiệm, điều này sẽ không thành công. Chuyển về
`deliver: GitHub_comment
` sau khi bạn hài lòng với kết quả được nhắc.
:::
``` bash
SECRET="your-webhook-secret-here"
BODY='\{"action":"opened","number":99,"pull_request":\{"title":"Test PR","body":"Adds a feature.","user":\{"login":"testuser"},"head":\{"ref":"feat/x"},"base":\{"ref":"main"},"html_url":"https://GitHub.com/org/repo/pull/99"},"repository":\{"full_name":"org/repo"}}'
SIG=$(printf '%s' "$BODY" | openSSL dgst -sha256 -hmac "$SECRET" -hex | awk '\{print "sha256="$2}')
curl -s -X POST http://localhost:8644/webhooks/GitHub-pr-review \
-H "Content-Type: application/JSON" \
-H "X-GitHub-Event: pull_request" \
-H "X-Hub-Signature-256: $SIG" \
-d "$BODY"
# Expected: \{"status":"accepted","route":"GitHub-pr-review","event":"pull_request","delivery_id":"..."}
`
``Sau đó xem đại lý chạy:
`
``` bash
tail -f "$\{Hermes_HOME:-$HOME/.Hermes}/logs/gateway.log"
`
:::note
`Hermes webhook test <name
` chỉ hoạt động đối với **đăng ký động** được tạo bằng
`Hermes webhook subscribe
. Nó không đọc các tuyến đường từ
`config.yaml
.
:::
---
## Lọc theo hành động cụ thể
GitHub gửi các sự kiện
`pull_request
` cho nhiều hành động:
`opened
,
`synchronize
,
`reopened
,
`closed
,
`labeled
, v.v. Danh sách
`events
` chỉ lọc theo giá trị tiêu đề
`X-GitHub-Event
` — nó không thể lọc theo loại hành động phụ ở cấp định tuyến.
Lời nhắc ở Bước 1 đã xử lý vấn đề này bằng cách hướng dẫn tổng đài viên dừng sớm đối với các sự kiện
`closed
` và
`labeled
.
:::warning[The agent still runs and consumes tokens]
Hướng dẫn "dừng ở đây" ngăn cản quá trình xem xét có ý nghĩa nhưng tác nhân vẫn chạy đến khi hoàn thành cho mọi sự kiện
`pull_request
` bất kể hành động. Webhooks GitHub chỉ có thể lọc theo loại sự kiện (
`pull_request
,
`push
,
`issues
, v.v.) — không phải theo loại hành động phụ (
`opened
,
`closed
,
`labeled
). Không có bộ lọc cấp độ định tuyến cho các hành động phụ. Đối với kho lưu trữ số lượng lớn, hãy chấp nhận chi phí này hoặc lọc ngược dòng bằng quy trình làm việc Hành động GitHub gọi URL webhook của bạn một cách có điều kiện.
:::
> Không có Jinja2 hoặc cú pháp mẫu có điều kiện.
\{field}
` và
\{nested.field}
` là những sản phẩm thay thế duy nhất được hỗ trợ. Bất cứ điều gì khác được chuyển nguyên văn cho đại lý.
---
## Sử dụng kỹ năng để có phong cách đánh giá nhất quán
Tải [Hermes skill](/docs/user-guide/features/skills) để cung cấp cho đại lý tính cách đánh giá nhất quán. Thêm
`skills
` vào tuyến đường của bạn bên trong
`platforms.webhook.extra.routes
` trong
`config.yaml
:
``` yaml
platforms:
webhook:
enabled: true
extra:
routes:
GitHub-pr-review:
secret: "your-webhook-secret-here"
events: [pull_request]
prompt: |
A pull request event was received (action: \{action}).
PR #\{number}: \{pull_request.title} by \{pull_request.user.login}
URL: \{pull_request.html_url}
If the action is "closed" or "labeled", stop here and do not post a comment.
Otherwise:
1. Run: gh pr diff \{number} --repo \{repository.full_name}
2. Review the diff using your review guidelines.
3. Write a concise, actionable review comment and post it.
skills:
- review
deliver: GitHub_comment
deliver_extra:
repo: "\{repository.full_name}"
pr_number: "\{number}"
`
``> **Lưu ý:** Chỉ có kỹ năng đầu tiên trong danh sách được tìm thấy mới được tải. Hermes không xếp chồng nhiều kỹ năng - các mục tiếp theo sẽ bị bỏ qua.
---
## Thay vào đó hãy gửi phản hồi tới Slack hoặc Discord
Thay thế các trường
`deliver
` và
`deliver_extra
` bên trong tuyến đường của bạn bằng nền tảng mục tiêu của bạn:
``` yaml
# Inside platforms.webhook.extra.routes.<route-name>:
# Slack
deliver: Slack
deliver_extra:
chat_id: "C0123456789" # Slack channel ID (omit to use the configured home channel)
# Discord
deliver: Discord
deliver_extra:
chat_id: "987654321012345678" # Discord channel ID (omit to use home channel)
`
``Nền tảng đích cũng phải được kích hoạt và kết nối trong cổng. Nếu
`chat_id
` bị bỏ qua, phản hồi sẽ được gửi đến kênh chính được định cấu hình của nền tảng đó.
Các giá trị
`deliver
` hợp lệ:
`log
` ·
`GitHub_comment
` ·
`Telegram
` ·
`Discord
` ·
`Slack
` ·
`Signal
` ·
`sms
---
## Hỗ trợ GitLab
Bộ điều hợp tương tự hoạt động với GitLab. GitLab sử dụng
`X-GitLab-Token
` để xác thực (khớp chuỗi đơn giản, không phải HMAC) - Hermes tự động xử lý cả hai.
Để lọc sự kiện, GitLab đặt
`X-GitLab-Event
` thành các giá trị như
`Merge Request Hook
,
`Push Hook
,
`pipeline Hook
. Sử dụng giá trị tiêu đề chính xác trong
`events
:
``` yaml
events:
- Merge Request Hook
`
``Các trường tải trọng của GitLab khác với của GitHub - ví dụ:
\{object_attributes.title}
` cho tiêu đề MR và
\{object_attributes.iid}
` cho số MR. Cách dễ nhất để khám phá cấu trúc tải trọng đầy đủ là nút **Kiểm tra** của GitLab trong cài đặt webhook của bạn, kết hợp với nhật ký **Giao hàng gần đây**. Ngoài ra, hãy bỏ qua
`prompt
` khỏi cấu hình tuyến đường của bạn — Hermes sau đó sẽ chuyển toàn bộ tải trọng dưới dạng JSON được định dạng trực tiếp cho tác nhân và phản hồi của tác nhân (hiển thị trong nhật ký cổng với
`deliver: log
) sẽ mô tả cấu trúc của nó.
---
## Ghi chú bảo mật- **Không bao giờ sử dụng
`INSECURE_NO_AUTH
** trong sản xuất — nó vô hiệu hóa hoàn toàn xác thực chữ ký. Nó chỉ dành cho sự phát triển của địa phương.
- **Xoay vòng bí mật webhook của bạn** định kỳ và cập nhật nó trong cả GitHub (cài đặt webhook) và
`config.yaml
` của bạn.
- **Giới hạn tốc độ** theo mặc định là 30 yêu cầu/phút trên mỗi tuyến (có thể định cấu hình qua
`extra.rate_limit
). Vượt quá nó sẽ trả về
`429
.
- **Các lần gửi trùng lặp** (thử lại webhook) được loại bỏ trùng lặp thông qua bộ nhớ đệm tạm thời trong 1 giờ. Khóa bộ đệm là
`X-GitHub-Delivery
` nếu có, sau đó là
`X-Request-ID
, sau đó là dấu thời gian mili giây. Khi cả tiêu đề ID phân phối đều không được đặt, các lần thử lại sẽ **không** được loại bỏ trùng lặp.
- **Tiêm nhắc:** Tiêu đề, mô tả và thông báo cam kết PR đều do kẻ tấn công kiểm soát. PR độc hại có thể cố gắng thao túng hành động của tác nhân. Chạy cổng trong môi trường hộp cát (Docker, VM) khi tiếp xúc với Internet công cộng.
---
## Khắc phục sự cố
| Triệu chứng | Kiểm tra |
|---|---|
|
`401 Invalid signature
` | Bí mật trong config.yaml không khớp với bí mật webhook GitHub |
|
`404 Unknown route
` | Tên tuyến trong URL không khớp với khóa trong
`routes:
` |
|
`429 Rate limit exceeded
` | Đã vượt quá 30 req/phút cho mỗi tuyến — phổ biến khi phân phối lại các sự kiện thử nghiệm từ giao diện người dùng của GitHub; đợi một chút hoặc raise
`extra.rate_limit
` |
| Không có bình luận nào được đăng |
gh
` chưa được cài đặt, không trên PATH hoặc chưa được xác thực (
`gh auth login
) |
| Đại lý chạy nhưng không bình luận | Kiểm tra nhật ký cổng — nếu đầu ra tác nhân trống hoặc chỉ "BỎ QUA", việc phân phối vẫn được thực hiện |
| Cổng đã được sử dụng | Thay đổi
`extra.port
` trong config.yaml |
| Agent chạy nhưng chỉ review PR mô tả | Lời nhắc không bao gồm hướng dẫn
`gh pr diff
` — khác biệt không có trong tải trọng webhook |
| Không thấy sự kiện ping | Các sự kiện bị bỏ qua chỉ trả lại
\{"status":"ignored","event":"ping"}
` ở cấp độ nhật ký DEBUG - kiểm tra nhật ký phân phối của GitHub (repo → Cài đặt → Webhooks → webhook của bạn → Giao hàng gần đây) |`**Tab Phân phối gần đây của GitHub** (repo → Cài đặt → Webhooks → webhook của bạn) hiển thị chính xác tiêu đề yêu cầu, tải trọng, trạng thái HTTP và nội dung phản hồi cho mỗi lần phân phối. Đó là cách nhanh nhất để chẩn đoán lỗi mà không cần chạm vào nhật ký máy chủ của bạn.
---
## Tham khảo cấu hình đầy đủ
``` yaml
platforms:
webhook:
enabled: true
extra:
host: "0.0.0.0" # bind address (default: 0.0.0.0)
port: 8644 # listen port (default: 8644)
secret: "" # optional global fallback secret
rate_limit: 30 # requests per minute per route
max_body_bytes: 1048576 # payload size limit in bytes (default: 1 MB)
routes:
<route-name:
secret: "required-per-route"
events: [] # [] = accept all; otherwise list X-GitHub-Event values
prompt: "" # \{field} / \{nested.field} resolved from payload
skills: [] # first matching skill is loaded (only one)
deliver: "log" # log | GitHub_comment | Telegram | Discord | Slack | Signal | sms
deliver_extra: \{} # repo + pr_number for GitHub_comment; chat_id for others
`
---
## Tiếp theo là gì?
- **[Cron-Based PR Reviews](./GitHub-pr-review-agent.md)** — thăm dò ý kiến PR theo lịch trình, không cần điểm cuối công khai
- **[Webhook Reference](/docs/user-guide/messaging/webhooks)** — tham khảo cấu hình đầy đủ cho nền tảng webhook
- **[Build a Plugin](/docs/guides/build-a-Hermes-plugin)** — logic đánh giá gói thành một plugin có thể chia sẻ
- **[Profiles](/docs/user-guide/profiles)** — chạy hồ sơ người đánh giá chuyên dụng với bộ nhớ và cấu hình riêng