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:

  • CiDedicatedHostedRunnerUsage and CiDedicatedHostedRunnerFilters take read_dedicated_hosted_runner_usage on 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 of definitions_todo.txt) and its own assignable permission, ci_cd/dedicated_hosted_runner_usage/read.yml, on the instance with the admin condition. It does not reuse read_runner_usage, which covers the ClickHouse runner usage data under other GlobalPolicy conditions.
  • CiDeletedRunner, returned only by CiDedicatedHostedRunnerFilters.deletedRunners, takes parent_authorizes: :read_dedicated_hosted_runner_usage.
  • CiDeletedNamespace takes read_dedicated_hosted_runner_usage on the instance itself: NamespaceUnion returns it next to Namespace, which has its own directive, so with parent_authorizes: gitlab:permissions:validate fails on CiDedicatedHostedRunnerUsage.rootNamespace. A namespace that still exists keeps Namespace'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

  1. As an administrator of an Ultimate instance with gitlab_dedicated_instance set 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 } } }
    }
  2. On master ciDedicatedHostedRunnerUsage has no nodes and ciDedicatedHostedRunnerFilters is null; on this branch they return the usage, the years and the IDs of the deleted namespace and runner.

  3. Remove Dedicated Hosted Runner Usage: Read from the token: no nodes and null again.

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, both compile_docs tasks (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.

Edited by José M. Requena Plens

Merge request reports

Loading
Loading