Fix verifyCommits error when push a new branch (#26664)
> ### Description > If a new branch is pushed, and the repository has a rule that would require signed commits for the new branch, the commit is rejected with a 500 error regardless of whether it's signed. > > When pushing a new branch, the "old" commit is the empty ID (0000000000000000000000000000000000000000). verifyCommits has no provision for this and passes an invalid commit range to git rev-list. Prior to 1.19 this wasn't an issue because only pre-existing individual branches could be protected. > > I was able to reproduce with [try.gitea.io/CraigTest/test](https://try.gitea.io/CraigTest/test), which is set up with a blanket rule to require commits on all branches. Fix #25565 Very thanks to @Craig-Holmquist-NTI for reporting the bug and suggesting an valid solution! --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
@ -276,4 +276,12 @@
|
||||
email: user2-2@example.com
|
||||
lower_email: user2-2@example.com
|
||||
is_activated: false
|
||||
is_primary: false
|
||||
is_primary: false
|
||||
|
||||
-
|
||||
id: 36
|
||||
uid: 36
|
||||
email: abcde@gitea.com
|
||||
lower_email: abcde@gitea.com
|
||||
is_activated: true
|
||||
is_primary: false
|
||||
|
@ -1 +1,23 @@
|
||||
[] # empty
|
||||
-
|
||||
id: 5
|
||||
owner_id: 36
|
||||
key_id: B15431642629B826
|
||||
primary_key_id:
|
||||
content: xsDNBGTrY3UBDAC2HLBqmMplAV15qSnC7g1c4dV406f5EHNhFr95Nup2My6b2eafTlvedv77s8PT/I7F3fy4apOZs5A7w2SsPlLMcQ3ev4uGOsxRtkq5RLy1Yb6SNueX0Da2UVKR5KTC5Q6BWaqxwS0IjKOLZ/xz0Pbe/ClV3bZSKBEY2omkVo3Z0HZ771vB2clPRvGJ/IdeKOsZ3ZytSFXfyiJBdARmeSPmydXLil8+Ibq5iLAeow5PK8hK1TCOnKHzLWNqcNq70tyjoHvcGi70iGjoVEEUgPCLLuU8WmzTJwlvA3BuDzjtaO7TLo/jdE6iqkHtMSS8x+43sAH6hcFRCWAVh/0Uq7n36uGDfNxGnX3YrmX3LR9x5IsBES1rGGWbpxio4o5GIf/Xd+JgDd9rzJCqRuZ3/sW/TxK38htWaVNZV0kMkHUCTc1ctzWpCm635hbFCHBhPYIp+/z206khkAKDbz/CNuU91Wazsh7KO07wrwDtxfDDbInJ8TfHE2TGjzjQzgChfmcAEQEAAQ==
|
||||
verified: true
|
||||
can_sign: true
|
||||
can_encrypt_comms: true
|
||||
can_encrypt_storage: true
|
||||
can_certify: true
|
||||
|
||||
-
|
||||
id: 6
|
||||
owner_id: 36
|
||||
key_id: EE3AF48454AFD619
|
||||
primary_key_id: B15431642629B826
|
||||
content: zsDNBGTrY3UBDADsHrzuOicQaPdUQm0+0UNrs92cESm/j/4yBBUk+sfLZAo6J99c4eh4nAQzzZ7al080rYKB0G+7xoRz1eHcQH6zrVcqB8KYtf/sdY47WaMiMyxM+kTSvzp7tsv7QuSQZ0neUEXRyYMz5ttBfIjWUd+3NDItuHyB+MtNWlS3zXgaUbe5VifqKaNmzN0Ye4yXTKcpypE3AOqPVz+iIFv3c6TmsqLHJaR4VoicCleAqLyF/28WsJO7M9dDW+EM3MZVnsVpycTURyHAJGfSk10waQZAaRwmarCN/q0KEJ+aEAK/SRliUneBZoMO5hY5iBeG432tofwaQqAahPv9uXIb1n2JEMKwnMlMA9UGD1AcDbywfj1m/ZGBBw95i4Ekkfn43RvV3THr7uJU/dRqqP+iic4MwpUrOxqELW/kmeHXlBcNbZZhEEvwRoW7U2/9eeuog4nRleRJ0pi/xOP9wmxkKjaIPIK3phdBtEpVk4w/UTAWNdyIIrFggukeAnZFyGJwlm8AEQEAAQ==
|
||||
verified: true
|
||||
can_sign: true
|
||||
can_encrypt_comms: true
|
||||
can_encrypt_storage: true
|
||||
can_certify: true
|
||||
|
@ -1301,7 +1301,7 @@
|
||||
lower_name: limited_org36
|
||||
name: limited_org36
|
||||
full_name: Limited Org 36
|
||||
email: limited_org36@example.com
|
||||
email: abcde@gitea.com
|
||||
keep_email_private: false
|
||||
email_notifications_preference: enabled
|
||||
passwd: ZogKvWdyEx:password
|
||||
@ -1320,7 +1320,7 @@
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar22
|
||||
avatar_email: limited_org36@example.com
|
||||
avatar_email: abcde@gitea.com
|
||||
use_custom_avatar: false
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
|
@ -28,23 +28,31 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
|
||||
_ = stdoutWriter.Close()
|
||||
}()
|
||||
|
||||
var command *git.Command
|
||||
if oldCommitID == git.EmptySHA {
|
||||
// When creating a new branch, the oldCommitID is empty, by using "newCommitID --not --all":
|
||||
// List commits that are reachable by following the newCommitID, exclude "all" existing heads/tags commits
|
||||
// So, it only lists the new commits received, doesn't list the commits already present in the receiving repository
|
||||
command = git.NewCommand(repo.Ctx, "rev-list").AddDynamicArguments(newCommitID).AddArguments("--not", "--all")
|
||||
} else {
|
||||
command = git.NewCommand(repo.Ctx, "rev-list").AddDynamicArguments(oldCommitID + "..." + newCommitID)
|
||||
}
|
||||
// This is safe as force pushes are already forbidden
|
||||
err = git.NewCommand(repo.Ctx, "rev-list").AddDynamicArguments(oldCommitID + "..." + newCommitID).
|
||||
Run(&git.RunOpts{
|
||||
Env: env,
|
||||
Dir: repo.Path,
|
||||
Stdout: stdoutWriter,
|
||||
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
|
||||
_ = stdoutWriter.Close()
|
||||
err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env)
|
||||
if err != nil {
|
||||
log.Error("%v", err)
|
||||
cancel()
|
||||
}
|
||||
_ = stdoutReader.Close()
|
||||
return err
|
||||
},
|
||||
})
|
||||
err = command.Run(&git.RunOpts{
|
||||
Env: env,
|
||||
Dir: repo.Path,
|
||||
Stdout: stdoutWriter,
|
||||
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
|
||||
_ = stdoutWriter.Close()
|
||||
err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env)
|
||||
if err != nil {
|
||||
log.Error("%v", err)
|
||||
cancel()
|
||||
}
|
||||
_ = stdoutReader.Close()
|
||||
return err
|
||||
},
|
||||
})
|
||||
if err != nil && !isErrUnverifiedCommit(err) {
|
||||
log.Error("Unable to check commits from %s to %s in %s: %v", oldCommitID, newCommitID, repo.Path, err)
|
||||
}
|
||||
|
43
routers/private/hook_verification_test.go
Normal file
43
routers/private/hook_verification_test.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package private
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var testReposDir = "tests/repos/"
|
||||
|
||||
func TestVerifyCommits(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
|
||||
gitRepo, err := git.OpenRepository(context.Background(), testReposDir+"repo1_hook_verification")
|
||||
defer gitRepo.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
base, head string
|
||||
verified bool
|
||||
}{
|
||||
{"72920278f2f999e3005801e5d5b8ab8139d3641c", "d766f2917716d45be24bfa968b8409544941be32", true},
|
||||
{git.EmptySHA, "93eac826f6188f34646cea81bf426aa5ba7d3bfe", true}, // New branch with verified commit
|
||||
{"9779d17a04f1e2640583d35703c62460b2d86e0a", "72920278f2f999e3005801e5d5b8ab8139d3641c", false},
|
||||
{git.EmptySHA, "9ce3f779ae33f31fce17fac3c512047b75d7498b", false}, // New branch with unverified commit
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
err = verifyCommits(tc.base, tc.head, gitRepo, nil)
|
||||
if tc.verified {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
}
|
17
routers/private/main_test.go
Normal file
17
routers/private/main_test.go
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package private
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
})
|
||||
}
|
1
routers/private/tests/repos/repo1_hook_verification/HEAD
Normal file
1
routers/private/tests/repos/repo1_hook_verification/HEAD
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/main
|
@ -0,0 +1,6 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = false
|
||||
bare = true
|
||||
symlinks = false
|
||||
ignorecase = true
|
@ -0,0 +1 @@
|
||||
d766f2917716d45be24bfa968b8409544941be32 refs/heads/main
|
@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 d766f2917716d45be24bfa968b8409544941be32 Gitea <gitea@fake.local> 1693148474 +0800 push
|
@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 d766f2917716d45be24bfa968b8409544941be32 Gitea <gitea@fake.local> 1693148474 +0800 push
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x<01><>K
|
||||
1]<5D><14><0B><><EFBFBD>A<EFBFBD>S<EFBFBD><53>$<1D>"32oo<6F><06><>W<EFBFBD><57><EFBFBD><EFBFBD>{<7B>!<21><>`<60><>JC%<25>.<2E>$<07>r]sѱe$<24>m<EFBFBD><6D>M<EFBFBD><4D>)<29><><EFBFBD>(O`<60>btl<>E[:;4<12><>H<>1_<31><5F><EFBFBD>ray<61><79><EFBFBD>l<EFBFBD><6C><EFBFBD><EFBFBD>~<7E><>E<EFBFBD>L@c<><02>Xv<58>M<EFBFBD><4D>":<3A>MۃG<DB83>_}<7D>?<3F>
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x<01><>1
|
||||
!ES{<7B><>AwGGa 9E<39>QgW<10><><EFBFBD>#<23>A<EFBFBD><0F><><EFBFBD><EFBFBD>Z<18>/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>p<EFBFBD><70>(<28>(<28><><EFBFBD><EFBFBD>Bh<42>ۼ&<26><11><14><><EFBFBD>:pLY`<60><><EFBFBD>U<EFBFBD><55>-<2D>z<EFBFBD><7A><EFBFBD><1A><>\<5C><>ZM:<3A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>xJ/<2F>G}:<3A>3
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
x<01><>A
|
||||
<EFBFBD>0E]<5D><14>$<24>L<EFBFBD><0C>x<EFBFBD>L2<4C>]<5D><><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD>
|
@ -0,0 +1,3 @@
|
||||
x<01><>ˮ<EFBFBD>FE3<45>+zn%44<34>!%Qx<51><78>ۀs<>A<EFBFBD>`8<><38><EFBFBD><EFBFBD>{<7B><>2IM<49>j<EFBFBD><6A><EFBFBD><EFBFBD><EFBFBD>d<EFBFBD><64>f<06><><EFBFBD>2<EFBFBD><32><EFBFBD>"<22>$<24>e<EFBFBD><65>
|
||||
-(<28> <20><04>!<21><>J"<22>a<EFBFBD><17>@<40>Ba<42><61>Ho3<6F><33>V<EFBFBD><56><04><$<24>/)<29>$J<>JD<04>B<EFBFBD><42>H<EFBFBD><1F><><EFBFBD>{<7B>#<23>RR<52><52>O<EFBFBD><4F>nf<6E><66>F<EFBFBD><46>O<EFBFBD><4F>
|
||||
<EFBFBD>q[<5B><>2<EFBFBD>̇~<7E><><EFBFBD><EFBFBD><7F><EFBFBD>zjj<6A><6A><EFBFBD><EFBFBD>L<EFBFBD><4C><EFBFBD><EFBFBD>}prm<72>Fqh<71><68>`@ث<><D8AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>f<D598>?3<>[7<><37><EFBFBD><EFBFBD><EFBFBD><EFBFBD>) ^<5E><>u<EFBFBD>ֿ,<2C><><EFBFBD>l7<6C>z<EFBFBD><06>r|&<10>Ou4<75><34>9<EFBFBD>:<3A><>Qj<51><6A><EFBFBD><15><>1x<31><78><EFBFBD>6<EFBFBD>Q<EFBFBD><51><EFBFBD><EFBFBD>%<25><>t<><74>s<EFBFBD><73><EFBFBD>V<EFBFBD>|(<1C>V<EFBFBD><56>,aL,<2C><>G~<7E><><16><><EFBFBD><EFBFBD><EFBFBD>r<1D><><EFBFBD><EFBFBD>@<40>`<60><><EFBFBD>$[! Xˊep<><70><1E>[8 o<><6F>(<28><><EFBFBD>k<EFBFBD>Z<EFBFBD>γy<CEB3>eй<65><D0B9><EFBFBD><05>Y<EFBFBD><59>k<EFBFBD>d<64><7F>6<EFBFBD>3<EFBFBD>;3<><06> R<>iދdY<64>Dk91V]/C<>#<23><>&<26><>po<70>F<EFBFBD>b<EFBFBD><62><EFBFBD>}<7D><><EFBFBD><EFBFBD><EFBFBD>uW&]+m xaqd<71>I<EFBFBD>X<EFBFBD><58>3
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user