Add granular token directives to MCP note, diff and wiki types
What does this MR do and why?
Closes #626742
With a fine-grained PAT, any GraphQL object type without an authorize_granular_token directive resolves to null, because Gitlab::Graphql::Authz::GranularScopeAuthorization denies when no directive is declared. GitLab's MCP server runs GraphQL queries on behalf of the token. Once the token is passed into the MCP GraphQL tools (#631630 (closed)), the note, merge request, commit, repository tree and wiki tools return no data.
This MR was split out of !261599 (merged) to make review easier. That MR keeps the work item changes. The two are independent and can merge in either order. They only both touch config/authz/graphql/authorization_todo.txt and the generated doc/auth/tokens/fine_grained_access_tokens_graphql.md.
Changes (see the implementation guide):
- Real directives:
Discussion:read_noteat the project and group boundaries, mirroringNote.WikiPage:read_wikiat the project and group boundaries via the wiki container. This also covers the rootQuery.wikiPagefield.
skip_reason: :parent_authorizeson value types that have no policy permission of their own. Following the interim guidance in https://gitlab.com/gitlab-org/gitlab/-/work_items/636258, these are all the fields that return them, with the permission each parent requires:Diff:Commit.diffs(read_code) andMergeRequest.diffs(read_merge_request)DiffStatsandDiffStatsSummary:Commit.diffStatsandCommit.diffStatsSummary(read_code),MergeRequest.diffStatsandMergeRequest.diffStatsSummary(read_merge_request)DiffPosition:Note.position(read_note)TreeEntryandSubmodule:Tree.treesandTree.submodules(read_repository_tree)AccessLevel:Project.maxAccessLevel(read_project),Group.maxAccessLevel(read_group), andProjectMember.accessLevelandGroupMember.accessLevel(read_member). The other parents (MemberApproval,MemberRole, the pending members, protected environments andUsersQueuedForRolePromotion) have no directive yet, so fine-grained tokens are denied there.
- The todo lines for these nine types are removed and the docs are regenerated.
- Specs: request specs for each directive and boundary, and for each skipped type through its MCP path, using the shared examples 'authorizing granular token permissions for GraphQL' and '... with a skipped child type'.
Behavior for legacy PATs is unchanged. Granular checks only run for fine-grained tokens (or namespaces that enforce them).
This MR also absorbs the DiffStats and DiffStatsSummary changes from !254455 (closed), and adds the commit path coverage its reviewers asked for. Thanks to its author for that work.
References
- Part of #631631
- Parent: #630327
- Token passthrough: #631630 (closed)
- Split from: !261599 (merged)
- Related: !254455 (closed) and https://gitlab.com/gitlab-org/gitlab/-/work_items/636258
Screenshots or screen recordings
Not applicable, this MR only changes the backend.
How to set up and validate locally
-
Create a fine-grained personal access token in the UI (User settings > Personal access tokens > Fine-grained) for a project, with the Project: Read, Merge request: Read and Work item: Read permissions. Work item: Read is the permission that grants
read_note, the same as forNotetoday. -
Run this query against
/api/graphqlwith the token, for example with curl:query { project(fullPath: "flightjs/Flight") { mergeRequest(iid: "1") { diffStatsSummary { additions } discussions { nodes { id } } } } }On master
diffStatsSummaryis null anddiscussionshas no nodes. With this MR both are returned.
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.