// Copyright 2019 Sorint.lab // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied // See the License for the specific language governing permissions and // limitations under the License. package gateway import ( "net/http" "github.com/sorintlab/agola/internal/services/common" csapi "github.com/sorintlab/agola/internal/services/configstore/api" "github.com/sorintlab/agola/internal/services/gateway/action" rsapi "github.com/sorintlab/agola/internal/services/runservice/api" "github.com/sorintlab/agola/internal/services/types" "github.com/sorintlab/agola/internal/util" "go.uber.org/zap" errors "golang.org/x/xerrors" ) type webhooksHandler struct { log *zap.SugaredLogger ah *action.ActionHandler configstoreClient *csapi.Client runserviceClient *rsapi.Client apiExposedURL string } func (h *webhooksHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { code, userErr, err := h.handleWebhook(r) if err != nil { h.log.Errorf("err: %+v", err) http.Error(w, userErr, code) } } func (h *webhooksHandler) handleWebhook(r *http.Request) (int, string, error) { ctx := r.Context() projectID := r.URL.Query().Get("projectid") if projectID == "" { return http.StatusBadRequest, "", errors.Errorf("bad webhook url %q. Missing projectid", r.URL) } defer r.Body.Close() csProject, _, err := h.configstoreClient.GetProject(ctx, projectID) if err != nil { return http.StatusBadRequest, "", errors.Errorf("failed to get project %s: %w", projectID, err) } project := csProject.Project user, _, err := h.configstoreClient.GetUserByLinkedAccount(ctx, project.LinkedAccountID) if err != nil { return http.StatusInternalServerError, "", errors.Errorf("failed to get user by linked account %q: %w", project.LinkedAccountID, err) } la := user.LinkedAccounts[project.LinkedAccountID] h.log.Infof("la: %s", util.Dump(la)) if la == nil { return http.StatusInternalServerError, "", errors.Errorf("linked account %q in user %q doesn't exist", project.LinkedAccountID, user.Name) } rs, _, err := h.configstoreClient.GetRemoteSource(ctx, la.RemoteSourceID) if err != nil { return http.StatusInternalServerError, "", errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, err) } gitSource, err := h.ah.GetGitSource(ctx, rs, user.Name, la) if err != nil { return http.StatusInternalServerError, "", errors.Errorf("failed to create gitea client: %w", err) } sshPrivKey := project.SSHPrivateKey sshHostKey := rs.SSHHostKey // use remotesource skipSSHHostKeyCheck config and override with project config if set to true there skipSSHHostKeyCheck := rs.SkipSSHHostKeyCheck if project.SkipSSHHostKeyCheck { skipSSHHostKeyCheck = project.SkipSSHHostKeyCheck } webhookData, err := gitSource.ParseWebhook(r, project.WebhookSecret) if err != nil { return http.StatusBadRequest, "", errors.Errorf("failed to parse webhook: %w", err) } // skip nil webhook data // TODO(sgotti) report the reason of the skip if webhookData == nil { h.log.Infof("skipping webhook") return 0, "", nil } cloneURL := webhookData.SSHURL h.log.Infof("webhookData: %s", util.Dump(webhookData)) req := &action.CreateRunRequest{ RunType: types.RunTypeProject, RefType: common.WebHookEventToRunRefType(webhookData.Event), RunCreationTrigger: types.RunCreationTriggerTypeWebhook, Project: project, User: nil, RepoPath: webhookData.Repo.Path, GitSource: gitSource, CommitSHA: webhookData.CommitSHA, Message: webhookData.Message, Branch: webhookData.Branch, Tag: webhookData.Tag, PullRequestID: webhookData.PullRequestID, Ref: webhookData.Ref, SSHPrivKey: sshPrivKey, SSHHostKey: sshHostKey, SkipSSHHostKeyCheck: skipSSHHostKeyCheck, CloneURL: cloneURL, CommitLink: webhookData.CommitLink, BranchLink: webhookData.BranchLink, TagLink: webhookData.TagLink, PullRequestLink: webhookData.PullRequestLink, CompareLink: webhookData.CompareLink, } if err := h.ah.CreateRuns(ctx, req); err != nil { return http.StatusInternalServerError, "", errors.Errorf("failed to create run: %w", err) } return 0, "", nil }