377 words
2 minutes
Disallowing merging MRs without approval using Gitlab CI
2025-05-17

Disclaimer#

Doing it this way introduces a UX drawback being every MR’s pipeline failing if it does not have an approval from someone who isn’t the author of the MR. This might be irritaating, but I have not found another way that is not upgrading your Gitlab to at least Premium.

Why?#

While there is a myriad of reasons including compliance with security and quality standards, let it be reason enough that it is a feature that Gitlab has and keeps for Premium and Ultimate customers as a middle finger to the free tier users..

How?#

In human language#

We will create a Ci job that runs for new commits on MRs by utilising a merge request pipeline. The job will use Gitlab’s API and jq to get the set of approvers and the author of the MR and check if there are approvers who are not the author.

Sidenote: since this way is going to utilise a merge request pipeline you might encounter the problem of duplicate pipelines if you have jobs that run on non-merge request pipelines. You can use gitlab workflows to switch between pipelines and merge request pipelines, just remember to add - if: $CI_COMMIT_TAG to the example workflow if you have any jobs that are supposed to run on tag.

Prerequisites#

In order to use Gitlab’s API you will need to create a project access token and e.g. store it as the project’s CI/CD variable — possibly masked if you don’t want it in your CI logs.

Script#

The script of the job itself is going to be simple enough:

script:
    - AUTHOR=$(curl --header "PRIVATE-TOKEN:$PROJECT_ACCESS_TOKEN" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}" | jq -r '.author.username')
    - VALID_APPROVALS=$(curl --header "PRIVATE-TOKEN:$PROJECT_ACCESS_TOKEN" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/approvals" | jq -r --arg author $AUTHOR '.approved_by[] | .user.username | select(. != $author)')
    - |
    if [ -z "$VALID_APPROVALS" ]; then
        exit 1
    fi

Script explanation#

The 1st line uses GET single MR endpoint to get JSON object with MR’s attributes and jq to extract the author’s username.

The 2nd line uses GET single merge request approval endpoint to get JSOn object with MR’s approvals and jq with arg to extract approved_by array, map it to user’s username and filter it by the user not having the same username as the author of the MR.

If there are no valid approval’s (i.e. not from the author) the job exits with non-zero status code.

Disallowing merging MRs without approval using Gitlab CI
https://vulwsztyn.codeberg.page/posts/disallowing-merges-without-approval-with-gitlab-ci/
Author
Artur Mostowski
Published at
2025-05-17
License
CC BY-NC-SA 4.0