Bind workflow tokens to foundational flow ID

What does this MR do and why?

Passes the Rails-authorized foundational flow ID to DWS when minting workflow tokens across every server-started execution path, allowing DWS to reject registered flow substitution. Non-foundational flows and the direct-access token endpoint remain unbound for compatibility. Vendors gitlab-duo-workflow-service-client 0.12, which adds flow_config_id to GenerateTokenRequest.

Related #2431

References

DWS/Rails Compatibility

Rails DWS Workflows Substitution blocked
Old Old Work No
Old New Work No; tokens remain unbound
New Old Work No; the optional protobuf field is ignored
New New Work Yes

Either MR can deploy first. Older self-managed GitLab versions remain compatible because DWS permits tokens without a binding. When a binding is present, DWS fails closed: it requires a non-empty string claim and permits only the matching registry flow. Debug users retain the existing binding bypass.

Screenshots or screen recordings

Not applicable. This change has no UI.

How to set up and validate locally

Run GDK with this Rails branch and DWS from gitlab-org/modelops/applied-ml/code-suggestions/ai-assist!6430 (merged). Enable Duo Agent Platform and the foundational flows used below for the test project. Configure their service accounts, then set:

export GITLAB_URL="http://gdk.test:3000"
export GITLAB_TOKEN="<personal-access-token-with-api-scope>"
export PROJECT_ID="<numeric-project-id>"

Generic workflow API path

This exercises API::Helpers::DuoWorkflowHelpers#start_workflow_params:

curl --request POST \
  --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  --header "Content-Type: application/json" \
  --data "{
    \"project_id\": \"$PROJECT_ID\",
    \"workflow_definition\": \"developer/v1\",
    \"goal\": \"Create hello.txt containing hello\",
    \"start_workflow\": true
  }" \
  --url "$GITLAB_URL/api/v4/ai/duo_workflows/workflows"

Confirm the workflow pipeline starts and DWS receives developer as the flow_config_id in the token request.

Catalog execution path

Enable Developer Flow from the AI Catalog for the test project. Look up its consumer ID:

curl --request POST \
  --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  --header "Content-Type: application/json" \
  --data "{\"query\":\"query { aiCatalogConfiguredItems(projectId: \\\"gid://gitlab/Project/$PROJECT_ID\\\") { nodes { id item { name } } } }\"}" \
  --url "$GITLAB_URL/api/graphql"

Use the numeric suffix from gid://gitlab/AiCatalogItemConsumer/<numeric-id>:

export AI_CATALOG_ITEM_CONSUMER_ID="<numeric-id>"

curl --request POST \
  --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  --header "Content-Type: application/json" \
  --data "{
    \"project_id\": \"$PROJECT_ID\",
    \"ai_catalog_item_consumer_id\": $AI_CATALOG_ITEM_CONSUMER_ID,
    \"goal\": \"Create hello.txt containing hello\",
    \"start_workflow\": true
  }" \
  --url "$GITLAB_URL/api/v4/ai/duo_workflows/workflows"

Confirm the workflow pipeline starts and DWS receives developer as the flow_config_id in the token request. This exercises Ai::Catalog::ExecuteWorkflowService.

Dedicated foundational-flow path

This path is used by code review, reviewer recommendations, and workplan generation. To exercise it with Code Review Flow:

  1. Enable Code Review Flow for a project and configure its service account.
  2. Create a non-draft merge request with a change to review.
  3. Assign @GitLabDuo as a reviewer, use the /assign_reviewer @GitLabDuo quick action, or mention @GitLabDuo and ask for a review.
  4. Confirm a session and workflow pipeline are created.
  5. Confirm DWS receives code_review as the flow_config_id in the token request.

This exercises Ai::DuoWorkflows::CreateAndStartWorkflowService.

Binding enforcement

For each server-started path above, the flow ID in the DWS token request must match the resolved flow used to start the workload. With the accompanying DWS branch, presenting a token bound to developer while requesting flowConfigId: secrets_fp_detection must fail with PERMISSION_DENIED before flow resolution.

The direct-access token-only endpoint is intentionally unbound because it does not authorize or start a specific flow.

MR acceptance checklist

  • Targeted service and client specs pass.
  • All server-started foundational flow paths bind the resolved flow ID.
  • Non-foundational and direct-access token callers remain backward-compatible.
  • Vendored gitlab-duo-workflow-service-client 0.12, regenerated from the rebased DWS branch.
Edited by Alper Akgun

Merge request reports

Loading
Loading