Feat: Add projectId filter to duoWorkflowWorkflows GraphQL query
What does this MR do and why?
Adds a projectId argument to the duoWorkflowWorkflows GraphQL query so Duo Agent Platform sessions (flows/workflows) can be filtered to a single project by its Global ID. The query already accepted projectPath, but callers holding a project Global ID had to resolve a full path first to use it. GitLab's GraphQL styleguide says object identifiers should use Types::GlobalIDType[Model], so this adds a proper Global ID argument alongside the existing one. This is backend only; the Sessions page UI filter is separate follow-up work.
Changed files:
ee/app/graphql/resolvers/ai/duo_workflows/workflows_resolver.rb- new optionalproject_idargument of typeTypes::GlobalIDType[::Project]. The resolver unwraps the Global ID to a numeric ID before passing it to the finder, so the finder stays free of GraphQL types.ee/app/finders/ai/duo_workflows/workflows_finder.rb- newresolve_project_idmethod. Looks up the project, checks the:duo_workflowability for the current user (same ability already used for theprojectPathfilter), and scopes results to that project. Returns no results if the project doesn't exist or isn't accessible, rather than raising, matching GraphQL convention.ee/spec/finders/ai/duo_workflows/workflows_finder_spec.rb- 3 new examples: user can access the project, user cannot access the project, project does not exist.ee/spec/requests/api/graphql/ai/duo_workflows/workflows_spec.rb- 2 new request-spec examples next to the existingproject_pathcoverage: filtering returns only that project's sessions, and a non-existent project Global ID returns an empty list.doc/api/graphql/reference/_index.md- regenerated viabundle exec rake gitlab:graphql:compile_docs.doc/development/ai_features/duo_agent_platform_observability.md- filter table forduoWorkflowWorkflowsnow listsprojectId.
No database migration, no new query patterns beyond a single project lookup, no new feature flag.
Open question for reviewers: both projectPath and projectId are accepted. If a caller passes both and they point at different projects, the filters intersect and the result is an empty list rather than an error. Worth discussing whether the two arguments should be mutually exclusive instead, so passing both by mistake raises an error rather than silently returning nothing.
References
Screenshots or screen recordings
Backend-only GraphQL change with no UI. Screenshots don't apply.
How to set up and validate locally
-
Check out the branch
622898-filter-sessions-by-project-id. In the GDK, make sure a project has Duo Agent Platform sessions - run a flow to create some, or use an existing project that already has sessions. -
Get the project's Global ID from a rails console:
Project.find_by_full_path('flightjs/Flight').to_global_id.to_s # => "gid://gitlab/Project/7" -
Open GraphiQL at
http://gdk.test:3000/-/graphql-explorerand run this query, substituting the Global ID from the previous step:query { duoWorkflowWorkflows(projectId: "gid://gitlab/Project/7") { nodes { id projectId project { fullPath } } } }Expected: only sessions whose
projectIdmatches the one passed in. -
Run the same query without the
projectIdargument and confirm more sessions come back, including ones from other projects:query { duoWorkflowWorkflows { nodes { id projectId project { fullPath } } } } -
Pass a Global ID for a project the current user can't access, or one that doesn't exist, and confirm
nodesis empty with no error:query { duoWorkflowWorkflows(projectId: "gid://gitlab/Project/999999") { nodes { id } } } -
Run the specs:
bundle exec rspec ee/spec/finders/ai/duo_workflows/workflows_finder_spec.rb ee/spec/requests/api/graphql/ai/duo_workflows/workflows_spec.rb
MR acceptance checklist
Check this MR against the MR acceptance checklist.
Verified locally: RuboCop reports no offenses on all 4 changed Ruby files. bundle exec rspec ee/spec/requests/api/graphql/ai/duo_workflows/workflows_spec.rb ee/spec/finders/ai/duo_workflows/workflows_finder_spec.rb ran 129 examples, 0 failures.