summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-12 21:10:43 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-12 21:10:43 +0000
commit3c0d198d0c0fff5a7949f676bb6cb414908bca02 (patch)
tree3101b330803e94e2110fc71ecc6b8324a71fb66a
parentb0fe37ef58e19bc6f5d1db99f2ddc809f180a6f5 (diff)
downloadgitlab-ce-3c0d198d0c0fff5a7949f676bb6cb414908bca02.tar.gz
Add latest changes from gitlab-org/security/gitlab@12-7-stable-ee
-rw-r--r--CHANGELOG.md1
-rw-r--r--VERSION2
-rw-r--r--app/services/users/refresh_authorized_projects_service.rb16
-rw-r--r--changelogs/unreleased/202520-fix_project_auth_calculation_for_group_shares.yml5
-rw-r--r--db/post_migrate/20200204113223_schedule_recalculate_project_authorizations.rb43
-rw-r--r--db/schema.rb2
-rw-r--r--lib/gitlab/background_migration/recalculate_project_authorizations.rb42
-rw-r--r--lib/gitlab/project_authorizations.rb12
-rw-r--r--spec/factories/project_authorizations.rb9
-rw-r--r--spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb243
-rw-r--r--spec/lib/gitlab/project_authorizations_spec.rb103
-rw-r--r--spec/migrations/schedule_recalculate_project_authorizations_spec.rb57
-rw-r--r--spec/services/users/refresh_authorized_projects_service_spec.rb36
13 files changed, 500 insertions, 71 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0811554922d..f69f35c24ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,6 @@ entry.
## 12.7.5
-- No changes.
### Fixed (4 changes, 1 of them is from the community)
- Add accidentally deleted project config for custom apply suggestions. !23687 (Fabio Huser)
diff --git a/VERSION b/VERSION
index 05712205cf6..00e175c6b48 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-12.7.5
+12.7.5-ee
diff --git a/app/services/users/refresh_authorized_projects_service.rb b/app/services/users/refresh_authorized_projects_service.rb
index ae67b4f5256..0e7a4821bdf 100644
--- a/app/services/users/refresh_authorized_projects_service.rb
+++ b/app/services/users/refresh_authorized_projects_service.rb
@@ -19,8 +19,10 @@ module Users
LEASE_TIMEOUT = 1.minute.to_i
# user - The User for which to refresh the authorized projects.
- def initialize(user)
+ def initialize(user, incorrect_auth_found_callback: nil, missing_auth_found_callback: nil)
@user = user
+ @incorrect_auth_found_callback = incorrect_auth_found_callback
+ @missing_auth_found_callback = missing_auth_found_callback
# We need an up to date User object that has access to all relations that
# may have been created earlier. The only way to ensure this is to reload
@@ -55,6 +57,10 @@ module Users
# rows not in the new list or with a different access level should be
# removed.
if !fresh[project_id] || fresh[project_id] != row.access_level
+ if incorrect_auth_found_callback
+ incorrect_auth_found_callback.call(project_id, row.access_level)
+ end
+
array << row.project_id
end
end
@@ -63,6 +69,10 @@ module Users
# rows not in the old list or with a different access level should be
# added.
if !current[project_id] || current[project_id].access_level != level
+ if missing_auth_found_callback
+ missing_auth_found_callback.call(project_id, level)
+ end
+
array << [user.id, project_id, level]
end
end
@@ -104,5 +114,9 @@ module Users
def fresh_authorizations
Gitlab::ProjectAuthorizations.new(user).calculate
end
+
+ private
+
+ attr_reader :incorrect_auth_found_callback, :missing_auth_found_callback
end
end
diff --git a/changelogs/unreleased/202520-fix_project_auth_calculation_for_group_shares.yml b/changelogs/unreleased/202520-fix_project_auth_calculation_for_group_shares.yml
new file mode 100644
index 00000000000..5dd163749f2
--- /dev/null
+++ b/changelogs/unreleased/202520-fix_project_auth_calculation_for_group_shares.yml
@@ -0,0 +1,5 @@
+---
+title: Fix ProjectAuthorization calculation for shared groups
+merge_request:
+author:
+type: security
diff --git a/db/post_migrate/20200204113223_schedule_recalculate_project_authorizations.rb b/db/post_migrate/20200204113223_schedule_recalculate_project_authorizations.rb
new file mode 100644
index 00000000000..83b58300115
--- /dev/null
+++ b/db/post_migrate/20200204113223_schedule_recalculate_project_authorizations.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+class ScheduleRecalculateProjectAuthorizations < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ MIGRATION = 'RecalculateProjectAuthorizations'
+ BATCH_SIZE = 2_500
+ DELAY_INTERVAL = 2.minutes.to_i
+
+ disable_ddl_transaction!
+
+ class Namespace < ActiveRecord::Base
+ include ::EachBatch
+
+ self.table_name = 'namespaces'
+ end
+
+ class ProjectAuthorization < ActiveRecord::Base
+ include ::EachBatch
+
+ self.table_name = 'project_authorizations'
+ end
+
+ def up
+ say "Scheduling #{MIGRATION} jobs"
+
+ max_group_id = Namespace.where(type: 'Group').maximum(:id)
+ project_authorizations = ProjectAuthorization.where('project_id <= ?', max_group_id)
+ .select(:user_id)
+ .distinct
+
+ project_authorizations.each_batch(of: BATCH_SIZE, column: :user_id) do |authorizations, index|
+ delay = index * DELAY_INTERVAL
+ user_ids = authorizations.map(&:user_id)
+ BackgroundMigrationWorker.perform_in(delay, MIGRATION, [user_ids])
+ end
+ end
+
+ def down
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 528631c4b36..41bebdb8eac 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2020_01_27_090233) do
+ActiveRecord::Schema.define(version: 2020_02_04_113223) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
diff --git a/lib/gitlab/background_migration/recalculate_project_authorizations.rb b/lib/gitlab/background_migration/recalculate_project_authorizations.rb
new file mode 100644
index 00000000000..3d2ce9fc10c
--- /dev/null
+++ b/lib/gitlab/background_migration/recalculate_project_authorizations.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # rubocop:disable Style/Documentation
+ class RecalculateProjectAuthorizations
+ def perform(user_ids)
+ user_ids.each do |user_id|
+ user = User.find_by(id: user_id)
+
+ next unless user
+
+ service = Users::RefreshAuthorizedProjectsService.new(
+ user,
+ incorrect_auth_found_callback:
+ ->(project_id, access_level) do
+ logger.info(message: 'Removing ProjectAuthorizations',
+ user_id: user.id,
+ project_id: project_id,
+ access_level: access_level)
+ end,
+ missing_auth_found_callback:
+ ->(project_id, access_level) do
+ logger.info(message: 'Creating ProjectAuthorizations',
+ user_id: user.id,
+ project_id: project_id,
+ access_level: access_level)
+ end
+ )
+
+ service.execute
+ end
+ end
+
+ private
+
+ def logger
+ @logger ||= Gitlab::BackgroundMigration::Logger.build
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/project_authorizations.rb b/lib/gitlab/project_authorizations.rb
index e2271b1492c..d65e8759ec9 100644
--- a/lib/gitlab/project_authorizations.rb
+++ b/lib/gitlab/project_authorizations.rb
@@ -68,12 +68,10 @@ module Gitlab
.select([namespaces[:id], members[:access_level]])
.except(:order)
- if Feature.enabled?(:share_group_with_group, default_enabled: true)
- # Namespaces shared with any of the group
- cte << Group.select([namespaces[:id], 'group_group_links.group_access AS access_level'])
- .joins(join_group_group_links)
- .joins(join_members_on_group_group_links)
- end
+ # Namespaces shared with any of the group
+ cte << Group.select([namespaces[:id], 'group_group_links.group_access AS access_level'])
+ .joins(join_group_group_links)
+ .joins(join_members_on_group_group_links)
# Sub groups of any groups the user is a member of.
cte << Group.select([
@@ -114,6 +112,8 @@ module Gitlab
members = Member.arel_table
cond = group_group_links[:shared_with_group_id].eq(members[:source_id])
+ .and(members[:source_type].eq('Namespace'))
+ .and(members[:requested_at].eq(nil))
.and(members[:user_id].eq(user.id))
Arel::Nodes::InnerJoin.new(members, Arel::Nodes::On.new(cond))
end
diff --git a/spec/factories/project_authorizations.rb b/spec/factories/project_authorizations.rb
new file mode 100644
index 00000000000..ffdf5576f84
--- /dev/null
+++ b/spec/factories/project_authorizations.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :project_authorization do
+ user
+ project
+ access_level { Gitlab::Access::REPORTER }
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb
new file mode 100644
index 00000000000..1ef2c451aa2
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb
@@ -0,0 +1,243 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizations, :migration, schema: 20200204113223 do
+ let(:users_table) { table(:users) }
+ let(:namespaces_table) { table(:namespaces) }
+ let(:projects_table) { table(:projects) }
+ let(:project_authorizations_table) { table(:project_authorizations) }
+ let(:members_table) { table(:members) }
+ let(:group_group_links) { table(:group_group_links) }
+ let(:project_group_links) { table(:project_group_links) }
+
+ let(:user) { users_table.create!(id: 1, email: 'user@example.com', projects_limit: 10) }
+ let(:group) { namespaces_table.create!(type: 'Group', name: 'group', path: 'group') }
+
+ subject { described_class.new.perform([user.id]) }
+
+ context 'missing authorization' do
+ context 'personal project' do
+ before do
+ user_namespace = namespaces_table.create!(owner_id: user.id, name: 'User', path: 'user')
+ projects_table.create!(id: 1,
+ name: 'personal-project',
+ path: 'personal-project',
+ visibility_level: 0,
+ namespace_id: user_namespace.id)
+ end
+
+ it 'creates correct authorization' do
+ expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
+ expect(project_authorizations_table.all).to(
+ match_array([have_attributes(user_id: 1, project_id: 1, access_level: 40)]))
+ end
+ end
+
+ context 'group membership' do
+ before do
+ projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
+ visibility_level: 0, namespace_id: group.id)
+ members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
+ type: 'GroupMember', access_level: 20, notification_level: 3)
+ end
+
+ it 'creates correct authorization' do
+ expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
+ expect(project_authorizations_table.all).to(
+ match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
+ end
+ end
+
+ context 'inherited group membership' do
+ before do
+ sub_group = namespaces_table.create!(type: 'Group', name: 'subgroup',
+ path: 'subgroup', parent_id: group.id)
+ projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
+ visibility_level: 0, namespace_id: sub_group.id)
+ members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
+ type: 'GroupMember', access_level: 20, notification_level: 3)
+ end
+
+ it 'creates correct authorization' do
+ expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
+ expect(project_authorizations_table.all).to(
+ match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
+ end
+ end
+
+ context 'project membership' do
+ before do
+ project = projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
+ visibility_level: 0, namespace_id: group.id)
+ members_table.create!(user_id: user.id, source_id: project.id, source_type: 'Project',
+ type: 'ProjectMember', access_level: 20, notification_level: 3)
+ end
+
+ it 'creates correct authorization' do
+ expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
+ expect(project_authorizations_table.all).to(
+ match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
+ end
+ end
+
+ context 'shared group' do
+ before do
+ members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
+ type: 'GroupMember', access_level: 30, notification_level: 3)
+
+ shared_group = namespaces_table.create!(type: 'Group', name: 'shared group',
+ path: 'shared-group')
+ projects_table.create!(id: 1, name: 'project', path: 'project', visibility_level: 0,
+ namespace_id: shared_group.id)
+
+ group_group_links.create(shared_group_id: shared_group.id, shared_with_group_id: group.id,
+ group_access: 20)
+ end
+
+ it 'creates correct authorization' do
+ expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
+ expect(project_authorizations_table.all).to(
+ match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
+ end
+ end
+
+ context 'shared project' do
+ before do
+ members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
+ type: 'GroupMember', access_level: 30, notification_level: 3)
+
+ another_group = namespaces_table.create!(type: 'Group', name: 'another group', path: 'another-group')
+ shared_project = projects_table.create!(id: 1, name: 'shared project', path: 'shared-project',
+ visibility_level: 0, namespace_id: another_group.id)
+
+ project_group_links.create(project_id: shared_project.id, group_id: group.id, group_access: 20)
+ end
+
+ it 'creates correct authorization' do
+ expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
+ expect(project_authorizations_table.all).to(
+ match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
+ end
+ end
+ end
+
+ context 'unapproved access requests' do
+ context 'group membership' do
+ before do
+ projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
+ visibility_level: 0, namespace_id: group.id)
+ members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
+ type: 'GroupMember', access_level: 20, requested_at: Time.now, notification_level: 3)
+ end
+
+ it 'does not create authorization' do
+ expect { subject }.not_to change { project_authorizations_table.count }.from(0)
+ end
+ end
+
+ context 'inherited group membership' do
+ before do
+ sub_group = namespaces_table.create!(type: 'Group', name: 'subgroup', path: 'subgroup',
+ parent_id: group.id)
+ projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
+ visibility_level: 0, namespace_id: sub_group.id)
+ members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
+ type: 'GroupMember', access_level: 20, requested_at: Time.now, notification_level: 3)
+ end
+
+ it 'does not create authorization' do
+ expect { subject }.not_to change { project_authorizations_table.count }.from(0)
+ end
+ end
+
+ context 'project membership' do
+ before do
+ project = projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
+ visibility_level: 0, namespace_id: group.id)
+ members_table.create!(user_id: user.id, source_id: project.id, source_type: 'Project',
+ type: 'ProjectMember', access_level: 20, requested_at: Time.now, notification_level: 3)
+ end
+
+ it 'does not create authorization' do
+ expect { subject }.not_to change { project_authorizations_table.count }.from(0)
+ end
+ end
+
+ context 'shared group' do
+ before do
+ members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
+ type: 'GroupMember', access_level: 30, requested_at: Time.now, notification_level: 3)
+
+ shared_group = namespaces_table.create!(type: 'Group', name: 'shared group',
+ path: 'shared-group')
+ projects_table.create!(id: 1, name: 'project', path: 'project', visibility_level: 0,
+ namespace_id: shared_group.id)
+
+ group_group_links.create(shared_group_id: shared_group.id, shared_with_group_id: group.id,
+ group_access: 20)
+ end
+
+ it 'does not create authorization' do
+ expect { subject }.not_to change { project_authorizations_table.count }.from(0)
+ end
+ end
+
+ context 'shared project' do
+ before do
+ members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
+ type: 'GroupMember', access_level: 30, requested_at: Time.now, notification_level: 3)
+
+ another_group = namespaces_table.create!(type: 'Group', name: 'another group', path: 'another-group')
+ shared_project = projects_table.create!(id: 1, name: 'shared project', path: 'shared-project',
+ visibility_level: 0, namespace_id: another_group.id)
+
+ project_group_links.create(project_id: shared_project.id, group_id: group.id, group_access: 20)
+ end
+
+ it 'does not create authorization' do
+ expect { subject }.not_to change { project_authorizations_table.count }.from(0)
+ end
+ end
+ end
+
+ context 'incorrect authorization' do
+ before do
+ project = projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
+ visibility_level: 0, namespace_id: group.id)
+ members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
+ type: 'GroupMember', access_level: 30, notification_level: 3)
+
+ project_authorizations_table.create!(user_id: user.id, project_id: project.id,
+ access_level: 10)
+ end
+
+ it 'fixes authorization' do
+ expect { subject }.not_to change { project_authorizations_table.count }.from(1)
+ expect(project_authorizations_table.all).to(
+ match_array([have_attributes(user_id: 1, project_id: 1, access_level: 30)]))
+ end
+ end
+
+ context 'unwanted authorization' do
+ before do
+ project = projects_table.create!(name: 'group-project', path: 'group-project',
+ visibility_level: 0, namespace_id: group.id)
+
+ project_authorizations_table.create!(user_id: user.id, project_id: project.id,
+ access_level: 10)
+ end
+
+ it 'deletes authorization' do
+ expect { subject }.to change { project_authorizations_table.count }.from(1).to(0)
+ end
+ end
+
+ context 'deleted user' do
+ let(:nonexistent_user_id) { User.maximum(:id).to_i + 999 }
+
+ it 'does not fail' do
+ expect { described_class.new.perform([nonexistent_user_id]) }.not_to raise_error
+ end
+ end
+end
diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb
index 6e5c36172e2..1c579128223 100644
--- a/spec/lib/gitlab/project_authorizations_spec.rb
+++ b/spec/lib/gitlab/project_authorizations_spec.rb
@@ -97,87 +97,68 @@ describe Gitlab::ProjectAuthorizations do
create(:group_group_link, shared_group: shared_group, shared_with_group: group)
end
- context 'when feature flag share_group_with_group is enabled' do
- before do
- stub_feature_flags(share_group_with_group: true)
- end
-
- context 'group user' do
- let(:user) { group_user }
+ context 'group user' do
+ let(:user) { group_user }
- it 'creates proper authorizations' do
- mapping = map_access_levels(authorizations)
+ it 'creates proper authorizations' do
+ mapping = map_access_levels(authorizations)
- expect(mapping[project_parent.id]).to be_nil
- expect(mapping[project.id]).to eq(Gitlab::Access::DEVELOPER)
- expect(mapping[project_child.id]).to eq(Gitlab::Access::DEVELOPER)
- end
+ expect(mapping[project_parent.id]).to be_nil
+ expect(mapping[project.id]).to eq(Gitlab::Access::DEVELOPER)
+ expect(mapping[project_child.id]).to eq(Gitlab::Access::DEVELOPER)
end
+ end
- context 'parent group user' do
- let(:user) { parent_group_user }
+ context 'parent group user' do
+ let(:user) { parent_group_user }
- it 'creates proper authorizations' do
- mapping = map_access_levels(authorizations)
+ it 'creates proper authorizations' do
+ mapping = map_access_levels(authorizations)
- expect(mapping[project_parent.id]).to be_nil
- expect(mapping[project.id]).to be_nil
- expect(mapping[project_child.id]).to be_nil
- end
+ expect(mapping[project_parent.id]).to be_nil
+ expect(mapping[project.id]).to be_nil
+ expect(mapping[project_child.id]).to be_nil
end
+ end
- context 'child group user' do
- let(:user) { child_group_user }
+ context 'child group user' do
+ let(:user) { child_group_user }
- it 'creates proper authorizations' do
- mapping = map_access_levels(authorizations)
+ it 'creates proper authorizations' do
+ mapping = map_access_levels(authorizations)
- expect(mapping[project_parent.id]).to be_nil
- expect(mapping[project.id]).to be_nil
- expect(mapping[project_child.id]).to be_nil
- end
+ expect(mapping[project_parent.id]).to be_nil
+ expect(mapping[project.id]).to be_nil
+ expect(mapping[project_child.id]).to be_nil
end
end
- context 'when feature flag share_group_with_group is disabled' do
- before do
- stub_feature_flags(share_group_with_group: false)
- end
-
- context 'group user' do
- let(:user) { group_user }
-
- it 'creates proper authorizations' do
- mapping = map_access_levels(authorizations)
+ context 'user without accepted access request' do
+ let!(:user) { create(:user) }
- expect(mapping[project_parent.id]).to be_nil
- expect(mapping[project.id]).to be_nil
- expect(mapping[project_child.id]).to be_nil
- end
- end
+ it 'does not have access to group and its projects' do
+ create(:group_member, :developer, :access_request, user: user, group: group)
- context 'parent group user' do
- let(:user) { parent_group_user }
+ mapping = map_access_levels(authorizations)
- it 'creates proper authorizations' do
- mapping = map_access_levels(authorizations)
-
- expect(mapping[project_parent.id]).to be_nil
- expect(mapping[project.id]).to be_nil
- expect(mapping[project_child.id]).to be_nil
- end
+ expect(mapping[project_parent.id]).to be_nil
+ expect(mapping[project.id]).to be_nil
+ expect(mapping[project_child.id]).to be_nil
end
+ end
- context 'child group user' do
- let(:user) { child_group_user }
+ context 'unrelated project owner' do
+ let(:common_id) { [Project.maximum(:id).to_i, Namespace.maximum(:id).to_i].max + 999 }
+ let!(:group) { create(:group, id: common_id) }
+ let!(:unrelated_project) { create(:project, id: common_id) }
+ let(:user) { unrelated_project.owner }
- it 'creates proper authorizations' do
- mapping = map_access_levels(authorizations)
+ it 'does not have access to group and its projects' do
+ mapping = map_access_levels(authorizations)
- expect(mapping[project_parent.id]).to be_nil
- expect(mapping[project.id]).to be_nil
- expect(mapping[project_child.id]).to be_nil
- end
+ expect(mapping[project_parent.id]).to be_nil
+ expect(mapping[project.id]).to be_nil
+ expect(mapping[project_child.id]).to be_nil
end
end
end
diff --git a/spec/migrations/schedule_recalculate_project_authorizations_spec.rb b/spec/migrations/schedule_recalculate_project_authorizations_spec.rb
new file mode 100644
index 00000000000..a739606ca8f
--- /dev/null
+++ b/spec/migrations/schedule_recalculate_project_authorizations_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20200204113223_schedule_recalculate_project_authorizations.rb')
+
+describe ScheduleRecalculateProjectAuthorizations, :migration, :sidekiq do
+ let(:users_table) { table(:users) }
+ let(:namespaces_table) { table(:namespaces) }
+ let(:projects_table) { table(:projects) }
+ let(:project_authorizations_table) { table(:project_authorizations) }
+
+ let(:user1) { users_table.create!(name: 'user1', email: 'user1@example.com', projects_limit: 1) }
+ let(:user2) { users_table.create!(name: 'user2', email: 'user2@example.com', projects_limit: 1) }
+ let(:group) { namespaces_table.create!(id: 1, type: 'Group', name: 'group', path: 'group') }
+ let(:project) do
+ projects_table.create!(id: 1, name: 'project', path: 'project',
+ visibility_level: 0, namespace_id: group.id)
+ end
+
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+
+ project_authorizations_table.create!(user_id: user1.id, project_id: project.id, access_level: 30)
+ project_authorizations_table.create!(user_id: user2.id, project_id: project.id, access_level: 30)
+ end
+
+ it 'schedules background migration' do
+ Sidekiq::Testing.fake! do
+ Timecop.freeze do
+ migrate!
+
+ expect(BackgroundMigrationWorker.jobs.size).to eq(2)
+ expect(described_class::MIGRATION).to be_scheduled_migration([user1.id])
+ expect(described_class::MIGRATION).to be_scheduled_migration([user2.id])
+ end
+ end
+ end
+
+ it 'ignores projects with higher id than maximum group id' do
+ another_user = users_table.create!(name: 'another user', email: 'another-user@example.com',
+ projects_limit: 1)
+ ignored_project = projects_table.create!(id: 2, name: 'ignored-project', path: 'ignored-project',
+ visibility_level: 0, namespace_id: group.id)
+ project_authorizations_table.create!(user_id: another_user.id, project_id: ignored_project.id,
+ access_level: 30)
+
+ Sidekiq::Testing.fake! do
+ Timecop.freeze do
+ migrate!
+
+ expect(BackgroundMigrationWorker.jobs.size).to eq(2)
+ expect(described_class::MIGRATION).to be_scheduled_migration([user1.id])
+ expect(described_class::MIGRATION).to be_scheduled_migration([user2.id])
+ end
+ end
+ end
+end
diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb
index f5a914bb482..d7ba7f5f69e 100644
--- a/spec/services/users/refresh_authorized_projects_service_spec.rb
+++ b/spec/services/users/refresh_authorized_projects_service_spec.rb
@@ -22,6 +22,42 @@ describe Users::RefreshAuthorizedProjectsService do
service.execute
end
+
+ context 'callbacks' do
+ let(:callback) { double('callback') }
+
+ context 'incorrect_auth_found_callback callback' do
+ let(:user) { create(:user) }
+ let(:service) do
+ described_class.new(user,
+ incorrect_auth_found_callback: callback)
+ end
+
+ it 'is called' do
+ access_level = Gitlab::Access::DEVELOPER
+ create(:project_authorization, user: user, project: project, access_level: access_level)
+
+ expect(callback).to receive(:call).with(project.id, access_level).once
+
+ service.execute
+ end
+ end
+
+ context 'missing_auth_found_callback callback' do
+ let(:service) do
+ described_class.new(user,
+ missing_auth_found_callback: callback)
+ end
+
+ it 'is called' do
+ ProjectAuthorization.delete_all
+
+ expect(callback).to receive(:call).with(project.id, Gitlab::Access::MAINTAINER).once
+
+ service.execute
+ end
+ end
+ end
end
describe '#execute_without_lease' do