Fix approval rule editing locked by non-instance settings
What does this MR do and why?
Related to MR approval rules reappear after deletion when ... (#605117 - closed)
Project maintainers could no longer edit or delete a project's approval rules when a group-level or project-level "Prevent editing approval rules in merge requests" setting was enabled. Updates returned 403 "Prohibited" and deletes returned a phantom 204 without actually removing the rule.
The root cause was that ApprovalProjectRulePolicy's lock was keyed off the project's resolved disable_overriding_approvers_per_merge_request? value, which folds together the instance, group, project, and merge request approval policy settings. Per the documentation, only the instance-level "Prevent editing approval rules in projects and merge requests" setting should lock the approval rules list in project settings. The group-level and project-level settings only prevent overriding approvers on individual merge requests — they must not lock the rules list.
This MR scopes the project approval rules list lock to the instance-level setting only, and consolidates the lock into the policy layer via delegation.
Changes
- Rename the base-policy condition
locked_approvers_rules→locked_approval_rules(ee/app/policies/ee/base_policy.rb). It reads only the instance-level setting (scope: :global). ProjectPolicyapplies the instance-only lock tomodify_approvers_rules,create_approval_rule,update_approval_rule, anddelete_approval_rule.- Reduce
ApprovalProjectRulePolicyandApprovalRules::ApprovalGroupRulePolicyto delegation so they inherit the instance-only lock fromProjectPolicy/GroupPolicyinstead of re-declaring resolved-value conditions. - Consolidate
GroupPolicy's approval rule prevents under the renamed condition. ApprovalMergeRequestRulePolicyrelies on the existingeditablegate (resolved per-MR value viacan_override_approvers?) for per-MR rules; the redundant instance-lock rule is removed.MergeRequests::ApprovalRulePolicykeeps its ownlocked_approval_rulescondition because its project-origin enable path bypasses theeditablegate.- Remove a misleading group UI label override so groups show "Prevent editing approval rules in merge requests" (
ee/app/assets/javascripts/approvals/constants.js).
Making modify_approvers_rules lock-aware also fixes the phantom 204: the API authorize! now fails before destroy_conditionally! runs.
Behaviour after this change
| Setting enabled | Editing the project approval rules list |
|---|---|
| Instance-level | Locked (instance admins bypass) |
| Group-level only | Allowed (per-MR overrides still blocked) |
| Project-level only | Allowed (per-MR overrides still blocked) |
| Merge request approval policy | Allowed (only affects per-MR overrides) |
Instance admins bypass the project-rules-list lock, but not the per-MR override lock (per MergeRequest#approval_rules_editable_by?).
Testing
Policy specs (project, group, MR, and v2 MR approval rule policies), ProjectPolicy/GroupPolicy specs, and API request specs were added/updated using real users and real application settings (no ability stubbing). A pre-existing strong_memoize test-pollution issue in approval_merge_request_rule_policy_spec.rb was fixed by reloading fixtures. Specs pass across multiple RSpec seeds.
Follow-up
The group and project approval rules APIs currently enforce different abilities, which blocks fully unifying the ability names. That consolidation is tracked separately in #605160.
Screenshots or screen recordings
N/A — backend authorization change.
MR acceptance checklist
- I have evaluated the MR acceptance checklist for this MR.
- Tests added/updated and passing across seeds.