jojo/services/pull/check_test.go
abdo e16dc2ebfd fix: apply signed-merge checks by merge style (#11403)
Fixes #6438

When a protected branch requires signed commits and no signing key is available, fast-forward-only merges should still be allowed because they do not create a new commit.

This patch applies signing checks by merge behaviour/style instead of one global gate:

- pass `mergeStyle` through `CheckPullMergeable(...)` in web/API/automerge paths
- require signing for commit-creating styles (`merge`, `rebase`, `rebase-merge`, `squash`)
- bypass signing precheck only for `fast-forward-only`
- align merge UI options with backend behaviour so signing-dependent styles are unavailable when signing cannot happen
- add Go unit tests for merge-style signing requirements
- add frontend unit coverage for the no-allowed-merge-styles guard

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11403
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: abdo <dev@abdo.wtf>
Co-committed-by: abdo <dev@abdo.wtf>
2026-04-09 20:26:27 +02:00

120 lines
3.1 KiB
Go

// Copyright 2019 The Gitea Authors.
// All rights reserved.
// SPDX-License-Identifier: MIT
package pull
import (
"strconv"
"testing"
"time"
"forgejo.org/models/db"
issues_model "forgejo.org/models/issues"
repo_model "forgejo.org/models/repo"
"forgejo.org/models/unittest"
"forgejo.org/modules/queue"
"forgejo.org/modules/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPullRequest_AddToTaskQueue(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
idChan := make(chan int64, 10)
testHandler := func(items ...string) []string {
for _, s := range items {
id, _ := strconv.ParseInt(s, 10, 64)
idChan <- id
}
return nil
}
cfg, err := setting.GetQueueSettings(setting.CfgProvider, "pr_patch_checker")
require.NoError(t, err)
prPatchCheckerQueue, err = queue.NewWorkerPoolQueueWithContext(t.Context(), "pr_patch_checker", cfg, testHandler, true)
require.NoError(t, err)
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2})
AddToTaskQueue(db.DefaultContext, pr)
assert.Eventually(t, func() bool {
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2})
return pr.Status == issues_model.PullRequestStatusChecking
}, 1*time.Second, 100*time.Millisecond)
has, err := prPatchCheckerQueue.Has(strconv.FormatInt(pr.ID, 10))
assert.True(t, has)
require.NoError(t, err)
go prPatchCheckerQueue.Run()
select {
case id := <-idChan:
assert.Equal(t, pr.ID, id)
case <-time.After(time.Second):
assert.FailNow(t, "Timeout: nothing was added to pullRequestQueue")
}
has, err = prPatchCheckerQueue.Has(strconv.FormatInt(pr.ID, 10))
assert.False(t, has)
require.NoError(t, err)
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2})
assert.Equal(t, issues_model.PullRequestStatusChecking, pr.Status)
prPatchCheckerQueue.ShutdownWait(5 * time.Second)
prPatchCheckerQueue = nil
}
func TestIsMergeSigningRequired(t *testing.T) {
testCases := []struct {
name string
mergeStyle repo_model.MergeStyle
expected bool
}{
{
name: "fast-forward never requires signing",
mergeStyle: repo_model.MergeStyleFastForwardOnly,
expected: false,
},
{
name: "rebase requires signing even when up to date",
mergeStyle: repo_model.MergeStyleRebase,
expected: true,
},
{
name: "rebase-merge requires signing",
mergeStyle: repo_model.MergeStyleRebaseMerge,
expected: true,
},
{
name: "squash commits require signing",
mergeStyle: repo_model.MergeStyleSquash,
expected: true,
},
{
name: "merge commits require signing",
mergeStyle: repo_model.MergeStyleMerge,
expected: true,
},
{
name: "rebase-update style still requires signing",
mergeStyle: repo_model.MergeStyleRebaseUpdate,
expected: true,
},
{
name: "empty merge style requires signing",
mergeStyle: "",
expected: true,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
assert.Equal(t, testCase.expected, isMergeSigningRequired(testCase.mergeStyle))
})
}
}