Record the parent workflow for agent-started workflows

What does this MR do and why?

A running agent can call POST /api/v4/ai/duo_workflows/agent_workflows to start another workflow. Today nothing limits how long that chain of workflows can get.

This MR passes the calling workflow to the services as the parent workflow, so the chain limits added in !258724 (merged) apply to this endpoint. The change is behind the ai_flow_trigger_chaining feature flag, which is off by default.

Changes:

  • When ai_flow_trigger_chaining is enabled for the container's top-level namespace, the endpoint in ee/lib/api/ai/duo_workflows/agent_workflows.rb reads duo_workflow_id from Gitlab::ApplicationContext. Gitlab::Middleware::DuoWorkflowId sets this value from the X-Gitlab-Duo-Workflow-Id header.
  • The endpoint loads that workflow and checks :update_duo_workflow for the current user. The client sets the header, so the workflow is always authorized before it is used.
  • If the workflow is found and authorized, it is passed as parent_workflow to both paths:
    • Ai::Catalog::Flows::ExecuteService, for catalog flows (when ai_catalog_item_consumer_id is given).
    • Ai::DuoWorkflows::CreateWorkflowService, for all other requests.
  • The depth, breadth, root human, and namespace checks from !258724 (merged) then apply.
  • If the header is missing, the workflow does not exist, or the user cannot update it, the request is rejected with 403. Every caller of this endpoint is a running agent, so a request without a parent is treated as an attempt to get around the limits.
  • When the flag is disabled, nothing changes. The header is ignored.
  • Chain rejections from CreateWorkflowService return 403 on the non-catalog path. On the catalog path they return 400, because that path already maps every service error to 400. This MR does not change that mapping.
  • Request specs in ee/spec/requests/api/ai/duo_workflows/agent_workflows_spec.rb cover:
    • A child workflow is created with the parent and trigger_source: flow.
    • Missing header.
    • Unknown workflow.
    • Workflow the user cannot update.
    • Depth limit.
    • Breadth limit.
    • Autonomous root.
    • Catalog path passes the parent.
    • Catalog path rejects a missing header.
    • Flag disabled ignores the header.
  • The rest of the spec file stubs the flag off, because those requests do not come from a running workflow.
  • No changelog, because the change is behind a default-off flag.

Known limitations

  • Before we enable the flag, we must confirm that every caller sends X-Gitlab-Duo-Workflow-Id on this request. Workhorse adds it to tool API calls, and glab sets it from DUO_WORKFLOW_WORKFLOW_ID. If a caller does not send it, every agent call from that caller returns 403 once the flag is on.
  • The authorization check is the same one used when linking notes and merge requests to a workflow. It proves the caller may update the workflow, not that the caller is that workflow. An agent could name another workflow of the same human, for example a shallower one, and get a smaller depth. The breadth limit still caps each parent, but we should discuss this before the flag is enabled.
  • The specs use a regular user token. In production the caller uses a composite identity token, and current_user is the human the flow acts for.

References

Screenshots or screen recordings

Not applicable. This is a backend-only change.

How to set up and validate locally

  1. In the Rails console, enable the flag:

    Feature.enable(:ai_flow_trigger_chaining)
  2. Pick a workflow you own:

    parent = Ai::DuoWorkflows::Workflow.where(user: User.find_by_username('root')).last
  3. Call the endpoint with the parent workflow ID in the header:

    curl --request POST \
      --header "PRIVATE-TOKEN: <token>" \
      --header "X-Gitlab-Duo-Workflow-Id: <parent id>" \
      --data "project_id=<id>&workflow_definition=software_development&goal=test" \
      "https://gitlab.example.com/api/v4/ai/duo_workflows/agent_workflows"

    Check that the new workflow has parent_workflow_id set.

  4. Repeat the request without the X-Gitlab-Duo-Workflow-Id header. You get a 403 response.

  5. Run the specs:

    bin/rspec ee/spec/requests/api/ai/duo_workflows/agent_workflows_spec.rb

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

Merge request reports

Loading
Loading