Let fine-grained tokens read AiCatalog versions and MCP servers

What does this MR do and why?

Without an authorize_granular_token directive, a fine-grained personal access token gets no data from seven catalog types. Each now declares one and leaves authorization_todo.txt:

  • AiCatalogAgentVersion, AiCatalogFlowVersion and AiCatalogThirdPartyFlowVersion take read_ai_catalog_item on the user, as their items do. AiCatalogSkillVersion, the fourth version type, already declares it on its project.
  • AiCatalogMcpServer takes read_ai_catalog_mcp_server on the user, the ability it already checks, from a new Read assignable permission next to Create, Update and Block. A token that reads catalog items does not read the MCP servers: an agent version's mcpServers and the MCP server mutations' mcpServer need this permission too. No token held it before, so none needs migrating.
  • AiCatalogMcpTool takes read_ai_catalog_item on the user, the permission Query.aiCatalogBuiltInTools checks for the built-in tools. The type carries it because Query.aiCatalogMcpTools is non-null.
  • AiCatalogMcpToolIcon and AiFoundationalChatAgentFlowConfig, returned only below a type that checks read_ai_catalog_item, declare it with parent_authorizes:.

It also declares parent_authorizes: :read_ai_catalog_item on AiCatalogItemPermissions, which !267273 (merged) left as a skip: its four parents check that permission, so no token changes. This is a follow-up promised in !269587 (comment 4204222716), and the domain in one MR, as agreed in !267273 (comment 4195231927).

References

Closes #639842

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 organization member, with the mcp_client and ai_catalog_mcp_servers flags on and a public agent whose latest version uses an MCP server, run with a fine-grained token that holds read_ai_catalog_item and read_ai_catalog_mcp_server on the user:

    query {
      aiCatalogItem(id: "<agent global ID>") {
        latestVersion { ... on AiCatalogAgentVersion { systemPrompt mcpServers { nodes { name } } } }
      }
      aiCatalogMcpTools { nodes { name icons { src } } }
    }
  2. On master latestVersion and every node of aiCatalogMcpTools are null; on this branch both return data.

  3. Drop read_ai_catalog_mcp_server: mcpServers is empty. Drop read_ai_catalog_item too: the item and the tools are gone.

Checks I ran (Ruby 3.3.11)

The changed request specs post aiCatalogItemVersions, aiCatalogMcpServer, aiCatalogMcpTools and aiFoundationalChatAgents with a fine-grained token, with and without the permission.

  • With master's types, the changed specs give 137 examples, 18 failures: the 8 new type checks and 10 of the new request examples (the others, such as the legacy token cases, pass on both). With the previous version of this MR, where read_ai_catalog_item granted read_ai_catalog_mcp_server, the two new mcpServers examples fail.
  • On this branch, the changed specs and the existing MCP server specs: 207 examples, 0 failures, 17 pending (the shared examples' cases that apply only to a project or group boundary).
  • gitlab:permissions:validate, RuboCop, the commit linter and Danger's linters pass; both compile_docs tasks leave the committed docs unchanged. 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