Restore granular token traversal in GraphQL type authorization
What does this MR do and why?
Follow-up to the type-level gPAT authorization work in
!238311 (merged) and
!241225 (merged), which moved
granular personal access token authorization in GraphQL from a per-field
extension to the object/type level. That move dropped the traversal
behavior the field extension provided: a granular token could no longer
reach a child resource through its parent boundary (for example
group { groupMembers }) without also holding the parent's read
permission, even though the equivalent REST endpoint allows it.
This MR restores traversal at the type level:
Gitlab::Graphql::Authz::TraversalSelectioninspects the fields selected on the object being authorized. When every selected field defers to an authorized, non-leaf child type, the object is reached only for traversal.- In that case the granular check verifies boundary visibility
(
read_boundary) instead of the object's own permission; the child types enforce their own permissions. - Reading the object's own data (scalar fields) still requires its
permission. Leaf children (all-scalar types, for example
RepositoryLanguageType) also still require the parent permission, because an empty collection would otherwise bypass authorization. - Abstract (interface/union) return types are resolved to their concrete
implementers (for example
MemberInterface).
It also removes the now-unused traversal: GraphQL directive argument and
its helper plumbing, and regenerates the introspection schema.
Related to #601728 (closed)
Closes #605833 (closed)
How to set up and validate locally
-
Enable the
granular_personal_access_tokensfeature flag. -
Create a fine-grained token scoped to a group with only
read_member(noread_group). -
Run:
curl --request POST \ --header "Authorization: Bearer <TOKEN>" \ --header "Content-Type: application/json" \ --data '{"query":"query { group(fullPath: \"<GROUP>\") { groupMembers { nodes { id } } } }"}' \ http://127.0.0.1:3000/api/graphqlThe members resolve even though the token does not hold
read_group, matchingGET /api/v4/groups/:id/members.
MR acceptance checklist
This MR meets the MR acceptance checklist.