| | |

GitLab 21 🦊 Managing Project Permissions, Roles, and Access Control

⏱️ Estimated read: 10 min | |

The previous chapters covered the CI/CD pipeline and its security scanners. This chapter covers the permission model that governs who can do what within a project. GitLab’s access control is built on roles: Guest, Reporter, Developer, Maintainer, and Owner. Each role is a bundle of permissions. The exam tests the distinction between the roles, the visibility levels (Private, Internal, Public), and the mechanisms that override the role-based model: protected branches and deploy tokens. The critical trap is that a role is not a single permission; it is a hierarchy. A Maintainer can do everything a Developer can do, plus more. A Developer can do everything a Reporter can do, plus more. The role assignment is the primary access control, and the protected branch is the secondary control that restricts even the role’s default permissions.

Key point: The five project roles are Guest, Reporter, Developer, Maintainer, and Owner. The role determines the baseline permissions. The protected branch settings override the role for specific branches: a Developer cannot push to main if the protected branch allows only Maintainers. The visibility level (Private, Internal, Public) determines who can see the project at all. The deploy token is a credential for automated access that does not require a user account.


Why project permissions require a specific mental model

The role hierarchy problem. The roles are cumulative. A Maintainer has all the permissions of a Developer, plus the ability to manage project settings, protected branches, and project members. A Developer has all the permissions of a Reporter, plus the ability to push code and create branches. A Reporter has all the permissions of a Guest, plus the ability to view the repository and clone it. The hierarchy is the foundation of the model, and the exam tests the specific permissions that distinguish one role from the next .

The protected branch problem. A Developer can push to the repository by default. But the main branch is protected by default on new projects. The protected branch setting restricts the push permission to a specific role or a specific group. A Developer cannot push to main if the protected branch allows only Maintainers. The role is the baseline; the protected branch is the override .

The visibility problem. The visibility level determines who can see the project. A Private project is visible only to its members. An Internal project is visible to any authenticated user. A Public project is visible to anyone, including unauthenticated users. The visibility does not change the role-based permissions; it changes the audience. A Guest in a Private project has the same permissions as a Guest in a Public project, but the Public project has more people who can see it .

The token problem. A deploy token is a credential that allows automated systems to clone the repository or pull the container image without a user account. The token has a scope: read_repository or read_registry. It does not have a role. It does not have the ability to push to a protected branch unless the branch settings explicitly allow it. The deploy token is the mechanism for CI/CD systems that need to pull code but should not have a user’s full permissions .

The trade-off. The role-based model is simple to understand and manage. The protected branch is the override that adds precision. The deploy token is the mechanism for automation. The exam tests the role permissions and the protected branch override. The most common mistake is assuming that a Developer can push to main because a Developer can push to a feature branch. The protected branch is the difference.


a. The five project roles and their permissions

The five roles form a hierarchy. Each role inherits the permissions of the role below it.

RoleKey Permissions
GuestView issues, comment on issues, view wiki
ReporterView repository, clone, view merge requests, view CI/CD
DeveloperPush to feature branches, create merge requests, run pipelines
MaintainerManage project settings, protected branches, project members
OwnerDelete project, transfer project, manage all settings

The Guest role is the most restricted. A Guest can view issues and leave comments, but cannot view the repository code. The Reporter role adds the ability to view the repository, clone it, and view merge requests. The Developer role adds the ability to push code, create branches, and create merge requests. The Maintainer role adds the ability to manage the project settings, including the protected branches and the project members. The Owner role is the highest; it can delete or transfer the project .

The role assignment is per project, not per group. A user can be a Maintainer on one project and a Guest on another. The group membership grants the role on all projects in the group, but the project-level assignment can override the group-level role. The highest role wins.


b. Visibility levels and access control

The visibility level determines who can see the project. The three levels are Private, Internal, and Public.

LevelVisible To
PrivateOnly project members
InternalAny authenticated user
PublicAnyone, including unauthenticated users

A Private project is the default for new projects. The project members can see the project, and no one else. An Internal project is visible to any user who has an account on the GitLab instance. A Public project is visible to the internet .

The visibility is not the same as the permission. A Public project is visible to everyone, but the role still determines what each person can do. A non-member of a Public project can view the code and clone it, but cannot push. A Guest of a Private project can view the issues, but cannot view the code .

The visibility of a project must be at least as restrictive as its parent group. A Private group cannot contain a Public project. The constraint is enforced by the system.


c. Protected branches and deploy tokens

The protected branch is the mechanism that restricts the push and merge permissions for specific branches. The main branch is protected by default on new projects. The settings allow you to specify the roles or users who can push and merge.

# Protected branch settings (conceptual)
Branch: main
Allowed to merge: Maintainers
Allowed to push: Maintainers
Allowed to force push: Disabled
Require code owner approval: Disabled

The Allowed to merge setting determines who can merge a merge request into the protected branch. The Allowed to push setting determines who can push directly to the branch. The Allowed to force push setting determines whether force pushes are permitted. The Require code owner approval setting requires an approval from a code owner before the merge .

The role selection is cumulative. Selecting “Maintainers” grants access to Maintainers and Owners. Selecting “Developers + Maintainers” grants access to Developers, Maintainers, and Owners. The higher roles always have the permissions of the lower roles .

The deploy token is the credential for automated access. It is created in the project settings under Settings → Repository → Deploy tokens. The token has a name, a username, and a scope: read_repository or read_registry. The token can clone the repository or pull the image, but cannot push unless the protected branch settings explicitly allow the deploy key .


Complete Example Session

# ============================================
# PART 1: VIEW PROJECT MEMBERS
# ============================================

# Settings → Members
# Shows the list of members and their roles.
# ============================================
# PART 2: ADD A MEMBER
# ============================================

# Settings → Members → Invite members
# Username: alice
# Role: Developer
# Invite
# ============================================
# PART 3: CHANGE A ROLE
# ============================================

# Settings → Members → alice → Edit
# Role: Maintainer
# Save
# ============================================
# PART 4: CHANGE VISIBILITY
# ============================================

# Settings → General → Visibility
# Project visibility: Private
# Save
# ============================================
# PART 5: CONFIGURE PROTECTED BRANCH
# ============================================

# Settings → Repository → Protected branches
# Branch: main
# Allowed to merge: Maintainers
# Allowed to push: Maintainers
# Save
# ============================================
# PART 6: VERIFY THE PUSH RESTRICTION
# ============================================

# As a Developer, attempt to push to main:
git checkout main
git commit --allow-empty -m "Test"
git push origin main
# Error: You are not allowed to push code to protected branches.
# ============================================
# PART 7: CREATE A DEPLOY TOKEN
# ============================================

# Settings → Repository → Deploy tokens → Add token
# Name: ci-read
# Scopes: read_repository
# Create deploy token
# Copy the username and token.
# ============================================
# PART 8: USE THE DEPLOY TOKEN
# ============================================

git clone https://<deploy-user>:<token>@gitlab.com/group/project.git
# The clone succeeds.
# ============================================
# PART 9: VERIFY THE DEPLOY TOKEN CANNOT PUSH
# ============================================

cd project
git commit --allow-empty -m "Test"
git push origin main
# Error: The deploy token does not have write access.

The nine parts trace the permission model: view members, add member, change role, change visibility, configure protected branch, verify push restriction, create deploy token, use deploy token, and verify token restriction.


Quick Reference

Project Roles

RoleKey Permissions
GuestView issues, comment, view wiki
ReporterView code, clone, view MRs
DeveloperPush, create branches, create MRs
MaintainerManage settings, protected branches, members
OwnerDelete project, transfer project

Visibility Levels

LevelVisible To
PrivateMembers only
InternalAuthenticated users
PublicAnyone

Protected Branch Settings

SettingOptions
Allowed to mergeNo one, Maintainers, Developers
Allowed to pushNo one, Maintainers, Developers
Allowed to force pushEnabled/Disabled
Require code owner approvalEnabled/Disabled

Token Types

TokenScopeUse Case
Deploy tokenread_repository, read_registryCI/CD clone, pull
Project access tokenapi, read_repository, write_repositoryAutomation with API
Personal access tokenUser-level scopesUser scripts

Best Practices

✅ Do This:

# Use the lowest role that works
<!-- Principle of least privilege -->                # ✅
# Protect main with Maintainers only
<!-- Developers use merge requests -->                # ✅
# Use deploy tokens for CI/CD
<!-- Avoid sharing user credentials -->              # ✅

❌ Don’t Do This:

# Grant Owner to everyone
<!-- Destructive actions become possible -->         # ❌
# Assume a Developer can push to main
<!-- Protected branch overrides the role -->         # ❌
# Use a personal access token for CI/CD
<!-- Deploy tokens are scoped and revocable -->      # ❌

Common Pitfalls

PitfallWhy It HappensFix
Developer cannot push to mainProtected branch restricts pushUse merge request
Cannot see projectVisibility is PrivateRequest access or change visibility
Deploy token cannot pushNo write_repository scopeUse project access token
Cannot delete projectRole is Maintainer, not OwnerTransfer ownership
Group member has no accessProject-level role overrides groupCheck project members

Real-World Examples

1. Add Member

Settings → Members → Invite members → Role: Developer

2. Change Role

Settings → Members → Edit → Role: Maintainer

3. Change Visibility

Settings → General → Visibility → Private

4. Protect Branch

Settings → Repository → Protected branches → main

5. Restrict Push

Allowed to push: Maintainers

6. Create Deploy Token

Settings → Repository → Deploy tokens → Add token

7. Clone with Deploy Token

git clone https://<user>:<token>@gitlab.com/group/project.git

8. Create Project Access Token

Settings → Access tokens → Add token

9. Verify Role

Settings → Members → View role

10. Remove Member

Settings → Members → Remove

Visual

Role Hierarchy

┌──────────────────────────────────────────────┐
│  Owner                                       │
│  ├── Delete project                          │
│  ├── Transfer project                        │
│  └── All Maintainer permissions              │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Maintainer                                  │
│  ├── Manage settings                         │
│  ├── Manage protected branches               │
│  └── All Developer permissions               │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Developer                                   │
│  ├── Push to branches                        │
│  ├── Create merge requests                   │
│  └── All Reporter permissions                │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Reporter                                    │
│  ├── View code                               │
│  ├── Clone repository                        │
│  └── All Guest permissions                   │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Guest                                       │
│  ├── View issues                             │
│  └── Comment                                 │
└──────────────────────────────────────────────┘

Protected Branch Override

┌──────────────────────────────────────────────┐
│  Developer role                              │
│  Default: can push to branches               │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Protected branch: main                      │
│  Allowed to push: Maintainers                │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Developer cannot push to main               │
│  Must use merge request                      │
└──────────────────────────────────────────────┘

Summary

ItemValue
Project rolesGuest, Reporter, Developer, Maintainer, Owner
Role hierarchyCumulative
Visibility levelsPrivate, Internal, Public
Protected branchOverrides role for specific branches
Default protected branchmain
Deploy token scoperead_repository, read_registry
Project access token scopeapi, read_repository, write_repository

Key takeaways:

  • The roles are cumulative. A Maintainer has all the permissions of a Developer, plus the ability to manage settings. The role assignment is the baseline permission .
  • The protected branch overrides the role. A Developer cannot push to main if the protected branch allows only Maintainers. The protected branch is the secondary control .
  • The visibility determines the audience. A Private project is visible only to members. A Public project is visible to everyone. The visibility does not change the role permissions .
  • The deploy token is for automation. It has a scope, not a role. It can clone or pull, but cannot push unless the branch settings allow it .
  • The project access token is for API automation. It has a bot user, scopes, and an expiration date. It is the alternative to a personal access token for CI/CD .

Remember: The role is the baseline. The protected branch is the override. The visibility is the audience. The token is the automation. The exam tests the role hierarchy and the protected branch settings. The most common mistake is assuming that a Developer can push to main because a Developer can push to a feature branch. The protected branch is the difference.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!