Draft: [skip ci] Claim a Slack workspace on the first group install

What does this MR do and why?

The easiest moment to choose where GitLab Duo runs is when an Owner installs the GitLab for Slack app on a group. This MR makes the first install of the app on a top-level group claim the Slack workspace for that group, so GitLab Duo works right after the install without another click. A reinstall never claims again, so an Owner who turned GitLab Duo off or moved it stays in control, and a claim that is refused never fails the install.

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

What's in it

  • EE::Integrations::SlackInstallation::GroupService: after the first install on a top-level group, it calls EnableService for the workspace that was just installed. Subgroups and reinstalls do nothing.
  • A refused claim never fails the install. The OAuth code from Slack is single-use, so nothing after saving the install may raise. A workspace that already runs GitLab Duo in another group, or an instance-wide workspace an Owner cannot claim, only leaves things as they were. Unexpected errors are reported to error tracking, a refusal is logged.
  • A tiny CE change: prepend_mod on the FOSS service.
  • With the flag off the claim is skipped before any work, so nothing is logged for the normal case.

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
  5. !262158 (closed): GitLab Duo section on the integration page
  6. !262159 (closed): Claim on the first group install (this MR)
  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: that claim_workspace can never raise out of the install flow (rescue StandardError plus error tracking), and the choice to hook on update_installation! with new_record? as the "first install" signal.
  • The CE spec for SlackInstallation::GroupService runs with this prepend active and still passes.

References

Screenshots or screen recordings

None: there is nothing to see in the UI, the result shows on the integration page of the previous MR.

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. Simulate a first install without a real Slack workspace. Open bin/rails console and run this. It pretends to be Slack for the OAuth code exchange and installs the app on a new group sd-claim twice:

    # A fake Slack that answers the OAuth code exchange for the workspace T0CLAIMDEMO.
    Integrations::SlackInstallation::BaseService.prepend(Module.new do
      private
    
      def exchange_slack_token
        { 'ok' => true, 'bot_user_id' => 'UBOT', 'access_token' => 'xoxb-demo',
          'team' => { 'id' => 'T0CLAIMDEMO', 'name' => 'Claim demo' }, 'authed_user' => { 'id' => 'UDEMO' },
          'scope' => 'app_mentions:read,chat:write' }
      end
    end)
    Gitlab::CurrentSettings.current_application_settings.update!(slack_app_enabled: true)
    
    owner = User.find_by_username('sd-owner')
    group = Groups::CreateService.new(User.admins.first, { name: 'sd-claim', path: 'sd-claim',
      organization_id: Organizations::Organization.default_organization.id }).execute.payload[:group]
    group.add_owner(owner)
    group.namespace_settings.update!(duo_features_enabled: true, duo_foundational_flows_enabled: true, experiment_features_enabled: true)
    (group.ai_settings || group.build_ai_settings).update!(duo_agent_platform_enabled: true)
    
    duo = Integrations::SlackWorkspace::DuoGroup
    install = -> { Integrations::SlackInstallation::GroupService.new(group, current_user: owner, params: { code: 'x' }).execute.success? }
    
    install.call                                  # => true
    duo.for_team('T0CLAIMDEMO').namespace.full_path # => "sd-claim"
    
    duo.where(team_id: 'T0CLAIMDEMO').destroy_all   # the Owner turns GitLab Duo off
    install.call                                  # => true, a reinstall
    duo.for_team('T0CLAIMDEMO')                   # => nil, not claimed again
  3. Open http://gdk.test:3000/groups/sd-claim/-/settings/integrations/gitlab_slack_application/edit between the two installs: after the first one, GitLab Duo is On and ready.

    Step What it shows
    First install The group becomes the Duo group, the Slack flow is on
    Reinstall after turning Duo off Not claimed again, the Owner stays in control
  4. Optional, with a real Slack app and a tunnel: install the app on a group from its integration page and check that the page shows GitLab Duo On.

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