Add ai_workflows scope to group GraphQL fields
What does this MR do and why?
Add ai_workflows scope to group GraphQL fields
Custom Flow composite identity tokens carry only the ai_workflows OAuth scope. GraphQL fields default to the api and read_api scopes, so Query.group and Query.groups silently returned null for these tokens regardless of the service account's role, while Query.project and Query.namespace already declared the scope.
Declaring the scope on the root fields alone is not enough:
- Namespace.projects lacked the scope, blocking group { projects }.
- Types::Namespaces::GroupInterface redefines id, name and fullPath, and GroupType redefines webUrl, so the scopes declared on NamespaceType do not apply to Group and those fields still resolved to null.
Align the affected fields with the ai_workflows allowlist already exposed by NamespaceType. Deeper authorization layers (read_group ability, Duo policy gates, composite identity) are unaffected.
References
Screenshots or screen recordings
| Before | After |
|---|---|
![]() |
![]() |
How to set up and validate locally
Prerequisites
- GDK with EE license and Duo features enabled
- A group with at least one project (e.g.
duo-test/apple)
Steps
- Create a custom flow in AI Catalog using the YAML below
- Trigger the flow from an issue in the group's project
- Verify all probe queries return data (not null):
groups(first: 5)— returns groupsgroup(fullPath:)— returns group datanamespace(fullPath:)— returns namespace datagroup.projects— returns projects
Flow YAML
version: v1
environment: ambient
components:
- name: graphql_auth_probe
type: AgentComponent
prompt_id: graphql_auth_probe_prompt
inputs:
- from: "context:goal"
as: "goal"
- from: "context:project_id"
as: "project_id"
toolset:
- "gitlab_graphql"
ui_log_events:
- "on_agent_final_answer"
- "on_tool_execution_success"
- "on_tool_execution_failed"
prompts:
- prompt_id: graphql_auth_probe_prompt
name: GraphQL auth probe
unit_primitives: []
prompt_template:
system: |
You are a GitLab GraphQL authorization diagnostic agent.
Your task is to verify whether the authentication context of the
Custom Flow can read GitLab GraphQL data.
You must dynamically discover accessible groups and projects.
Do not hardcode any group or project paths.
Requirements:
- You may only use the gitlab_graphql tool.
- Do not use the REST API.
- Do not guess or fabricate any results.
- Execute each query one by one.
- Report the raw JSON returned by every executed query.
- Replace TARGET_GROUP_PATH and TARGET_PROJECT_PATH with the paths
discovered from previous query results.
## Execution plan
Step 1:
Run Query 0 to inspect the current authenticated user.
Step 2:
Run Query 1 to discover accessible groups.
If no groups are returned:
- Report that group-level probes cannot continue.
- Skip Queries 2 through 5.
- Go directly to the final summary.
Step 3:
Take the fullPath of the first group returned by Query 1 and use it
as TARGET_GROUP_PATH for Queries 2, 3, and 4.
Step 4:
Run Query 2 using TARGET_GROUP_PATH.
Step 5:
Run Query 3 using TARGET_GROUP_PATH.
Step 6:
Run Query 4 using TARGET_GROUP_PATH.
If projects are returned:
- Take the fullPath of the first project.
- Use it as TARGET_PROJECT_PATH for Query 5.
If no projects are returned:
- Report that project-level probes cannot continue.
- Skip Query 5.
Step 7:
Run Query 5 using TARGET_PROJECT_PATH.
After all executable queries have completed, provide a concise
authorization diagnostic summary covering:
- Whether currentUser returned data.
- Whether groups(first: 5) returned any groups.
- Whether group(fullPath:) returned null or data.
- Whether namespace(fullPath:) returned null or data.
- Whether group.projects returned visible projects.
- Whether project(fullPath:) returned basic project data.
- Which authorization layer is most likely responsible for any failure.
user: |
Run the following GitLab GraphQL authorization probe queries in the
current Custom Flow session.
Context:
- Trigger goal: {{goal}}
- Trigger project_id: {{project_id}}
## Query 0: Current authenticated user
query CurrentUserProbe {
currentUser {
id
username
name
webUrl
}
}
## Query 1: Discover accessible groups
query DiscoverGroups {
groups(first: 5) {
nodes {
id
name
fullPath
}
}
}
Use the fullPath of the first group returned by Query 1 as
TARGET_GROUP_PATH.
If Query 1 returns no groups, skip Queries 2 through 5 and go
directly to the authorization diagnostic summary.
## Query 2: Group by fullPath
query GroupProbe {
group(fullPath: "TARGET_GROUP_PATH") {
id
name
fullPath
}
}
## Query 3: Namespace by fullPath
query NamespaceProbe {
namespace(fullPath: "TARGET_GROUP_PATH") {
id
name
fullPath
}
}
## Query 4: Group projects
query GroupProjectsProbe {
group(fullPath: "TARGET_GROUP_PATH") {
id
name
fullPath
projects(first: 5, includeSubgroups: true) {
nodes {
id
name
fullPath
}
}
}
}
Use the fullPath of the first project returned by Query 4 as
TARGET_PROJECT_PATH.
If Query 4 returns no projects, skip Query 5.
## Query 5: Project by fullPath
query ProjectProbe {
project(fullPath: "TARGET_PROJECT_PATH") {
id
name
fullPath
}
}
Return the raw JSON result of each executed query, followed by the
authorization diagnostic findings.
params:
timeout: 300
routers:
- from: graphql_auth_probe
to: end
flow:
entry_point: graphql_auth_probeMR 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.

