Commit e9c2fc48 authored by Robert Speicher's avatar Robert Speicher

Merge branch 'filter-commit-sha' into 'master'

Chain of custody report filter by merge commit sha

See merge request gitlab-org/gitlab!46581
parents 48e33a5e 4a293726
......@@ -7,15 +7,21 @@ class Groups::Security::MergeCommitReportsController < Groups::ApplicationContro
feature_category :compliance_management
def index
csv_data = MergeCommits::ExportCsvService.new(current_user, group).csv_data
response = MergeCommits::ExportCsvService.new(current_user, group, filter_params).csv_data
respond_to do |format|
format.csv do
if response&.success?
send_data(
csv_data,
response.payload,
type: 'text/csv; charset=utf-8; header=present',
filename: merge_commits_csv_filename
)
else
flash[:alert] = _('An error occurred while trying to generate the report. Please try again later.')
redirect_to group_security_compliance_dashboard_path(group)
end
end
end
end
......@@ -25,4 +31,8 @@ class Groups::Security::MergeCommitReportsController < Groups::ApplicationContro
def merge_commits_csv_filename
"#{group.id}-merge-commits-#{Time.current.to_i}.csv"
end
def filter_params
params.permit(:commit_sha)
end
end
......@@ -8,7 +8,10 @@ module EE
override :filter_items
def filter_items(items)
items = super(items)
by_approvers(items)
items = by_approvers(items)
items = by_merge_commit_sha(items)
items
end
# Filter by merge requests approval list that contains specified user directly or as part of group membership
......@@ -18,6 +21,12 @@ module EE
.execute(items)
end
def by_merge_commit_sha(items)
return items unless params[:merge_commit_sha].present?
items.by_merge_commit_sha(params[:merge_commit_sha])
end
class_methods do
extend ::Gitlab::Utils::Override
......
......@@ -2,26 +2,29 @@
module MergeCommits
class ExportCsvService
TARGET_FILESIZE = 15_000_000 # file size restricted to 15MB
include Gitlab::Utils::StrongMemoize
TARGET_FILESIZE = 15.megabytes
def initialize(current_user, group)
def initialize(current_user, group, filter_params = {})
@current_user = current_user
@group = group
@filter_params = filter_params
end
def csv_data
csv_builder.render(TARGET_FILESIZE)
ServiceResponse.success(payload: csv_builder.render(TARGET_FILESIZE))
end
private
attr_reader :current_user, :group
attr_reader :current_user, :group, :filter_params
def csv_builder
@csv_builder ||= CsvBuilder.new(data, header_to_value_hash)
end
def data
strong_memoize(:merge_commits_data) do
MergeRequestsFinder
.new(current_user, finder_options)
.execute
......@@ -30,11 +33,13 @@ module MergeCommits
.preload_target_project
.preload_metrics([:merged_by])
end
end
def finder_options
{
group_id: group.id,
state: 'merged'
state: 'merged',
merge_commit_sha: filter_params[:commit_sha]
}
end
......
---
title: Chain of custody report filter by merge commit sha
merge_request: 46581
author:
type: added
......@@ -26,7 +26,9 @@ RSpec.describe Groups::Security::MergeCommitReportsController do
CSV
end
let(:export_csv_service) { instance_spy(MergeCommits::ExportCsvService, csv_data: csv_data) }
let(:export_csv_service) do
instance_spy(MergeCommits::ExportCsvService, csv_data: ServiceResponse.success(payload: csv_data))
end
before_all do
group.add_owner(user)
......@@ -72,6 +74,18 @@ RSpec.describe Groups::Security::MergeCommitReportsController do
])
end
end
context 'when invalid' do
let(:export_csv_service) do
instance_spy(MergeCommits::ExportCsvService, csv_data: nil)
end
it do
subject
expect(flash[:alert]).to eq 'An error occurred while trying to generate the report. Please try again later.'
end
end
end
context 'when user does not have access to dashboard' do
......
......@@ -13,5 +13,22 @@ RSpec.describe MergeRequestsFinder do
expect(merge_requests).to contain_exactly(merge_request1)
end
context 'merge commit sha' do
let_it_be(:merged_merge_request) do
create(:merge_request, :simple, author: user,
source_project: project4, target_project: project4,
state: :merged, merge_commit_sha: 'rurebf')
end
it 'filters by merge commit sha' do
merge_requests = described_class.new(
user,
merge_commit_sha: merged_merge_request.merge_commit_sha
).execute
expect(merge_requests).to contain_exactly(merged_merge_request)
end
end
end
end
......@@ -18,6 +18,8 @@ RSpec.describe MergeCommits::ExportCsvService do
project.add_maintainer(user)
end
it { expect(subject.csv_data).to be_success }
it 'includes the appropriate headers' do
expect(csv.headers).to eq(['Merge Commit', 'Author', 'Merge Request', 'Merged By', 'Pipeline', 'Group', 'Project', 'Approver(s)'])
end
......@@ -57,14 +59,34 @@ RSpec.describe MergeCommits::ExportCsvService do
end
context 'with multiple merge requests' do
let_it_be(:merge_request_2) { create(:merge_request_with_diffs, source_project: project, target_project: project, state: :merged) }
let_it_be(:merge_request_2) { create(:merge_request_with_diffs, source_project: project, target_project: project, state: :merged, merge_commit_sha: 'rurebf') }
it { expect(csv.count).to eq 2 }
context 'by commit_sha filter' do
context 'when valid' do
subject { described_class.new(user, group, { commit_sha: merge_request_2.merge_commit_sha }) }
it { expect(subject.csv_data).to be_success }
it { expect(csv.count).to eq 1 }
it do
expect(csv.count).to eq 2
expect(csv[0]['Merge Commit']).to eq merge_request_2.merge_commit_sha
end
end
context 'when merge commit does not exist' do
subject { described_class.new(user, group, { commit_sha: 'inexistent' }) }
it { expect(csv.count).to eq 0 }
end
end
end
def csv
CSV.parse(subject.csv_data, headers: true)
data = subject.csv_data.payload
CSV.parse(data, headers: true)
end
end
......@@ -3198,6 +3198,9 @@ msgstr ""
msgid "An error occurred while triggering the job."
msgstr ""
msgid "An error occurred while trying to generate the report. Please try again later."
msgstr ""
msgid "An error occurred while trying to run a new pipeline for this Merge Request."
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment