Forbid branch protection force-push updates with policy in place
What does this MR do and why?
MR approval policies support the prevent_pushing_and_force_pushing
property which prevents force-pushing to any branch affected by a policy. This is achieved through an access check.
We also disable the UI controls for protected branches matched by such a policy. However we don't prevent changes via API to a protected branch's allow_force_push
column or its push access levels. Since our access check works independently of protected branches, this is not a policy bypass but merely confusing.
This MR rejects changes to a protected branch's allow_force_push
column or its push access levels when a policy applies that sets prevent_pushing_and_force_pushing
.
Database
New query:
SELECT
*
FROM
"scan_result_policies"
WHERE
"scan_result_policies"."project_id" = 57505981
AND (project_approval_settings ->> 'prevent_pushing_and_force_pushing' = 'true')
LIMIT 1;
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/28603/commands/89175
We process up to 20 policies so there are no more than 20 rows to filter per project_id
.
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
How to set up and validate locally
-
Create a new project and note its ID
-
Navigate to
Code > Branches
and create a new branch, sayfoobar
-
Navigate to
Secure > Policies
and create the following MR approval policy:
type: approval_policy
name: Prevent force-pushing
enabled: true
rules:
- type: any_merge_request
branches: [foobar]
commits: any
actions:
- type: require_approval
approvals_required: 1
role_approvers:
- owner
approval_settings:
prevent_pushing_and_force_pushing: true
-
Navigate to
Settings > Repository
and create a protected branch forfoobar
. -
Verify you cannot update
allows_force_push
via API:
curl -X PATCH -H "PRIVATE-TOKEN: glpat-REDACTED" -H "Content-Type: application/json" -d '{"allow_force_push": true}' "http://gdk.test:3000/api/v4/projects/$PROJECT_ID/protected_branches/foobar"
- Verify you cannot update its push access levels via API:
curl -X PATCH -H "PRIVATE-TOKEN: glpat-REDACTED" -H "Content-Type: application/json" -d '{"allowed_to_push": [{"access_level": 40}]}' "http://gdk.test:3000/api/v4/projects/$PROJECT_ID/protected_branches/foobar"
Related to #436539 (closed)