Merge request approval policy with block_branch_modification causes generic error
Summary
When attempting to delete a branch rule in a project that is affected by a merge request approval policy you get a Something went wrong while deleting branch rule. error message. While the failure to delete is intentional due to block_branch_modification: true, the error message for affected users is confusing and not actionable.
Steps to reproduce
- Create a new project
- Add a new branch rule for a
Branch name or patternand protect e.g. the patternprotected* - Set up a Merge Request approval policy for this project
- It can be extremely simple, the key is
block_branch_modification: trueandbranch_type: protected:
approval_policy: - name: Test description: '' enabled: true policy_scope: compliance_frameworks: - id: 1019736 rules: - type: any_merge_request branch_type: protected commits: any actions: - type: send_bot_message enabled: true approval_settings: block_branch_modification: true prevent_pushing_and_force_pushing: false prevent_approval_by_author: false prevent_approval_by_commit_author: false remove_approvals_with_new_commit: false require_password_to_approve: false - It can be extremely simple, the key is
- Attempt to delete the branch rule from step 2
- Observe
Something went wrong while deleting branch rule.error message - Update policy to say
branch_type: default - Attempt to delete the branch rule from step 2
- Observe successful deletion
Step 2 can also performed after step 3, which makes this a bit confusing: I can create new branch rules, but I can't delete them afterwards. This is in line with our documentation:
When enabled, prevents a user from removing a branch from the protected branches list, deleting a protected branch, or changing the default branch if that branch is included in the security policy.
But when a user who hasn't set up the policy sees the error, they can't really know what is going on.
Example Project
https://gitlab.com/gl-demo-ultimate-mgrabowski/zd-566179 – not very helpful though as this all happens in project settings. Let me know if anyone wants to get added to this project to verify.
What is the current bug behavior?
Attempting to delete a branch rule in these circumstances causes an error message that doesn't explain why the rule can't be deleted.
What is the expected correct behavior?
The error message should state clearly why the rule can't be deleted, ideally mentioning the specific Merge Request Approval Policy name that is blocking deletion.
Relevant logs and/or screenshots
Output of checks
This bug happens on GitLab.com
Possible fixes
- The error message comes from index.vue – not sure if the branch_rule_delete.mutation.graphql that it uses can already provide a more detailed error that we just have to use in the frontend. Otherwise we'd likely need to make sure the mutation can return a better error message first.
Likely the latter, the current GraphQL response is
"message": "The resource that you are attempting to access does not exist or you don't have permission to perform this action". - Disable the button to delete when a security policy is enabled and show a tooltip
While the block_branch_modification setting still prevents the deletion with the new Delete rule button and Edit button of the Rule target, we would prefer to have the buttons disabled with a tooltip for this button and potentially any future buttons.
Similarly, the prevent_pushing_and_force_pushing setting still prevents the change of the Allow force push toggle from being turned on, but disabling it and adding a tooltip would make it more clear.
| Scenario | Screenshot |
|---|---|
Protected branches block_branch_modification
|
![]() |
Protected branch block_force_push
|
![]() |
| New page | ![]() |
Incomplete Patch for delete button
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue b/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue
index 5c07b1f39ff3..3ed10a6ed271 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue
@@ -1,7 +1,15 @@
<script>
// eslint-disable-next-line no-restricted-imports
import { mapActions } from 'vuex';
-import { GlSprintf, GlLink, GlLoadingIcon, GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
+import {
+ GlSprintf,
+ GlLink,
+ GlLoadingIcon,
+ GlButton,
+ GlModal,
+ GlModalDirective,
+ GlTooltipDirective,
+} from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { sprintf, n__, s__ } from '~/locale';
import {
@@ -55,6 +63,7 @@ export default {
pushRulesHelpDocLink,
directives: {
GlModal: GlModalDirective,
+ GlTooltip: GlTooltipDirective,
},
editModalId: EDIT_RULE_MODAL_ID,
components: {
@@ -396,13 +405,21 @@ export default {
<div v-else>
<crud-component :title="$options.i18n.ruleTarget" data-testid="rule-target-card">
<template #actions>
- <gl-button
- v-if="glFeatures.editBranchRules && !isPredefinedRule && canAdminProtectedBranches"
- v-gl-modal="$options.editModalId"
- data-testid="edit-rule-name-button"
- size="small"
- >{{ $options.i18n.edit }}</gl-button
+ <span
+ v-gl-tooltip="{
+ title: $options.i18n.disabledTooltip,
+ disabled: !branchRule.isProtectedBySecurityPolicy,
+ }"
>
+ <gl-button
+ v-if="glFeatures.editBranchRules && !isPredefinedRule && canAdminProtectedBranches"
+ v-gl-modal="$options.editModalId"
+ :disabled="branchRule.isProtectedBySecurityPolicy"
+ data-testid="edit-rule-name-button"
+ size="small"
+ >{{ $options.i18n.edit }}</gl-button
+ >
+ </span>
</template>
<div v-if="allBranches" class="gl-mt-2" data-testid="all-branches">*</div>
diff --git a/ee/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql b/ee/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql
index 1d0bce0ac936..bc4daa32fe67 100644
--- a/ee/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql
+++ b/ee/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql
@@ -13,6 +13,7 @@ query getBranchRulesDetailsEE($projectPath: ID!, $buildMissing: Boolean = false)
branchProtection {
allowForcePush
codeOwnerApprovalRequired
+ isProtectedBySecurityPolicy
mergeAccessLevels {
edges {
node {
diff --git a/ee/app/graphql/ee/types/branch_rules/branch_protection_type.rb b/ee/app/graphql/ee/types/branch_rules/branch_protection_type.rb
index 7ac6e3b977fa..62e9ad1cf45d 100644
--- a/ee/app/graphql/ee/types/branch_rules/branch_protection_type.rb
+++ b/ee/app/graphql/ee/types/branch_rules/branch_protection_type.rb
@@ -16,6 +16,11 @@ module BranchProtectionType
type: GraphQL::Types::Boolean,
null: false,
description: 'Enforce code owner approvals before allowing a merge.'
+
+ field :is_protected_by_security_policy,
+ type: GraphQL::Types::Boolean,
+ null: false,
+ description: 'Indicates if the branch is protected by a security policy.'
end
end
end



