Authorize fine-grained tokens to read achievements
What does this MR do and why?
A fine-grained personal access token gets no achievements or awards back: the lists come back empty. The Achievement, UserAchievement and UserAchievementCount GraphQL types have no authorize_granular_token directive, and read_achievement and read_user_achievement are only listed in definitions_todo.txt, so no permission a user can select grants them.
This MR:
- defines both permissions and removes them from
definitions_todo.txt; - adds the
read_achievementassignable permission (Achievement: Read, group and user boundaries) holding both, asdelete_achievementholds its two; - declares the user boundary on
UserAchievementandUserAchievementCount, which belong to the recipient, and the group boundary on theNamespace.achievementsfield; - lets
Achievementskip withparent_authorizes: a recipient can read it without access to its group, and a group boundary on the type would always take precedence over a user one; - removes the three types from
authorization_todo.txtand regeneratesdoc/auth/tokens/fine_grained_access_tokens_graphql.md.
Policies do not change. A group's achievements need Group: Read and Achievement: Read on the group. A user profile (userAchievements, achievementCounts) needs User: Read and Achievement: Read on the user boundary, and the awards listed under a group's achievements need Achievement: Read on the user boundary too.
The choices to check are the new assignable permission and the parent_authorizes skip on Achievement.
References
- #593878 is the umbrella issue for these gaps.
- !261898 (merged) and !261986 (merged) added the granular checks of the achievement mutations.
I found this while working on gitlab-mcp-server.
Screenshots or screen recordings
Not applicable: no frontend change.
How to set up and validate locally
-
Create a fine-grained token in the Rails console as in Step 7 of
doc/development/permissions/granular_access/graphql_implementation_guide.md, for a member of a group with an awarded achievement, with the group as the boundary andpermissions: [:read_group, :read_achievement]. -
Query the group's achievements with it:
curl --request POST --header "PRIVATE-TOKEN: <token>" --header "Content-Type: application/json" \ --data '{"query": "{ group(fullPath: \"<group>\") { achievements { nodes { name userAchievements { nodes { id } } } } } }"}' \ --url "http://gdk.test:3000/api/graphql" -
On master
read_achievementcannot be granted andnodesis empty. On this branch the achievements are returned, their awards only when the token also holdsread_achievementon the user boundary, and a token withoutread_achievementgets no achievements.
Specs I ran (Ruby 3.3.11)
- On master's code the new group spec does not load: the shared example finds no assignable permission for
read_achievement. - On the first commit's code, with group boundaries on the three types: 29 examples, 8 failures, among them a token with only the user boundary reading its own awards.
- On this branch, the changed specs, every other achievement spec (types, resolvers, policies, mutations, the user achievements query with its N+1 example), the namespace, group and user type specs, and the authz and permission task specs: 899 examples, 3 pending, and 6 failures, all in
awarded_achievements_controller_spec.rb, which needs the built frontend. bundle exec rake gitlab:permissions:validate: all six checks pass. RuboCop on the changed Ruby files: no offenses. The commit linter: no findings.- Left to the pipeline: Ruby 3.4.10, the FOSS-only jobs and
awarded_achievements_controller_spec.rb, which needs the built frontend.
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.