Commit 9e3e43be authored by Olivier Gonzalez's avatar Olivier Gonzalez Committed by Dmitriy Zaporozhets

Add locations POROs for vulnerabilities

Move fingerprint logic into the location class for later reuse
parent 18edd650
...@@ -50,11 +50,11 @@ module Security ...@@ -50,11 +50,11 @@ module Security
find_params = { find_params = {
scanner: scanners_objects[occurrence.scanner.key], scanner: scanners_objects[occurrence.scanner.key],
primary_identifier: identifiers_objects[occurrence.primary_identifier.key], primary_identifier: identifiers_objects[occurrence.primary_identifier.key],
location_fingerprint: occurrence.location_fingerprint location_fingerprint: occurrence.location.fingerprint
} }
create_params = occurrence.to_hash create_params = occurrence.to_hash
.except(:compare_key, :identifiers, :scanner) # rubocop: disable CodeReuse/ActiveRecord .except(:compare_key, :identifiers, :location, :scanner) # rubocop: disable CodeReuse/ActiveRecord
begin begin
project.vulnerabilities project.vulnerabilities
......
...@@ -50,7 +50,7 @@ module Gitlab ...@@ -50,7 +50,7 @@ module Gitlab
report_type: report.type, report_type: report.type,
name: data['message'], name: data['message'],
compare_key: data['cve'], compare_key: data['cve'],
location_fingerprint: generate_location_fingerprint(data['location']), location: create_location(data['location']),
severity: parse_level(data['severity']), severity: parse_level(data['severity']),
confidence: parse_level(data['confidence']), confidence: parse_level(data['confidence']),
scanner: scanner, scanner: scanner,
...@@ -96,7 +96,7 @@ module Gitlab ...@@ -96,7 +96,7 @@ module Gitlab
input.blank? ? 'undefined' : input.downcase input.blank? ? 'undefined' : input.downcase
end end
def generate_location_fingerprint(location) def create_location(location_data)
raise NotImplementedError raise NotImplementedError
end end
end end
......
...@@ -131,8 +131,12 @@ module Gitlab ...@@ -131,8 +131,12 @@ module Gitlab
nil nil
end end
def generate_location_fingerprint(location) def create_location(location_data)
Digest::SHA1.hexdigest("#{location['operating_system']}:#{location.dig('dependency', 'package', 'name')}") ::Gitlab::Ci::Reports::Security::Locations::ContainerScanning.new(
image: location_data['image'],
operating_system: location_data['operating_system'],
package_name: location_data.dig('dependency', 'package', 'name'),
package_version: location_data.dig('dependency', 'version'))
end end
end end
end end
......
...@@ -45,8 +45,12 @@ module Gitlab ...@@ -45,8 +45,12 @@ module Gitlab
end end
end end
def generate_location_fingerprint(location) def create_location(location_data)
Digest::SHA1.hexdigest("#{location['path']}:#{location['method']}:#{location['param']}") ::Gitlab::Ci::Reports::Security::Locations::Dast.new(
hostname: location_data['hostname'],
method_name: location_data['method'],
param: location_data['param'],
path: location_data['path'])
end end
end end
end end
......
...@@ -11,8 +11,11 @@ module Gitlab ...@@ -11,8 +11,11 @@ module Gitlab
private private
def generate_location_fingerprint(location) def create_location(location_data)
Digest::SHA1.hexdigest("#{location['file']}:#{location.dig('dependency', 'package', 'name')}") ::Gitlab::Ci::Reports::Security::Locations::DependencyScanning.new(
file_path: location_data['file'],
package_name: location_data.dig('dependency', 'package', 'name'),
package_version: location_data.dig('dependency', 'version'))
end end
end end
end end
......
...@@ -11,8 +11,13 @@ module Gitlab ...@@ -11,8 +11,13 @@ module Gitlab
private private
def generate_location_fingerprint(location) def create_location(location_data)
Digest::SHA1.hexdigest("#{location['file']}:#{location['start_line']}:#{location['end_line']}") ::Gitlab::Ci::Reports::Security::Locations::Sast.new(
file_path: location_data['file'],
start_line: location_data['start_line'],
end_line: location_data['end_line'],
class_name: location_data['class'],
method_name: location_data['method'])
end end
end end
end end
......
# frozen_string_literal: true
module Gitlab
module Ci
module Reports
module Security
module Locations
class Base
include ::Gitlab::Utils::StrongMemoize
def ==(other)
other.fingerprint == fingerprint
end
def fingerprint
strong_memoize(:fingerprint) do
Digest::SHA1.hexdigest(fingerprint_data)
end
end
private
def fingerprint_data
raise NotImplemented
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
module Reports
module Security
module Locations
class ContainerScanning < Base
attr_reader :image
attr_reader :operating_system
attr_reader :package_name
attr_reader :package_version
def initialize(image:, operating_system:, package_name: nil, package_version: nil)
@image = image
@operating_system = operating_system
@package_name = package_name
@package_version = package_version
end
private
def fingerprint_data
"#{operating_system}:#{package_name}"
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
module Reports
module Security
module Locations
class Dast < Base
attr_reader :hostname
attr_reader :method_name
attr_reader :param
attr_reader :path
def initialize(hostname:, method_name:, path:, param: nil)
@hostname = hostname
@method_name = method_name
@param = param
@path = path
end
private
def fingerprint_data
"#{path}:#{method_name}:#{param}"
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
module Reports
module Security
module Locations
class DependencyScanning < Base
attr_reader :file_path
attr_reader :package_name
attr_reader :package_version
def initialize(file_path:, package_name:, package_version: nil)
@file_path = file_path
@package_name = package_name
@package_version = package_version
end
private
def fingerprint_data
"#{file_path}:#{package_name}"
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
module Reports
module Security
module Locations
class Sast < Base
attr_reader :class_name
attr_reader :end_line
attr_reader :file_path
attr_reader :method_name
attr_reader :start_line
def initialize(file_path:, start_line:, end_line: nil, class_name: nil, method_name: nil)
@class_name = class_name
@end_line = end_line
@file_path = file_path
@method_name = method_name
@start_line = start_line
end
private
def fingerprint_data
"#{file_path}:#{start_line}:#{end_line}"
end
end
end
end
end
end
end
...@@ -8,7 +8,7 @@ module Gitlab ...@@ -8,7 +8,7 @@ module Gitlab
attr_reader :compare_key attr_reader :compare_key
attr_reader :confidence attr_reader :confidence
attr_reader :identifiers attr_reader :identifiers
attr_reader :location_fingerprint attr_reader :location
attr_reader :metadata_version attr_reader :metadata_version
attr_reader :name attr_reader :name
attr_reader :project_fingerprint attr_reader :project_fingerprint
...@@ -18,11 +18,11 @@ module Gitlab ...@@ -18,11 +18,11 @@ module Gitlab
attr_reader :severity attr_reader :severity
attr_reader :uuid attr_reader :uuid
def initialize(compare_key:, identifiers:, location_fingerprint:, metadata_version:, name:, raw_metadata:, report_type:, scanner:, uuid:, confidence: nil, severity: nil) # rubocop:disable Metrics/ParameterLists def initialize(compare_key:, identifiers:, location:, metadata_version:, name:, raw_metadata:, report_type:, scanner:, uuid:, confidence: nil, severity: nil) # rubocop:disable Metrics/ParameterLists
@compare_key = compare_key @compare_key = compare_key
@confidence = confidence @confidence = confidence
@identifiers = identifiers @identifiers = identifiers
@location_fingerprint = location_fingerprint @location = location
@metadata_version = metadata_version @metadata_version = metadata_version
@name = name @name = name
@raw_metadata = raw_metadata @raw_metadata = raw_metadata
...@@ -39,7 +39,7 @@ module Gitlab ...@@ -39,7 +39,7 @@ module Gitlab
compare_key compare_key
confidence confidence
identifiers identifiers
location_fingerprint location
metadata_version metadata_version
name name
project_fingerprint project_fingerprint
...@@ -59,7 +59,7 @@ module Gitlab ...@@ -59,7 +59,7 @@ module Gitlab
def ==(other) def ==(other)
other.report_type == report_type && other.report_type == report_type &&
other.location_fingerprint == location_fingerprint && other.location == location &&
other.primary_identifier == primary_identifier other.primary_identifier == primary_identifier
end end
......
# frozen_string_literal: true
FactoryBot.define do
factory :ci_reports_security_locations_container_scanning, class: ::Gitlab::Ci::Reports::Security::Locations::ContainerScanning do
image 'registry.gitlab.com/my/project:latest'
operating_system 'debian:9'
package_name 'glibc'
package_version '1.2.3'
skip_create
initialize_with do
::Gitlab::Ci::Reports::Security::Locations::ContainerScanning.new(attributes)
end
end
end
# frozen_string_literal: true
FactoryBot.define do
factory :ci_reports_security_locations_dast, class: ::Gitlab::Ci::Reports::Security::Locations::Dast do
hostname 'my-app.com'
method_name 'GET'
param 'X-Content-Type-Options'
path '/some/path'
skip_create
initialize_with do
::Gitlab::Ci::Reports::Security::Locations::Dast.new(attributes)
end
end
end
# frozen_string_literal: true
FactoryBot.define do
factory :ci_reports_security_locations_dependency_scanning, class: ::Gitlab::Ci::Reports::Security::Locations::DependencyScanning do
file_path 'app/pom.xml'
package_name 'io.netty/netty'
package_version '1.2.3'
skip_create
initialize_with do
::Gitlab::Ci::Reports::Security::Locations::DependencyScanning.new(attributes)
end
end
end
# frozen_string_literal: true
FactoryBot.define do
factory :ci_reports_security_locations_sast, class: ::Gitlab::Ci::Reports::Security::Locations::Sast do
file_path 'maven/src/main/java/com/gitlab/security_products/tests/App.java'
start_line 29
end_line 31
class_name 'com.gitlab.security_products.tests.App'
method_name 'insecureCypher'
skip_create
initialize_with do
::Gitlab::Ci::Reports::Security::Locations::Sast.new(attributes)
end
end
end
...@@ -5,7 +5,7 @@ FactoryBot.define do ...@@ -5,7 +5,7 @@ FactoryBot.define do
compare_key 'this_is_supposed_to_be_a_unique_value' compare_key 'this_is_supposed_to_be_a_unique_value'
confidence :medium confidence :medium
identifiers { Array.new(1) { FactoryBot.build(:ci_reports_security_identifier) } } identifiers { Array.new(1) { FactoryBot.build(:ci_reports_security_identifier) } }
location_fingerprint '4e5b6966dd100170b4b1ad599c7058cce91b57b4' location factory: :ci_reports_security_locations_sast
metadata_version 'sast:1.0' metadata_version 'sast:1.0'
name 'Cipher with no integrity' name 'Cipher with no integrity'
report_type :sast report_type :sast
......
...@@ -31,10 +31,16 @@ describe Gitlab::Ci::Parsers::Security::ContainerScanning do ...@@ -31,10 +31,16 @@ describe Gitlab::Ci::Parsers::Security::ContainerScanning do
expect(report.scanners.length).to eq(1) expect(report.scanners.length).to eq(1)
end end
it "generates expected location fingerprint" do it 'generates expected location' do
expected = Digest::SHA1.hexdigest('debian:9:glibc') location = report.occurrences.first.location
expect(report.occurrences.first.location_fingerprint).to eq(expected) expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::ContainerScanning)
expect(location).to have_attributes(
image: 'registry.gitlab.com/groulot/container-scanning-test/master:5f21de6956aee99ddb68ae49498662d9872f50ff',
operating_system: 'debian:9',
package_name: 'glibc',
package_version: '2.24-11+deb9u3'
)
end end
it "generates expected metadata_version" do it "generates expected metadata_version" do
......
...@@ -23,12 +23,16 @@ describe Gitlab::Ci::Parsers::Security::Dast do ...@@ -23,12 +23,16 @@ describe Gitlab::Ci::Parsers::Security::Dast do
expect(report.scanners.length).to eq(1) expect(report.scanners.length).to eq(1)
end end
it 'generates expected location fingerprint' do it 'generates expected location' do
expected1 = Digest::SHA1.hexdigest(':GET:X-Content-Type-Options') location = report.occurrences.first.location
expected2 = Digest::SHA1.hexdigest('/:GET:X-Content-Type-Options')
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::Dast)
expect(report.occurrences.first.location_fingerprint).to eq(expected1) expect(location).to have_attributes(
expect(report.occurrences.last.location_fingerprint).to eq(expected2) hostname: 'http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io',
method_name: 'GET',
param: 'X-Content-Type-Options',
path: ''
)
end end
describe 'occurrence properties' do describe 'occurrence properties' do
......
...@@ -12,10 +12,10 @@ describe Gitlab::Ci::Parsers::Security::DependencyScanning do ...@@ -12,10 +12,10 @@ describe Gitlab::Ci::Parsers::Security::DependencyScanning do
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type) } let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type) }
let(:parser) { described_class.new } let(:parser) { described_class.new }
where(:report_format, :occurrence_count, :identifier_count, :scanner_count, :fingerprint, :version) do where(:report_format, :occurrence_count, :identifier_count, :scanner_count, :file_path, :package_name, :package_version, :version) do
:dependency_scanning | 4 | 7 | 2 | '2773f8cc955346ab1f756b94aa310db8e17c0944' | '1.3' :dependency_scanning | 4 | 7 | 2 | 'app/pom.xml' | 'io.netty/netty' | '3.9.1.Final' | '1.3'
:dependency_scanning_deprecated | 4 | 7 | 2 | '2773f8cc955346ab1f756b94aa310db8e17c0944' | '1.3' :dependency_scanning_deprecated | 4 | 7 | 2 | 'app/pom.xml' | 'io.netty/netty' | '3.9.1.Final' | '1.3'
:dependency_scanning_remediation | 2 | 3 | 1 | '228998b5db51d86d3b091939e2f5873ada0a14a1' | '2.0' :dependency_scanning_remediation | 2 | 3 | 1 | 'yarn.lock' | 'debug' | '1.0.5' | '2.0'
end end
with_them do with_them do
...@@ -33,8 +33,15 @@ describe Gitlab::Ci::Parsers::Security::DependencyScanning do ...@@ -33,8 +33,15 @@ describe Gitlab::Ci::Parsers::Security::DependencyScanning do
expect(report.scanners.length).to eq(scanner_count) expect(report.scanners.length).to eq(scanner_count)
end end
it "generates expected location fingerprint" do it 'generates expected location' do
expect(report.occurrences.first.location_fingerprint).to eq(fingerprint) location = report.occurrences.first.location
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::DependencyScanning)
expect(location).to have_attributes(
file_path: file_path,
package_name: package_name,
package_version: package_version
)
end end
it "generates expected metadata_version" do it "generates expected metadata_version" do
......
...@@ -26,8 +26,17 @@ describe Gitlab::Ci::Parsers::Security::Sast do ...@@ -26,8 +26,17 @@ describe Gitlab::Ci::Parsers::Security::Sast do
expect(report.scanners.length).to eq(3) expect(report.scanners.length).to eq(3)
end end
it "generates expected location fingerprint" do it 'generates expected location' do
expect(report.occurrences.first.location_fingerprint).to eq('d869ba3f0b3347eb2749135a437dc07c8ae0f420') location = report.occurrences.first.location
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::Sast)
expect(location).to have_attributes(
file_path: 'python/hardcoded/hardcoded-tmp.py',
start_line: 1,
end_line: 1,
class_name: nil,
method_name: nil
)
end end
it "generates expected metadata_version" do it "generates expected metadata_version" do
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Ci::Reports::Security::Locations::ContainerScanning do
let(:params) do
{
image: 'registry.gitlab.com/my/project:latest',
operating_system: 'debian:9',
package_name: 'glibc',
package_version: '1.2.3'
}
end
let(:mandatory_params) { %i[image operating_system] }
let(:expected_fingerprint) { Digest::SHA1.hexdigest('debian:9:glibc') }
it_behaves_like 'vulnerability location'
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Ci::Reports::Security::Locations::Dast do
let(:params) do
{
hostname: 'my-app.com',
method_name: 'GET',
param: 'X-Content-Type-Options',
path: '/some/path'
}
end
let(:mandatory_params) { %i[path method_name] }
let(:expected_fingerprint) { Digest::SHA1.hexdigest('/some/path:GET:X-Content-Type-Options') }
it_behaves_like 'vulnerability location'
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Ci::Reports::Security::Locations::DependencyScanning do
let(:params) do
{
file_path: 'app/pom.xml',
package_name: 'io.netty/netty',
package_version: '1.2.3'
}
end
let(:mandatory_params) { %i[file_path package_name] }
let(:expected_fingerprint) { Digest::SHA1.hexdigest('app/pom.xml:io.netty/netty') }
it_behaves_like 'vulnerability location'
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Ci::Reports::Security::Locations::Sast do
let(:params) do
{
file_path: 'src/main/App.java',
start_line: 29,
end_line: 31,
class_name: 'com.gitlab.security_products.tests.App',
method_name: 'insecureCypher'
}
end
let(:mandatory_params) { %i[file_path start_line] }
let(:expected_fingerprint) { Digest::SHA1.hexdigest('src/main/App.java:29:31') }
it_behaves_like 'vulnerability location'
end
...@@ -9,13 +9,14 @@ describe Gitlab::Ci::Reports::Security::Occurrence do ...@@ -9,13 +9,14 @@ describe Gitlab::Ci::Reports::Security::Occurrence do
let(:primary_identifier) { create(:ci_reports_security_identifier) } let(:primary_identifier) { create(:ci_reports_security_identifier) }
let(:other_identifier) { create(:ci_reports_security_identifier) } let(:other_identifier) { create(:ci_reports_security_identifier) }
let(:scanner) { create(:ci_reports_security_scanner) } let(:scanner) { create(:ci_reports_security_scanner) }
let(:location) { create(:ci_reports_security_locations_sast) }
let(:params) do let(:params) do
{ {
compare_key: 'this_is_supposed_to_be_a_unique_value', compare_key: 'this_is_supposed_to_be_a_unique_value',
confidence: :medium, confidence: :medium,
identifiers: [primary_identifier, other_identifier], identifiers: [primary_identifier, other_identifier],
location_fingerprint: '4e5b6966dd100170b4b1ad599c7058cce91b57b4', location: location,
metadata_version: 'sast:1.0', metadata_version: 'sast:1.0',
name: 'Cipher with no integrity', name: 'Cipher with no integrity',
raw_metadata: 'I am a stringified json object', raw_metadata: 'I am a stringified json object',
...@@ -35,7 +36,7 @@ describe Gitlab::Ci::Reports::Security::Occurrence do ...@@ -35,7 +36,7 @@ describe Gitlab::Ci::Reports::Security::Occurrence do
confidence: :medium, confidence: :medium,
project_fingerprint: '9a73f32d58d87d94e3dc61c4c1a94803f6014258', project_fingerprint: '9a73f32d58d87d94e3dc61c4c1a94803f6014258',
identifiers: [primary_identifier, other_identifier], identifiers: [primary_identifier, other_identifier],
location_fingerprint: '4e5b6966dd100170b4b1ad599c7058cce91b57b4', location: location,
metadata_version: 'sast:1.0', metadata_version: 'sast:1.0',
name: 'Cipher with no integrity', name: 'Cipher with no integrity',
raw_metadata: 'I am a stringified json object', raw_metadata: 'I am a stringified json object',
...@@ -47,7 +48,7 @@ describe Gitlab::Ci::Reports::Security::Occurrence do ...@@ -47,7 +48,7 @@ describe Gitlab::Ci::Reports::Security::Occurrence do
end end
end end
%i[compare_key identifiers location_fingerprint metadata_version name raw_metadata report_type scanner uuid].each do |attribute| %i[compare_key identifiers location metadata_version name raw_metadata report_type scanner uuid].each do |attribute|
context "when attribute #{attribute} is missing" do context "when attribute #{attribute} is missing" do
before do before do
params.delete(attribute) params.delete(attribute)
...@@ -70,7 +71,7 @@ describe Gitlab::Ci::Reports::Security::Occurrence do ...@@ -70,7 +71,7 @@ describe Gitlab::Ci::Reports::Security::Occurrence do
compare_key: occurrence.compare_key, compare_key: occurrence.compare_key,
confidence: occurrence.confidence, confidence: occurrence.confidence,
identifiers: occurrence.identifiers, identifiers: occurrence.identifiers,
location_fingerprint: occurrence.location_fingerprint, location: occurrence.location,
metadata_version: occurrence.metadata_version, metadata_version: occurrence.metadata_version,
name: occurrence.name, name: occurrence.name,
project_fingerprint: occurrence.project_fingerprint, project_fingerprint: occurrence.project_fingerprint,
...@@ -101,22 +102,19 @@ describe Gitlab::Ci::Reports::Security::Occurrence do ...@@ -101,22 +102,19 @@ describe Gitlab::Ci::Reports::Security::Occurrence do
let(:identifier) { create(:ci_reports_security_identifier) } let(:identifier) { create(:ci_reports_security_identifier) }
let(:other_identifier) { create(:ci_reports_security_identifier, external_type: 'other_identifier') } let(:other_identifier) { create(:ci_reports_security_identifier, external_type: 'other_identifier') }
let(:location) { create(:ci_reports_security_locations_sast) }
report_type = 'sast' let(:other_location) { create(:ci_reports_security_locations_sast, file_path: 'other/file.rb') }
fingerprint = '4e5b6966dd100170b4b1ad599c7058cce91b57b4'
other_report_type = 'dependency_scanning' where(:report_type_1, :location_1, :identifier_1, :report_type_2, :location_2, :identifier_2, :equal, :case_name) do
other_fingerprint = '368d8604fb8c0g455d129274f5773aa2f31d4f7q' 'sast' | -> { location } | -> { identifier } | 'sast' | -> { location } | -> { identifier } | true | 'when report_type, location and primary identifier are equal'
'sast' | -> { location } | -> { identifier } | 'dependency_scanning' | -> { location } | -> { identifier } | false | 'when report_type is different'
where(:report_type_1, :location_fingerprint_1, :identifier_1, :report_type_2, :location_fingerprint_2, :identifier_2, :equal, :case_name) do 'sast' | -> { location } | -> { identifier } | 'sast' | -> { other_location } | -> { identifier } | false | 'when location is different'
report_type | fingerprint | -> { identifier } | report_type | fingerprint | -> { identifier } | true | 'when report_type, location_fingerprint and primary identifier are equal' 'sast' | -> { location } | -> { identifier } | 'sast' | -> { location } | -> { other_identifier } | false | 'when primary identifier is different'
report_type | fingerprint | -> { identifier } | other_report_type | fingerprint | -> { identifier } | false | 'when report_type is different'
report_type | fingerprint | -> { identifier } | report_type | other_fingerprint | -> { identifier } | false | 'when location_fingerprint is different'
report_type | fingerprint | -> { identifier } | report_type | fingerprint | -> { other_identifier } | false | 'when primary identifier is different'
end end
with_them do with_them do
let(:occurrence_1) { create(:ci_reports_security_occurrence, report_type: report_type_1, location_fingerprint: location_fingerprint_1, identifiers: [identifier_1.call]) } let(:occurrence_1) { create(:ci_reports_security_occurrence, report_type: report_type_1, location: location_1.call, identifiers: [identifier_1.call]) }
let(:occurrence_2) { create(:ci_reports_security_occurrence, report_type: report_type_2, location_fingerprint: location_fingerprint_2, identifiers: [identifier_2.call]) } let(:occurrence_2) { create(:ci_reports_security_occurrence, report_type: report_type_2, location: location_2.call, identifiers: [identifier_2.call]) }
it "returns #{params[:equal]}" do it "returns #{params[:equal]}" do
expect(occurrence_1 == occurrence_2).to eq(equal) expect(occurrence_1 == occurrence_2).to eq(equal)
......
# frozen_string_literal: true
shared_examples 'vulnerability location' do
describe '#initialize' do
subject { described_class.new(**params) }
context 'when all params are given' do
it 'initializes an instance' do
expect { subject }.not_to raise_error
expect(subject).to have_attributes(**params)
end
end
where(:param) do
mandatory_params
end
with_them do
context "when param #{params[:param]} is missing" do
before do
params.delete(param)
end
it 'raises an error' do
expect { subject }.to raise_error(ArgumentError)
end
end
end
end
describe '#fingerprint' do
subject { described_class.new(**params).fingerprint }
it "generates expected fingerprint" do
expect(subject).to eq(expected_fingerprint)
end
end
describe '#==' do
let(:location_1) { create(:ci_reports_security_locations_sast) }
let(:location_2) { create(:ci_reports_security_locations_sast) }
subject { location_1 == location_2 }
it "returns true when fingerprints are equal" do
allow(location_1).to receive(:fingerprint).and_return('fingerprint')
allow(location_2).to receive(:fingerprint).and_return('fingerprint')
expect(subject).to eq(true)
end
it "returns false when fingerprints are different" do
allow(location_1).to receive(:fingerprint).and_return('fingerprint')
allow(location_2).to receive(:fingerprint).and_return('another_fingerprint')
expect(subject).to eq(false)
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