Return project settings to fine-grained tokens
What does this MR do and why?
A fine-grained token with update_project can run ProjectSettingsUpdate, but it gets no settings back, because ProjectSetting declares no authorize_granular_token directive. On master the mutation saves the settings and then answers Cannot return null for non-nullable field ProjectSettingsUpdatePayload.projectSettings. DuoContextExclusionSettings declares none either, so Project.duoContextExclusionSettings is null for a token with read_project.
Both types hold settings of one project, so both now declare parent_authorizes: :read_project, the form added by !266839 (merged), and leave authorization_todo.txt. That matches REST, where GET /projects/:id asks a fine-grained token for read_project and returns project settings. ProjectSetting is still returned only in the payload of ProjectSettingsUpdate, which checks update_project.
The checks for the user do not change, so a token reads no more than its user can. The project field of ProjectSetting keeps read_project, so update_project alone gets project: null on a private project.
References
- Part of #638945, the Code Review GraphQL types for fine-grained tokens.
- Related to #593878, the GraphQL gaps for fine-grained tokens.
I found this while working on gitlab-mcp-server.
Screenshots or screen recordings
No UI change.
How to set up and validate locally
- Where
ProjectSettingsUpdateis available (GitLab.com, or an instance with an active GitLab Duo add-on), create a fine-grained token with Project: Update for a project you maintain. - Run
mutation { projectSettingsUpdate(input: { fullPath: "<project>", duoFeaturesEnabled: true }) { projectSettings { duoFeaturesEnabled } errors } }with it. - On master the setting is saved and the response is the error above; on this branch
projectSettingsreturns the settings. - With a token that has Project: Read, run
query { project(fullPath: "<project>") { duoContextExclusionSettings { exclusionRules } } }:nullon master, the rules on this branch.
I ran these steps as new examples of the two request specs: they fail on master's types and pass on this branch.
Checks I ran (Ruby 3.3.11)
mutations/projects/project_settings_update_spec.rb: the token withupdate_projectgets the settings, the exclusion rules among them, and theprojectfield staysnullfor it. The payload has its own examples because the skipped child type shared example expects no GraphQL error when the token lacks the parent's permission, and a refused mutation returns one.project/duo_context_exclusion_settings_spec.rb: the skipped child type shared example withread_projectonProject.duoContextExclusionSettings.- With master's types and todo list, the two request specs give 18 examples, 3 failures, all three new or changed.
- On this branch, the two request specs, the two type specs and the
ProjectSettingsUpdatemutation spec: 43 examples, 0 failures. The two request specs andgitlab:permissions:validatealso pass on a local merge with current master. gitlab:permissions:validate, RuboCop and the commit linter pass; the three compile_docs tasks change nothing of this MR. 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.