Commit e4c8de23 authored by Shinya Maeda's avatar Shinya Maeda

Merge branch 'add_scanned_resources_count_to_dast_endpoint_11024' into 'master'

Add scan field to MR dast report endpoint

See merge request gitlab-org/gitlab!28718
parents 03c9758e 3ad1f9dc
......@@ -8,7 +8,8 @@ module Ci
# issue: https://gitlab.com/gitlab-org/gitlab/issues/34224
class CompareReportsBaseService < ::BaseService
def execute(base_pipeline, head_pipeline)
comparer = comparer_class.new(get_report(base_pipeline), get_report(head_pipeline))
comparer = build_comparer(base_pipeline, head_pipeline)
{
status: :parsed,
key: key(base_pipeline, head_pipeline),
......@@ -28,6 +29,12 @@ module Ci
data&.fetch(:key, nil) == key(base_pipeline, head_pipeline)
end
protected
def build_comparer(base_pipeline, head_pipeline)
comparer_class.new(get_report(base_pipeline), get_report(head_pipeline))
end
private
def key(base_pipeline, head_pipeline)
......
# frozen_string_literal: true
class Vulnerabilities::OccurrenceReportsComparerEntity < Grape::Entity
include RequestAwareEntity
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
expose :scans, using: Vulnerabilities::ScanEntity
end
# frozen_string_literal: true
class Vulnerabilities::ScanEntity < Grape::Entity
include RequestAwareEntity
expose :scanned_resources_count do |scan|
scan.scanned_resources_count || 0
end
expose :job_path do |scan|
project_job_path(scan.build.project, scan.build)
end
end
......@@ -13,5 +13,9 @@ module Ci
def get_report(pipeline)
Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: { report_type: %w[container_scanning], scope: 'all' }).execute
end
def build_comparer(base_pipeline, head_pipeline)
comparer_class.new(get_report(base_pipeline), get_report(head_pipeline), head_security_scans: head_pipeline.security_scans)
end
end
end
......@@ -13,5 +13,9 @@ module Ci
def get_report(pipeline)
Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: { report_type: %w[dast] }).execute
end
def build_comparer(base_pipeline, head_pipeline)
comparer_class.new(get_report(base_pipeline), get_report(head_pipeline), head_security_scans: head_pipeline.security_scans)
end
end
end
......@@ -13,5 +13,9 @@ module Ci
def get_report(pipeline)
Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: { report_type: %w[dependency_scanning], scope: 'all' }).execute
end
def build_comparer(base_pipeline, head_pipeline)
comparer_class.new(get_report(base_pipeline), get_report(head_pipeline), head_security_scans: head_pipeline.security_scans)
end
end
end
......@@ -13,5 +13,9 @@ module Ci
def get_report(pipeline)
Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: { report_type: %w[sast], scope: 'all' }).execute
end
def build_comparer(base_pipeline, head_pipeline)
comparer_class.new(get_report(base_pipeline), get_report(head_pipeline), head_security_scans: head_pipeline.security_scans)
end
end
end
---
title: Show the number of scanned resources in the DAST vulnerability report
merge_request: 28718
author:
type: added
......@@ -7,13 +7,14 @@ module Gitlab
class VulnerabilityReportsComparer
include Gitlab::Utils::StrongMemoize
attr_reader :base_report, :head_report
attr_reader :base_report, :head_report, :security_scans
ACCEPTABLE_REPORT_AGE = 1.week
def initialize(base_report, head_report)
def initialize(base_report, head_report, **extra_metadata)
@base_report = base_report
@head_report = head_report
@security_scans = extra_metadata[:head_security_scans]
end
def base_report_created_at
......@@ -48,6 +49,10 @@ module Gitlab
head_report.occurrences & base_report.occurrences
end
end
def scans
@security_scans
end
end
end
end
......
......@@ -16,7 +16,7 @@ describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
allow(head_vulnerability).to receive(:location).and_return({})
end
subject { described_class.new(base_report, head_report) }
subject { described_class.new(base_report, head_report, head_security_scans: []) }
describe '#base_report_out_of_date' do
context 'no base report' do
......@@ -140,7 +140,7 @@ describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
let(:empty_report) { build(:ci_reports_security_aggregated_reports, reports: [], occurrences: [])}
it 'returns empty array when reports are not present' do
comparer = described_class.new(empty_report, empty_report)
comparer = described_class.new(empty_report, empty_report, head_security_scans: [])
expect(comparer.existing).to eq([])
expect(comparer.fixed).to eq([])
......@@ -148,7 +148,7 @@ describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end
it 'returns added vulnerability when base is empty and head is not empty' do
comparer = described_class.new(empty_report, head_report)
comparer = described_class.new(empty_report, head_report, head_security_scans: [])
expect(comparer.existing).to eq([])
expect(comparer.fixed).to eq([])
......@@ -156,11 +156,21 @@ describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end
it 'returns fixed vulnerability when head is empty and base is not empty' do
comparer = described_class.new(base_report, empty_report)
comparer = described_class.new(base_report, empty_report, head_security_scans: [])
expect(comparer.existing).to eq([])
expect(comparer.fixed).to eq([base_vulnerability])
expect(comparer.added).to eq([])
end
end
describe 'security_scans' do
let(:scan) { build(:security_scan, scanned_resources_count: 10) }
let(:security_scans) { [scan] }
it 'sets the security scans' do
comparer = described_class.new(base_report, head_report, head_security_scans: security_scans)
expect(comparer.security_scans).to be(security_scans)
end
end
end
......@@ -14,7 +14,10 @@ describe Vulnerabilities::OccurrenceReportsComparerEntity do
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) }
let(:scan) { create(:security_scan, scanned_resources_count: 10) }
let(:security_scans) { [scan] }
let(:comparer) { Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer.new(base_report, head_report, head_security_scans: security_scans) }
let(:request) { double('request') }
......@@ -31,6 +34,17 @@ describe Vulnerabilities::OccurrenceReportsComparerEntity do
allow(request).to receive(:current_user).and_return(user)
end
it 'avoids N+1 database queries' do
comparer = Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer.new(base_report, head_report, head_security_scans: [])
entity = described_class.new(comparer, request: request)
control_count = ActiveRecord::QueryRecorder.new { entity.as_json }.count
scans = create_list(:security_scan, 5)
comparer = Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer.new(base_report, head_report, head_security_scans: scans)
entity = described_class.new(comparer, request: request)
expect { entity.as_json }.not_to exceed_query_limit(control_count)
end
it 'contains the added existing and fixed vulnerabilities for container scanning' do
expect(subject.keys).to include(:added)
expect(subject.keys).to include(:existing)
......@@ -42,6 +56,23 @@ describe Vulnerabilities::OccurrenceReportsComparerEntity do
expect(subject.keys).to include(:base_report_out_of_date)
expect(subject.keys).to include(:head_report_created_at)
end
it 'contains the scan fields' do
expect(subject.keys).to include(:scans)
expect(subject[:scans].length).to be(1)
expect(subject[:scans].first[:scanned_resources_count]).to be(10)
project = scan.build.project
expect(subject[:scans].first[:job_path]).to eq("/#{project.namespace.path}/#{project.path}/-/jobs/#{scan.build.id}")
end
context 'scanned_resources_count is nil' do
let(:scan) { create(:security_scan, scanned_resources_count: nil) }
let(:security_scans) { [scan] }
it 'shows the scanned_resources_count is 0' do
expect(subject[:scans].first[:scanned_resources_count]).to be(0)
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Vulnerabilities::ScanEntity do
let(:scan) { build(:security_scan, scanned_resources_count: 10) }
let(:request) { double('request') }
let(:entity) do
described_class.represent(scan, request: request)
end
describe '#as_json' do
subject { entity.as_json }
it 'contains required fields' do
expect(subject).to include(:scanned_resources_count)
expect(subject).to include(:job_path)
end
describe 'job_path' do
it 'returns path to the job log' do
project = scan.build.project
expect(subject[:job_path]).to eq("/#{project.namespace.path}/#{project.path}/-/jobs/#{scan.build.id}")
end
end
describe 'scanned_resources_count' do
context 'is nil' do
let(:scan) { build(:security_scan, scanned_resources_count: nil) }
it 'shows a count of 0' do
expect(subject[:scanned_resources_count]).to be(0)
end
end
context 'has a value' do
it 'shows the count' do
expect(subject[:scanned_resources_count]).to be(10)
end
end
end
end
end
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