Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate webhook before change any data (#2221) #2222

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 46 additions & 17 deletions server/api/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ func PostHook(c *gin.Context) {
_store := store.FromContext(c)
forge := server.Config.Services.Forge

//
// 1. Parse webhook
//

tmpRepo, tmpBuild, err := forge.Hook(c, c.Request)
if err != nil {
if errors.Is(err, &types.ErrIgnoreEvent{}) {
Expand Down Expand Up @@ -136,6 +140,11 @@ func PostHook(c *gin.Context) {
return
}

//
// Skip if commit message contains skip-ci
// TODO: move into global pipeline conditions logic
//

// skip the tmpBuild if any case-insensitive combination of the words "skip" and "ci"
// wrapped in square brackets appear in the commit message
skipMatch := skipRe.FindString(tmpBuild.Message)
Expand All @@ -146,6 +155,10 @@ func PostHook(c *gin.Context) {
return
}

//
// 2. Get related repo from store and take repo renaming into account
//

repo, err := _store.GetRepoNameFallback(tmpRepo.ForgeRemoteID, tmpRepo.FullName)
if err != nil {
msg := fmt.Sprintf("failure to get repo %s from store", tmpRepo.FullName)
Expand All @@ -159,24 +172,19 @@ func PostHook(c *gin.Context) {
c.String(http.StatusNoContent, msg)
return
}

oldFullName := repo.FullName
if oldFullName != tmpRepo.FullName {
// create a redirection
err = _store.CreateRedirection(&model.Redirection{RepoID: repo.ID, FullName: repo.FullName})
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
}

repo.Update(tmpRepo)
err = _store.UpdateRepo(repo)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
if repo.UserID == 0 {
msg := fmt.Sprintf("ignoring hook. repo %s has no owner.", repo.FullName)
log.Warn().Msg(msg)
c.String(http.StatusNoContent, msg)
return
}

//
// 3. Check if the webhook is a valid and authorized one
//

// get the token and verify the hook is authorized
parsed, err := token.ParseRequest(c.Request, func(_ *token.Token) (string, error) {
return repo.Hash, nil
Expand Down Expand Up @@ -205,20 +213,41 @@ func PostHook(c *gin.Context) {
return
}

if repo.UserID == 0 {
msg := fmt.Sprintf("ignoring hook. repo %s has no owner.", repo.FullName)
log.Warn().Msg(msg)
c.String(http.StatusNoContent, msg)
//
// 4. Update repo
//

if oldFullName != tmpRepo.FullName {
// create a redirection
err = _store.CreateRedirection(&model.Redirection{RepoID: repo.ID, FullName: repo.FullName})
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
}

repo.Update(tmpRepo)
err = _store.UpdateRepo(repo)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}

//
// 5. Check if pull requests are allowed for this repo
//

if tmpBuild.Event == model.EventPull && !repo.AllowPull {
msg := "ignoring hook: pull requests are disabled for this repo in woodpecker"
log.Debug().Str("repo", repo.FullName).Msg(msg)
c.String(http.StatusNoContent, msg)
return
}

//
// 6. Finally create a pipeline
//

pl, err := pipeline.Create(c, _store, repo, tmpBuild)
if err != nil {
handlePipelineErr(c, err)
Expand Down