Skip to content

Commit

Permalink
Update: allow push to certain branches
Browse files Browse the repository at this point in the history
This extends MasterOnly and makes it configurable. The idea is to
set arbitrary branch names which are allowed to be pushed to and
otherwise return an error.

Resolves: #33
  • Loading branch information
till committed Jun 16, 2023
1 parent 7ca9dd9 commit 1d2f53d
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 6 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/gofrs/uuid v4.0.0+incompatible
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
golang.org/x/exp v0.0.0-20230203172020-98cc5a0785f9
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/exp v0.0.0-20230203172020-98cc5a0785f9 h1:frX3nT9RkKybPnjyI+yvZh6ZucTZatCCEm9D47sZ2zo=
golang.org/x/exp v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
Expand Down
30 changes: 24 additions & 6 deletions receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import (
"strings"

"github.com/gofrs/uuid"
"golang.org/x/exp/slices"
)

const ZeroSHA = "0000000000000000000000000000000000000000"

type Receiver struct {
Debug bool
MasterOnly bool
TmpDir string
HandlerFunc func(*HookInfo, string) error
Debug bool
MasterOnly bool
AllowedBranches []string
TmpDir string
HandlerFunc func(*HookInfo, string) error
}

func ReadCommitMessage(sha string) (string, error) {
Expand Down Expand Up @@ -45,14 +47,30 @@ func IsForcePush(hook *HookInfo) (bool, error) {
return base != hook.OldRev, nil
}

func (r *Receiver) CheckAllowedBranch(hook *HookInfo) error {
if r.MasterOnly { // for BC
r.AllowedBranches = append(r.AllowedBranches, "refs/heads/master")
}

if len(r.AllowedBranches) == 0 {
return nil
}

if !slices.Contains(r.AllowedBranches, hook.Ref) {
return fmt.Errorf("cannot push branch, allowed branches: %s", strings.Join(r.AllowedBranches, ", "))
}

return nil
}

func (r *Receiver) Handle(reader io.Reader) error {
hook, err := ReadHookInput(reader)
if err != nil {
return err
}

if r.MasterOnly && hook.Ref != "refs/heads/master" {
return fmt.Errorf("cant push to non-master branch")
if err = r.CheckAllowedBranch(hook); err != nil {
return err
}

id, err := uuid.NewV4()
Expand Down
94 changes: 94 additions & 0 deletions receiver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package gitkit_test

import (
"testing"

"github.com/sosedoff/gitkit"
"github.com/stretchr/testify/assert"
)

type gitReceiveMock struct {
name string
masterOnly bool
allowedBranches []string
ref string
isErr bool
}

func TestMasterOnly(t *testing.T) {
testCases := []gitReceiveMock{
{
name: "push to master, no error",
masterOnly: true,
ref: "refs/heads/master",
isErr: false,
},
{
name: "push to a branch, should trigger error",
masterOnly: true,
ref: "refs/heads/branch",
isErr: true,
},
}

for _, tc := range testCases {
r := &gitkit.Receiver{
MasterOnly: tc.masterOnly,
}

err := r.CheckAllowedBranch(&gitkit.HookInfo{
Ref: tc.ref,
})

if !tc.isErr {
assert.NoError(t, err, "expected no error: %s", tc.name)
} else {
assert.Error(t, err, "expected an error: %s", tc.name)
}
}
}

func TestAllowedBranches(t *testing.T) {
testCases := []gitReceiveMock{
{
name: "push to master, no error",
allowedBranches: []string{"refs/heads/master"},
ref: "refs/heads/master",
isErr: false,
},
{
name: "push to a branch, should trigger error",
allowedBranches: []string{"refs/heads/master"},
ref: "refs/heads/some-branch",
isErr: true,
},
{
name: "push to another-branch",
allowedBranches: []string{"refs/heads/another-branch"},
ref: "refs/heads/another-branch",
isErr: false,
},
{
name: "push to main and only allow main",
allowedBranches: []string{"refs/heads/main"},
ref: "refs/heads/main",
isErr: false,
},
}

for _, tc := range testCases {
r := &gitkit.Receiver{
AllowedBranches: tc.allowedBranches,
}

err := r.CheckAllowedBranch(&gitkit.HookInfo{
Ref: tc.ref,
})

if !tc.isErr {
assert.NoError(t, err, "expected no error: %s", tc.name)
} else {
assert.Error(t, err, "expected an error: %s", tc.name)
}
}
}

0 comments on commit 1d2f53d

Please sign in to comment.