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_ruleslocked_approval_rules (ee/app/policies/ee/base_policy.rb). It reads only the instance-level setting (scope: :global).
  • ProjectPolicy applies the instance-only lock to modify_approvers_rules, create_approval_rule, update_approval_rule, and delete_approval_rule.
  • Reduce ApprovalProjectRulePolicy and ApprovalRules::ApprovalGroupRulePolicy to delegation so they inherit the instance-only lock from ProjectPolicy / GroupPolicy instead of re-declaring resolved-value conditions.
  • Consolidate GroupPolicy's approval rule prevents under the renamed condition.
  • ApprovalMergeRequestRulePolicy relies on the existing editable gate (resolved per-MR value via can_override_approvers?) for per-MR rules; the redundant instance-lock rule is removed.
  • MergeRequests::ApprovalRulePolicy keeps its own locked_approval_rules condition because its project-origin enable path bypasses the editable gate.
  • 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

Edited by Joe Woodward

Merge request reports

Loading