Duo Messaging: workspace project
## Problem The [Duo Messaging Service architecture (ADR 008)](https://gitlab.com/gitlab-com/content-sites/handbook/-/merge_requests/19020) requires a CI pipeline to execute agent flows triggered from messaging services. CI pipelines fundamentally require a project (`Ci::Pipeline` validates `project: presence: true`), but messaging services like Slack have no project context. ## Proposal Implement `Ai::Messaging::WorkspaceProjectService` — a find-or-create service that provides a `duo-workspace` project per top-level namespace: - Finds an existing project by path or creates a new private project at the **root namespace** of the user's `duo_default_namespace` (e.g., `gitlab-org/duo-workspace`, not `gitlab-org/editor-extensions/duo-workspace`) - One workspace project per top-level group — avoids proliferation across nested namespaces - The project starts with a README explaining what it is and how to customize the agent environment, linking to relevant docs: - [AGENTS.md customization files](https://docs.gitlab.com/user/duo_agent_platform/customize/agents_md/) for documenting project conventions - [Configure flow execution](https://docs.gitlab.com/user/duo_agent_platform/flows/execution/) for `agent-config.yml` (Docker image, tooling, scripts) - Follows the same auto-creation pattern as [Security Policy Projects](https://docs.gitlab.com/ee/user/application_security/policies/) - Handles concurrent creation via `ActiveRecord::RecordNotUnique` rescue + retry lookup ### Service account: reuses `developer/v1` catalog SA During implementation, we investigated three approaches for the messaging service account: | Option | Approach | Tradeoff | |--------|----------|----------| | **A: Reuse `developer/v1` catalog SA** :white_check_mark: | Messaging uses the existing SA created when admin enables the Developer flow | Messaging triggers `developer/v1`, so it should use its SA | | B: New `messaging/v1` foundational flow | New catalog entry with its own SA | No actual `messaging/v1` workflow definition exists — bends the abstraction | | C: Self-bootstrapping SA (PoC approach) | Messaging creates its own SA on-demand | Redundant — creates a second SA for the same flow in the same namespace | We chose **Option A**. Messaging is a trigger mechanism for `developer/v1`, not a separate flow. The SA identity reflects the flow being executed, not the trigger source. The originally scoped `ResolveServiceAccountService` was removed — the `TriggerFlowService` (issue #2) resolves the existing catalog SA instead. ### Scope - `ee/app/services/ai/messaging/workspace_project_service.rb` + spec No feature flag needed — this service is inert without a caller. ### MR - !232332 ## Related - Parent issue: https://gitlab.com/gitlab-org/gitlab/-/work_items/590434 - ADR: https://gitlab.com/gitlab-com/content-sites/handbook/-/merge_requests/19020 - Blocks: https://gitlab.com/gitlab-org/gitlab/-/work_items/597570
task