Skip to content
代码片段 群组 项目
未验证 提交 743c9ea7 编辑于 作者: mo khan's avatar mo khan 提交者: GitLab
浏览文件

Filter dependencies by project membership

上级 620482f1
No related branches found
No related tags found
无相关合并请求
...@@ -133,7 +133,8 @@ class Occurrence < ApplicationRecord ...@@ -133,7 +133,8 @@ class Occurrence < ApplicationRecord
scope :visible_to, ->(user) do scope :visible_to, ->(user) do
return self if user.can_read_all_resources? return self if user.can_read_all_resources?
where(project_id: user.project_authorizations.select(:project_id)) joins(project: [:project_authorizations])
.where(project_authorizations: { user_id: user.id })
end end
def location def location
......
...@@ -14,7 +14,7 @@ def filename ...@@ -14,7 +14,7 @@ def filename
def each def each
yield header yield header
each_batch do |batch| iterator.each_batch do |batch|
build_list_for(batch).each do |occurrence| build_list_for(batch).each do |occurrence|
yield to_csv([ yield to_csv([
occurrence.component_name, occurrence.component_name,
...@@ -34,10 +34,23 @@ def header ...@@ -34,10 +34,23 @@ def header
to_csv(%w[Name Version Packager Location]) to_csv(%w[Name Version Packager Location])
end end
def each_batch def iterator
Gitlab::Pagination::Keyset::Iterator if export.organization.owner?(export.author) || export.author.can_read_all_resources?
.new(scope: export.organization.sbom_occurrences) Gitlab::Pagination::Keyset::Iterator
.each_batch { |batch| yield batch } .new(scope: export.organization.sbom_occurrences)
else
clazz = ::Sbom::Occurrence
# rubocop: disable CodeReuse/ActiveRecord -- where clause
Gitlab::Pagination::Keyset::Iterator.new(
scope: export.organization.sbom_occurrences.order(:id),
in_operator_optimization_options: {
array_scope: export.author.project_authorizations.select(:project_id),
array_mapping_scope: ->(id) { clazz.where(clazz.arel_table[:project_id].eq(id)) },
finder_query: ->(id) { clazz.where(clazz.arel_table[:id].eq(id)) }
}
)
# rubocop: enable CodeReuse/ActiveRecord
end
end end
def build_list_for(batch) def build_list_for(batch)
......
...@@ -204,7 +204,7 @@ ...@@ -204,7 +204,7 @@
end end
end end
context 'when user is not admin' do context 'when the user is not a member of the default organization' do
let_it_be(:user) { create(:user, :without_default_org) } let_it_be(:user) { create(:user, :without_default_org) }
before do before do
......
...@@ -4,8 +4,9 @@ ...@@ -4,8 +4,9 @@
RSpec.describe Dependencies::ExportSerializers::OrganizationDependenciesService, feature_category: :dependency_management do RSpec.describe Dependencies::ExportSerializers::OrganizationDependenciesService, feature_category: :dependency_management do
let_it_be(:organization) { create(:organization) } let_it_be(:organization) { create(:organization) }
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:project) { create(:project, organization: organization) } let_it_be_with_reload(:project) { create(:project, organization: organization) }
let_it_be(:export) { create(:dependency_list_export, project: nil, organization: organization) } let_it_be(:export) { create(:dependency_list_export, project: nil, organization: organization, author: user) }
let(:service_class) { described_class.new(export) } let(:service_class) { described_class.new(export) }
...@@ -26,16 +27,61 @@ ...@@ -26,16 +27,61 @@
create(:sbom_occurrence, :mit, project: project, component: bundler, component_version: bundler_v1) create(:sbom_occurrence, :mit, project: project, component: bundler, component_version: bundler_v1)
end end
it 'includes each occurrence' do context 'when the user is an organization owner' do
expect(dependencies).to match_array([ let_it_be(:organization_user) { create(:organization_user, :owner, organization: organization, user: user) }
header,
CSV.generate_line([ it 'includes each occurrence', :aggregate_failures do
occurrence_1.component_name, expect(dependencies.count).to eq(2)
occurrence_1.version, expect(dependencies).to match_array([
occurrence_1.package_manager, header,
occurrence_1.location[:blob_path] CSV.generate_line([
], force_quotes: true) occurrence_1.component_name,
]) occurrence_1.version,
occurrence_1.package_manager,
occurrence_1.location[:blob_path]
], force_quotes: true)
])
end
end
context 'when the user is an admin', :enable_admin_mode do
before_all do
user.update!(admin: true)
end
it 'includes each occurrence' do
expect(dependencies).to match_array([
header,
CSV.generate_line([
occurrence_1.component_name,
occurrence_1.version,
occurrence_1.package_manager,
occurrence_1.location[:blob_path]
], force_quotes: true)
])
end
end
context 'when the user has limited access' do
let_it_be(:other_project) { create(:project, organization: organization) }
let_it_be(:visible_occurrence) { create(:sbom_occurrence, project: other_project) }
before_all do
other_project.add_developer(export.author)
end
it 'includes each occurrence they have access to', :aggregate_failures do
expect(dependencies.count).to eq(2)
expect(dependencies).to match_array([
header,
CSV.generate_line([
visible_occurrence.component_name,
visible_occurrence.version,
visible_occurrence.package_manager,
visible_occurrence.location[:blob_path]
], force_quotes: true)
])
end
end end
it 'avoids N+1 queries' do it 'avoids N+1 queries' do
......
...@@ -92,9 +92,13 @@ ...@@ -92,9 +92,13 @@
let_it_be(:organization) { create(:organization) } let_it_be(:organization) { create(:organization) }
let_it_be(:project) { create(:project, organization: organization) } let_it_be(:project) { create(:project, organization: organization) }
let_it_be(:occurrences) { create_list(:sbom_occurrence, 2, project: project) } let_it_be(:occurrences) { create_list(:sbom_occurrence, 2, project: project) }
let(:export) { create(:dependency_list_export, project: nil, exportable: organization) } let_it_be_with_reload(:export) { create(:dependency_list_export, project: nil, exportable: organization) }
let(:expected_filename) { "#{organization.to_param}_dependencies_#{timestamp}.csv" } let(:expected_filename) { "#{organization.to_param}_dependencies_#{timestamp}.csv" }
before_all do
project.add_developer(export.author)
end
it { expect(execute).to be_present } it { expect(execute).to be_present }
it { expect { execute }.to change { export.file.filename }.to(expected_filename) } it { expect { execute }.to change { export.file.filename }.to(expected_filename) }
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册