Add archive_group as a customizable permission

TL:DR

We have a role for delete but not for archive subgroup. We have delete and archive for project. It would be nice to archive supgroup without being an owner.

What does this MR do and why?

Adds archive_subgroup as a custom role ability, so archiving a group can be delegated without handing over the ability to delete it.

Today a custom role can be granted "Delete subgroup" (remove_group), but there is no ability for archiving. That leaves the permission model backwards: deleting is destructive and needs a retention window to recover from, while archiving is lighter-weight and can be undone with unarchive. Archiving is not fully reversible, though: it unlinks projects in the subgroup from their fork networks and closes their open cross-fork merge requests, and unarchiving restores neither. The ability description warns about this. Delegating group lifecycle work to a non-Owner meant granting the destructive option, because archive_group was reachable only through the Owner role (config/authz/roles/owner.yml).

Projects already have this split. archive_project has been a custom ability alongside remove_project since 16.6.

The change is a single ability definition plus regenerated docs:

  • ee/config/custom_abilities/archive_subgroup.yml mirrors archive_project.yml: group_ability: true, enabled_for_group_access_levels: [50], group_permissions: [_archive_subgroup].
  • No policy change. EE::GroupPolicy already iterates MemberRole.all_customizable_group_permissions and enables each ability's declared group_permissions (ee/app/policies/ee/group_policy.rb:264-272).
  • No migration. member_roles.permissions is a jsonb column.
  • doc/user/custom_roles/abilities.md regenerated with rake gitlab:custom_roles:compile_docs; GraphQL reference and introspection schemas regenerated with rake gitlab:graphql:update_all. The archive_subgroup row in doc/api/member_roles.md is hand-added, matching how that file already lists archive_project and remove_group.

Open question for the reviewer

One ability covers both directions, because POST /groups/:id/archive and POST /groups/:id/unarchive both call authorize!(:archive_group, group). I deliberately did not list unarchive_group in group_permissions: nothing checks it (it exists only as a granular-token route setting), and listing it would hard-code the bundling that #597400 is asking to undo for projects. If that issue lands a split, groups should follow the same shape.

References

Screenshots or screen recordings

No UI change. The new ability appears in the existing custom role permission list, rendered from the same generated definitions as every other ability.

How to set up and validate locally

  1. Enable custom roles:

    Feature.enable(:custom_roles)
  2. In the rails console, create a Guest-based custom role with the new ability and assign it:

    group = Group.first
    role = MemberRole.create!(namespace: group, base_access_level: 10, name: 'Group archiver', archive_subgroup: true)
    group.add_member(User.find_by_username('your-user'), 10, member_role: role)
  3. As that user, archive the group and confirm it succeeds:

    curl --request POST --header "PRIVATE-TOKEN: <token>" \
      "http://127.0.0.1:3000/api/v4/groups/<group_id>/archive"
  4. Unarchive it the same way with /unarchive, and confirm DELETE /api/v4/groups/<group_id> returns 403.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

  • Tests: ee/spec/requests/custom_roles/regular/archive_subgroup/request_spec.rb added, covering archive, unarchive, and that deletion is still refused. Passes locally (3 examples, 0 failures). ee/spec/lib/gitlab/custom_roles/definition_spec.rb also passes (59 examples, 0 failures).
  • Changelog: Changelog: added with EE: true on the commit.
  • Documentation: updated, see above.
  • Database review: not needed, no migration or schema change.
  • Application Security review: this adds an authorization ability, so a look from the Authorization group is worth having. The ability grants only archive_group, which is already enforced in Namespaces::Groups::ArchiveService and UnarchiveService.
  • Feature flag: not used. The ability is inert until an instance admin adds it to a custom role.
  • Translation: no new user-facing strings; the ability title and description come from the YAML and flow through the existing generated docs.
Edited by Jimmy Spagnola

Merge request reports

Loading
Loading