[FF] duo_workflow_local_tool_governance -- enforce Duo tool governance on local surfaces

Summary

Roll out the duo_workflow_local_tool_governance feature flag, which enforces human-in-the-loop AI tool governance rules for GitLab Duo agentic flows on local surfaces (IDE, CLI, Chat). When enabled, local-surface sessions resolve tool permissions against the local_access rule column and client-supplied agent privileges are clamped to that governance resolution. Default off; when off, behavior is byte-identical to today (web_access resolution). See Governance tool rules (Ai::ToolRule) are not ap... (#606343 - closed) for context. Introduced in Enforce tool governance on local surfaces for D... (!249463 - merged). The confidential security tracker gitlab#606692 can be closed once this flag is enabled.

  • DRI: @dbernardi
  • Team Slack channel: #g_developer_clients

What could go wrong?

The flip affects all execution modes on local surfaces, not only auto mode. Manual-mode users will silently gain pre-approvals wherever a local allow rule differs from the web rules, and a local deny will block a tool regardless of execution mode. There is also a known fail-open: if governance resolution errors at the JWT-claim mint sites, denied tools resolve to empty (admin denies are dropped) rather than failing closed. This is pre-existing master behavior tracked for the re-key follow-up.

Watch Duo workflow error rates and tool-approval metrics on https://dashboards.gitlab.net during each rollout step.

Blockers before enabling

  • Re-key surface selection and the privilege clamp off the server-derived FlowExecutionAuthorizer execution classification (from Govern Duo flow runs by how they are executed (!248339 - merged)) instead of the client-supplied environment, so the column choice cannot be spoofed. This must land before this flag or duo_client_executed_flow_governance or duo_workflow_background_tool_governance goes GA.
  • Settle the external surface split-brain: on master the degraded_surface passthrough reads the local_access column on the creation-resolution path while the clamp and JWT mints fall back to web, so the two can resolve against different columns for the same workflow. Decide the intended external-surface behavior and make it consistent before enabling.
  • Row-derived pre-approval intersects the JWT ceiling (ai-assist!6491 / #608968). With local ask rules live, a tool can still be auto-approved through the workflow row, which sits outside the ceiling - so the admin's ask wouldn't actually hold. This is the "one gap" I flagged on the epic.
  • Empty or errored governance claim fails closed (#611843). An empty tool_access_policies claim is read as "no ceiling" today, and the mint-side case you already noted above (resolution error -> empty denied_tools) drops admin denies instead of failing closed. Both need to fail closed before we lean on the token to carry local denies.
  • Token bound to its workflow (#605431). This flag puts local deny into the token; while tokens are unbound a permissive one can be replayed onto a governed workflow and that deny is bypassed - so binding needs to be in effect, with client adoption, before the flip.

Rollout

Run all production /chatops in #production and cross-post results to #g_developer_clients.

Non-production

/chatops gitlab run feature set duo_workflow_local_tool_governance 50 --actors --dev --pre --staging --staging-ref


/chatops gitlab run feature set duo_workflow_local_tool_governance true --dev --pre --staging --staging-ref

Production — percentage rollout (wait at least 15 min between steps, watch dashboards):

/chatops gitlab run feature set duo_workflow_local_tool_governance <percentage> --actors

Or target specific actors instead:

/chatops gitlab run feature set --group=gitlab-org,gitlab-com duo_workflow_local_tool_governance true


/chatops gitlab run feature set --user=dbernardi duo_workflow_local_tool_governance true

Before global rollout

Confirm the relevant gotchas before going to 100%, see enabling a feature for GitLab.com:

Cleanup

Remove the flag once deemed stable. Remove the flag and its YAML definition from the codebase, then:

/chatops gitlab run release check <merge-request-url> <milestone>


/chatops gitlab run feature delete duo_workflow_local_tool_governance --dev --pre --staging --staging-ref --production

Rollback

/chatops gitlab run feature set duo_workflow_local_tool_governance false                                         # production


/chatops gitlab run feature set duo_workflow_local_tool_governance false --dev --pre --staging --staging-ref     # non-production


/chatops gitlab run feature delete duo_workflow_local_tool_governance --dev --pre --staging --staging-ref --production  # remove entirely
Edited by Dylan Bernardi