Skip to content

Commit

Permalink
Add alternate_object_dirs support to githook handlers (#1141)
Browse files Browse the repository at this point in the history
  • Loading branch information
johannesHarness authored and Harness committed Mar 26, 2024
1 parent 96f35b6 commit e96ab41
Show file tree
Hide file tree
Showing 23 changed files with 179 additions and 83 deletions.
27 changes: 0 additions & 27 deletions app/api/controller/githook/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,15 @@ import (
"github.com/harness/gitness/app/services/protection"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/app/url"
"github.com/harness/gitness/git"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)

// ServerHookOutput represents the output of server hook api calls.
// TODO: support non-error messages (once we need it).
type ServerHookOutput struct {
// Error contains the user facing error (like "branch is protected", ...).
Error *string `json:"error,omitempty"`
}

// ReferenceUpdate represents an update of a git reference.
type ReferenceUpdate struct {
// Ref is the full name of the reference that got updated.
Ref string `json:"ref"`
// Old is the old commmit hash (before the update).
Old string `json:"old"`
// New is the new commit hash (after the update).
New string `json:"new"`
}

// BaseInput contains the base input for any githook api call.
type BaseInput struct {
RepoID int64 `json:"repo_id"`
PrincipalID int64 `json:"principal_id"`
}

type Controller struct {
authorizer authz.Authorizer
principalStore store.PrincipalStore
repoStore store.RepoStore
gitReporter *eventsgit.Reporter
git git.Interface
pullreqStore store.PullReqStore
urlProvider url.Provider
protectionManager *protection.Manager
Expand All @@ -74,7 +49,6 @@ func NewController(
principalStore store.PrincipalStore,
repoStore store.RepoStore,
gitReporter *eventsgit.Reporter,
git git.Interface,
pullreqStore store.PullReqStore,
urlProvider url.Provider,
protectionManager *protection.Manager,
Expand All @@ -89,7 +63,6 @@ func NewController(
principalStore: principalStore,
repoStore: repoStore,
gitReporter: gitReporter,
git: git,
pullreqStore: pullreqStore,
urlProvider: urlProvider,
protectionManager: protectionManager,
Expand Down
6 changes: 6 additions & 0 deletions app/api/controller/githook/extender.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
type PreReceiveExtender interface {
Extend(
context.Context,
RestrictedGIT,
*auth.Session,
*types.Repository,
types.GithookPreReceiveInput,
Expand All @@ -35,6 +36,7 @@ type PreReceiveExtender interface {
type UpdateExtender interface {
Extend(
context.Context,
RestrictedGIT,
*auth.Session,
*types.Repository,
types.GithookUpdateInput,
Expand All @@ -45,6 +47,7 @@ type UpdateExtender interface {
type PostReceiveExtender interface {
Extend(
context.Context,
RestrictedGIT,
*auth.Session,
*types.Repository,
types.GithookPostReceiveInput,
Expand All @@ -61,6 +64,7 @@ func NewPreReceiveExtender() PreReceiveExtender {

func (NoOpPreReceiveExtender) Extend(
context.Context,
RestrictedGIT,
*auth.Session,
*types.Repository,
types.GithookPreReceiveInput,
Expand All @@ -78,6 +82,7 @@ func NewUpdateExtender() UpdateExtender {

func (NoOpUpdateExtender) Extend(
context.Context,
RestrictedGIT,
*auth.Session,
*types.Repository,
types.GithookUpdateInput,
Expand All @@ -95,6 +100,7 @@ func NewPostReceiveExtender() PostReceiveExtender {

func (NoOpPostReceiveExtender) Extend(
context.Context,
RestrictedGIT,
*auth.Session,
*types.Repository,
types.GithookPostReceiveInput,
Expand Down
30 changes: 30 additions & 0 deletions app/api/controller/githook/git.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2023 Harness, Inc.
//
// 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:https://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 githook

import (
"context"

"github.com/harness/gitness/git"
)

// RestrictedGIT is a git client that is restricted to a subset of operations of git.Interface
// which can be executed on quarantine data that is part of git-hooks (e.g. pre-receive, update, ..)
// and don't alter the repo (so only read operations).
// NOTE: While it doesn't apply to all git-hooks (e.g. post-receive), we still use the interface across the board
// to "soft enforce" no write operations being executed as part of githooks.
type RestrictedGIT interface {
IsAncestor(ctx context.Context, params git.IsAncestorParams) (git.IsAncestorOutput, error)
}
17 changes: 12 additions & 5 deletions app/api/controller/githook/post_receive.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
// PostReceive executes the post-receive hook for a git repository.
func (c *Controller) PostReceive(
ctx context.Context,
rgit RestrictedGIT,
session *auth.Session,
in types.GithookPostReceiveInput,
) (hook.Output, error) {
Expand All @@ -52,15 +53,15 @@ func (c *Controller) PostReceive(
}

// report ref events (best effort)
c.reportReferenceEvents(ctx, repo, in.PrincipalID, in.PostReceiveInput)
c.reportReferenceEvents(ctx, rgit, repo, in.PrincipalID, in.PostReceiveInput)

// create output object and have following messages fill its messages
out := hook.Output{}

// handle branch updates related to PRs - best effort
c.handlePRMessaging(ctx, repo, in.PostReceiveInput, &out)

err = c.postReceiveExtender.Extend(ctx, session, repo, in, &out)
err = c.postReceiveExtender.Extend(ctx, rgit, session, repo, in, &out)
if out.Error != nil {
return out, nil
}
Expand All @@ -76,14 +77,15 @@ func (c *Controller) PostReceive(
// TODO: in the future we might want to think about propagating errors so user is aware of events not being triggered.
func (c *Controller) reportReferenceEvents(
ctx context.Context,
rgit RestrictedGIT,
repo *types.Repository,
principalID int64,
in hook.PostReceiveInput,
) {
for _, refUpdate := range in.RefUpdates {
switch {
case strings.HasPrefix(refUpdate.Ref, gitReferenceNamePrefixBranch):
c.reportBranchEvent(ctx, repo, principalID, refUpdate)
c.reportBranchEvent(ctx, rgit, repo, principalID, in.Environment, refUpdate)
case strings.HasPrefix(refUpdate.Ref, gitReferenceNamePrefixTag):
c.reportTagEvent(ctx, repo, principalID, refUpdate)
default:
Expand All @@ -94,8 +96,10 @@ func (c *Controller) reportReferenceEvents(

func (c *Controller) reportBranchEvent(
ctx context.Context,
rgit RestrictedGIT,
repo *types.Repository,
principalID int64,
env hook.Environment,
branchUpdate hook.ReferenceUpdate,
) {
switch {
Expand All @@ -114,8 +118,11 @@ func (c *Controller) reportBranchEvent(
SHA: branchUpdate.Old.String(),
})
default:
result, err := c.git.IsAncestor(ctx, git.IsAncestorParams{
ReadParams: git.ReadParams{RepoUID: repo.GitUID},
result, err := rgit.IsAncestor(ctx, git.IsAncestorParams{
ReadParams: git.ReadParams{
RepoUID: repo.GitUID,
AlternateObjectDirs: env.AlternateObjectDirs,
},
AncestorCommitSHA: branchUpdate.Old,
DescendantCommitSHA: branchUpdate.New,
})
Expand Down
5 changes: 2 additions & 3 deletions app/api/controller/githook/pre_receive.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ import (
)

// PreReceive executes the pre-receive hook for a git repository.
//
//nolint:revive // not yet fully implemented
func (c *Controller) PreReceive(
ctx context.Context,
rgit RestrictedGIT,
session *auth.Session,
in types.GithookPreReceiveInput,
) (hook.Output, error) {
Expand Down Expand Up @@ -87,7 +86,7 @@ func (c *Controller) PreReceive(
return hook.Output{}, fmt.Errorf("failed to check protection rules: %w", err)
}

err = c.preReceiveExtender.Extend(ctx, session, repo, in, &output)
err = c.preReceiveExtender.Extend(ctx, rgit, session, repo, in, &output)
if output.Error != nil {
return output, nil
}
Expand Down
5 changes: 2 additions & 3 deletions app/api/controller/githook/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ import (
)

// Update executes the update hook for a git repository.
//
//nolint:revive // not yet implemented
func (c *Controller) Update(
ctx context.Context,
rgit RestrictedGIT,
session *auth.Session,
in types.GithookUpdateInput,
) (hook.Output, error) {
Expand All @@ -39,7 +38,7 @@ func (c *Controller) Update(

output := hook.Output{}

err = c.updateExtender.Extend(ctx, session, repo, in, &output)
err = c.updateExtender.Extend(ctx, rgit, session, repo, in, &output)
if output.Error != nil {
return output, nil
}
Expand Down
9 changes: 7 additions & 2 deletions app/api/handler/githook/post_receive.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ import (
controllergithook "github.com/harness/gitness/app/api/controller/githook"
"github.com/harness/gitness/app/api/render"
"github.com/harness/gitness/app/api/request"
"github.com/harness/gitness/git"
"github.com/harness/gitness/types"
)

// HandlePostReceive returns a handler function that handles post-receive git hooks.
func HandlePostReceive(githookCtrl *controllergithook.Controller) http.HandlerFunc {
func HandlePostReceive(
githookCtrl *controllergithook.Controller,
git git.Interface,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
session, _ := request.AuthSessionFrom(ctx)
Expand All @@ -37,7 +41,8 @@ func HandlePostReceive(githookCtrl *controllergithook.Controller) http.HandlerFu
return
}

out, err := githookCtrl.PostReceive(ctx, session, in)
// gitness doesn't require any custom git connector.
out, err := githookCtrl.PostReceive(ctx, git, session, in)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
Expand Down
9 changes: 7 additions & 2 deletions app/api/handler/githook/pre_receive.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ import (
controllergithook "github.com/harness/gitness/app/api/controller/githook"
"github.com/harness/gitness/app/api/render"
"github.com/harness/gitness/app/api/request"
"github.com/harness/gitness/git"
"github.com/harness/gitness/types"
)

// HandlePreReceive returns a handler function that handles pre-receive git hooks.
func HandlePreReceive(githookCtrl *controllergithook.Controller) http.HandlerFunc {
func HandlePreReceive(
githookCtrl *controllergithook.Controller,
git git.Interface,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
session, _ := request.AuthSessionFrom(ctx)
Expand All @@ -37,7 +41,8 @@ func HandlePreReceive(githookCtrl *controllergithook.Controller) http.HandlerFun
return
}

out, err := githookCtrl.PreReceive(ctx, session, in)
// gitness doesn't require any custom git connector.
out, err := githookCtrl.PreReceive(ctx, git, session, in)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
Expand Down
11 changes: 8 additions & 3 deletions app/api/handler/githook/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ import (
"encoding/json"
"net/http"

githookcontroller "github.com/harness/gitness/app/api/controller/githook"
controllergithook "github.com/harness/gitness/app/api/controller/githook"
"github.com/harness/gitness/app/api/render"
"github.com/harness/gitness/app/api/request"
"github.com/harness/gitness/git"
"github.com/harness/gitness/types"
)

// HandleUpdate returns a handler function that handles update git hooks.
func HandleUpdate(githookCtrl *githookcontroller.Controller) http.HandlerFunc {
func HandleUpdate(
githookCtrl *controllergithook.Controller,
git git.Interface,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
session, _ := request.AuthSessionFrom(ctx)
Expand All @@ -37,7 +41,8 @@ func HandleUpdate(githookCtrl *githookcontroller.Controller) http.HandlerFunc {
return
}

out, err := githookCtrl.Update(ctx, session, in)
// gitness doesn't require any custom git connector.
out, err := githookCtrl.Update(ctx, git, session, in)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
Expand Down
Loading

0 comments on commit e96ab41

Please sign in to comment.