Commit 5fe4b7d0 authored by Cameron Swords's avatar Cameron Swords Committed by Thong Kuah

Parsers have access to JobArtifacts

The JobArtifact is required to retrieve the creation date
parent d9d063b9
......@@ -887,7 +887,7 @@ module Ci
def each_report(report_types)
job_artifacts_for_types(report_types).each do |report_artifact|
report_artifact.each_blob do |blob|
yield report_artifact.file_type, blob
yield report_artifact.file_type, blob, report_artifact
end
end
end
......
......@@ -24,13 +24,9 @@ module Security
end
def execute
reports = pipeline_reports
return [] if reports.nil?
occurrences = reports.each_with_object([]) do |(type, report), occurrences|
next unless requested_type?(type)
requested_reports = pipeline_reports.select { |report_type| requested_type?(report_type) }
occurrences = requested_reports.each_with_object([]) do |(type, report), occurrences|
raise ParseError, 'JSON parsing failed' if report.error.is_a?(Gitlab::Ci::Parsers::Security::Common::SecurityReportParserError)
normalized_occurrences = normalize_report_occurrences(
......@@ -41,7 +37,7 @@ module Security
occurrences.concat(filtered_occurrences)
end
sort_occurrences(occurrences)
Gitlab::Ci::Reports::Security::AggregatedReport.new(requested_reports.values, sort_occurrences(occurrences))
end
private
......@@ -63,7 +59,7 @@ module Security
end
def pipeline_reports
pipeline&.security_reports&.reports
pipeline&.security_reports&.reports || {}
end
def vulnerabilities_by_finding_fingerprint(report_type, report)
......
......@@ -48,8 +48,8 @@ module EE
end
def collect_security_reports!(security_reports)
each_report(::Ci::JobArtifact::SECURITY_REPORT_FILE_TYPES) do |file_type, blob|
security_reports.get_report(file_type).tap do |security_report|
each_report(::Ci::JobArtifact::SECURITY_REPORT_FILE_TYPES) do |file_type, blob, report_artifact|
security_reports.get_report(file_type, report_artifact).tap do |security_report|
next unless project.feature_available?(LICENSED_PARSER_FEATURES.fetch(file_type))
parse_security_artifact_blob(security_report, blob)
......@@ -75,7 +75,7 @@ module EE
if project.feature_available?(:dependency_scanning)
dependency_list = ::Gitlab::Ci::Parsers::Security::DependencyList.new(project, sha)
each_report(::Ci::JobArtifact::DEPENDENCY_LIST_REPORT_FILE_TYPES) do |file_type, blob|
each_report(::Ci::JobArtifact::DEPENDENCY_LIST_REPORT_FILE_TYPES) do |_, blob|
dependency_list.parse!(blob, dependency_list_report)
end
end
......@@ -87,7 +87,7 @@ module EE
if project.feature_available?(:dependency_scanning)
dependency_list = ::Gitlab::Ci::Parsers::Security::DependencyList.new(project, sha)
each_report(::Ci::JobArtifact::LICENSE_MANAGEMENT_REPORT_FILE_TYPES) do |file_type, blob|
each_report(::Ci::JobArtifact::LICENSE_MANAGEMENT_REPORT_FILE_TYPES) do |_, blob|
dependency_list.parse_licenses!(blob, dependency_list_report)
end
end
......
# frozen_string_literal: true
class Vulnerabilities::OccurrenceReportsComparerEntity < Grape::Entity
expose :base_report_created_at
expose :base_report_out_of_date
expose :head_report_created_at
expose :added, using: Vulnerabilities::OccurrenceEntity
expose :fixed, using: Vulnerabilities::OccurrenceEntity
expose :existing, using: Vulnerabilities::OccurrenceEntity
......
......@@ -20,7 +20,8 @@ module Security
@source_reports = source_reports
@target_report = ::Gitlab::Ci::Reports::Security::Report.new(
@source_reports.first.type,
@source_reports.first.commit_sha
@source_reports.first.commit_sha,
@source_reports.first.created_at
)
@occurrences = []
end
......
......@@ -14,7 +14,8 @@ module API
return [] unless pipeline
Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: params).execute
aggregated_report = Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: params).execute
aggregated_report.occurrences
end
end
......
......@@ -18,7 +18,6 @@ module Gitlab
report = super
if report.is_a?(Array)
puts self.class
report = {
"version" => self.class::DEPRECATED_REPORT_VERSION,
"vulnerabilities" => report
......
# frozen_string_literal: true
# Used to represent combined Security Reports. This is typically done for vulnerability deduplication purposes.
module Gitlab
module Ci
module Reports
module Security
class AggregatedReport
attr_reader :occurrences
def initialize(reports, occurrences)
@reports = reports
@occurrences = occurrences
end
def created_at
@reports.map(&:created_at).compact.min
end
end
end
end
end
end
......@@ -7,6 +7,7 @@ module Gitlab
class Report
UNSAFE_SEVERITIES = %w[unknown high critical].freeze
attr_reader :created_at
attr_reader :type
attr_reader :commit_sha
attr_reader :occurrences
......@@ -15,9 +16,10 @@ module Gitlab
attr_accessor :error
def initialize(type, commit_sha)
def initialize(type, commit_sha, created_at)
@type = type
@commit_sha = commit_sha
@created_at = created_at
@occurrences = []
@scanners = {}
@identifiers = {}
......@@ -40,7 +42,7 @@ module Gitlab
end
def clone_as_blank
Report.new(type, commit_sha)
Report.new(type, commit_sha, created_at)
end
def replace_with!(other)
......
......@@ -14,8 +14,8 @@ module Gitlab
@commit_sha = commit_sha
end
def get_report(report_type)
reports[report_type] ||= Report.new(report_type, commit_sha)
def get_report(report_type, report_artifact)
reports[report_type] ||= Report.new(report_type, commit_sha, report_artifact.created_at)
end
def violates_default_policy?
......
......@@ -9,27 +9,43 @@ module Gitlab
attr_reader :base_report, :head_report
ACCEPTABLE_REPORT_AGE = 1.week
def initialize(base_report, head_report)
@base_report = base_report || []
@head_report = head_report || []
@base_report = base_report
@head_report = head_report
end
def base_report_created_at
@base_report.created_at
end
def head_report_created_at
@head_report.created_at
end
def base_report_out_of_date
return false unless @base_report.created_at
ACCEPTABLE_REPORT_AGE.ago > @base_report.created_at
end
def added
strong_memoize(:added) do
head_report - base_report
head_report.occurrences - base_report.occurrences
end
end
def fixed
strong_memoize(:fixed) do
base_report - head_report
base_report.occurrences - head_report.occurrences
end
end
def existing
strong_memoize(:existing) do
# Existing vulnerabilities should point to source report for most recent information
head_report & base_report
head_report.occurrences & base_report.occurrences
end
end
end
......
# frozen_string_literal: true
FactoryBot.define do
factory :ci_reports_security_aggregated_reports, class: ::Gitlab::Ci::Reports::Security::AggregatedReport do
reports { FactoryBot.build_list(:ci_reports_security_report, 1) }
occurrences { FactoryBot.build_list(:ci_reports_security_occurrence, 1) }
initialize_with do
::Gitlab::Ci::Reports::Security::AggregatedReport.new(reports, occurrences)
end
end
end
......@@ -4,6 +4,7 @@ FactoryBot.define do
factory :ci_reports_security_report, class: ::Gitlab::Ci::Reports::Security::Report do
type { :sast }
commit_sha { Digest::SHA1.hexdigest(SecureRandom.hex) }
created_at { 2.weeks.ago }
transient do
occurrences { [] }
......@@ -20,7 +21,7 @@ FactoryBot.define do
skip_create
initialize_with do
::Gitlab::Ci::Reports::Security::Report.new(type, commit_sha)
::Gitlab::Ci::Reports::Security::Report.new(type, commit_sha, created_at)
end
end
end
......@@ -6,7 +6,7 @@ describe Gitlab::Ci::Parsers::Security::ContainerScanning do
let(:parser) { described_class.new }
let(:project) { artifact.project }
let(:pipeline) { artifact.job.pipeline }
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type, pipeline.sha) }
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type, pipeline.sha, 2.weeks.ago) }
before do
artifact.each_blob do |blob|
......
......@@ -9,7 +9,7 @@ describe Gitlab::Ci::Parsers::Security::Dast do
let(:project) { artifact.project }
let(:pipeline) { artifact.job.pipeline }
let(:artifact) { create(:ee_ci_job_artifact, :dast) }
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type, pipeline.sha) }
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type, pipeline.sha, 2.weeks.ago) }
let(:parser) { described_class.new }
where(:report_format,
......
......@@ -9,7 +9,7 @@ describe Gitlab::Ci::Parsers::Security::DependencyScanning do
let(:project) { artifact.project }
let(:pipeline) { artifact.job.pipeline }
let(:artifact) { create(:ee_ci_job_artifact, :dependency_scanning) }
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type, pipeline.sha) }
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type, pipeline.sha, 2.weeks.ago) }
let(:parser) { described_class.new }
where(:report_format, :occurrence_count, :identifier_count, :scanner_count, :file_path, :package_name, :package_version, :version) do
......
......@@ -7,12 +7,13 @@ describe Gitlab::Ci::Parsers::Security::Sast do
subject(:parser) { described_class.new }
let(:commit_sha) { "d8978e74745e18ce44d88814004d4255ac6a65bb" }
let(:created_at) { 2.weeks.ago }
context "when parsing valid reports" do
where(report_format: %i(sast sast_deprecated))
with_them do
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type, commit_sha) }
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type, commit_sha, created_at) }
let(:artifact) { create(:ee_ci_job_artifact, report_format) }
before do
......@@ -47,7 +48,7 @@ describe Gitlab::Ci::Parsers::Security::Sast do
end
context "when parsing an empty report" do
let(:report) { Gitlab::Ci::Reports::Security::Report.new('sast', commit_sha) }
let(:report) { Gitlab::Ci::Reports::Security::Report.new('sast', commit_sha, created_at) }
let(:blob) { JSON.generate({}) }
it { expect(parser.parse!(blob, report)).to be_empty }
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Ci::Reports::Security::AggregatedReport do
subject { described_class.new(reports, occurrences) }
let(:reports) { build_list(:ci_reports_security_report, 1) }
let(:occurrences) { build_list(:ci_reports_security_occurrence, 1) }
describe '#created_at' do
context 'no reports' do
let(:reports) { [] }
it 'has no created date' do
expect(subject.created_at).to be_nil
end
end
context 'report with no created date' do
let(:reports) { build_list(:ci_reports_security_report, 1, created_at: nil) }
it 'has no created date' do
expect(subject.created_at).to be_nil
end
end
context 'has reports' do
let(:a_long_time_ago) { 2.months.ago }
let(:a_while_ago) { 2.weeks.ago }
let(:yesterday) { 1.day.ago }
let(:reports) do
[build(:ci_reports_security_report, created_at: a_while_ago),
build(:ci_reports_security_report, created_at: a_long_time_ago),
build(:ci_reports_security_report, created_at: nil),
build(:ci_reports_security_report, created_at: yesterday)]
end
it 'has oldest created date' do
expect(subject.created_at).to eq(a_long_time_ago)
end
end
end
end
......@@ -3,8 +3,9 @@
require 'spec_helper'
describe Gitlab::Ci::Reports::Security::Report do
let(:report) { described_class.new('sast', commit_sha) }
let(:report) { described_class.new('sast', commit_sha, created_at) }
let(:commit_sha) { "d8978e74745e18ce44d88814004d4255ac6a65bb" }
let(:created_at) { 2.weeks.ago }
it { expect(report.type).to eq('sast') }
......@@ -65,6 +66,7 @@ describe Gitlab::Ci::Reports::Security::Report do
expect(clone.type).to eq(report.type)
expect(clone.commit_sha).to eq(report.commit_sha)
expect(clone.created_at).to eq(report.created_at)
expect(clone.occurrences).to eq([])
expect(clone.scanners).to eq({})
expect(clone.identifiers).to eq({})
......@@ -111,7 +113,7 @@ describe Gitlab::Ci::Reports::Security::Report do
allow(report).to receive(:replace_with!)
end
subject { report.merge!(described_class.new('sast', commit_sha)) }
subject { report.merge!(described_class.new('sast', commit_sha, created_at)) }
it 'invokes the merge with other report and then replaces this report contents by merge result' do
subject
......@@ -121,7 +123,7 @@ describe Gitlab::Ci::Reports::Security::Report do
end
describe "#safe?" do
subject { described_class.new('sast', commit_sha) }
subject { described_class.new('sast', commit_sha, created_at) }
context "when the sast report has an unsafe vulnerability" do
where(severity: %w[unknown Unknown high High critical Critical])
......
......@@ -5,19 +5,21 @@ require 'spec_helper'
describe Gitlab::Ci::Reports::Security::Reports do
let(:commit_sha) { '20410773a37f49d599e5f0d45219b39304763538' }
let(:security_reports) { described_class.new(commit_sha) }
let(:artifact) { create(:ee_ci_job_artifact, :sast) }
describe '#get_report' do
subject { security_reports.get_report(report_type) }
subject { security_reports.get_report(report_type, artifact) }
context 'when report type is sast' do
let(:report_type) { 'sast' }
it { expect(subject.type).to eq('sast') }
it { expect(subject.commit_sha).to eq(commit_sha) }
it { expect(subject.created_at).to eq(artifact.created_at) }
it 'initializes a new report and returns it' do
expect(Gitlab::Ci::Reports::Security::Report).to receive(:new)
.with('sast', commit_sha).and_call_original
.with('sast', commit_sha, artifact.created_at).and_call_original
is_expected.to be_a(Gitlab::Ci::Reports::Security::Report)
end
......@@ -44,8 +46,8 @@ describe Gitlab::Ci::Reports::Security::Reports do
context "when a report has a high severity vulnerability" do
before do
subject.get_report('sast').add_occurrence(high_severity)
subject.get_report('dependency_scanning').add_occurrence(low_severity)
subject.get_report('sast', artifact).add_occurrence(high_severity)
subject.get_report('dependency_scanning', artifact).add_occurrence(low_severity)
end
it { expect(subject.violates_default_policy?).to be(true) }
......@@ -53,8 +55,8 @@ describe Gitlab::Ci::Reports::Security::Reports do
context "when none of the reports have a high severity vulnerability" do
before do
subject.get_report('sast').add_occurrence(low_severity)
subject.get_report('dependency_scanning').add_occurrence(low_severity)
subject.get_report('sast', artifact).add_occurrence(low_severity)
subject.get_report('dependency_scanning', artifact).add_occurrence(low_severity)
end
it { expect(subject.violates_default_policy?).to be(false) }
......
......@@ -14,6 +14,7 @@ describe Ci::Build do
end
let(:job) { create(:ci_build, pipeline: pipeline) }
let(:artifact) { create(:ee_ci_job_artifact, :sast, job: job, project: job.project) }
describe '#shared_runners_minutes_limit_enabled?' do
subject { job.shared_runners_minutes_limit_enabled? }
......@@ -112,58 +113,59 @@ describe Ci::Build do
context 'when build has a security report' do
context 'when there is a sast report' do
before do
create(:ee_ci_job_artifact, :sast, job: job, project: job.project)
end
let!(:artifact) { create(:ee_ci_job_artifact, :sast, job: job, project: job.project) }
it 'parses blobs and add the results to the report' do
subject
expect(security_reports.get_report('sast').occurrences.size).to eq(33)
expect(security_reports.get_report('sast', artifact).occurrences.size).to eq(33)
end
it 'adds the created date to the report' do
subject
expect(security_reports.get_report('sast', artifact).created_at.to_s).to eq(artifact.created_at.to_s)
end
end
context 'when there are multiple reports' do
before do
create(:ee_ci_job_artifact, :sast, job: job, project: job.project)
create(:ee_ci_job_artifact, :dependency_scanning, job: job, project: job.project)
create(:ee_ci_job_artifact, :container_scanning, job: job, project: job.project)
create(:ee_ci_job_artifact, :dast, job: job, project: job.project)
end
let!(:sast_artifact) { create(:ee_ci_job_artifact, :sast, job: job, project: job.project) }
let!(:ds_artifact) { create(:ee_ci_job_artifact, :dependency_scanning, job: job, project: job.project) }
let!(:cs_artifact) { create(:ee_ci_job_artifact, :container_scanning, job: job, project: job.project) }
let!(:dast_artifact) { create(:ee_ci_job_artifact, :dast, job: job, project: job.project) }
it 'parses blobs and adds the results to the reports' do
subject
expect(security_reports.get_report('sast').occurrences.size).to eq(33)
expect(security_reports.get_report('dependency_scanning').occurrences.size).to eq(4)
expect(security_reports.get_report('container_scanning').occurrences.size).to eq(8)
expect(security_reports.get_report('dast').occurrences.size).to eq(20)
expect(security_reports.get_report('sast', sast_artifact).occurrences.size).to eq(33)
expect(security_reports.get_report('dependency_scanning', ds_artifact).occurrences.size).to eq(4)
expect(security_reports.get_report('container_scanning', cs_artifact).occurrences.size).to eq(8)
expect(security_reports.get_report('dast', dast_artifact).occurrences.size).to eq(20)
end
end
context 'when there is a corrupted sast report' do
before do
create(:ee_ci_job_artifact, :sast_with_corrupted_data, job: job, project: job.project)
end
let!(:artifact) { create(:ee_ci_job_artifact, :sast_with_corrupted_data, job: job, project: job.project) }
it 'stores an error' do
subject
expect(security_reports.get_report('sast')).to be_errored
expect(security_reports.get_report('sast', artifact)).to be_errored
end
end
end
context 'when there is unsupported file type' do
let!(:artifact) { create(:ee_ci_job_artifact, :codequality, job: job, project: job.project) }
before do
stub_const("Ci::JobArtifact::SECURITY_REPORT_FILE_TYPES", %w[codequality])
create(:ee_ci_job_artifact, :codequality, job: job, project: job.project)
end
it 'stores an error' do
subject
expect(security_reports.get_report('codequality')).to be_errored
expect(security_reports.get_report('codequality', artifact)).to be_errored
end
end
end
......
......@@ -159,14 +159,14 @@ describe Ci::Pipeline do
let(:build_ds_2) { create(:ci_build, :success, name: 'ds_2', pipeline: pipeline, project: project) }
let(:build_cs_1) { create(:ci_build, :success, name: 'cs_1', pipeline: pipeline, project: project) }
let(:build_cs_2) { create(:ci_build, :success, name: 'cs_2', pipeline: pipeline, project: project) }
let!(:sast1_artifact) { create(:ee_ci_job_artifact, :sast, job: build_sast_1, project: project) }
let!(:sast2_artifact) { create(:ee_ci_job_artifact, :sast, job: build_sast_2, project: project) }
let!(:ds1_artifact) { create(:ee_ci_job_artifact, :dependency_scanning, job: build_ds_1, project: project) }
let!(:ds2_artifact) { create(:ee_ci_job_artifact, :dependency_scanning, job: build_ds_2, project: project) }
let!(:cs1_artifact) { create(:ee_ci_job_artifact, :container_scanning, job: build_cs_1, project: project) }
let!(:cs2_artifact) { create(:ee_ci_job_artifact, :container_scanning, job: build_cs_2, project: project) }
before do
create(:ee_ci_job_artifact, :sast, job: build_sast_1, project: project)
create(:ee_ci_job_artifact, :sast, job: build_sast_2, project: project)
create(:ee_ci_job_artifact, :dependency_scanning, job: build_ds_1, project: project)
create(:ee_ci_job_artifact, :dependency_scanning, job: build_ds_2, project: project)
create(:ee_ci_job_artifact, :container_scanning, job: build_cs_1, project: project)
create(:ee_ci_job_artifact, :container_scanning, job: build_cs_2, project: project)
end
it 'assigns pipeline commit_sha to the reports' do
......@@ -178,18 +178,18 @@ describe Ci::Pipeline do
expect(subject.reports.keys).to contain_exactly('sast', 'dependency_scanning', 'container_scanning')
# for each of report categories, we have merged 2 reports with the same data (fixture)
expect(subject.get_report('sast').occurrences.size).to eq(33)
expect(subject.get_report('dependency_scanning').occurrences.size).to eq(4)
expect(subject.get_report('container_scanning').occurrences.size).to eq(8)
expect(subject.get_report('sast', sast1_artifact).occurrences.size).to eq(33)
expect(subject.get_report('dependency_scanning', ds1_artifact).occurrences.size).to eq(4)
expect(subject.get_report('container_scanning', cs1_artifact).occurrences.size).to eq(8)
end
context 'when builds are retried' do
let(:build_sast_1) { create(:ci_build, :retried, name: 'sast_1', pipeline: pipeline, project: project) }
it 'does not take retried builds into account' do
expect(subject.get_report('sast').occurrences.size).to eq(33)
expect(subject.get_report('dependency_scanning').occurrences.size).to eq(4)
expect(subject.get_report('container_scanning').occurrences.size).to eq(8)
expect(subject.get_report('sast', sast1_artifact).occurrences.size).to eq(33)
expect(subject.get_report('dependency_scanning', ds1_artifact).occurrences.size).to eq(4)
expect(subject.get_report('container_scanning', cs1_artifact).occurrences.size).to eq(8)
end
end
end
......
......@@ -6,8 +6,13 @@ describe Vulnerabilities::OccurrenceReportsComparerEntity do
describe 'container scanning report comparison' do
set(:user) { create(:user) }
let(:base_report) { create_list(:vulnerabilities_occurrence, 2) }
let(:head_report) { create_list(:vulnerabilities_occurrence, 1) }
let(:base_occurrences) { create_list(:vulnerabilities_occurrence, 2) }
let(:base_combined_reports) { build_list(:ci_reports_security_report, 1, created_at: nil) }
let(:base_report) { build(:ci_reports_security_aggregated_reports, reports: base_combined_reports, occurrences: base_occurrences)}
let(:head_occurrences) { create_list(:vulnerabilities_occurrence, 1) }
let(:head_combined_reports) { build_list(:ci_reports_security_report, 1, created_at: 2.days.ago) }
let(:head_report) { build(:ci_reports_security_aggregated_reports, reports: head_combined_reports, occurrences: head_occurrences)}
let(:comparer) { Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer.new(base_report, head_report) }
......@@ -27,7 +32,15 @@ describe Vulnerabilities::OccurrenceReportsComparerEntity do
end
it 'contains the added existing and fixed vulnerabilities for container scanning' do
expect(subject.keys).to match_array([:added, :existing, :fixed])
expect(subject.keys).to include(:added)
expect(subject.keys).to include(:existing)
expect(subject.keys).to include(:fixed)
end
it 'contains the report out of date fields' do
expect(subject.keys).to include(:base_report_created_at)
expect(subject.keys).to include(:base_report_out_of_date)
expect(subject.keys).to include(:head_report_created_at)
end
end
end
......
......@@ -6,7 +6,7 @@ describe Security::StoreReportService, '#execute' do
let(:artifact) { create(:ee_ci_job_artifact, report_type) }
let(:project) { artifact.project }
let(:pipeline) { artifact.job.pipeline }
let(:report) { pipeline.security_reports.get_report(report_type.to_s) }
let(:report) { pipeline.security_reports.get_report(report_type.to_s, artifact) }
before do
stub_licensed_features(sast: true, dependency_scanning: true, container_scanning: true)
......@@ -52,7 +52,7 @@ describe Security::StoreReportService, '#execute' do
let!(:new_artifact) { create(:ee_ci_job_artifact, :sast, job: new_build) }
let(:new_build) { create(:ci_build, pipeline: new_pipeline) }
let(:new_pipeline) { create(:ci_pipeline, project: project) }
let(:new_report) { new_pipeline.security_reports.get_report(report_type.to_s) }
let(:new_report) { new_pipeline.security_reports.get_report(report_type.to_s, artifact) }
let(:report_type) { :sast }
let!(:occurrence) do
......
......@@ -32,10 +32,12 @@ describe Security::StoreReportsService do
context 'when StoreReportService returns an error for a report' do
let(:reports) { Gitlab::Ci::Reports::Security::Reports.new(pipeline.sha) }
let(:sast_report) { reports.get_report('sast') }
let(:dast_report) { reports.get_report('dast') }
let(:sast_report) { reports.get_report('sast', sast_artifact) }
let(:dast_report) { reports.get_report('dast', dast_artifact) }
let(:success) { { status: :success } }
let(:error) { { status: :error, message: "something went wrong" } }
let(:sast_artifact) { create(:ee_ci_job_artifact, :sast) }
let(:dast_artifact) { create(:ee_ci_job_artifact, :dast) }
before do
allow(pipeline).to receive(:security_reports).and_return(reports)
......
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