Draft: [skip ci] Run Slack GitLab Duo sessions in the Duo group of the workspace

What does this MR do and why?

When someone mentions @gitlab in Slack, the session should run in the group an Owner chose for that Slack workspace, not in the default namespace of whoever mentioned the bot. This MR makes the mention path do that: it looks up the Duo group of the workspace, checks that the person is a member of it, and runs the Slack flow there, so the Duo group's settings and credits apply to everyone in the workspace. A workspace without a Duo group does not fall back to the old behaviour: the person gets a reply that says GitLab Duo is not set up yet and who can set it up.

With the feature flag off nothing changes. It builds on !262156 (closed).

What's in it

  • MentionResolver: decides where a mention runs. It returns nothing while the feature is off for the workspace (old behaviour), the Duo group for a member, or a reason the Slack adapter turns into a reply.
  • Replies in Slack for the new cases: GitLab Duo is not set up yet (and who can set it up: the Owners of the one group the workspace is connected in, the administrator for an instance-wide install, or a generic pointer), the person is not a member of the Duo group (the group is only named if they can see it), and the Slack flow is off in the Duo group.
  • DefaultProjectFlowResolver takes the namespace as an input, so a Duo group replaces the user's default Duo namespace.
  • The flags are checked for the workspace's group, not for the person: the Duo group or, while the workspace has none, the one top-level group it is connected in. A person's default namespace never decides for the other Slack workspaces they use, so a rollout for one group cannot break unrelated workspaces. slack_duo_api_flow has to be on too, because a workflow run checks it for the same group.
  • Analytics event block_slack_duo_mention counts the replies that stop a mention (property = reason).

Where this fits

This is one of a stack of merge requests. Each one targets the branch of the one before it, so review and merge them in this order. Audit events and the documentation follow as separate merge requests.

  1. !261830 (closed): Table and model
  2. !261845 (closed): Services to turn GitLab Duo on or off
  3. !262156 (closed): Endpoint and page data
  4. !262157 (closed): Mention path (this MR)
  5. !262158 (closed): GitLab Duo section on the integration page
  6. !262159 (closed): Claim on the first group install
  7. !262160 (closed): Admin area picker (self-managed)
  8. !262161 (closed): Slack Marketplace install page
  9. !262165 (closed): Audit events
  10. !262171 (closed): Documentation

Plan and decisions: #633566. Rollout of the feature flag: #633582. Design discussion: gitlab-org#23704.

Context for review agents
  • Goal: every GitLab Duo session started from a Slack workspace runs and bills in one top-level group chosen by an Owner (the administrator on self-managed for an instance-wide install), instead of each user's default Duo namespace. Plan: #633566.
  • Everything is behind the default-off slack_duo_group feature flag (type wip, becomes beta before rollout, rolled out per top-level group). The Slack flow has its own flag slack_duo_api_flow; DuoGroup.available? requires both for the same group.
  • Deliberate decisions, do not flag them unless you find a real defect:
    • One Duo group per workspace (team_id unique), one group can run several workspaces. No organization_id column: namespace_id is the single sharding key. The unique index on team_id holds per cell only, tracked in #633611.
    • A group install claims the workspace, a project install does not. Copies of group or instance installs (inherit_from_id) never let a group claim a workspace. A workspace installed for the whole instance (self-managed only) is the administrator's to assign.
    • An unclaimed workspace has no fallback to the user's default namespace once the flag is on: the user gets a reply that says who can set it up.
    • A Duo group always runs the Slack API flow (slack_assistant/v1), the Developer flow is out. Members of the Duo group only, also on self-managed. Guests pass the membership check and are blocked later, documented as not supported for now.
    • Audit events for enable and disable come in a separate small MR before the flag leaves wip.
  • Test world for manual validation: #633566 (comment 4012898135).
  • Please look hard at: the flag actor in MentionResolver#flag_actor (the workspace's group, never the user), the interaction of the two flags, and that a failed membership or flow check never starts a session.
  • Guests pass the membership check (group.member?) and are blocked later by the workflow's own access check. This is a known limitation, documented in the docs MR.

References

Screenshots or screen recordings

None: the mention path has no UI. The replies Slack users see are described below.

How to set up and validate locally

  1. Seed the test world (users, groups and fake Slack installs in every state, no Slack needed): #633566 (comment 4012898135). Run it from your gitlab directory:

    bin/rails runner -e development seed_duo_slack.rb

    It also enables the slack_duo_group, slack_duo_agent and slack_duo_api_flow feature flags. Run it again at any time to reset all GitLab Duo state.

  2. Open bin/rails console and ask the resolver what happens to a mention, for different workspaces and people:

    duo = Integrations::SlackWorkspace::DuoGroup
    resolve = lambda do |team, username|
      result = Integrations::SlackWorkspace::DuoGroups::MentionResolver.new(
        team_id: team, user: User.find_by_username(username)
      ).execute
      next 'old behaviour (flag off)' if result.nil?
      next "runs in #{result.payload[:namespace].full_path}" if result.success?
    
      "#{result.reason} #{result.payload.compact.slice(:setup_by, :setup_group_name, :duo_group_name).inspect}"
    end
    duo.where(team_id: %w[T0WWA T0WWS T0AEZN8LUTY]).destroy_all
    
    resolve.('T0WWS', 'sd-owner')    # connected in one group, no Duo group yet
    resolve.('T0NOBODY', 'sd-owner') # unknown workspace

    Expected: duo_group_not_set_up {:setup_by=>"owner", :setup_group_name=>"sd-single"} and duo_group_not_set_up {:setup_by=>"unknown"}. On self-managed, the instance-wide workspace answers setup_by: "admin"; on GitLab.com instance-wide installs do not exist.

  3. Choose the Duo group and ask again:

    Integrations::SlackWorkspace::DuoGroups::EnableService.new(
      group: Group.find_by_full_path('sd-a'), current_user: User.find_by_username('sd-owner'), params: { team_id: 'T0WWA' }
    ).execute
    
    resolve.('T0WWA', 'sd-dev')      # => "runs in sd-a"
    resolve.('T0WWA', 'sd-outsider') # => "duo_group_not_member {}"
  4. Turn the flag off and ask again: Feature.disable(:slack_duo_group), then resolve.('T0WWA', 'sd-dev') answers old behaviour (flag off). Enable the flag again afterwards.

    Case What the Slack user gets
    Member of the Duo group The session runs in the Duo group and uses its settings and credits
    Not a member A reply naming the group (only if they can see it) and asking for access
    No Duo group yet A reply that says GitLab Duo is not set up and who can set it up
    Flag off The old behaviour, nothing changes
  5. Optional, with a real Slack workspace: mention @gitlab in Slack after the steps above, and check that the session shows up in sd-a under Automate > Sessions.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Thomas Schmidt

Merge request reports

Loading
Loading