diff --git a/server/limit_rate_gh.go b/server/limit_rate_gh.go index d904dab..34259e6 100644 --- a/server/limit_rate_gh.go +++ b/server/limit_rate_gh.go @@ -37,24 +37,3 @@ func (s *Server) CheckLimitRateAndSleep() { } } -// CheckLimitRateAndAbortRequest checks the api rate and abort the request if needed -func (s *Server) CheckLimitRateAndAbortRequest() bool { - s.Logger.Info("Checking the rate limit on Github and will abort request if need...") - - client := newGithubClient(s.Config.GithubAccessToken) - rate, _, err := client.RateLimits(context.Background()) - if err != nil { - s.Logger.WithError(err).Error("Error getting the rate limit") - time.Sleep(30 * time.Second) - return false - } - s.Logger.WithFields(logrus.Fields{ - "Remaining Rate": rate.Core.Remaining, - "Limit Rate": rate.Core.Limit, - }).Info("Current rate limit") - if rate.Core.Remaining <= s.Config.GitHubTokenReserve { - s.Logger.Error("Request will be aborted...") - return true - } - return false -} diff --git a/server/push_events.go b/server/push_events.go index 2ede44e..2a4fd68 100644 --- a/server/push_events.go +++ b/server/push_events.go @@ -42,7 +42,14 @@ func (s *Server) handlePushEvent(event *github.PushEvent) { // Release-branch push trigger was removed; release stabilization is covered by PR-label E2E and CMT. if s.Config.E2EAutoTriggerOnMaster && (branch == "master" || branch == "main") { - logger.WithField("type", "master_main").Info("Master/main branch detected, triggering E2E tests") + sha := "" + if event.GetHeadCommit() != nil { + sha = event.GetHeadCommit().GetID() + } + logger.WithFields(logrus.Fields{ + "type": "master_main", + "sha": sha, + }).Info("Master/main branch detected, triggering E2E tests") go s.handlePushEventE2E(event, branch) return } @@ -94,6 +101,7 @@ func (s *Server) handlePushEventE2E(event *github.PushEvent, branch string) { if !isDesktop && !isMobile { logger.Warn("Repository is neither desktop nor mobile, skipping E2E tests") + s.notifyMattermost("E2E on %s %s (%s) skipped: repo is neither mobile nor desktop", repoName, branch, sha) return } @@ -104,10 +112,12 @@ func (s *Server) handlePushEventE2E(event *github.PushEvent, branch string) { if sha == "" { logger.Error("Push event has no commit SHA, skipping E2E dispatch") + s.notifyMattermost("E2E on %s %s did not run: push event had no commit SHA", repoName, branch) return } logger.WithField("instanceType", instanceType).Info("Creating E2E instances for push event") + s.notifyMattermost("E2E on %s %s (%s): received push — provisioning %s test servers", repoName, branch, sha, instanceType) instances, err := s.createMultipleE2EInstancesForPushEvent(repoName, instanceType, branch) if err != nil { @@ -125,6 +135,7 @@ func (s *Server) handlePushEventE2E(event *github.PushEvent, branch string) { } logger.WithField("instanceCount", len(instances)).Info("E2E instances created successfully") + s.notifyMattermost("E2E on %s %s (%s): provisioned %d test servers — dispatching workflow", repoName, branch, sha, len(instances)) // Key on the branch HEAD resolved now (just before dispatch), not the push SHA: the // dispatched (ref=branch) run reports its head_sha as the branch HEAD at dispatch time, @@ -157,6 +168,7 @@ func (s *Server) handlePushEventE2E(event *github.PushEvent, branch string) { } logger.Info("E2E workflow triggered successfully and instances tracked for cleanup") + s.notifyMattermost("E2E on %s %s (%s): workflow dispatched successfully (%d servers)", repoName, branch, sha, len(instances)) } // createMultipleE2EInstancesForPushEvent creates all platform instances in parallel. diff --git a/server/server.go b/server/server.go index 3e37444..5be8056 100644 --- a/server/server.go +++ b/server/server.go @@ -5,6 +5,7 @@ package server import ( "bytes" + "errors" "fmt" "io" "net/http" @@ -176,14 +177,26 @@ func (s *Server) ping(w http.ResponseWriter, r *http.Request) { w.Write([]byte(msg)) } +const githubWebhookMaxBodyBytes = 10 << 20 // 10 MiB — GitHub payloads are far smaller; bound memory before signature check. + func (s *Server) githubEvent(w http.ResponseWriter, r *http.Request) { - overLimit := s.CheckLimitRateAndAbortRequest() - if overLimit { + // Do not gate webhook ingest on GitHub API rate reserve. A silent abort here + // drops the delivery forever (GitHub does not auto-retry), so main-push E2E + // never starts and nothing is logged. Rate limiting belongs on outbound calls. + r.Body = http.MaxBytesReader(w, r.Body, githubWebhookMaxBodyBytes) + buf, err := io.ReadAll(r.Body) + if err != nil { + var maxBytesErr *http.MaxBytesError + if errors.As(err, &maxBytesErr) { + s.Logger.WithError(err).Error("GitHub webhook body too large") + w.WriteHeader(http.StatusRequestEntityTooLarge) + return + } + s.Logger.WithError(err).Error("Failed to read webhook body") + w.WriteHeader(http.StatusBadRequest) return } - buf, _ := io.ReadAll(r.Body) - receivedHash := strings.SplitN(r.Header.Get("X-Hub-Signature"), "=", 2) if receivedHash[0] != "sha1" { s.Logger.Error("Invalid webhook hash signature: SHA1") @@ -191,7 +204,7 @@ func (s *Server) githubEvent(w http.ResponseWriter, r *http.Request) { return } - err := ValidateSignature(receivedHash, buf, s.Config.GitHubWebhookSecret) + err = ValidateSignature(receivedHash, buf, s.Config.GitHubWebhookSecret) if err != nil { s.Logger.Error(err.Error()) w.WriteHeader(http.StatusForbidden) diff --git a/server/utils.go b/server/utils.go index c6f85f2..1bb43c5 100644 --- a/server/utils.go +++ b/server/utils.go @@ -10,6 +10,11 @@ import ( ) func (s *Server) logErrorToMattermost(msg string, args ...interface{}) { + s.notifyMattermost(msg, args...) +} + +// notifyMattermost posts a lifecycle/status message to the configured webhook. +func (s *Server) notifyMattermost(msg string, args ...interface{}) { if s.Config.MattermostWebhookURL == "" { s.Logger.Warn("No Mattermost webhook URL set: unable to send message") return diff --git a/server/webhook.go b/server/webhook.go index 2aa3fc5..6c81610 100644 --- a/server/webhook.go +++ b/server/webhook.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "net/http" + "time" ) // WebhookRequest defines the message to send to MM @@ -23,7 +24,7 @@ func (s *Server) sendToWebhook(webhookRequest *WebhookRequest) error { return err } - client := http.Client{} + client := http.Client{Timeout: 10 * time.Second} request, err := http.NewRequest("POST", s.Config.MattermostWebhookURL, bytes.NewReader(b)) if err != nil { return err @@ -34,6 +35,7 @@ func (s *Server) sendToWebhook(webhookRequest *WebhookRequest) error { if err != nil { return err } + defer response.Body.Close() if response.StatusCode != http.StatusOK { contents, _ := io.ReadAll(response.Body)