Skip to content

Commit

Permalink
Merge branch 'main' into enhance/pending-approval-timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
ecrupper committed Dec 26, 2024
2 parents d2478f3 + fa93fa8 commit 5b9cb2d
Show file tree
Hide file tree
Showing 292 changed files with 9,847 additions and 514 deletions.
40 changes: 40 additions & 0 deletions api/auth/get_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ package auth
import (
"fmt"
"net/http"
"strconv"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"

"github.com/go-vela/server/api/types"
"github.com/go-vela/server/constants"
"github.com/go-vela/server/database"
"github.com/go-vela/server/internal/token"
"github.com/go-vela/server/scm"
Expand All @@ -36,6 +38,14 @@ import (
// name: redirect_uri
// description: The URL where the user will be sent after authorization
// type: string
// - in: query
// name: setup_action
// description: The specific setup action callback identifier
// type: string
// - in: query
// name: installation_id
// description: The specific installation identifier for a GitHub App integration
// type: integer
// responses:
// '200':
// description: Successfully authenticated
Expand All @@ -46,6 +56,10 @@ import (
// "$ref": "#/definitions/Token"
// '307':
// description: Redirected for authentication
// '400':
// description: Bad Request
// schema:
// "$ref": "#/definitions/Error"
// '401':
// description: Unauthorized
// schema:
Expand All @@ -69,6 +83,32 @@ func GetAuthToken(c *gin.Context) {
// capture the OAuth state if present
oAuthState := c.Request.FormValue("state")

// handle scm setup events
// setup_action==install represents the GitHub App installation callback redirect
if c.Request.FormValue("setup_action") == constants.AppInstallSetupActionInstall {
installID, err := strconv.ParseInt(c.Request.FormValue("installation_id"), 10, 0)
if err != nil {
retErr := fmt.Errorf("unable to parse installation_id: %w", err)

util.HandleError(c, http.StatusBadRequest, retErr)

return
}

r, err := scm.FromContext(c).FinishInstallation(ctx, c.Request, installID)
if err != nil {
retErr := fmt.Errorf("unable to finish installation: %w", err)

util.HandleError(c, http.StatusInternalServerError, retErr)

return
}

c.Redirect(http.StatusTemporaryRedirect, r)

return
}

// capture the OAuth code if present
code := c.Request.FormValue("code")
if len(code) == 0 {
Expand Down
2 changes: 2 additions & 0 deletions api/build/compile_publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ func CompileAndPublish(
WithRepo(repo).
WithUser(u).
WithLabels(cfg.Labels).
WithSCM(scm).
WithDatabase(database).
Compile(ctx, pipelineFile)
if err != nil {
// format the error message with extra information
Expand Down
48 changes: 48 additions & 0 deletions api/build/enqueue.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import (
"encoding/json"
"time"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"

"github.com/go-vela/server/api/types"
"github.com/go-vela/server/constants"
"github.com/go-vela/server/database"
"github.com/go-vela/server/queue"
"github.com/go-vela/server/queue/models"
"github.com/go-vela/server/scm"
)

// Enqueue is a helper function that pushes a queue item (build, repo, user) to the queue.
Expand Down Expand Up @@ -65,3 +69,47 @@ func Enqueue(ctx context.Context, queue queue.Service, db database.Interface, it

l.Info("updated build as enqueued")
}

// ShouldEnqueue is a helper function that will determine whether to publish a build to the queue or place it
// in pending approval status.
func ShouldEnqueue(c *gin.Context, l *logrus.Entry, b *types.Build, r *types.Repo) (bool, error) {
// if the webhook was from a Pull event from a forked repository, verify it is allowed to run
if b.GetFork() {
l.Tracef("inside %s workflow for fork PR build %s/%d", r.GetApproveBuild(), r.GetFullName(), b.GetNumber())

switch r.GetApproveBuild() {
case constants.ApproveForkAlways:
return false, nil
case constants.ApproveForkNoWrite:
// determine if build sender has write access to parent repo. If not, this call will result in an error
level, err := scm.FromContext(c).RepoAccess(c.Request.Context(), b.GetSender(), r.GetOwner().GetToken(), r.GetOrg(), r.GetName())
if err != nil || (level != "admin" && level != "write") {
//nolint:nilerr // an error here is not something we want to return since we are gating it anyway
return false, nil
}

l.Debugf("fork PR build %s/%d automatically running without approval. sender %s has %s access", r.GetFullName(), b.GetNumber(), b.GetSender(), level)
case constants.ApproveOnce:
// determine if build sender is in the contributors list for the repo
//
// NOTE: this call is cumbersome for repos with lots of contributors. Potential TODO: improve this if
// GitHub adds a single-contributor API endpoint.
contributor, err := scm.FromContext(c).RepoContributor(c.Request.Context(), r.GetOwner(), b.GetSender(), r.GetOrg(), r.GetName())
if err != nil {
return false, err
}

if !contributor {
return false, nil
}

fallthrough
case constants.ApproveNever:
fallthrough
default:
l.Debugf("fork PR build %s/%d automatically running without approval", r.GetFullName(), b.GetNumber())
}
}

return true, nil
}
54 changes: 54 additions & 0 deletions api/build/gatekeep.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: Apache-2.0

package build

import (
"fmt"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"

"github.com/go-vela/server/api/types"
"github.com/go-vela/server/constants"
"github.com/go-vela/server/database"
"github.com/go-vela/server/scm"
)

// GatekeepBuild is a helper function that will set the status of a build to 'pending approval' and
// send a status update to the SCM.
func GatekeepBuild(c *gin.Context, b *types.Build, r *types.Repo) error {
l := c.MustGet("logger").(*logrus.Entry)

l = l.WithFields(logrus.Fields{
"org": r.GetOrg(),
"repo": r.GetName(),
"repo_id": r.GetID(),
"build": b.GetNumber(),
"build_id": b.GetID(),
})

l.Debug("fork PR build waiting for approval")

b.SetStatus(constants.StatusPendingApproval)

_, err := database.FromContext(c).UpdateBuild(c, b)
if err != nil {
return fmt.Errorf("unable to update build for %s/%d: %w", r.GetFullName(), b.GetNumber(), err)
}

l.Info("build updated")

// update the build components to pending approval status
err = UpdateComponentStatuses(c, b, constants.StatusPendingApproval)
if err != nil {
return fmt.Errorf("unable to update build components for %s/%d: %w", r.GetFullName(), b.GetNumber(), err)
}

// send API call to set the status on the commit
err = scm.FromContext(c).Status(c, r.GetOwner(), b, r.GetOrg(), r.GetName())
if err != nil {
l.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), b.GetNumber(), err)
}

return nil
}
27 changes: 26 additions & 1 deletion api/build/restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package build

import (
"context"
"fmt"
"net/http"
"strings"
Expand Down Expand Up @@ -149,13 +150,37 @@ func RestartBuild(c *gin.Context) {
}

// determine whether or not to send compiled build to queue
err = TrafficBuild(c, l, item.Build, r, item)
shouldEnqueue, err := ShouldEnqueue(c, l, item.Build, r)
if err != nil {
util.HandleError(c, http.StatusInternalServerError, err)

return
}

if shouldEnqueue {
// send API call to set the status on the commit
err := scm.Status(c.Request.Context(), r.GetOwner(), b, r.GetOrg(), r.GetName())
if err != nil {
l.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), b.GetNumber(), err)
}

// publish the build to the queue
go Enqueue(
context.WithoutCancel(c.Request.Context()),
queue.FromGinContext(c),
database.FromContext(c),
item,
b.GetHost(),
)
} else {
err := GatekeepBuild(c, b, r)
if err != nil {
util.HandleError(c, http.StatusInternalServerError, err)

return
}
}

l.WithFields(logrus.Fields{
"new_build": item.Build.GetNumber(),
"new_build_id": item.Build.GetID(),
Expand Down
130 changes: 0 additions & 130 deletions api/build/traffic.go

This file was deleted.

2 changes: 1 addition & 1 deletion api/pipeline/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/go-vela/server/api/types"
"github.com/go-vela/server/compiler"
"github.com/go-vela/server/compiler/registry/github"
"github.com/go-vela/server/compiler/types/yaml"
"github.com/go-vela/server/compiler/types/yaml/yaml"
"github.com/go-vela/server/internal"
"github.com/go-vela/server/router/middleware/org"
"github.com/go-vela/server/router/middleware/pipeline"
Expand Down
Loading

0 comments on commit 5b9cb2d

Please sign in to comment.