Let fine-grained tokens read the Organizations GraphQL types
What does this MR do and why?
A fine-grained personal access token gets null or an empty list from ten user, member and custom attribute GraphQL types that declare no authorize_granular_token directive. Each now declares one and leaves authorization_todo.txt:
- Its own check, with the permission REST asks for:
UserStatus(read_user_status),CustomAttribute(read_custom_attribute, admins only, on the project, the group or, for a user's attributes, the instance),PendingGroupMemberandPendingProjectMember(read_pending_member, paired withadmin_*_memberas inGET /groups/:id/pending_members). parent_authorizes: :read_user:Ide,UserCallout,UserGroupCallout,UserDuoStatus,RecentlyViewedItem(itsitemkeeps its own check).NamespaceCommitEmailtakesread_user_email, asEmaildoes.
As agreed in !269587 (comment 4202991029), nine parent_authorizes: entries name the permission their parents already check, so no token gains or loses access:
read_user:UserPermissions.read_group:GroupPermissions,NamespaceProjectStatistics.read_member:GroupMemberPermissions.read_namespace:NamespacePermissions.read_organization_user:OrganizationUserPermissions.read_project:ProjectStatistics,ProjectStatisticsRedirect.read_achievement:Achievement.
ProjectStatistics takes read_project, as GET /projects/:id?statistics=true does; read_statistic covers the daily fetch counts and is no ability of ProjectPolicy or GroupPolicy. Achievement takes the read_achievement that Namespace.achievements and Group.achievements check; UserAchievement.achievement now checks it too, and one assignable permission grants it with read_user_achievement.
The checks for the user do not change. This is the Organizations domain's merge request (!267273 (comment 4195231927)).
References
Closes #638957
- Related to #593878.
I found this while working on gitlab-mcp-server.
Screenshots or screen recordings
No UI change.
How to set up and validate locally
- Create a fine-grained token with User: Read for the user scope.
- Run
query { currentUser { ide { codeSuggestionsEnabled } } }with it. - On master
ideisnull; on this branch it returns data.
I ran these steps as the new request spec examples: those that expect the ten types' data fail on master, and all pass on this branch.
Checks I ran (Ruby 3.3.11)
- For each parent field of the six new
parent_authorizestypes, the skipped child type shared example:ide,callouts,groupCallouts,namespaceCommitEmailsandduoStatusof a user, andCurrentUser.recentlyViewedItems; forNamespaceCommitEmail, also the parent-only example withread_user; and the callout and commit email mutations returning their record. - For the four types with their own check: an example that expects the data with the right permission and one without it (
status,customAttributesof a project, a group and a user,Group.pendingMemberswith a pending group member and a pending project member). UserPermissionsthrough the six user types that had no example: the author, assignees, reviewers and participants of a merge request,Project.autocompleteUsersandNamespace.addOnEligibleUsers.- With master's types and todo list, the new examples give 114 examples, 23 failures: the 8 type spec examples and the 15 that expect data of the ten types. The
UserPermissionsexamples pass on master too, since that entry changes no access. - On this branch, the 22 changed spec files and the existing examples of the nine entries (
-e granular): 187 examples, 0 failures, 28 pending; the three achievement request specs: 36 examples, 0 failures, 1 pending. gitlab:permissions:validate, RuboCop and the commit linter pass;gitlab:permissions:graphql:compile_docsadds the rows ofUserStatus,CustomAttribute,PendingGroupMemberandPendingProjectMember, and the routes task changes nothing. 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.