Pre-approve Orbit MCP tools in tool_access_policies claim

What does this MR do and why?

Orbit MCP tools (orbit_list_commands, orbit_invoke_command) prompt for approval on every call in web Duo Chat since 2026-07-10, breaking agentic Orbit flows. The Duo Workflow Service treats the tool_access_policies JWT claim as the pre-approval ceiling (hardening for https://gitlab.com/gitlab-org/gitlab/-/issues/604720), and the claim is built from the tool governance registry, which cannot express MCP tool names, so the Orbit pre-approvals Workhorse sends are always dropped.

This MR adds the Orbit tool names to the claim's allow list, prefixed orbit_<tool> exactly as Workhorse registers them with DWS. The two tools are read-only, have no ai_tool_rules registry entries (no admin rule can target them today), and for custom agents the claim is bounded to the agent's selected subset.

The GitLab MCP server tools (search, gitlab_search, ...) lost pre-approval to the same ceiling but are intentionally out of scope: their names shadow governed capabilities (deny/ask twins spelled differently in the registry), so restoring them safely belongs with the governance mapping planned in https://gitlab.com/gitlab-org/gitlab/-/work_items/606073. This MR addresses the Orbit part of https://gitlab.com/gitlab-org/gitlab/-/issues/607151.

Root cause and scope notes
  • Chain: McpConfigService marks Orbit tools as PreApprovedTools -> Workhorse prefixes them and sends startRequest.preapproved_tools (workhorse/internal/ai_assist/duoworkflow/mcp.go) -> DWS _merge_jwt_governance_claims replaces that list with the claim's allow list whenever governance is active, which is effectively always (read_only_gitlab defaults to allow; gitlab_duo_governance_settings is default enabled since 19.0).
  • The affected path is the legacy chat definition. agentic_chat/v1 consumes only the claim's deny half today; allow-side enforcement is tracked in https://gitlab.com/gitlab-org/gitlab/-/issues/603024 and this MR keeps the claim correct for when it lands.
  • The ws endpoint is the only claim-minting site that injects the Orbit MCP server; IDE/CLI sessions bring their own MCP config and stay capped by design.
  • For ask-everything namespaces the claim's allow list was previously empty and the DWS ceiling never engaged; the two Orbit names now make it engage, which fails in the strict direction.

References

Screenshots or screen recordings

GDK, web Duo Chat, legacy chat definition, governance flag on, DWS auth enabled (the GDK default disables it, which hides this bug).

Before (master) After (this MR)
orbit-bug-before orbit-fix-after-legacy

How to set up and validate locally

  1. In <gdk>/gitlab-ai-gateway/.env set DUO_WORKFLOW_AUTH__ENABLED=true (needs a valid DUO_WORKFLOW_SELF_SIGNED_JWT__VALIDATION_KEY PEM and the mkcert root CA in REQUESTS_CA_BUNDLE), then gdk restart duo-workflow-service.
  2. Disable agentic_chat_flow_registry_migration so web chat uses the legacy chat definition; keep gitlab_duo_governance_settings enabled, with Orbit enabled for the user.
  3. In web Duo Chat ask: "Use orbit_query_graph to list projects whose full_path starts with gitlab-org/". Without this MR the first Orbit call shows an approval card; with it, the tool runs immediately.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

Edited by Michael Angelo Rivera

Merge request reports

Loading