ServeHTTP validates the webhook signature and dispatches to event-specific handlers. Currently supports push events for triggering deployments. Unknown event types are acknowledged with 200 OK but not processed.
(w http.ResponseWriter, r *http.Request)
| 32 | // handlers. Currently supports push events for triggering deployments. |
| 33 | // Unknown event types are acknowledged with 200 OK but not processed. |
| 34 | func (s *GitHubWebhook) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
| 35 | logger.Info("GitHub webhook request received", |
| 36 | "method", r.Method, |
| 37 | "path", r.URL.Path, |
| 38 | "remote_addr", r.RemoteAddr, |
| 39 | ) |
| 40 | |
| 41 | if r.Method != http.MethodPost { |
| 42 | logger.Warn("GitHub webhook rejected: method not allowed", "method", r.Method) |
| 43 | http.Error(w, "method not allowed", http.StatusMethodNotAllowed) |
| 44 | return |
| 45 | } |
| 46 | |
| 47 | event := r.Header.Get("X-GitHub-Event") |
| 48 | if event == "" { |
| 49 | http.Error(w, "missing X-GitHub-Event header", http.StatusBadRequest) |
| 50 | return |
| 51 | } |
| 52 | |
| 53 | signature := r.Header.Get("X-Hub-Signature-256") |
| 54 | if signature == "" { |
| 55 | logger.Warn("GitHub webhook rejected: missing signature header") |
| 56 | http.Error(w, "missing X-Hub-Signature-256 header", http.StatusUnauthorized) |
| 57 | return |
| 58 | } |
| 59 | |
| 60 | body, err := io.ReadAll(http.MaxBytesReader(w, r.Body, maxWebhookBodySize)) |
| 61 | if err != nil { |
| 62 | logger.Warn("GitHub webhook rejected: failed to read body", "error", err) |
| 63 | http.Error(w, "failed to read body", http.StatusBadRequest) |
| 64 | return |
| 65 | } |
| 66 | |
| 67 | if !githubclient.VerifyWebhookSignature(body, signature, s.webhookSecret) { |
| 68 | logger.Warn("GitHub webhook rejected: invalid signature") |
| 69 | http.Error(w, "invalid signature", http.StatusUnauthorized) |
| 70 | return |
| 71 | } |
| 72 | |
| 73 | logger.Info("GitHub webhook signature verified", "event", event) |
| 74 | |
| 75 | deliveryID := r.Header.Get("X-GitHub-Delivery") |
| 76 | |
| 77 | switch event { |
| 78 | case "push": |
| 79 | s.handlePush(r.Context(), w, body, deliveryID) |
| 80 | case "pull_request": |
| 81 | s.handlePullRequest(r.Context(), w, body, deliveryID) |
| 82 | case "create", "delete": |
| 83 | logger.Info("Branch lifecycle event ignored", "event", event) |
| 84 | w.WriteHeader(http.StatusOK) |
| 85 | case "installation": |
| 86 | logger.Info("Installation event received") |
| 87 | w.WriteHeader(http.StatusOK) |
| 88 | default: |
| 89 | logger.Info("Unhandled event type", "event", event) |
| 90 | w.WriteHeader(http.StatusOK) |
| 91 | } |