Commit 4a293726 authored by Aishwarya Subramanian's avatar Aishwarya Subramanian

Chain of custody report filter by merge commit

Filter the chain of custody report
by merge commit sha. To be extended to all commits
in a future iteration.
parent 60e145b1
......@@ -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
send_data(
csv_data,
type: 'text/csv; charset=utf-8; header=present',
filename: merge_commits_csv_filename
)
if response&.success?
send_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,39 +2,44 @@
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
MergeRequestsFinder
.new(current_user, finder_options)
.execute
.preload_author
.preload_approved_by_users
.preload_target_project
.preload_metrics([:merged_by])
strong_memoize(:merge_commits_data) do
MergeRequestsFinder
.new(current_user, finder_options)
.execute
.preload_author
.preload_approved_by_users
.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 do
expect(csv.count).to eq 2
it { expect(csv.count).to eq 1 }
it do
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
......@@ -3199,6 +3199,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