Let fine-grained tokens read Dedicated hosted runner usage
What does this MR do and why?
Without an authorize_granular_token directive, a fine-grained personal access token gets no nodes from ciDedicatedHostedRunnerUsage and null from ciDedicatedHostedRunnerFilters, the GitLab Dedicated hosted runner usage queries. Their four types now declare one and leave authorization_todo.txt:
CiDedicatedHostedRunnerUsageandCiDedicatedHostedRunnerFilterstakeread_dedicated_hosted_runner_usageon the instance, the permission they already check for the user, which only an administrator of a Dedicated instance has. This MR adds its definition (out ofdefinitions_todo.txt) and its own assignable permission,ci_cd/dedicated_hosted_runner_usage/read.yml, on the instance with theadmincondition. It does not reuseread_runner_usage, which covers the ClickHouse runner usage data under otherGlobalPolicyconditions.CiDeletedRunner, returned only byCiDedicatedHostedRunnerFilters.deletedRunners, takesparent_authorizes: :read_dedicated_hosted_runner_usage.CiDeletedNamespacetakesread_dedicated_hosted_runner_usageon the instance itself:NamespaceUnionreturns it next toNamespace, which has its own directive, so withparent_authorizes:gitlab:permissions:validatefails onCiDedicatedHostedRunnerUsage.rootNamespace. A namespace that still exists keepsNamespace's own check.
This is the Hosted Runners domain in one MR, as agreed in !267273 (comment 4195231927).
References
Closes #639750
Related to #593878.
I found this while working on gitlab-mcp-server.
Screenshots or screen recordings
No UI change.
How to set up and validate locally
-
As an administrator of an Ultimate instance with
gitlab_dedicated_instanceset and hosted runner usage for a runner and a namespace deleted since, create a fine-grained token for the instance with Dedicated Hosted Runner Usage: Read and run:query { ciDedicatedHostedRunnerUsage(grouping: PER_ROOT_NAMESPACE, year: 2026) { nodes { computeMinutes rootNamespace { ... on CiDeletedNamespace { id } } } } ciDedicatedHostedRunnerFilters { years deletedRunners { nodes { id } } } } -
On master
ciDedicatedHostedRunnerUsagehas no nodes andciDedicatedHostedRunnerFiltersisnull; on this branch they return the usage, the years and the IDs of the deleted namespace and runner. -
Remove Dedicated Hosted Runner Usage: Read from the token: no nodes and
nullagain.
Checks I ran (Ruby 3.3.11)
I ran the steps above as examples of the new request specs, with the granular token shared examples.
- With master's types and todo list, the changed specs give 43 examples, 7 failures, 4 pending: the failures are the four directive pins and the three examples where a fine-grained token reads the data.
- On this branch, the changed specs and those of the usage resolver and
NamespaceUnion: 56 examples, 0 failures, 4 pending (the shared examples' cases for a top-level group and a public resource, which do not apply to the instance). The same specs on this commit merged locally with today's master: 54 examples, 0 failures, 4 pending. gitlab:permissions:validate, bothcompile_docstasks (no change after the committed pages), RuboCop, the commit linter and Danger's linters pass. Left to the pipeline: Ruby 3.4 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.