73VW
**Describe the bug** The login check of the GitLab backend (`hasWriteAccess` in `packages/decap-cms-backend-gitlab/src/API.ts`) gives different answers for the same GitLab role, depending on where the user gets it from. GitLab grants the same rights in all these cases: | Where the Developer role comes from | Decap today | |---|---| | Direct member of the project | Let in | | Member of the project's group or of an ancestor group | Let in | | Group invited to the project | Let in only if `developers_can_push` and `developers_can_merge` are both true on the default branch | | Group invited to an ancestor group of the project | Refused: "Your GitLab user account does not have access to this repo." | Maintainers and Owners are let in in the first three cases, and refused in the last one. Why: - A group invited to an ancestor group appears nowhere in `GET /projects/:id`: `permissions.project_access` and `permissions.group_access` are `null`, and `shared_with_groups` only lists the groups invited to the project itself. - For groups invited to the project, Decap reads the level of the invitation, not the user's role: a Reporter of a group invited as Maintainer is let in (noted while testing #3122). - `developers_can_push` and `developers_can_merge` are only true on a protected branch that explicitly allows Developers. On an unprotected branch, both are `false`. A Developer through an invited group is therefore refused when the default branch is not protected at all. - The branch check added in #3122 does not apply to direct members, and ignores the publish mode, although with `publish_mode: editorial_workflow`, saving an entry only pushes its own `cms/…` branch and opens a merge request. **To Reproduce** 1. Create a group `parent` and a project `parent/site`, with `main` protected (Maintainers allowed to push and merge). 2. Create a group `team` and add a user as Developer or Maintainer of `team` only. 3. In `parent` → Manage → Members, invite the group `team`. 4. Configure Decap with the GitLab backend on `parent/site` and log in as that user. 5. See "Your GitLab user account does not have access to this repo." For that user, `GET /projects/parent%2Fsite/members/all/<user id>` returns the role GitLab applies: `"access_level": 30` or `40`. **Expected behavior** The check depends on the user's effective role on the project, whatever gives it, and on the publish mode: | Publish mode | Let in if | |---|---| | `editorial_workflow` | Effective access level ≥ Developer (30), whether the branch is protected or not | | Simple | `can_push` is true on the configured branch, whatever the role | Everyone else (Reporter, Guest…) is refused. Proposed implementation, replacing the checks on `permissions`, `shared_with_groups` and `developers_can_*`: - Effective role: `GET /projects/:id/members/all?user_ids[]=<id>&state=active` returns the highest active membership of the user across direct membership, ancestor groups, groups invited to the project and groups invited to ancestor groups. An empty list means no role. - Simple mode: `GET /projects/:id/repository/branches/:branch` returns `can_push`, computed for the current user with the branch protection rules. `members/all/:user_id` exists since GitLab 12.4, counts groups invited to the project at least since 13.7, and groups invited to ancestor groups since 16.0. On older versions, the last case stays refused, as today. Out of scope, see #8015: with the editorial workflow, a Developer on a protected branch still sees Publish, which GitLab refuses to merge, and media library uploads and deletions, as well as deleting a published entry, still write to the base branch. **Applicable Versions:** - Decap CMS version: 3.16.3 (decap-cms-core 3.19.1), the check is unchanged on `main` - Git provider: GitLab (self-managed) - OS / Browser: not specific **CMS configuration** ```yaml backend: name: gitlab repo: parent/site branch: main base_url: https://gitlab.example.com api_root: https://gitlab.example.com/api/v4 auth_type: pkce app_id: <application id> publish_mode: editorial_workflow ``` **Additional context** Follows #3120 and #3122, which added `shared_with_groups` for groups invited to the project. A PR will follow.