Let fine-grained tokens read blame and CODEOWNERS validation in GraphQL
What does this MR do and why?
A fine-grained personal access token gets null for RepositoryBlob.blame and Repository.validateCodeownerFile even when it can read the repository: the five types below them declare no authorize_granular_token directive, which denies them to any fine-grained token.
Each type is returned by one field only, under a parent that already authorizes the token, so each now declares skip_reason: :parent_authorizes and leaves authorization_todo.txt:
| Type | Returned only by | Token checked at |
|---|---|---|
Blame |
RepositoryBlob.blame |
RepositoryBlob, read_repository_blob |
Groups |
Blame.groups |
RepositoryBlob, read_repository_blob |
CommitData |
Groups.commitData |
RepositoryBlob, read_repository_blob |
RepositoryCodeownerValidation (EE) |
Repository.validateCodeownerFile |
Repository, read_code |
RepositoryCodeownerError (EE) |
RepositoryCodeownerValidation.validationErrors |
Repository, read_code |
BlameResolver and Repository still check read_code for the user. REST blame takes read_repository_file_blame, in the same assignable permission as read_repository_blob, so a separate permission would not narrow anything.
References
- Related to #593878, the remaining GraphQL gaps for fine-grained tokens.
- !266025 (merged) gave
QuickActionsStatusthe same annotation.
I found this while working on gitlab-mcp-server.
Screenshots or screen recordings
Not applicable: no UI change.
How to set up and validate locally
-
In a project with a
CODEOWNERSfile, create a fine-grained token with Project: Read, Code: Read and Repository: Read. -
Run with it:
query { project(fullPath: "<path>") { repository { blobs(paths: ["README.md"]) { nodes { blame { groups { commitData { ageMapClass } } } } } validateCodeownerFile { total validationErrors { code } } } } } -
On master
blameandvalidateCodeownerFilearenull; on this branch they return data.
I ran steps 2 and 3 as the new examples in spec/requests/api/graphql/project/repository/blame_spec.rb and ee/spec/requests/api/graphql/project/repository/validate_codeowner_file_spec.rb, request specs that post step 2's blame and validateCodeownerFile fields with a fine-grained token: one that reads the project's code gets no data and no error on master's code and the data on this branch, and one with no permission gets no data on both.
Checks I ran (Ruby 3.3.11)
- With master's types and todo list, the two changed specs give 10 examples, 2 failures: the two new examples.
- Removing any one directive fails the example that reads its type.
- On this branch, with the blobs, repository and CODEOWNERS validation specs: 81 examples, 0 failures, 5 pending.
gitlab:permissions:validate, RuboCop and the commit linter pass;gitlab:permissions:graphql:compile_docschanges 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.