Include users from custom roles as MR approvers
What does this MR do and why?
Support custom roles in merge request approval ... (&13550 - closed) will allow MR approval policies to be created with custom roles as approvers along with roles. This MR adds the users belonging to the custom role as approvers the approval rules.
Database query
SELECT
"users"."id",
"users"."email",
"users"."encrypted_password",
"users"."reset_password_token",
"users"."reset_password_sent_at",
"users"."remember_created_at",
"users"."sign_in_count",
"users"."current_sign_in_at",
"users"."last_sign_in_at",
"users"."current_sign_in_ip",
"users"."last_sign_in_ip",
"users"."created_at",
"users"."updated_at",
"users"."name",
"users"."admin",
"users"."projects_limit",
"users"."failed_attempts",
"users"."locked_at",
"users"."username",
"users"."can_create_group",
"users"."can_create_team",
"users"."state",
"users"."color_scheme_id",
"users"."password_expires_at",
"users"."created_by_id",
"users"."last_credential_check_at",
"users"."avatar",
"users"."confirmation_token",
"users"."confirmed_at",
"users"."confirmation_sent_at",
"users"."unconfirmed_email",
"users"."hide_no_ssh_key",
"users"."admin_email_unsubscribed_at",
"users"."notification_email",
"users"."hide_no_password",
"users"."password_automatically_set",
"users"."encrypted_otp_secret",
"users"."encrypted_otp_secret_iv",
"users"."encrypted_otp_secret_salt",
"users"."otp_required_for_login",
"users"."otp_backup_codes",
"users"."public_email",
"users"."dashboard",
"users"."project_view",
"users"."consumed_timestep",
"users"."layout",
"users"."hide_project_limit",
"users"."note",
"users"."unlock_token",
"users"."otp_grace_period_started_at",
"users"."external",
"users"."incoming_email_token",
"users"."auditor",
"users"."require_two_factor_authentication_from_group",
"users"."two_factor_grace_period",
"users"."last_activity_on",
"users"."notified_of_own_activity",
"users"."preferred_language",
"users"."theme_id",
"users"."accepted_term_id",
"users"."feed_token",
"users"."private_profile",
"users"."roadmap_layout",
"users"."include_private_contributions",
"users"."commit_email",
"users"."group_view",
"users"."managing_group_id",
"users"."first_name",
"users"."last_name",
"users"."static_object_token",
"users"."role",
"users"."user_type",
"users"."static_object_token_encrypted",
"users"."otp_secret_expires_at",
"users"."onboarding_in_progress",
"users"."color_mode_id",
"users"."composite_identity_enforced"
FROM
"users"
INNER JOIN
"project_authorizations" ON "users"."id" = "project_authorizations"."user_id"
INNER JOIN
"members" ON "members"."user_id" = "users"."id"
WHERE
"project_authorizations"."project_id" = 13927617
AND (
"project_authorizations"."access_level" = 30
OR "members"."member_role_id" = 2003941
)
Gather (cost=1033.79..12035.93 rows=1921 width=1489) (actual time=3.875..65.792 rows=1580 loops=1)
Workers Planned: 1
Workers Launched: 1
Buffers: shared hit=2640 read=1571 dirtied=66
WAL: records=70 fpi=66 bytes=510794
I/O Timings: read=62.256 write=0.000
-> Nested Loop (cost=33.78..10843.83 rows=1130 width=1489) (actual time=1.230..50.845 rows=790 loops=2)
Buffers: shared hit=2640 read=1571 dirtied=66
WAL: records=70 fpi=66 bytes=510794
I/O Timings: read=62.256 write=0.000
-> Nested Loop (cost=33.22..7953.45 rows=1306 width=1497) (actual time=0.777..37.028 rows=162 loops=2)
Buffers: shared hit=629 read=1005 dirtied=35
WAL: records=39 fpi=35 bytes=263151
I/O Timings: read=41.045 write=0.000
-> Parallel Bitmap Heap Scan on public.project_authorizations (cost=32.78..3472.11 rows=1306 width=8) (actual time=0.529..18.617 rows=162 loops=2)
Buffers: shared read=330 dirtied=15
WAL: records=17 fpi=15 bytes=122453
I/O Timings: read=9.176 write=0.000
-> Bitmap Index Scan using index_project_authorizations_on_project_user_access_level (cost=0.00..32.23 rows=2220 width=0) (actual time=0.777..0.777 rows=325 loops=1)
Index Cond: (project_authorizations.project_id = 13927617)
Buffers: shared read=5
I/O Timings: read=0.349 write=0.000
-> Index Scan using users_pkey on public.users (cost=0.44..3.43 rows=1 width=1489) (actual time=0.112..0.112 rows=1 loops=325)
Index Cond: (users.id = project_authorizations.user_id)
Buffers: shared hit=627 read=675 dirtied=18
WAL: records=20 fpi=18 bytes=129900
I/O Timings: read=31.869 write=0.000
-> Index Only Scan using idx_members_on_user_and_source_and_source_type_and_member_role on public.members (cost=0.56..1.46 rows=50 width=12) (actual time=0.060..0.082 rows=5 loops=325)
Index Cond: (members.user_id = users.id)
Heap Fetches: 168
Buffers: shared hit=2011 read=566 dirtied=31
WAL: records=31 fpi=31 bytes=247643
I/O Timings: read=21.211 write=0.000
Settings: jit = 'off', random_page_cost = '1.5', work_mem = '100MB', effective_cache_size = '472585MB', seq_page_cost = '4'
Time: 77.674 ms
- planning: 11.604 ms
- execution: 66.070 ms
- I/O read: 62.256 ms
- I/O write: 0.000 ms
Shared buffers:
- hits: 2640 (~20.60 MiB) from the buffer pool
- reads: 1571 (~12.30 MiB) from the OS file cache, including disk I/O
- dirtied: 66 (~528.00 KiB)
- writes: 0
References
Please include cross links to any resources that are relevant to this MR. This will give reviewers and future readers helpful context to give an efficient review of the changes introduced.
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.
Screenshots or screen recordings
Before | After |
---|---|
![]() |
![]() |
How to set up and validate locally
- Create a custom role at the admin level (e.g. Admin => Settings => Roles and permissions) with
Approve merge request
permission - Enable the custom role feature flag
echo "Feature.enable(:security_policy_custom_roles)" | rails c
- Create a group and create MR approval policy with the custom role as approver:
type: approval_policy
name: Custom role approver
description: ''
enabled: true
policy_scope:
projects:
excluding: []
rules:
- type: any_merge_request
branch_type: protected
commits: any
actions:
- type: require_approval
approvals_required: 1
role_approvers:
- 1
- type: send_bot_message
enabled: true
approval_settings:
block_branch_modification: true
block_group_branch_modification: true
prevent_pushing_and_force_pushing: true
prevent_approval_by_author: true
prevent_approval_by_commit_author: true
remove_approvals_with_new_commit: true
require_password_to_approve: false
fallback_behavior:
fail: closed
- Add a user to the custom role from
Manage
->Members
- Create a project with the group and create an MR by updating the README
- Verify that the user is added as approver
Edited by Sashi Kumar Kumaresan