Return suggested reviewers, blockers and diffs to fine-grained tokens

What does this MR do and why?

A fine-grained personal access token that can read a merge request gets no data for three of its EE fields, because their types declare no authorize_granular_token directive. Each type is returned only by its field on MergeRequest, which authorizes the token with read_merge_request, and each now declares a directive and leaves authorization_todo.txt:

Type Returned only by Directive
SuggestedReviewersType MergeRequest.suggestedReviewers parent_authorizes: :read_merge_request
BlockingMergeRequests MergeRequest.blockingMergeRequests read_merge_request_dependency
MergeRequestDiff MergeRequest.mergeRequestDiffs parent_authorizes: :read_merge_request

BlockingMergeRequests asks for read_merge_request_dependency on the merge request's project, as the REST merge request dependency routes do. It is in Merge Request: Read with read_merge_request, as read_merge_request_diff and read_merge_request_reviewer are, so a token with that group reads the three fields and the skips widen nothing.

The checks for the user stay as they are. Each merge request in visibleMergeRequests is a MergeRequest checked against the token again, which leaves out a blocker in a project the token does not cover; totalCount still counts it, as GitLab already shows users how many blockers they cannot read.

SuggestedReviewersType and MergeRequestDiff use the parent_authorizes: form added by !266839 (merged).

References

  • Part of #638945, the Code Review GraphQL types for fine-grained tokens.
  • Related to #593878, the GraphQL gaps for fine-grained tokens.
  • MergeRequestRiskAssessment and ApprovalRuleBlockageReason already skip with parent_authorizes.

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

Screenshots or screen recordings

No UI change.

How to set up and validate locally

  1. In a private project with a merge request, create a fine-grained token with Project: Read and Merge Request: Read for that project, and run:

    query {
      project(fullPath: "<project>") {
        mergeRequest(iid: "<iid>") {
          blockingMergeRequests { totalCount }
          mergeRequestDiffs { nodes { createdAt } }
        }
      }
    }
  2. On master blockingMergeRequests is null and mergeRequestDiffs.nodes is empty; on this branch both return data.

The new examples check each field, a token without read_merge_request_dependency, and a blocker in a project the token does not cover.

Checks I ran (Ruby 3.3.11)
  • Step 1 as a request spec, suggestedReviewers included: master returns suggestedReviewers: null, blockingMergeRequests: null and mergeRequestDiffs: { nodes: [] } with no error, and this branch returns the three.
  • With a second blocker in another project the user can read, the token gets totalCount: 2, hiddenCount: 0 and only the blocker in its own project in visibleMergeRequests.
  • With master's types and todo list, the new examples give 7 examples, 4 failures: every example that expects data fails.
  • Putting back any one type file from master fails only the examples that read that type.
  • With the skip BlockingMergeRequests had before, the new examples give 7 examples, 1 failure: the one without read_merge_request_dependency.
  • On this branch, the changed spec, the three type specs and the blocking merge requests mutation spec: 27 examples, 0 failures, 1 pending (a shared example that needs a top-level group).
  • gitlab:permissions:validate, RuboCop and the commit linter pass; gitlab:permissions:graphql:compile_docs changes nothing beyond the row it adds for BlockingMergeRequests, which is committed. Left to the pipeline: Ruby 3.4.10 and the FOSS run.

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