forgejo/web_src/js/components/PullRequestMergeForm.test.js
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

66 lines
2.3 KiB
JavaScript

// Copyright 2024 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
import {flushPromises, mount} from '@vue/test-utils';
import PullRequestMergeForm from './PullRequestMergeForm.vue';
async function renderMergeForm(branchName) {
window.config.pageData.pullRequestMergeForm = {
textDeleteBranch: `Delete branch "${branchName}"`,
textDoMerge: 'Merge',
defaultMergeStyle: 'merge',
isPullBranchDeletable: true,
canMergeNow: true,
mergeStyles: [{
'name': 'merge',
'allowed': true,
'textDoMerge': 'Merge',
'mergeTitleFieldText': 'Merge PR',
'mergeMessageFieldText': 'Description',
'hideAutoMerge': 'Hide this message',
}],
};
const mergeform = mount(PullRequestMergeForm);
mergeform.get('.merge-button').trigger('click');
await flushPromises();
return mergeform;
}
test('renders escaped branch name', async () => {
let mergeform = await renderMergeForm('<b>evil</b>');
expect(mergeform.get('label[for="delete-branch-after-merge"]').text()).toBe('Delete branch "<b>evil</b>"');
mergeform = await renderMergeForm('<script class="evil">alert("evil message");</script>');
expect(mergeform.get('label[for="delete-branch-after-merge"]').text()).toBe('Delete branch "<script class="evil">alert("evil message");</script>"');
});
test('hides merge controls when no merge style is allowed', () => {
window.config.pageData.pullRequestMergeForm = {
textDeleteBranch: 'Delete branch',
textAutoMergeButtonWhenSucceed: 'when checks succeed',
textAutoMergeWhenSucceed: 'Auto merge when checks succeed',
textAutoMergeCancelSchedule: 'Cancel schedule',
textCancel: 'Cancel',
defaultDeleteBranchAfterMerge: false,
defaultMergeMessage: '',
defaultMergeStyle: 'merge',
emptyCommit: false,
hasPendingPullRequestMerge: false,
hasPendingPullRequestMergeTip: '',
isPullBranchDeletable: false,
canMergeNow: true,
allOverridableChecksOk: true,
pullHeadCommitID: 'abc123',
mergeStyles: [{
name: 'merge',
allowed: false,
textDoMerge: 'Merge',
mergeTitleFieldText: '',
mergeMessageFieldText: '',
hideAutoMerge: false,
}],
};
const mergeform = mount(PullRequestMergeForm);
expect(mergeform.find('.merge-button').exists()).toBe(false);
expect(mergeform.find('form.form-fetch-action').exists()).toBe(false);
});