Add slack_workspaces table and model for GitLab Duo in Slack
What does this MR do and why?
Today a Slack @GitLab mention runs and bills in the mentioning user's default GitLab Duo namespace, so people in the same Slack workspace end up in different groups. In the new design, each Slack workspace (team_id) runs GitLab Duo in exactly one top-level group, the "Duo group". An Owner of that group chooses it, or the administrator does for instance-wide installs on self-managed. No row means GitLab Duo is off for that workspace.
This MR adds the data model:
- New
slack_workspacestable:team_idunique,duo_namespace_idforeign key tonamespaceswithON DELETE CASCADE, which is also the sharding key. Integrations::SlackWorkspace::Workspacemodel, factory, development fixture,db/docsentries including the data retention policy.
No callers, no queries, no feature flag. The eligibility rule, the services, the mention path and the UI follow in later merge requests of #633566.
Why a separate table
A Slack workspace's Duo group is a decision an Owner makes once. slack_integrations rows are not decisions, they are copies: a group install propagates a row to every subgroup and project, and Integrations::SlackInstallation::BaseService#update_other_installations! mass-updates every row that shares a team_id. The comment above that method calls the duplication a modelling problem that GitLab papers over. Storing the Duo group there would put the Owner's choice on a row the install service creates, rewrites and deletes.
The table is named after the workspace, not after GitLab Duo, so that the bot token and scopes can move into it later (#636530). That turns the existing modelling debt into a merge into this table rather than a reshape.
Cells
- Sharding key
duo_namespace_id. Every row belongs to exactly one top-level group, so this is the most specific key. It follows the group on transfers, so there is noorganization_idcopy to keep in sync. Changed in review: !263649 (comment 4100379399) - Unique index on
team_idis global, because one Slack workspace has exactly one Duo group. Scoping it toduo_namespace_idwould enforce nothing. Same shape asjira_connect_installations.forge_installation_xid, which keeps its global index next to its Cells claim. - The Cells claim for
team_idlands before any code writes rows. This MR adds no writers. The claim needs a new claim type in the Topology Service and is tracked in #633611. MR 3 of #633566, the first one that creates rows, does not merge without it. - Changing the Duo group of a workspace means a new row. The sharding key is immutable, so the admin picker in a later MR deletes and recreates the row instead of updating
duo_namespace_id.
For the database reviewer
- Cascade-only deletion.
slack_workspaces.duo_namespace_idis listed inspec/support/database/destroy_service_foreign_keys_todo.yml: the row has no application cleanup of its own. Approved in review.
Migration output
== 20261020112417 CreateSlackWorkspaces: migrating ============================
-- create_table(:slack_workspaces)
-> 0.0356s
== 20261020112418 AddSlackWorkspacesForeignKeys: migrating ====================
-- ALTER TABLE slack_workspaces ADD CONSTRAINT fk_717a4fd17f FOREIGN KEY (duo_namespace_id) REFERENCES namespaces (id) ON DELETE CASCADEBoth migrations roll back cleanly. db:gitlabcom-database-testing ran them on GitLab.com data at 769fc6d1: 3.5 s and 3.6 s on main, +40 KiB, no failures on main, ci or sec.
References
- Implementation issue: #633566
- Reference MR, full build, not to merge: !262856 (closed)
How to set up and validate locally
bundle exec rails db:migratebundle exec rspec ee/spec/models/integrations/slack_workspace/workspace_spec.rbbundle exec rake db:seed_fu FILTER=slack_workspaces
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.