From 0a78102fee09aa0ef49ef890f696165a9ab4e2f1 Mon Sep 17 00:00:00 2001 From: till Date: Sun, 5 Feb 2023 17:35:24 +0100 Subject: [PATCH 1/4] Chore: upgrade go to 1.19 --- .github/workflows/build.yml | 2 +- go.mod | 9 ++++++++- go.sum | 11 ++++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b35171f..79f78cb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ on: - push env: - GO_VERSION: 1.18 + GO_VERSION: 1.19 jobs: build: diff --git a/go.mod b/go.mod index 1fc9f41..b1b2e5c 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,16 @@ module github.com/sosedoff/gitkit -go 1.16 +go 1.19 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 ) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/sys v0.1.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect +) diff --git a/go.sum b/go.sum index 1607b45..61f751a 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -9,13 +10,9 @@ 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/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= From 7ca9dd905215df790715a903255e6ceffebdf203 Mon Sep 17 00:00:00 2001 From: till Date: Sun, 5 Feb 2023 18:11:32 +0100 Subject: [PATCH 2/4] Chore: update actions --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79f78cb..205e757 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,12 +14,12 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - name: Setup Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} From 1d2f53d33e5708b8221a46064b8ba05b5affbe06 Mon Sep 17 00:00:00 2001 From: till Date: Sun, 5 Feb 2023 18:04:09 +0100 Subject: [PATCH 3/4] Update: allow push to certain branches 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: sosedoff/gitkit#33 --- go.mod | 1 + go.sum | 2 ++ receiver.go | 30 ++++++++++++---- receiver_test.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 receiver_test.go diff --git a/go.mod b/go.mod index b1b2e5c..1cea0d1 100644 --- a/go.mod +++ b/go.mod @@ -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 ( diff --git a/go.sum b/go.sum index 61f751a..e0b183a 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/receiver.go b/receiver.go index f4a02fb..592668c 100644 --- a/receiver.go +++ b/receiver.go @@ -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) { @@ -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() diff --git a/receiver_test.go b/receiver_test.go new file mode 100644 index 0000000..261049c --- /dev/null +++ b/receiver_test.go @@ -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) + } + } +} From 17559cfee87d265796247a15a8baac7f1eabbf96 Mon Sep 17 00:00:00 2001 From: till Date: Fri, 16 Jun 2023 17:35:00 +0200 Subject: [PATCH 4/4] Chore: address feedback from CR - renamed AllowedBranches to AllowedRefs - use t.Run() in tests --- receiver.go | 18 ++++++++-------- receiver_test.go | 55 +++++++++++++++++++++++------------------------- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/receiver.go b/receiver.go index 592668c..29ade01 100644 --- a/receiver.go +++ b/receiver.go @@ -15,11 +15,11 @@ import ( const ZeroSHA = "0000000000000000000000000000000000000000" type Receiver struct { - Debug bool - MasterOnly bool - AllowedBranches []string - TmpDir string - HandlerFunc func(*HookInfo, string) error + Debug bool + MasterOnly bool + AllowedRefs []string + TmpDir string + HandlerFunc func(*HookInfo, string) error } func ReadCommitMessage(sha string) (string, error) { @@ -49,15 +49,15 @@ func IsForcePush(hook *HookInfo) (bool, error) { func (r *Receiver) CheckAllowedBranch(hook *HookInfo) error { if r.MasterOnly { // for BC - r.AllowedBranches = append(r.AllowedBranches, "refs/heads/master") + r.AllowedRefs = append(r.AllowedRefs, "refs/heads/master") } - if len(r.AllowedBranches) == 0 { + if len(r.AllowedRefs) == 0 { return nil } - if !slices.Contains(r.AllowedBranches, hook.Ref) { - return fmt.Errorf("cannot push branch, allowed branches: %s", strings.Join(r.AllowedBranches, ", ")) + if !slices.Contains(r.AllowedRefs, hook.Ref) { + return fmt.Errorf("cannot push branch, allowed branches: %s", strings.Join(r.AllowedRefs, ", ")) } return nil diff --git a/receiver_test.go b/receiver_test.go index 261049c..2c6309f 100644 --- a/receiver_test.go +++ b/receiver_test.go @@ -1,6 +1,7 @@ package gitkit_test import ( + "fmt" "testing" "github.com/sosedoff/gitkit" @@ -12,7 +13,7 @@ type gitReceiveMock struct { masterOnly bool allowedBranches []string ref string - isErr bool + err error } func TestMasterOnly(t *testing.T) { @@ -21,30 +22,28 @@ func TestMasterOnly(t *testing.T) { name: "push to master, no error", masterOnly: true, ref: "refs/heads/master", - isErr: false, + err: nil, }, { name: "push to a branch, should trigger error", masterOnly: true, ref: "refs/heads/branch", - isErr: true, + err: fmt.Errorf("cannot push branch, allowed branches: refs/heads/master"), }, } for _, tc := range testCases { - r := &gitkit.Receiver{ - MasterOnly: tc.masterOnly, - } + t.Run(tc.name, func(t *testing.T) { + r := &gitkit.Receiver{ + MasterOnly: tc.masterOnly, + } - err := r.CheckAllowedBranch(&gitkit.HookInfo{ - Ref: tc.ref, - }) + 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) - } + assert.Equal(t, tc.err, err) + }) } } @@ -54,41 +53,39 @@ func TestAllowedBranches(t *testing.T) { name: "push to master, no error", allowedBranches: []string{"refs/heads/master"}, ref: "refs/heads/master", - isErr: false, + err: nil, }, { name: "push to a branch, should trigger error", allowedBranches: []string{"refs/heads/master"}, ref: "refs/heads/some-branch", - isErr: true, + err: fmt.Errorf("cannot push branch, allowed branches: refs/heads/master"), }, { name: "push to another-branch", allowedBranches: []string{"refs/heads/another-branch"}, ref: "refs/heads/another-branch", - isErr: false, + err: nil, }, { name: "push to main and only allow main", allowedBranches: []string{"refs/heads/main"}, ref: "refs/heads/main", - isErr: false, + err: nil, }, } for _, tc := range testCases { - r := &gitkit.Receiver{ - AllowedBranches: tc.allowedBranches, - } + t.Run(tc.name, func(t *testing.T) { + r := &gitkit.Receiver{ + AllowedRefs: tc.allowedBranches, + } - err := r.CheckAllowedBranch(&gitkit.HookInfo{ - Ref: tc.ref, - }) + 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) - } + assert.Equal(t, tc.err, err) + }) } }