Check read_boundary instead of membership for token boundaries
What does this MR do and why?
Fine-grained personal access tokens are scoped to one group or project. Two decisions were being made with a membership check: whether you may scope a token to a resource, and whether you may be told that resource exists at all.
Membership isn't how GitLab grants access, so you couldn't scope a token to a public or internal project you weren't a member of — even though you can act on it. The only way round it was the broadest "all memberships" scope, which applies the permission to every group and project you belong to. Fixing the authorization half alone would have pushed people toward exactly that.
Both decisions now check a read_boundary permission on the group or project,
declared in the role definitions rather than in the policy files. Alongside that,
Authz::Boundary no longer answers any authorization questions — it's back to
being a plain description of a boundary.
Users who reach a resource without being a member — through a public or internal
project, a parent group they see via a subproject, or organization ownership —
can now scope tokens to it. Resources you can't see still return 404 rather
than revealing they exist.
Stacked on !256275 (merged) and
targets its branch; it will retarget to master once that merges.
References
Screenshots or screen recordings
Not applicable — no UI changes. The token creation form still lists only your memberships, so this is reachable through the REST and GraphQL APIs for now.
How to set up and validate locally
-
Create a public project your user is not a member of.
-
Scope a fine-grained token to it:
curl --request POST --header "PRIVATE-TOKEN: <token>" \ --header "Content-Type: application/json" \ --data '{"name":"t","expires_at":"2026-12-01","granular_scopes":[{"access":"selected_memberships","permissions":["read_job"],"project_ids":[<project_id>]}]}' \ "http://gdk.test:3000/api/v4/user/personal_access_tokens" -
Before:
404. After: the token is created and scoped to that project. -
Repeat with a private project you can't see — still
404.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist.
Specs run locally: 3874 examples, 0 failures, across the boundary model and policy,
the authorization service, role definitions, project and group policies, the REST
and GraphQL token-creation specs, and group packages. rake gitlab:permissions:validate
passes.