Let fine-grained tokens read closing merge requests and related branches

What does this MR do and why?

A fine-grained personal access token gets no closing merge requests or related branches for a work item it can read, and workItemAddClosingMergeRequest returns null for the link it creates. The two types declare no authorize_granular_token directive, so no fine-grained token can read them.

Type Returned by Declares
WorkItemClosingMergeRequest WorkItemWidgetDevelopment.closingMergeRequests and the workItemAddClosingMergeRequest payload parent_authorizes: :read_work_item
WorkItemRelatedBranch WorkItemWidgetDevelopment.relatedBranches parent_authorizes: :read_branch

A closing link is returned only below a parent that authorizes the token, a WorkItem with read_work_item or the mutation with update_work_item. Its merge request keeps its own read_merge_request check, which a new example covers.

Related branches are branch names of the project, and comparePath names its default branch: data the Branch type gates with read_branch on the project, which Work Item: Read does not grant. So relatedBranches checks read_branch on the project of the work item with a field directive, and the development widget delegates project to its work item for that check.

Both types leave authorization_todo.txt. WorkItemLinkedResource, which the linked resources widget returns, stays on it as on master, for a separate change.

References

  • Related to #593878, the GraphQL gaps left for fine-grained tokens.
  • !266046 (merged) did the same for linked items.

I found this while working on gitlab-mcp-server.

Screenshots or screen recordings

Not applicable: no UI change.

How to set up and validate locally

  1. Give a work item a closing merge request and a branch named after it, and create a fine-grained token with Work Item: Read and Branch: Read on its project.

  2. Run with it:

    query { workItem(id: "gid://gitlab/WorkItem/<id>") { features {
      development { closingMergeRequests { nodes { id } } relatedBranches { nodes { name } } } } } }
  3. On master the token reads neither the link nor the branch name; on this branch it reads both. With Work Item: Read alone it reads the link, and relatedBranches is null.

I ran steps 2 and 3 as the closing merge requests and related branches examples of spec/requests/api/graphql/work_item_spec.rb, which post the two halves of this query.

Checks I ran (Ruby 3.3.11)
  • With master's types and todo list: 13 examples, 8 failures, all in the new or changed examples.
  • With the types of the previous version (d6cbc3ba): 7 examples, 4 failures, all new; a token with Work Item: Read alone got the branch name and a comparePath naming master.
  • On this branch, the request, type, model and entity specs the change reaches: 332 examples, 0 failures, 5 pending (skips of the shared examples).
  • gitlab:permissions:validate, RuboCop and the commit linter pass; graphql:compile_docs adds the relatedBranches row under Branch: Read, and both compile_docs tasks change nothing more. With parent_authorizes: :read_branch and no field directive, gitlab:permissions:validate fails on WorkItemWidgetDevelopment.relatedBranches. Left to the pipeline: Ruby 3.4.10 and 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