Let fine-grained tokens read linked work items in GraphQL

What does this MR do and why?

A fine-grained personal access token gets null for every node of Issue.linkedWorkItems, Epic.linkedWorkItems and the work item linked items widget, even when it can read the issue, epic or work item: LinkedWorkItemType declares no authorize_granular_token directive, and a fine-grained token is denied any type without one.

Each node of the type is the linked WorkItem itself, which can belong to another project or group than the issue, epic or work item it is linked from. So the type now declares the same directive as Types::WorkItemType (read_work_item, with the item's project or group as the boundary) and leaves config/authz/graphql/authorization_todo.txt. A token gets each linked item its boundary covers, and one outside it is left out of nodes, even when the user can read that item. LinkedItemsResolver still drops linked items the user cannot read.

The three fields get the regular authorizing granular token permissions for GraphQL examples with read_work_item and a check that a token on the project or group gets its linked items. Query.issue also covers a linked item in a second project the user can read but the token does not cover.

This takes over !254455 (closed) by @Mahaveer1013, co-author of the commit. Since then WorkItemType (Types::WorkItems::TypeType) merged in !251840 (merged) and DiffStats and DiffStatsSummary moved to !265425 (merged), so LinkedWorkItemType is what was left.

References

Related to #626742 (its diff stats part is in !265425 (merged)).

Found while maintaining https://github.com/jmrplens/gitlab-mcp-server, whose upstream-bugs.md lists the other types that still return null to these tokens; those go in separate MRs.

Screenshots or screen recordings

Not applicable: no UI change.

How to set up and validate locally

  1. Create a fine-grained personal access token for a project with Project: Read and Work item: Read.

  2. Link an issue of that project to another issue of the same project and to one in a project you can read that the token does not cover, then run with the token:

    query { project(fullPath: "<project path>") { issue(iid: "<iid>") { linkedWorkItems { nodes { linkId linkType workItem { id } } } } } }
  3. On master every node is null. With this MR the link within the project returns its fields, and the link to the other project is not returned.

Spec runs

Run locally on Ruby 3.3.11 and PostgreSQL 17, with the branch on master at 1261480d. It merges cleanly into today's master, which has not changed the type, its resolver or Types::WorkItemType since.

  • The granular token examples of the three fields and of Query.work_item, on master's code (no directive, the type on the todo list): 24 examples, 3 failures. The three checks that a token gets its linked items fail, since every node is null.
  • The same 24 examples on the first version of this MR (the parent_authorizes skip): 1 failure. The linked item outside the token's project comes back as {"linkType"=>"relates_to", "workItem"=>nil}.
  • With the change, the three spec files whole: 289 examples, 1 failure, 3 pending. The failure is Query.work_item(id) when project is archived, a GraphQL timeout on WorkItem.titleHtml under host load, which passes on its own. The pending ones are the enforcement examples of Query.issue, which skip without a top-level group.
  • bundle exec rake gitlab:permissions:graphql:compile_docs adds the type to the Work Item table of doc/auth/tokens/fine_grained_access_tokens_graphql.md, for the project and group boundaries, and bundle exec rake gitlab:permissions:validate passes.
  • RuboCop on the four Ruby files: no offenses.

Left to the pipeline: the specs on Ruby 3.4 and as FOSS.

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.

Edited by José M. Requena Plens

Merge request reports

Loading
Loading