[go: up one dir, main page]

Draft: Mark Organization and Group as "not isolated"

What does this MR do and why?

Most data in the database belongs to an organization and in many cases also to a namespace. If we want to transfer a Top Level Group to an organization, we need to be sure that all the data in that group is part of the same organization.

We expect that the logic will work like this:

  • A crawler will establish that a group is isolated
  • The logic in this MR will check if the group (or organization) is still isolated

Implementation

  • after_commit, we check if any belongs_to associations have been updated
  • If so, a Organizations::CheckOrganizationIsolationStatusWorker is scheduled. Arguments: model name, record id, changed fields
  • The worker returns if the record is not found or the state of the record has been changed
  • The worker will call Gitlab::Organizations::IsolationStatus.new(record, changed_associations).verify!
  • This class will check if the record and the updated belongs_to record belong to the same organization.
  • If they don't match, the isolation state of the Organization and (if exist) the Namespace will be changed to false

References

Related to #577780

How to set up and validate locally

Adding a member to a group

While working in Default Organization, we will invate an user from another organization. This will change the isolation status to false for both the group and the organization

Use rails console to create a user in another user:

my_org = Organizations::Organization.find_or_create_by!(path: 'my-org') { |org| org.name = 'My Org' }

# Mark groups and organizations as isolated
Organizations::Organization.all.each{|o| o.mark_as_isolated! }
Group.all.each{|g| g.mark_as_isolated!}

root = User.find_by(username: 'root')
other_user = User.find_by(username: 'user-in-my-org') || ::Users::AuthorizedCreateService.new(root, {name: 'User In MyOrg', username: 'user-in-my-org', organization_id: my_org.id, email: 'test@example.org', password: 'r234234cc#'}).execute

# We will use the group 'twitter' and the 'Default org'
# Both should be isolated:
Group.find_by(path: 'twitter').isolated?
Organizations::Organization.find_by(path: 'default').isolated?

Use the web interface to add a user to 'Twitter' group

Return to Rails console and check isolation status:

Group.find_by(path: 'twitter').isolated?
Organizations::Organization.find_by(path: 'default').isolated?

# Remove member
other_user.destroy

Test composite primary key

my_org = Organizations::Organization.find_or_create_by!(path: 'my-org') { |org| org.name = 'My Org' }

# Mark groups and organizations as isolated
Organizations::Organization.all.each{|o| o.mark_as_isolated! }
Group.all.each{|g| g.mark_as_isolated!}

root = User.find_by(username: 'root')
other_user = User.find_by(username: 'user-in-my-org') || ::Users::AuthorizedCreateService.new(root, {name: 'User In MyOrg', username: 'user-in-my-org', organization_id: my_org.id, email: 'test@example.org', password: 'r234234cc#'}).execute

root.organization.isolated? # true

Now, while logged in as user root:

root.organization.isolated? # Is now false

# Cleanup
Users::UserFollowUser.where(follower: root, followee: other_user).delete_all

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 Rutger Wessels

Merge request reports

Loading