Disclaimer: This is only relevant for Gitlab Enterprise Edition
Objective
I have several GitLab Projects (repositories) in several Groups and Subgroups. I have another set of Gitlab Groups and Subgroups which contain Members. Each of the projects can use a CODEOWNERS file to determine who can approve Merge Requests. The goal is to have everyone being able to contribute code everywhere and at the same time have dedicated groups of merge request approvers.
Detail
I don’t want to repeat what has been already written in the docs. Please read those first in case this doesn’t make sense. Specifically, look at Project, Group, Member, Permissions and CODEOWNERS.
Consider following structure
where fooprojects
is a Gitlab Group containing several projects, one of which is bar
.
Next, each Subgroup of peoplegroups
contains Members whom I want to give some level of Gitlab access.
My goal for this example is that all bazengineers
can make code contributions in all fooprojects
and that quuxengineers
are merge request approvers for the bar
project.
How do?
Giving bazengineers
access to fooprojects
is as simple as inviting them to the fooprojects
group with at least Developer permissions.
Since permission cascades, they can now contribute everywhere.
However, with Developer permissions, bazengineers
have also gained the permission to approve Merge Requests.
To fix what we’ve done, we can either make a cumbersome custom Approval rule in the repository. I repeat. In each repository. This sucks even when done in Terraform (check this provider).
The other option is to use the cryptic “All eligible users”, which is a black magic incantation permitting the use of CODEOWNERS schema.
So, what this rule actually does?
It takes Eligible users as Merge Request approvers.
As of now, those eligible users are only Developers invited into the project (bar
).
To include quuxengineers
, we will invite them to the bar
project.
Next, let’s setup CODEOWNERS file in the project root with following contents
|
|
This makes quuxengineers
Code Owners of the whole repository. List of owners can be conveniently seen at the top of each file.
To have complete setup, we must require Code Owners Approval. This setting is not in Merge Request Approvals, but in Protected Branches under Repository settings.
Finally, we have what we wanted.
All bazengineers
can create merge requests in all repositories under fooprojects
.
In each repository we can set specific groups of owners for specific files in CODEOWNERS and require their approval for related changes.
Caveats
I have skipped over some pitfalls which can be encountered when trying to set up the above system.
Terraforming this
I mentioned “Eligible Users” setting to be cryptic and these are the reasons why.
What this setting actually does is not clear, but it creates any_approver
approval rule to appear in the Projects API responce.
You can check be hitting Gitlab API with https://<yourgitlabhost>/api/v4/projects/<yourprojectid>/approval_rules
and getting something like this:
Obscure thing about this any_approver
rule is that unless you increase the number of approvals required above zero, this rule does not appear at all.
Since then, it is there forever. And it breaks Terraform as of now.
What happens is that if you play around with this setting in a project and then try to create this rule via Terraform, apply fails because there can be only one rule of this kind.
Inheriting Owner Groups
Given all the necessary setup in Gitlab Projects, it is quite natural to assume that inviting quuxengineers
just to fooprojects
would be enough.
However, this is not the case.
Firstly, it doesn’t work because it is not supported and after careful reading it can be seen the CODEOWNERS docs:
Inviting Subgroup Y to a parent group of Project A is not supported. To set Subgroup Y as Code Owners, add this group directly to the project itself.
Secondly, if you do actually set it up, it will appear as if it works even though it doesn’t.
To illustrate it in our example, let’s invite quuxengineers
to fooprojects
as Owners.
We will now see that in bar
project, the quuxengineers
group is member with source fooprojects
.
Now, let’s create a new project under fooprojects
, name it nope
, and set up CODEOWNERS
file same as in bar
.
Inspecting membership, we will see that quuxengineers
are member with source fooprojects
, same as in bar
.
However, when we try to make a Merge Request, the approvers don’t appear there.
Also, if we take a look at any file in the repository, we don’t see the Code Owners list header.
What is happening here is that Gitlab UI sucks, because the two repositories look the same yet they don’t behave the same.
Problem is in how the permissions are displayed.
What is shown is the Max Role.
We have set up Owner role on the fooprojects
and this is what it shows and where it comes from.
However, this inheritance does not work for CODEOWNERS, so these permissions are essentially useless in this respect.
What is actually permitting the CODEOWNERS approvals is the Developer level access directly granted in project bar
, but this permission is overshadowed by the one from fooprojects
.