docs: Correct epic permissions across group hierarchies
What does this MR do?
Two documentation pages state different prerequisites for the same action, and one of them is wrong.
doc/user/work_items/child_items.md says, for both "Add an existing issue to an
epic" and "Remove an issue from an epic":
You must have the Guest, Planner, Reporter, Developer, Maintainer, or Owner role for the issue's project and the epic's group.
doc/user/permissions.md says, for the "Add issues to an epic" row of the Group
planning table (footnote 2):
You must have permission to view the epic and edit the issue.
The second one matches the code. In
ee/app/services/ee/work_items/parent_links/create_service.rb, can_add_to_parent?
returns can?(current_user, :read_work_item, parent_work_item) when the parent is
a group-level epic, under a comment that states the intent:
For legacy epics, we allow to add child items to the epic, when the user only has read access to the group. This could be the case when the group is public, or also when the group is private, but the user has access to a project within the group.
ee/app/services/ee/issues/base_service.rb guards the same relation with
can?(current_user, :read_epic, epic) && can?(current_user, :admin_issue_relation, issue).
This MR restates the epic side of both prerequisite blocks as permission to view the epic, which is what the code enforces, and links to the section that defines it.
Two smaller corrections on doc/user/group/epics/manage_epics.md:
- "Who can view an epic" and "View epics list" say a viewer can be a member of "a
project in one of the group's subgroups". Read plainly, that is one level down.
Read access reaches descendant groups at any depth.
child_items.mdalready uses the accurate wording elsewhere, "the epic's group or one of its descendant subgroups", so this aligns the two pages. - "Who can view an epic" does not say what a viewer can then see. The Child
items list is filtered to items the viewer can access, and the counts are
not.
child_items.mdalready documents this ("The numbers reflect all child work items associated with the epic, including those you might not have permission to view"), but a reader who wants to know who can see an epic is on the other page. This adds a cross-reference, not a new claim.
Why it matters
A reader mapping several organizations onto one group hierarchy needs to know what crosses the boundary: a top-level group, a middle group per organization, lower groups beneath, projects at the bottom. They read "role for the epic's group" as that boundary and design a release-of-information posture around it. The role is not a boundary: a person with a role in one project can attach their issues to an epic several levels above them, and can read that epic's title and description.
The behavior is intended. #208425 (closed) changed the permissions on purpose in 14.5 (!66865 (merged)), and #358612 (closed) asked for the opposite behavior and was closed as won't do. #443534 reported this documentation mismatch on the removal side and was closed as won't do, with the ruling "This is indeed expected behaviour but there is an error in the documentation". #456241 was opened to fix that documentation and has not moved. This MR changes documentation only and asks for no change in the product.
Reproduction
The rule corrected here is read from the master source quoted above, so it does
not turn on a release. I also confirmed it by measurement, on a GitLab Self-Managed
19.x Enterprise Edition instance: Linux package (Omnibus), single node, Ultimate
license. Epics need Premium or Ultimate, and multi-level child epics need
Ultimate.
Minimal setup:
- Create a private top-level group
top, a private subgrouptop/mid, and a private subgrouptop/mid/low. - Create a project
top/mid/low/appand a second project under a sibling subgroup,top/mid/other/app2. - Create an epic in
top/midand add three children: one issue fromtop/mid/low/app, one issue fromtop/mid/other/app2, and one child epic. - Create an epic in
topand add thetop/midepic plus children of your choice below it. - Add a user as Developer on
top/mid/low/apponly. Give them no role intop,top/mid,top/mid/low, or any other project.
Observed with that user's own token:
| Request | Response |
|---|---|
GET /api/v4/groups/top%2Fmid/epics/1 |
200, with title and description |
GET /api/v4/groups/top/epics/1 |
200, with title and description |
| Epic in an unrelated top-level group | 404 |
POST /api/v4/groups/top%2Fmid/epics/1/issues/<issue_id> for an issue in top/mid/low/app |
201, the issue becomes a child of the top/mid epic |
In the epic view for the same user, the Child items section of the top/mid
epic listed only the item from top/mid/low/app while the section header count
read 3, and the top epic listed 1 item while the header count read 7. Both are
consistent with what child_items.md already documents about counts.
The 201 above was observed on the Epic Issues REST endpoint, deprecated since 17.0. The proposed wording states the requirement as permission to view the epic and names no single interface, because that is the condition the code checks on the work-items path as well.
One question for the reviewer
Three more prerequisite blocks on child_items.md carry the same "role for the
issue's project and the epic's group" wording: "Create an issue from an epic",
"Reorder issues assigned to an epic", and "Move issues between epics". I did not
measure those three, so I left them alone. If the same correction applies, say so
and I will fold them into this MR.
Related issues
- Related to #456241 (Update epic permissions documentation). That issue asks for an audit of every place the epic permissions documentation disagrees with the permissions model. This MR fixes two of them and supplies the measured rule its thread was missing.
- Context, no change requested: #443534, #208425 (closed), !66865 (merged), #358612 (closed), #505855.
Author's checklist
- Optional. Consider taking the GitLab Technical Writing Fundamentals course.
- Follow the:
- If you're adding a new page, add the product availability details under the H1 topic title.
- If you are a GitLab team member, request a review based on:
- The documentation page's metadata.
- The associated Technical Writer.
If you are a GitLab team member and only adding documentation, do not add any of the following labels:
~"frontend"~"backend"~"type::bug"~"database"
These labels cause the MR to be added to code verification QA issues.
Reviewer's checklist
Documentation-related MRs should be reviewed by a Technical Writer for a non-blocking review, based on Documentation Guidelines and the Style Guide.
If you aren't sure which tech writer to ask, use roulette or ask in the #docs Slack channel.
- If the content requires it, ensure the information is reviewed by a subject matter expert.
- Technical writer review items:
- Ensure docs metadata is present and up-to-date.
- Ensure the appropriate labels are added to this MR.
- Ensure a release milestone is set.
- If relevant to this MR, ensure content topic type principles are in use, including:
- The headings should be something you'd do a Google search for. Instead of
Default behavior, say something likeDefault behavior when you close an issue. - The headings (other than the page title) should be active. Instead of
Configuring GDK, say something likeConfigure GDK. - Any task steps should be written as a numbered list.
- If the content still needs to be edited for topic types, you can create a follow-up issue with the docs-technical-debt label.
- The headings should be something you'd do a Google search for. Instead of
- Review by assigned maintainer, who can always request/require the reviews above. Maintainer's review can occur before or after a technical writer review.
AI-Generated Content Disclosure: This MR was prepared with assistance from Claude
Code. Every factual claim was verified against master source or a fetched upstream
issue, the behavior was confirmed on a GitLab Self-Managed instance, and the wording
was checked against the documentation style guide.