Commit 39c5d919 authored by Gabriel Mazetto's avatar Gabriel Mazetto

Merge branch '214704-rename-vulnerabilities-occurrence-to-vulnerabilities-finding' into 'master'

Rename Vulnerabilities::Occurrence to Vulnerabilities::Finding

See merge request gitlab-org/gitlab!36280
parents 6135870d 58420132
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# Security::PipelineVulnerabilitiesFinder # Security::PipelineVulnerabilitiesFinder
# #
# Used to retrieve security vulnerabilities from an associated Pipeline, # Used to retrieve security vulnerabilities from an associated Pipeline,
# This involves normalizing Report::Occurrence POROs to Vulnerabilities::Occurrence # This involves normalizing Report::Occurrence POROs to Vulnerabilities::Finding
# #
# Arguments: # Arguments:
# pipeline - object to filter vulnerabilities # pipeline - object to filter vulnerabilities
...@@ -26,23 +26,23 @@ module Security ...@@ -26,23 +26,23 @@ module Security
def execute def execute
requested_reports = pipeline_reports.select { |report_type| requested_type?(report_type) } requested_reports = pipeline_reports.select { |report_type| requested_type?(report_type) }
occurrences = requested_reports.each_with_object([]) do |(type, report), occurrences| findings = requested_reports.each_with_object([]) do |(type, report), findings|
raise ParseError, 'JSON parsing failed' if report.error.is_a?(Gitlab::Ci::Parsers::Security::Common::SecurityReportParserError) raise ParseError, 'JSON parsing failed' if report.error.is_a?(Gitlab::Ci::Parsers::Security::Common::SecurityReportParserError)
normalized_occurrences = normalize_report_occurrences( normalized_findings = normalize_report_findings(
report.occurrences, report.findings,
vulnerabilities_by_finding_fingerprint(type, report)) vulnerabilities_by_finding_fingerprint(type, report))
filtered_occurrences = filter(normalized_occurrences) filtered_findings = filter(normalized_findings)
occurrences.concat(filtered_occurrences) findings.concat(filtered_findings)
end end
Gitlab::Ci::Reports::Security::AggregatedReport.new(requested_reports.values, sort_occurrences(occurrences)) Gitlab::Ci::Reports::Security::AggregatedReport.new(requested_reports.values, sort_findings(findings))
end end
private private
def sort_occurrences(occurrences) def sort_findings(findings)
# This sort is stable (see https://en.wikipedia.org/wiki/Sorting_algorithm#Stability) contrary to the bare # This sort is stable (see https://en.wikipedia.org/wiki/Sorting_algorithm#Stability) contrary to the bare
# Ruby sort_by method. Using just sort_by leads to instability across different platforms (e.g., x86_64-linux and # Ruby sort_by method. Using just sort_by leads to instability across different platforms (e.g., x86_64-linux and
# x86_64-darwin18) which in turn leads to different sorting results for the equal elements across these platforms. # x86_64-darwin18) which in turn leads to different sorting results for the equal elements across these platforms.
...@@ -51,7 +51,7 @@ module Security ...@@ -51,7 +51,7 @@ module Security
# This is easier to address from within the class rather than from tests because this leads to bad class design # This is easier to address from within the class rather than from tests because this leads to bad class design
# and exposing too much of its implementation details to the test suite. # and exposing too much of its implementation details to the test suite.
# See also https://stackoverflow.com/questions/15442298/is-sort-in-ruby-stable. # See also https://stackoverflow.com/questions/15442298/is-sort-in-ruby-stable.
Gitlab::Utils.stable_sort_by(occurrences) { |x| [-x.severity_value, -x.confidence_value] } Gitlab::Utils.stable_sort_by(findings) { |x| [-x.severity_value, -x.confidence_value] }
end end
def pipeline_reports def pipeline_reports
...@@ -59,49 +59,49 @@ module Security ...@@ -59,49 +59,49 @@ module Security
end end
def vulnerabilities_by_finding_fingerprint(report_type, report) def vulnerabilities_by_finding_fingerprint(report_type, report)
Vulnerabilities::Occurrence Vulnerabilities::Finding
.with_vulnerabilities_for_state( .with_vulnerabilities_for_state(
project: pipeline.project, project: pipeline.project,
report_type: report_type, report_type: report_type,
project_fingerprints: report.occurrences.map(&:project_fingerprint)) project_fingerprints: report.findings.map(&:project_fingerprint))
.each_with_object({}) do |occurrence, hash| .each_with_object({}) do |finding, hash|
hash[occurrence.project_fingerprint] = occurrence.vulnerability hash[finding.project_fingerprint] = finding.vulnerability
end end
end end
# This finder is used for fetching vulnerabilities for any pipeline, if we used it to fetch # This finder is used for fetching vulnerabilities for any pipeline, if we used it to fetch
# vulnerabilities for a non-default-branch, the occurrences will be unpersisted, so we # vulnerabilities for a non-default-branch, the findings will be unpersisted, so we
# coerce the POROs into unpersisted AR records to give them a common object. # coerce the POROs into unpersisted AR records to give them a common object.
# See https://gitlab.com/gitlab-org/gitlab/issues/33588#note_291849433 for more context # See https://gitlab.com/gitlab-org/gitlab/issues/33588#note_291849433 for more context
# on why this happens. # on why this happens.
def normalize_report_occurrences(report_occurrences, vulnerabilities) def normalize_report_findings(report_findings, vulnerabilities)
report_occurrences.map do |report_occurrence| report_findings.map do |report_finding|
occurrence_hash = report_occurrence.to_hash finding_hash = report_finding.to_hash
.except(:compare_key, :identifiers, :location, :scanner) .except(:compare_key, :identifiers, :location, :scanner)
occurrence = Vulnerabilities::Occurrence.new(occurrence_hash) finding = Vulnerabilities::Finding.new(finding_hash)
# assigning Vulnerabilities to Findings to enable the computed state # assigning Vulnerabilities to Findings to enable the computed state
occurrence.location_fingerprint = report_occurrence.location.fingerprint finding.location_fingerprint = report_finding.location.fingerprint
occurrence.vulnerability = vulnerabilities[occurrence.project_fingerprint] finding.vulnerability = vulnerabilities[finding.project_fingerprint]
occurrence.project = pipeline.project finding.project = pipeline.project
occurrence.sha = pipeline.sha finding.sha = pipeline.sha
occurrence.build_scanner(report_occurrence.scanner&.to_hash) finding.build_scanner(report_finding.scanner&.to_hash)
occurrence.identifiers = report_occurrence.identifiers.map do |identifier| finding.identifiers = report_finding.identifiers.map do |identifier|
Vulnerabilities::Identifier.new(identifier.to_hash) Vulnerabilities::Identifier.new(identifier.to_hash)
end end
occurrence finding
end end
end end
def filter(occurrences) def filter(findings)
occurrences.select do |occurrence| findings.select do |finding|
next if !include_dismissed? && dismissal_feedback?(occurrence) next if !include_dismissed? && dismissal_feedback?(finding)
next unless confidence_levels.include?(occurrence.confidence) next unless confidence_levels.include?(finding.confidence)
next unless severity_levels.include?(occurrence.severity) next unless severity_levels.include?(finding.severity)
next if scanners.present? && !scanners.include?(occurrence.scanner.external_id) next if scanners.present? && !scanners.include?(finding.scanner.external_id)
occurrence finding
end end
end end
...@@ -113,8 +113,8 @@ module Security ...@@ -113,8 +113,8 @@ module Security
params[:scope] == 'all' params[:scope] == 'all'
end end
def dismissal_feedback?(occurrence) def dismissal_feedback?(finding)
dismissal_feedback_by_fingerprint[occurrence.project_fingerprint] dismissal_feedback_by_fingerprint[finding.project_fingerprint]
end end
def dismissal_feedback_by_fingerprint def dismissal_feedback_by_fingerprint
...@@ -127,15 +127,15 @@ module Security ...@@ -127,15 +127,15 @@ module Security
end end
def confidence_levels def confidence_levels
Array(params.fetch(:confidence, Vulnerabilities::Occurrence.confidences.keys)) Array(params.fetch(:confidence, Vulnerabilities::Finding.confidences.keys))
end end
def report_types def report_types
Array(params.fetch(:report_type, Vulnerabilities::Occurrence.report_types.keys)) Array(params.fetch(:report_type, Vulnerabilities::Finding.report_types.keys))
end end
def severity_levels def severity_levels
Array(params.fetch(:severity, Vulnerabilities::Occurrence.severities.keys)) Array(params.fetch(:severity, Vulnerabilities::Finding.severities.keys))
end end
def scanners def scanners
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Security::VulnerabilityFindingsFinder # Security::VulnerabilityFindingsFinder
# #
# Used to filter Vulnerabilities::Occurrences by set of params for Security Dashboard # Used to filter Vulnerabilities::Findings by set of params for Security Dashboard
# #
# Arguments: # Arguments:
# pipeline_ids - IDs for the pipelines to fetch vulnerabilities for # pipeline_ids - IDs for the pipelines to fetch vulnerabilities for
...@@ -40,7 +40,7 @@ module Security ...@@ -40,7 +40,7 @@ module Security
return items unless params[:report_type].present? return items unless params[:report_type].present?
items.by_report_types( items.by_report_types(
Vulnerabilities::Occurrence::REPORT_TYPES.values_at( Vulnerabilities::Finding::REPORT_TYPES.values_at(
*params[:report_type]).compact) *params[:report_type]).compact)
end end
...@@ -54,7 +54,7 @@ module Security ...@@ -54,7 +54,7 @@ module Security
return items unless params[:severity].present? return items unless params[:severity].present?
items.by_severities( items.by_severities(
Vulnerabilities::Occurrence::SEVERITY_LEVELS.values_at( Vulnerabilities::Finding::SEVERITY_LEVELS.values_at(
*params[:severity]).compact) *params[:severity]).compact)
end end
...@@ -62,7 +62,7 @@ module Security ...@@ -62,7 +62,7 @@ module Security
return items unless params[:confidence].present? return items unless params[:confidence].present?
items.by_confidences( items.by_confidences(
Vulnerabilities::Occurrence::CONFIDENCE_LEVELS.values_at( Vulnerabilities::Finding::CONFIDENCE_LEVELS.values_at(
*params[:confidence]).compact) *params[:confidence]).compact)
end end
...@@ -76,9 +76,9 @@ module Security ...@@ -76,9 +76,9 @@ module Security
def init_collection def init_collection
if include_sha if include_sha
::Vulnerabilities::Occurrence.for_pipelines_with_sha(pipeline_ids) ::Vulnerabilities::Finding.for_pipelines_with_sha(pipeline_ids)
else else
::Vulnerabilities::Occurrence.for_pipelines(pipeline_ids) ::Vulnerabilities::Finding.for_pipelines(pipeline_ids)
end end
end end
end end
......
...@@ -17,7 +17,7 @@ module Security ...@@ -17,7 +17,7 @@ module Security
attr_reader :projects attr_reader :projects
def vulnerabilities def vulnerabilities
::Vulnerabilities::Occurrence ::Vulnerabilities::Finding
.select(1) .select(1)
.undismissed .undismissed
.scoped_project .scoped_project
......
...@@ -11,7 +11,7 @@ module Representation ...@@ -11,7 +11,7 @@ module Representation
attr_reader :raw_entry attr_reader :raw_entry
def report_type def report_type
::Vulnerabilities::Occurrence::REPORT_TYPES.key(@report_type) || @report_type ::Vulnerabilities::Finding::REPORT_TYPES.key(@report_type) || @report_type
end end
def ==(other) def ==(other)
......
...@@ -6,7 +6,7 @@ module Types ...@@ -6,7 +6,7 @@ module Types
graphql_name 'SecurityReportSummary' graphql_name 'SecurityReportSummary'
description 'Represents summary of a security report' description 'Represents summary of a security report'
::Vulnerabilities::Occurrence::REPORT_TYPES.keys.each do |report_type| ::Vulnerabilities::Finding::REPORT_TYPES.keys.each do |report_type|
field report_type, ::Types::SecurityReportSummarySectionType, null: true, field report_type, ::Types::SecurityReportSummarySectionType, null: true,
description: "Aggregated counts for the #{report_type} scan" description: "Aggregated counts for the #{report_type} scan"
end end
......
...@@ -29,7 +29,7 @@ module Types ...@@ -29,7 +29,7 @@ module Types
when 'coverage_fuzzing' when 'coverage_fuzzing'
VulnerabilityLocation::CoverageFuzzingType VulnerabilityLocation::CoverageFuzzingType
else else
raise UnexpectedReportType, "Report type must be one of #{::Vulnerabilities::Occurrence::REPORT_TYPES.keys}" raise UnexpectedReportType, "Report type must be one of #{::Vulnerabilities::Finding::REPORT_TYPES.keys}"
end end
end end
end end
......
...@@ -5,7 +5,7 @@ module Types ...@@ -5,7 +5,7 @@ module Types
graphql_name 'VulnerabilityReportType' graphql_name 'VulnerabilityReportType'
description 'The type of the security scan that found the vulnerability.' description 'The type of the security scan that found the vulnerability.'
::Vulnerabilities::Occurrence::REPORT_TYPES.keys.each do |report_type| ::Vulnerabilities::Finding::REPORT_TYPES.keys.each do |report_type|
value report_type.to_s.upcase, value: report_type.to_s value report_type.to_s.upcase, value: report_type.to_s
end end
end end
......
...@@ -6,7 +6,7 @@ module Types ...@@ -6,7 +6,7 @@ module Types
graphql_name 'VulnerabilitySeveritiesCount' graphql_name 'VulnerabilitySeveritiesCount'
description 'Represents vulnerability counts by severity' description 'Represents vulnerability counts by severity'
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.each do |severity| ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.each do |severity|
field severity, GraphQL::INT_TYPE, null: true, field severity, GraphQL::INT_TYPE, null: true,
description: "Number of vulnerabilities of #{severity.upcase} severity of the project" description: "Number of vulnerabilities of #{severity.upcase} severity of the project"
end end
......
...@@ -5,7 +5,7 @@ module Types ...@@ -5,7 +5,7 @@ module Types
graphql_name 'VulnerabilitySeverity' graphql_name 'VulnerabilitySeverity'
description 'The severity of the vulnerability.' description 'The severity of the vulnerability.'
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.each do |severity| ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.each do |severity|
value severity.to_s.upcase, value: severity.to_s value severity.to_s.upcase, value: severity.to_s
end end
end end
......
...@@ -22,10 +22,10 @@ module Types ...@@ -22,10 +22,10 @@ module Types
description: "State of the vulnerability (#{::Vulnerability.states.keys.join(', ').upcase})" description: "State of the vulnerability (#{::Vulnerability.states.keys.join(', ').upcase})"
field :severity, VulnerabilitySeverityEnum, null: true, field :severity, VulnerabilitySeverityEnum, null: true,
description: "Severity of the vulnerability (#{::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.join(', ').upcase})" description: "Severity of the vulnerability (#{::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.join(', ').upcase})"
field :report_type, VulnerabilityReportTypeEnum, null: true, field :report_type, VulnerabilityReportTypeEnum, null: true,
description: "Type of the security report that found the vulnerability (#{::Vulnerabilities::Occurrence::REPORT_TYPES.keys.join(', ').upcase})" description: "Type of the security report that found the vulnerability (#{::Vulnerabilities::Finding::REPORT_TYPES.keys.join(', ').upcase})"
field :user_notes_count, GraphQL::INT_TYPE, null: false, field :user_notes_count, GraphQL::INT_TYPE, null: false,
description: 'Number of user notes attached to the vulnerability' description: 'Number of user notes attached to the vulnerability'
......
...@@ -14,8 +14,8 @@ module EE ...@@ -14,8 +14,8 @@ module EE
prepended do prepended do
include UsageStatistics include UsageStatistics
has_many :vulnerabilities_finding_pipelines, class_name: 'Vulnerabilities::FindingPipeline' has_many :vulnerabilities_finding_pipelines, class_name: 'Vulnerabilities::FindingPipeline', inverse_of: :pipeline
has_many :vulnerability_findings, source: :occurrence, through: :vulnerabilities_finding_pipelines, class_name: 'Vulnerabilities::Occurrence' has_many :vulnerability_findings, source: :finding, through: :vulnerabilities_finding_pipelines, class_name: 'Vulnerabilities::Finding'
has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id' has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id'
has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id' has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id'
......
...@@ -63,7 +63,7 @@ module EE ...@@ -63,7 +63,7 @@ module EE
has_many :vulnerabilities has_many :vulnerabilities
has_many :vulnerability_feedback, class_name: 'Vulnerabilities::Feedback' has_many :vulnerability_feedback, class_name: 'Vulnerabilities::Feedback'
has_many :vulnerability_historical_statistics, class_name: 'Vulnerabilities::HistoricalStatistic' has_many :vulnerability_historical_statistics, class_name: 'Vulnerabilities::HistoricalStatistic'
has_many :vulnerability_findings, class_name: 'Vulnerabilities::Occurrence' do has_many :vulnerability_findings, class_name: 'Vulnerabilities::Finding', inverse_of: :project do
def lock_for_confirmation!(id) def lock_for_confirmation!(id)
where(vulnerability_id: nil).lock.find(id) where(vulnerability_id: nil).lock.find(id)
end end
...@@ -129,7 +129,7 @@ module EE ...@@ -129,7 +129,7 @@ module EE
scope :with_protected_branches, -> { joins(:protected_branches) } scope :with_protected_branches, -> { joins(:protected_branches) }
scope :with_repositories_enabled, -> { joins(:project_feature).where(project_features: { repository_access_level: ::ProjectFeature::ENABLED }) } scope :with_repositories_enabled, -> { joins(:project_feature).where(project_features: { repository_access_level: ::ProjectFeature::ENABLED }) }
scope :with_security_reports_stored, -> { where('EXISTS (?)', ::Vulnerabilities::Occurrence.scoped_project.select(1)) } scope :with_security_reports_stored, -> { where('EXISTS (?)', ::Vulnerabilities::Finding.scoped_project.select(1)) }
scope :with_security_reports, -> { where('EXISTS (?)', ::Ci::JobArtifact.security_reports.scoped_project.select(1)) } scope :with_security_reports, -> { where('EXISTS (?)', ::Ci::JobArtifact.security_reports.scoped_project.select(1)) }
scope :with_github_service_pipeline_events, -> { joins(:github_service).merge(GithubService.pipeline_hooks) } scope :with_github_service_pipeline_events, -> { joins(:github_service).merge(GithubService.pipeline_hooks) }
scope :with_active_prometheus_service, -> { joins(:prometheus_service).merge(PrometheusService.active) } scope :with_active_prometheus_service, -> { joins(:prometheus_service).merge(PrometheusService.active) }
......
...@@ -76,7 +76,7 @@ module Vulnerabilities ...@@ -76,7 +76,7 @@ module Vulnerabilities
comment.present? && comment_author.present? comment.present? && comment_author.present?
end end
def occurrence_key def finding_key
{ {
project_id: project_id, project_id: project_id,
category: category, category: category,
......
# frozen_string_literal: true # frozen_string_literal: true
module Vulnerabilities module Vulnerabilities
class Occurrence < ApplicationRecord class Finding < ApplicationRecord
include ShaAttribute include ShaAttribute
include ::Gitlab::Utils::StrongMemoize include ::Gitlab::Utils::StrongMemoize
include Presentable include Presentable
# https://gitlab.com/groups/gitlab-org/-/epics/3148
# https://gitlab.com/gitlab-org/gitlab/-/issues/214563#note_370782508 is why the table names are not renamed
self.table_name = "vulnerability_occurrences" self.table_name = "vulnerability_occurrences"
OCCURRENCES_PER_PAGE = 20 FINDINGS_PER_PAGE = 20
paginates_per OCCURRENCES_PER_PAGE paginates_per FINDINGS_PER_PAGE
sha_attribute :project_fingerprint sha_attribute :project_fingerprint
sha_attribute :location_fingerprint sha_attribute :location_fingerprint
belongs_to :project belongs_to :project, inverse_of: :vulnerability_findings
belongs_to :scanner, class_name: 'Vulnerabilities::Scanner' belongs_to :scanner, class_name: 'Vulnerabilities::Scanner'
belongs_to :primary_identifier, class_name: 'Vulnerabilities::Identifier', inverse_of: :primary_occurrences belongs_to :primary_identifier, class_name: 'Vulnerabilities::Identifier', inverse_of: :primary_findings, foreign_key: 'primary_identifier_id'
belongs_to :vulnerability, inverse_of: :findings belongs_to :vulnerability, class_name: 'Vulnerability', inverse_of: :findings, foreign_key: 'vulnerability_id'
has_many :finding_identifiers, class_name: 'Vulnerabilities::FindingIdentifier' has_many :finding_identifiers, class_name: 'Vulnerabilities::FindingIdentifier', inverse_of: :finding, foreign_key: 'occurrence_id'
has_many :identifiers, through: :finding_identifiers, class_name: 'Vulnerabilities::Identifier' has_many :identifiers, through: :finding_identifiers, class_name: 'Vulnerabilities::Identifier'
has_many :finding_pipelines, class_name: 'Vulnerabilities::FindingPipeline'
has_many :finding_pipelines, class_name: 'Vulnerabilities::FindingPipeline', inverse_of: :finding, foreign_key: 'occurrence_id'
has_many :pipelines, through: :finding_pipelines, class_name: 'Ci::Pipeline' has_many :pipelines, through: :finding_pipelines, class_name: 'Ci::Pipeline'
attr_writer :sha attr_writer :sha
...@@ -122,7 +125,7 @@ module Vulnerabilities ...@@ -122,7 +125,7 @@ module Vulnerabilities
end end
def self.with_vulnerabilities_for_state(project:, report_type:, project_fingerprints:) def self.with_vulnerabilities_for_state(project:, report_type:, project_fingerprints:)
Vulnerabilities::Occurrence Vulnerabilities::Finding
.joins(:vulnerability) .joins(:vulnerability)
.where( .where(
project: project, project: project,
...@@ -191,10 +194,10 @@ module Vulnerabilities ...@@ -191,10 +194,10 @@ module Vulnerabilities
end end
def load_feedback def load_feedback
BatchLoader.for(occurrence_key).batch(replace_methods: false) do |occurrence_keys, loader| BatchLoader.for(finding_key).batch(replace_methods: false) do |finding_keys, loader|
project_ids = occurrence_keys.map { |key| key[:project_id] } project_ids = finding_keys.map { |key| key[:project_id] }
categories = occurrence_keys.map { |key| key[:category] } categories = finding_keys.map { |key| key[:category] }
fingerprints = occurrence_keys.map { |key| key[:project_fingerprint] } fingerprints = finding_keys.map { |key| key[:project_fingerprint] }
feedback = Vulnerabilities::Feedback.all_preloaded.where( feedback = Vulnerabilities::Feedback.all_preloaded.where(
project_id: project_ids.uniq, project_id: project_ids.uniq,
...@@ -202,10 +205,10 @@ module Vulnerabilities ...@@ -202,10 +205,10 @@ module Vulnerabilities
project_fingerprint: fingerprints.uniq project_fingerprint: fingerprints.uniq
).to_a ).to_a
occurrence_keys.each do |occurrence_key| finding_keys.each do |finding_key|
loader.call( loader.call(
occurrence_key, finding_key,
feedback.select { |f| occurrence_key == f.occurrence_key } feedback.select { |f| finding_key == f.finding_key }
) )
end end
end end
...@@ -308,7 +311,7 @@ module Vulnerabilities ...@@ -308,7 +311,7 @@ module Vulnerabilities
private private
def occurrence_key def finding_key
{ {
project_id: project_id, project_id: project_id,
category: report_type, category: report_type,
......
...@@ -4,10 +4,12 @@ module Vulnerabilities ...@@ -4,10 +4,12 @@ module Vulnerabilities
class FindingIdentifier < ApplicationRecord class FindingIdentifier < ApplicationRecord
self.table_name = "vulnerability_occurrence_identifiers" self.table_name = "vulnerability_occurrence_identifiers"
belongs_to :occurrence, class_name: 'Vulnerabilities::Occurrence' alias_attribute :finding_id, :occurrence_id
belongs_to :identifier, class_name: 'Vulnerabilities::Identifier'
validates :occurrence, presence: true belongs_to :finding, class_name: 'Vulnerabilities::Finding', inverse_of: :finding_identifiers, foreign_key: 'occurrence_id'
belongs_to :identifier, class_name: 'Vulnerabilities::Identifier', inverse_of: :finding_identifiers
validates :finding, presence: true
validates :identifier, presence: true validates :identifier, presence: true
validates :identifier_id, uniqueness: { scope: [:occurrence_id] } validates :identifier_id, uniqueness: { scope: [:occurrence_id] }
end end
......
...@@ -4,10 +4,12 @@ module Vulnerabilities ...@@ -4,10 +4,12 @@ module Vulnerabilities
class FindingPipeline < ApplicationRecord class FindingPipeline < ApplicationRecord
self.table_name = "vulnerability_occurrence_pipelines" self.table_name = "vulnerability_occurrence_pipelines"
belongs_to :occurrence, class_name: 'Vulnerabilities::Occurrence' alias_attribute :finding_id, :occurrence_id
belongs_to :finding, class_name: 'Vulnerabilities::Finding', inverse_of: :finding_pipelines, foreign_key: 'occurrence_id'
belongs_to :pipeline, class_name: '::Ci::Pipeline' belongs_to :pipeline, class_name: '::Ci::Pipeline'
validates :occurrence, presence: true validates :finding, presence: true
validates :pipeline, presence: true validates :pipeline, presence: true
validates :pipeline_id, uniqueness: { scope: [:occurrence_id] } validates :pipeline_id, uniqueness: { scope: [:occurrence_id] }
end end
......
...@@ -8,10 +8,10 @@ module Vulnerabilities ...@@ -8,10 +8,10 @@ module Vulnerabilities
sha_attribute :fingerprint sha_attribute :fingerprint
has_many :finding_identifiers, class_name: 'Vulnerabilities::FindingIdentifier' has_many :finding_identifiers, class_name: 'Vulnerabilities::FindingIdentifier', inverse_of: :identifier, foreign_key: 'identifier_id'
has_many :occurrences, through: :finding_identifiers, class_name: 'Vulnerabilities::Occurrence' has_many :findings, through: :finding_identifiers, class_name: 'Vulnerabilities::Finding'
has_many :primary_occurrences, class_name: 'Vulnerabilities::Occurrence', inverse_of: :primary_identifier has_many :primary_findings, class_name: 'Vulnerabilities::Finding', inverse_of: :primary_identifier, foreign_key: 'primary_identifier_id'
belongs_to :project belongs_to :project
......
...@@ -4,7 +4,7 @@ module Vulnerabilities ...@@ -4,7 +4,7 @@ module Vulnerabilities
class Scanner < ApplicationRecord class Scanner < ApplicationRecord
self.table_name = "vulnerability_scanners" self.table_name = "vulnerability_scanners"
has_many :occurrences, class_name: 'Vulnerabilities::Occurrence' has_many :findings, class_name: 'Vulnerabilities::Finding', inverse_of: :scanner
belongs_to :project belongs_to :project
...@@ -17,7 +17,7 @@ module Vulnerabilities ...@@ -17,7 +17,7 @@ module Vulnerabilities
scope :for_projects, -> (project_ids) { where(project_id: project_ids) } scope :for_projects, -> (project_ids) { where(project_id: project_ids) }
scope :with_report_type, -> do scope :with_report_type, -> do
joins(:occurrences) joins(:findings)
.select('DISTINCT ON ("vulnerability_scanners"."external_id", "vulnerability_occurrences"."report_type") "vulnerability_scanners".*, "vulnerability_occurrences"."report_type" AS "report_type"') .select('DISTINCT ON ("vulnerability_scanners"."external_id", "vulnerability_occurrences"."report_type") "vulnerability_scanners".*, "vulnerability_occurrences"."report_type" AS "report_type"')
.order('"vulnerability_scanners"."external_id" ASC, "vulnerability_occurrences"."report_type" ASC') .order('"vulnerability_scanners"."external_id" ASC, "vulnerability_occurrences"."report_type" ASC')
end end
......
...@@ -33,7 +33,7 @@ class Vulnerability < ApplicationRecord ...@@ -33,7 +33,7 @@ class Vulnerability < ApplicationRecord
has_one :group, through: :project has_one :group, through: :project
has_many :findings, class_name: 'Vulnerabilities::Occurrence', inverse_of: :vulnerability has_many :findings, class_name: 'Vulnerabilities::Finding', inverse_of: :vulnerability
has_many :issue_links, class_name: 'Vulnerabilities::IssueLink', inverse_of: :vulnerability has_many :issue_links, class_name: 'Vulnerabilities::IssueLink', inverse_of: :vulnerability
has_many :related_issues, through: :issue_links, source: :issue do has_many :related_issues, through: :issue_links, source: :issue do
def with_vulnerability_links def with_vulnerability_links
...@@ -46,9 +46,9 @@ class Vulnerability < ApplicationRecord ...@@ -46,9 +46,9 @@ class Vulnerability < ApplicationRecord
has_many :user_mentions, class_name: 'VulnerabilityUserMention' has_many :user_mentions, class_name: 'VulnerabilityUserMention'
enum state: { detected: 1, dismissed: 2, resolved: 3, confirmed: 4 } enum state: { detected: 1, dismissed: 2, resolved: 3, confirmed: 4 }
enum severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS, _prefix: :severity enum severity: Vulnerabilities::Finding::SEVERITY_LEVELS, _prefix: :severity
enum confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS, _prefix: :confidence enum confidence: Vulnerabilities::Finding::CONFIDENCE_LEVELS, _prefix: :confidence
enum report_type: Vulnerabilities::Occurrence::REPORT_TYPES enum report_type: Vulnerabilities::Finding::REPORT_TYPES
validates :project, :author, :title, :severity, :confidence, :report_type, presence: true validates :project, :author, :title, :severity, :confidence, :report_type, presence: true
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Security module Security
class VulnerableProjectPresenter < ::Gitlab::View::Presenter::Delegated class VulnerableProjectPresenter < ::Gitlab::View::Presenter::Delegated
SEVERITY_LEVELS = ::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys SEVERITY_LEVELS = ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys
presents :project presents :project
...@@ -14,7 +14,7 @@ module Security ...@@ -14,7 +14,7 @@ module Security
def counts_for_project(project) def counts_for_project(project)
SEVERITY_LEVELS.each_with_object({}) do |severity, counts| SEVERITY_LEVELS.each_with_object({}) do |severity, counts|
counts["#{severity}_vulnerability_count".to_sym] = ::Vulnerabilities::Occurrence.batch_count_by_project_and_severity(project.id, severity) counts["#{severity}_vulnerability_count".to_sym] = ::Vulnerabilities::Finding.batch_count_by_project_and_severity(project.id, severity)
end end
end end
end end
......
# frozen_string_literal: true # frozen_string_literal: true
module Vulnerabilities module Vulnerabilities
class OccurrencePresenter < Gitlab::View::Presenter::Delegated class FindingPresenter < Gitlab::View::Presenter::Delegated
presents :occurrence presents :finding
def blob_path def blob_path
return '' unless sha.present? return '' unless sha.present?
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
class Vulnerabilities::HistoryEntity < Grape::Entity class Vulnerabilities::HistoryEntity < Grape::Entity
present_collection true present_collection true
Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.each do |level| Vulnerabilities::Finding::SEVERITY_LEVELS.keys.each do |level|
expose level do |object| expose level do |object|
counts(by_severity[level]&.group_by(&:day) || {}) counts(by_severity[level]&.group_by(&:day) || {})
end end
......
# frozen_string_literal: true # frozen_string_literal: true
class VulnerabilitySummaryEntity < Grape::Entity class VulnerabilitySummaryEntity < Grape::Entity
Vulnerabilities::Occurrence::SEVERITY_LEVELS.each do |severity_name, severity| Vulnerabilities::Finding::SEVERITY_LEVELS.each do |severity_name, severity|
expose severity_name do |param| expose severity_name do |param|
object[severity] || 0 object[severity] || 0
end end
......
# frozen_string_literal: true # frozen_string_literal: true
class VulnerableProjectEntity < ProjectEntity class VulnerableProjectEntity < ProjectEntity
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.each_key do |severity_level| ::Vulnerabilities::Finding::SEVERITY_LEVELS.each_key do |severity_level|
expose "#{severity_level}_vulnerability_count" expose "#{severity_level}_vulnerability_count"
end end
end end
...@@ -75,7 +75,7 @@ module Security ...@@ -75,7 +75,7 @@ module Security
level_i = dep_i.dig(:vulnerabilities, 0, :severity) || :info level_i = dep_i.dig(:vulnerabilities, 0, :severity) || :info
level_j = dep_j.dig(:vulnerabilities, 0, :severity) || :info level_j = dep_j.dig(:vulnerabilities, 0, :severity) || :info
::Vulnerabilities::Occurrence::SEVERITY_LEVELS[level_j] <=> ::Vulnerabilities::Occurrence::SEVERITY_LEVELS[level_i] ::Vulnerabilities::Finding::SEVERITY_LEVELS[level_j] <=> ::Vulnerabilities::Finding::SEVERITY_LEVELS[level_i]
end end
end end
end end
......
...@@ -34,18 +34,18 @@ module Security ...@@ -34,18 +34,18 @@ module Security
@source_reports.first.commit_sha, @source_reports.first.commit_sha,
@source_reports.first.created_at @source_reports.first.created_at
) )
@occurrences = [] @findings = []
end end
def execute def execute
@source_reports.each do |source| @source_reports.each do |source|
copy_scanners_to_target(source) copy_scanners_to_target(source)
copy_identifiers_to_target(source) copy_identifiers_to_target(source)
copy_occurrences_to_buffer(source) copy_findings_to_buffer(source)
copy_scanned_resources_to_target(source) copy_scanned_resources_to_target(source)
end end
copy_occurrences_to_target copy_findings_to_target
@target_report @target_report
end end
...@@ -62,8 +62,8 @@ module Security ...@@ -62,8 +62,8 @@ module Security
source_report.identifiers.values.each { |identifier| @target_report.add_identifier(identifier) } source_report.identifiers.values.each { |identifier| @target_report.add_identifier(identifier) }
end end
def copy_occurrences_to_buffer(source) def copy_findings_to_buffer(source)
@occurrences.concat(source.occurrences) @findings.concat(source.findings)
end end
def copy_scanned_resources_to_target(source_report) def copy_scanned_resources_to_target(source_report)
...@@ -82,49 +82,49 @@ module Security ...@@ -82,49 +82,49 @@ module Security
end end
end end
def deduplicate_occurrences! def deduplicate_findings!
seen_identifiers = Set.new seen_identifiers = Set.new
deduplicated = [] deduplicated = []
@occurrences.each do |occurrence| @findings.each do |finding|
seen = false seen = false
# We are looping through all identifiers in order to find the same vulnerabilities reported for the same location # We are looping through all identifiers in order to find the same vulnerabilities reported for the same location
# but from different source reports and keeping only first of them # but from different source reports and keeping only first of them
occurrence.identifiers.each do |identifier| finding.identifiers.each do |identifier|
# TODO: remove .downcase here after the DAST parser is harmonized to the common library identifiers' keys format # TODO: remove .downcase here after the DAST parser is harmonized to the common library identifiers' keys format
# See https://gitlab.com/gitlab-org/gitlab/issues/11976#note_191257912 # See https://gitlab.com/gitlab-org/gitlab/issues/11976#note_191257912
next if %w[cwe wasc].include?(identifier.external_type.downcase) # ignored because these describe a class of vulnerabilities next if %w[cwe wasc].include?(identifier.external_type.downcase) # ignored because these describe a class of vulnerabilities
seen = check_or_mark_seen_identifier!(identifier, occurrence.location.fingerprint, seen_identifiers) seen = check_or_mark_seen_identifier!(identifier, finding.location.fingerprint, seen_identifiers)
break if seen break if seen
end end
deduplicated << occurrence unless seen deduplicated << finding unless seen
end end
@occurrences = deduplicated @findings = deduplicated
end end
def sort_occurrences! def sort_findings!
@occurrences.sort! do |a, b| @findings.sort! do |a, b|
a_severity, b_severity = a.severity, b.severity a_severity, b_severity = a.severity, b.severity
if a_severity == b_severity if a_severity == b_severity
a.compare_key <=> b.compare_key a.compare_key <=> b.compare_key
else else
Vulnerabilities::Occurrence::SEVERITY_LEVELS[b_severity] <=> Vulnerabilities::Finding::SEVERITY_LEVELS[b_severity] <=>
Vulnerabilities::Occurrence::SEVERITY_LEVELS[a_severity] Vulnerabilities::Finding::SEVERITY_LEVELS[a_severity]
end end
end end
end end
def copy_occurrences_to_target def copy_findings_to_target
deduplicate_occurrences! deduplicate_findings!
sort_occurrences! sort_findings!
@occurrences.each { |occurrence| @target_report.add_occurrence(occurrence) } @findings.each { |finding| @target_report.add_finding(finding) }
end end
def sort_by_ds_analyzers! def sort_by_ds_analyzers!
......
...@@ -5,7 +5,7 @@ module Security ...@@ -5,7 +5,7 @@ module Security
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
# @param [Ci::Pipeline] pipeline # @param [Ci::Pipeline] pipeline
# @param [Hash[Symbol, Array[Symbol]] selection_information keys must be in the set of Vulnerabilities::Occurrence::REPORT_TYPES for example: {dast: [:scanned_resources_count, :vulnerabilities_count], container_scanning:[:vulnerabilities_count]} # @param [Hash[Symbol, Array[Symbol]] selection_information keys must be in the set of Vulnerabilities::Finding::REPORT_TYPES for example: {dast: [:scanned_resources_count, :vulnerabilities_count], container_scanning:[:vulnerabilities_count]}
def initialize(pipeline, selection_information) def initialize(pipeline, selection_information)
@pipeline = pipeline @pipeline = pipeline
@selection_information = selection_information @selection_information = selection_information
......
...@@ -6,7 +6,7 @@ module Security ...@@ -6,7 +6,7 @@ module Security
# #
class ScannedResourcesCountingService class ScannedResourcesCountingService
# @param [Ci::Pipeline] pipeline # @param [Ci::Pipeline] pipeline
# @param Array[Symbol] report_types Summary report types. Valid values are members of Vulnerabilities::Occurrence::REPORT_TYPES # @param Array[Symbol] report_types Summary report types. Valid values are members of Vulnerabilities::Finding::REPORT_TYPES
def initialize(pipeline, report_types) def initialize(pipeline, report_types)
@pipeline = pipeline @pipeline = pipeline
@report_types = report_types @report_types = report_types
......
...@@ -6,7 +6,7 @@ module Security ...@@ -6,7 +6,7 @@ module Security
# #
class ScannedResourcesService class ScannedResourcesService
# @param [Ci::Pipeline] pipeline # @param [Ci::Pipeline] pipeline
# @param Array[Symbol] report_types Summary report types. Valid values are members of Vulnerabilities::Occurrence::REPORT_TYPES # @param Array[Symbol] report_types Summary report types. Valid values are members of Vulnerabilities::Finding::REPORT_TYPES
# @param [Int] The maximum number of scanned resources to return # @param [Int] The maximum number of scanned resources to return
def initialize(pipeline, report_types, limit = nil) def initialize(pipeline, report_types, limit = nil)
@pipeline = pipeline @pipeline = pipeline
......
...@@ -30,20 +30,20 @@ module Security ...@@ -30,20 +30,20 @@ module Security
end end
def create_all_vulnerabilities! def create_all_vulnerabilities!
@report.occurrences.each do |occurrence| @report.findings.each do |finding|
create_vulnerability_finding(occurrence) create_vulnerability_finding(finding)
end end
end end
def create_vulnerability_finding(occurrence) def create_vulnerability_finding(finding)
vulnerability_params = occurrence.to_hash.except(:compare_key, :identifiers, :location, :scanner) vulnerability_params = finding.to_hash.except(:compare_key, :identifiers, :location, :scanner)
vulnerability_finding = create_or_find_vulnerability_finding(occurrence, vulnerability_params) vulnerability_finding = create_or_find_vulnerability_finding(finding, vulnerability_params)
update_vulnerability_scanner(occurrence) update_vulnerability_scanner(finding)
update_vulnerability_finding(vulnerability_finding, vulnerability_params) update_vulnerability_finding(vulnerability_finding, vulnerability_params)
occurrence.identifiers.map do |identifier| finding.identifiers.map do |identifier|
create_or_update_vulnerability_identifier_object(vulnerability_finding, identifier) create_or_update_vulnerability_identifier_object(vulnerability_finding, identifier)
end end
...@@ -53,13 +53,13 @@ module Security ...@@ -53,13 +53,13 @@ module Security
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def create_or_find_vulnerability_finding(occurrence, create_params) def create_or_find_vulnerability_finding(finding, create_params)
return if occurrence.scanner.blank? return if finding.scanner.blank?
find_params = { find_params = {
scanner: scanners_objects[occurrence.scanner.key], scanner: scanners_objects[finding.scanner.key],
primary_identifier: identifiers_objects[occurrence.primary_identifier.key], primary_identifier: identifiers_objects[finding.primary_identifier.key],
location_fingerprint: occurrence.location.fingerprint location_fingerprint: finding.location.fingerprint
} }
begin begin
...@@ -74,11 +74,11 @@ module Security ...@@ -74,11 +74,11 @@ module Security
end end
end end
def update_vulnerability_scanner(occurrence) def update_vulnerability_scanner(finding)
return if occurrence.scanner.blank? return if finding.scanner.blank?
scanner = scanners_objects[occurrence.scanner.key] scanner = scanners_objects[finding.scanner.key]
scanner.update!(occurrence.scanner.to_hash) scanner.update!(finding.scanner.to_hash)
end end
def update_vulnerability_finding(vulnerability_finding, update_params) def update_vulnerability_finding(vulnerability_finding, update_params)
......
...@@ -6,15 +6,15 @@ module Security ...@@ -6,15 +6,15 @@ module Security
# #
class VulnerabilityCountingService class VulnerabilityCountingService
# @param [Ci::Pipeline] pipeline # @param [Ci::Pipeline] pipeline
# @param Array[String] report_types Summary report types. Valid values are members of Vulnerabilities::Occurrence::REPORT_TYPES # @param Array[String] report_types Summary report types. Valid values are members of Vulnerabilities::Finding::REPORT_TYPES
def initialize(pipeline, report_types) def initialize(pipeline, report_types)
@pipeline = pipeline @pipeline = pipeline
@report_types = report_types @report_types = report_types
end end
def execute def execute
findings = ::Security::PipelineVulnerabilitiesFinder.new(pipeline: @pipeline, params: { report_type: @report_types }).execute vulnerabilities = ::Security::PipelineVulnerabilitiesFinder.new(pipeline: @pipeline, params: { report_type: @report_types }).execute
findings.occurrences.group_by(&:report_type).compact.transform_values(&:size).reverse_merge(no_counts) vulnerabilities.findings.group_by(&:report_type).compact.transform_values(&:size).reverse_merge(no_counts)
end end
private private
......
...@@ -15,7 +15,7 @@ module Vulnerabilities ...@@ -15,7 +15,7 @@ module Vulnerabilities
vulnerability = Vulnerability.new vulnerability = Vulnerability.new
Vulnerabilities::Occurrence.transaction(requires_new: true) do Vulnerabilities::Finding.transaction(requires_new: true) do
# we're using `lock` instead of `with_lock` to avoid extra call to `find` under the hood # we're using `lock` instead of `with_lock` to avoid extra call to `find` under the hood
finding = @project.vulnerability_findings.lock_for_confirmation!(@finding_id) finding = @project.vulnerability_findings.lock_for_confirmation!(@finding_id)
......
...@@ -128,15 +128,15 @@ class Gitlab::Seeder::Vulnerabilities ...@@ -128,15 +128,15 @@ class Gitlab::Seeder::Vulnerabilities
end end
def random_confidence_level def random_confidence_level
::Vulnerabilities::Occurrence::CONFIDENCE_LEVELS.keys.sample ::Vulnerabilities::Finding::CONFIDENCE_LEVELS.keys.sample
end end
def random_severity_level def random_severity_level
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.sample ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.sample
end end
def random_report_type def random_report_type
::Vulnerabilities::Occurrence::REPORT_TYPES.keys.sample ::Vulnerabilities::Finding::REPORT_TYPES.keys.sample
end end
def metadata(line) def metadata(line)
......
...@@ -16,11 +16,11 @@ module API ...@@ -16,11 +16,11 @@ module API
end end
end end
def vulnerability_occurrences_by(params) def vulnerability_findings_by(params)
return [] unless pipeline return [] unless pipeline
aggregated_report = Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: params).execute aggregated_report = Security::PipelineVulnerabilitiesFinder.new(pipeline: pipeline, params: params).execute
aggregated_report.occurrences aggregated_report.findings
end end
end end
...@@ -36,8 +36,8 @@ module API ...@@ -36,8 +36,8 @@ module API
optional :report_type, type: Array[String], optional :report_type, type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
desc: 'The type of report vulnerability belongs to', desc: 'The type of report vulnerability belongs to',
values: ::Vulnerabilities::Occurrence.report_types.keys, values: ::Vulnerabilities::Finding.report_types.keys,
default: ::Vulnerabilities::Occurrence.report_types.keys default: ::Vulnerabilities::Finding.report_types.keys
optional :scope, type: String, desc: 'Return vulnerabilities for the given scope: `dismissed` or `all`', optional :scope, type: String, desc: 'Return vulnerabilities for the given scope: `dismissed` or `all`',
default: 'dismissed', values: %w[all dismissed] default: 'dismissed', values: %w[all dismissed]
optional :severity, optional :severity,
...@@ -45,16 +45,16 @@ module API ...@@ -45,16 +45,16 @@ module API
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
desc: 'Returns vulnerabilities belonging to specified severity level: '\ desc: 'Returns vulnerabilities belonging to specified severity level: '\
'`info`, `unknown`, `low`, `medium`, `high`, or `critical`. Defaults to all', '`info`, `unknown`, `low`, `medium`, `high`, or `critical`. Defaults to all',
values: ::Vulnerabilities::Occurrence.severities.keys, values: ::Vulnerabilities::Finding.severities.keys,
default: ::Vulnerabilities::Occurrence.severities.keys default: ::Vulnerabilities::Finding.severities.keys
optional :confidence, optional :confidence,
type: Array[String], type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
desc: 'Returns vulnerabilities belonging to specified confidence level: '\ desc: 'Returns vulnerabilities belonging to specified confidence level: '\
'`ignore`, `unknown`, `experimental`, `low`, `medium`, `high`, or `confirmed`. '\ '`ignore`, `unknown`, `experimental`, `low`, `medium`, `high`, or `confirmed`. '\
'Defaults to all', 'Defaults to all',
values: ::Vulnerabilities::Occurrence.confidences.keys, values: ::Vulnerabilities::Finding.confidences.keys,
default: ::Vulnerabilities::Occurrence.confidences.keys default: ::Vulnerabilities::Finding.confidences.keys
optional :scanner, optional :scanner,
type: Array[String], type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
...@@ -74,15 +74,15 @@ module API ...@@ -74,15 +74,15 @@ module API
# Kaminari.paginate_array here is correct # Kaminari.paginate_array here is correct
# See https://gitlab.com/gitlab-org/gitlab/issues/33588#note_291849433 # See https://gitlab.com/gitlab-org/gitlab/issues/33588#note_291849433
# for discussion # for discussion
vulnerability_occurrences = paginate( vulnerability_findings = paginate(
Kaminari.paginate_array( Kaminari.paginate_array(
vulnerability_occurrences_by(declared_params) vulnerability_findings_by(declared_params)
) )
) )
Gitlab::Vulnerabilities::FindingsPreloader.preload_feedback!(vulnerability_occurrences) Gitlab::Vulnerabilities::FindingsPreloader.preload_feedback!(vulnerability_findings)
present vulnerability_occurrences, present vulnerability_findings,
with: ::Vulnerabilities::FindingEntity, with: ::Vulnerabilities::FindingEntity,
request: GrapeRequestProxy.new(request, current_user) request: GrapeRequestProxy.new(request, current_user)
end end
......
...@@ -54,7 +54,7 @@ module Gitlab ...@@ -54,7 +54,7 @@ module Gitlab
def create_vulnerability(report, data, version) def create_vulnerability(report, data, version)
scanner = create_scanner(report, data['scanner'] || mutate_scanner_tool(data['tool'])) scanner = create_scanner(report, data['scanner'] || mutate_scanner_tool(data['tool']))
identifiers = create_identifiers(report, data['identifiers']) identifiers = create_identifiers(report, data['identifiers'])
report.add_occurrence( report.add_finding(
::Gitlab::Ci::Reports::Security::Occurrence.new( ::Gitlab::Ci::Reports::Security::Occurrence.new(
uuid: SecureRandom.uuid, uuid: SecureRandom.uuid,
report_type: report.type, report_type: report.type,
...@@ -104,13 +104,13 @@ module Gitlab ...@@ -104,13 +104,13 @@ module Gitlab
end end
def parse_severity_level(input) def parse_severity_level(input)
return input if ::Vulnerabilities::Occurrence::SEVERITY_LEVELS.key?(input) return input if ::Vulnerabilities::Finding::SEVERITY_LEVELS.key?(input)
'unknown' 'unknown'
end end
def parse_confidence_level(input) def parse_confidence_level(input)
return input if ::Vulnerabilities::Occurrence::CONFIDENCE_LEVELS.key?(input) return input if ::Vulnerabilities::Finding::CONFIDENCE_LEVELS.key?(input)
'unknown' 'unknown'
end end
......
...@@ -7,11 +7,11 @@ module Gitlab ...@@ -7,11 +7,11 @@ module Gitlab
module Reports module Reports
module Security module Security
class AggregatedReport class AggregatedReport
attr_reader :occurrences attr_reader :findings
def initialize(reports, occurrences) def initialize(reports, findings)
@reports = reports @reports = reports
@occurrences = occurrences @findings = findings
end end
def created_at def created_at
......
...@@ -10,7 +10,7 @@ module Gitlab ...@@ -10,7 +10,7 @@ module Gitlab
attr_reader :created_at attr_reader :created_at
attr_reader :type attr_reader :type
attr_reader :commit_sha attr_reader :commit_sha
attr_reader :occurrences attr_reader :findings
attr_reader :scanners attr_reader :scanners
attr_reader :identifiers attr_reader :identifiers
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
@type = type @type = type
@commit_sha = commit_sha @commit_sha = commit_sha
@created_at = created_at @created_at = created_at
@occurrences = [] @findings = []
@scanners = {} @scanners = {}
@identifiers = {} @identifiers = {}
@scanned_resources = [] @scanned_resources = []
...@@ -39,8 +39,8 @@ module Gitlab ...@@ -39,8 +39,8 @@ module Gitlab
identifiers[identifier.key] ||= identifier identifiers[identifier.key] ||= identifier
end end
def add_occurrence(occurrence) def add_finding(finding)
occurrences << occurrence findings << finding
end end
def clone_as_blank def clone_as_blank
...@@ -62,7 +62,7 @@ module Gitlab ...@@ -62,7 +62,7 @@ module Gitlab
end end
def safe? def safe?
severities = occurrences.map(&:severity).compact.map(&:downcase) severities = findings.map(&:severity).compact.map(&:downcase)
(severities & UNSAFE_SEVERITIES).empty? (severities & UNSAFE_SEVERITIES).empty?
end end
end end
......
...@@ -33,20 +33,20 @@ module Gitlab ...@@ -33,20 +33,20 @@ module Gitlab
def added def added
strong_memoize(:added) do strong_memoize(:added) do
head_report.occurrences - base_report.occurrences head_report.findings - base_report.findings
end end
end end
def fixed def fixed
strong_memoize(:fixed) do strong_memoize(:fixed) do
base_report.occurrences - head_report.occurrences base_report.findings - head_report.findings
end end
end end
def existing def existing
strong_memoize(:existing) do strong_memoize(:existing) do
# Existing vulnerabilities should point to source report for most recent information # Existing vulnerabilities should point to source report for most recent information
head_report.occurrences & base_report.occurrences head_report.findings & base_report.findings
end end
end end
......
...@@ -29,7 +29,7 @@ module Gitlab ...@@ -29,7 +29,7 @@ module Gitlab
critical: 0 critical: 0
} }
summary_keys = ::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.map(&:to_sym) summary_keys = ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.map(&:to_sym)
project_ids_to_fetch.each do |project_id| project_ids_to_fetch.each do |project_id|
project_summary = Gitlab::Vulnerabilities::SummaryCache project_summary = Gitlab::Vulnerabilities::SummaryCache
......
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
FactoryBot.define do FactoryBot.define do
factory :ci_reports_security_aggregated_reports, class: '::Gitlab::Ci::Reports::Security::AggregatedReport' do factory :ci_reports_security_aggregated_reports, class: '::Gitlab::Ci::Reports::Security::AggregatedReport' do
reports { FactoryBot.build_list(:ci_reports_security_report, 1) } reports { FactoryBot.build_list(:ci_reports_security_report, 1) }
occurrences { FactoryBot.build_list(:ci_reports_security_occurrence, 1) } findings { FactoryBot.build_list(:ci_reports_security_finding, 1) }
initialize_with do initialize_with do
::Gitlab::Ci::Reports::Security::AggregatedReport.new(reports, occurrences) ::Gitlab::Ci::Reports::Security::AggregatedReport.new(reports, findings)
end end
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
FactoryBot.define do FactoryBot.define do
factory :ci_reports_security_occurrence, class: '::Gitlab::Ci::Reports::Security::Occurrence' do factory :ci_reports_security_finding, class: '::Gitlab::Ci::Reports::Security::Occurrence' do
compare_key { "#{identifiers.first.external_type}:#{identifiers.first.external_id}:#{location.fingerprint}" } compare_key { "#{identifiers.first.external_type}:#{identifiers.first.external_id}:#{location.fingerprint}" }
confidence { :medium } confidence { :medium }
identifiers { Array.new(1) { FactoryBot.build(:ci_reports_security_identifier) } } identifiers { Array.new(1) { FactoryBot.build(:ci_reports_security_identifier) } }
...@@ -30,7 +30,7 @@ FactoryBot.define do ...@@ -30,7 +30,7 @@ FactoryBot.define do
end end
scanner factory: :ci_reports_security_scanner scanner factory: :ci_reports_security_scanner
severity { :high } severity { :high }
sequence(:uuid) { generate(:vulnerability_occurrence_uuid) } sequence(:uuid) { generate(:vulnerability_finding_uuid) }
skip_create skip_create
......
...@@ -8,7 +8,7 @@ FactoryBot.define do ...@@ -8,7 +8,7 @@ FactoryBot.define do
scanned_resources { [] } scanned_resources { [] }
transient do transient do
occurrences { [] } findings { [] }
scanners { [] } scanners { [] }
identifiers { [] } identifiers { [] }
end end
...@@ -16,7 +16,7 @@ FactoryBot.define do ...@@ -16,7 +16,7 @@ FactoryBot.define do
after :build do |report, evaluator| after :build do |report, evaluator|
evaluator.scanners.each { |s| report.add_scanner(s) } evaluator.scanners.each { |s| report.add_scanner(s) }
evaluator.identifiers.each { |id| report.add_identifier(id) } evaluator.identifiers.each { |id| report.add_identifier(id) }
evaluator.occurrences.each { |o| report.add_occurrence(o) } evaluator.findings.each { |o| report.add_finding(o) }
end end
skip_create skip_create
......
...@@ -45,13 +45,13 @@ FactoryBot.define do ...@@ -45,13 +45,13 @@ FactoryBot.define do
severity { :low } severity { :low }
end end
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.each do |severity_level| ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.each do |severity_level|
trait severity_level do trait severity_level do
severity { severity_level } severity { severity_level }
end end
end end
::Vulnerabilities::Occurrence::REPORT_TYPES.keys.each do |report_type| ::Vulnerabilities::Finding::REPORT_TYPES.keys.each do |report_type|
trait report_type do trait report_type do
report_type { report_type } report_type { report_type }
end end
...@@ -59,20 +59,20 @@ FactoryBot.define do ...@@ -59,20 +59,20 @@ FactoryBot.define do
trait :with_findings do trait :with_findings do
after(:build) do |vulnerability| after(:build) do |vulnerability|
occurrences_with_solution = build_list( findings_with_solution = build_list(
:vulnerabilities_occurrence, :vulnerabilities_finding,
2, 2,
vulnerability: vulnerability, vulnerability: vulnerability,
report_type: vulnerability.report_type, report_type: vulnerability.report_type,
project: vulnerability.project) project: vulnerability.project)
occurrences_with_remediation = build_list( findings_with_remediation = build_list(
:vulnerabilities_occurrence, :vulnerabilities_finding,
2, 2,
:with_remediation, :with_remediation,
vulnerability: vulnerability, vulnerability: vulnerability,
report_type: vulnerability.report_type, report_type: vulnerability.report_type,
project: vulnerability.project) project: vulnerability.project)
vulnerability.findings = occurrences_with_solution + occurrences_with_remediation vulnerability.findings = findings_with_solution + findings_with_remediation
end end
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
FactoryBot.define do FactoryBot.define do
factory :vulnerabilities_finding_identifier, class: 'Vulnerabilities::FindingIdentifier' do factory :vulnerabilities_finding_identifier, class: 'Vulnerabilities::FindingIdentifier' do
occurrence factory: :vulnerabilities_occurrence finding factory: :vulnerabilities_finding
identifier factory: :vulnerabilities_identifier identifier factory: :vulnerabilities_identifier
end end
end end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
FactoryBot.define do FactoryBot.define do
factory :vulnerabilities_finding_pipeline, class: 'Vulnerabilities::FindingPipeline' do factory :vulnerabilities_finding_pipeline, class: 'Vulnerabilities::FindingPipeline' do
occurrence factory: :vulnerabilities_occurrence finding factory: :vulnerabilities_finding
pipeline factory: :ci_pipeline pipeline factory: :ci_pipeline
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
FactoryBot.define do FactoryBot.define do
sequence :vulnerability_occurrence_uuid do |n| sequence :vulnerability_finding_uuid do |n|
SecureRandom.uuid SecureRandom.uuid
end end
factory :vulnerabilities_occurrence_with_remediation, parent: :vulnerabilities_occurrence do factory :vulnerabilities_finding_with_remediation, parent: :vulnerabilities_finding do
transient do transient do
summary { nil } summary { nil }
end end
...@@ -24,10 +24,10 @@ FactoryBot.define do ...@@ -24,10 +24,10 @@ FactoryBot.define do
end end
end end
factory :vulnerabilities_occurrence, class: 'Vulnerabilities::Occurrence', aliases: [:vulnerabilities_finding] do factory :vulnerabilities_finding, class: 'Vulnerabilities::Finding', aliases: [:vulnerabilities_occurrence] do
name { 'Cipher with no integrity' } name { 'Cipher with no integrity' }
project project
sequence(:uuid) { generate(:vulnerability_occurrence_uuid) } sequence(:uuid) { generate(:vulnerability_finding_uuid) }
project_fingerprint { generate(:project_fingerprint) } project_fingerprint { generate(:project_fingerprint) }
primary_identifier factory: :vulnerabilities_identifier primary_identifier factory: :vulnerabilities_identifier
location_fingerprint { '4e5b6966dd100170b4b1ad599c7058cce91b57b4' } location_fingerprint { '4e5b6966dd100170b4b1ad599c7058cce91b57b4' }
...@@ -114,7 +114,7 @@ FactoryBot.define do ...@@ -114,7 +114,7 @@ FactoryBot.define do
end end
end end
::Vulnerabilities::Occurrence::REPORT_TYPES.keys.each do |security_report_type| ::Vulnerabilities::Finding::REPORT_TYPES.keys.each do |security_report_type|
trait security_report_type do trait security_report_type do
report_type { security_report_type } report_type { security_report_type }
end end
......
{ {
"type": "array", "type": "array",
"items": { "$ref": "occurrence.json" } "items": { "$ref": "finding.json" }
} }
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilitySeveritiesCount'] do RSpec.describe GitlabSchema.types['VulnerabilitySeveritiesCount'] do
let_it_be(:fields) do let_it_be(:fields) do
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys
end end
it { expect(described_class).to have_graphql_fields(fields) } it { expect(described_class).to have_graphql_fields(fields) }
......
...@@ -13,9 +13,9 @@ RSpec.describe Gitlab::BackgroundMigration::UpdateVulnerabilitiesFromDismissalFe ...@@ -13,9 +13,9 @@ RSpec.describe Gitlab::BackgroundMigration::UpdateVulnerabilitiesFromDismissalFe
let(:feedback) { table(:vulnerability_feedback) } let(:feedback) { table(:vulnerability_feedback) }
let(:namespaces) { table(:namespaces)} let(:namespaces) { table(:namespaces)}
let(:severity) { Vulnerabilities::Occurrence::SEVERITY_LEVELS[:unknown] } let(:severity) { Vulnerabilities::Finding::SEVERITY_LEVELS[:unknown] }
let(:confidence) { Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:medium] } let(:confidence) { Vulnerabilities::Finding::CONFIDENCE_LEVELS[:medium] }
let(:report_type) { Vulnerabilities::Occurrence::REPORT_TYPES[:sast] } let(:report_type) { Vulnerabilities::Finding::REPORT_TYPES[:sast] }
let!(:user) { users.create!(email: 'author@example.com', username: 'author', projects_limit: 10) } let!(:user) { users.create!(email: 'author@example.com', username: 'author', projects_limit: 10) }
let!(:project) { projects.create!(namespace_id: namespace.id, name: 'gitlab', path: 'gitlab') } let!(:project) { projects.create!(namespace_id: namespace.id, name: 'gitlab', path: 'gitlab') }
......
...@@ -12,9 +12,9 @@ RSpec.describe Gitlab::BackgroundMigration::UpdateVulnerabilitiesToDismissed, :m ...@@ -12,9 +12,9 @@ RSpec.describe Gitlab::BackgroundMigration::UpdateVulnerabilitiesToDismissed, :m
let(:identifiers) { table(:vulnerability_identifiers) } let(:identifiers) { table(:vulnerability_identifiers) }
let(:feedback) { table(:vulnerability_feedback) } let(:feedback) { table(:vulnerability_feedback) }
let(:severity) { Vulnerabilities::Occurrence::SEVERITY_LEVELS[:unknown] } let(:severity) { Vulnerabilities::Finding::SEVERITY_LEVELS[:unknown] }
let(:confidence) { Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:medium] } let(:confidence) { Vulnerabilities::Finding::CONFIDENCE_LEVELS[:medium] }
let(:report_type) { Vulnerabilities::Occurrence::REPORT_TYPES[:sast] } let(:report_type) { Vulnerabilities::Finding::REPORT_TYPES[:sast] }
let!(:user) { users.create!(id: 13, email: 'author@example.com', username: 'author', projects_limit: 10) } let!(:user) { users.create!(id: 13, email: 'author@example.com', username: 'author', projects_limit: 10) }
let!(:project) { projects.create!(id: 123, namespace_id: 12, name: 'gitlab', path: 'gitlab') } let!(:project) { projects.create!(id: 123, namespace_id: 12, name: 'gitlab', path: 'gitlab') }
......
...@@ -18,10 +18,10 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do ...@@ -18,10 +18,10 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
parser.parse!(blob, report) parser.parse!(blob, report)
end end
expect(report.occurrences.map(&:severity)).to include("unknown") expect(report.findings.map(&:severity)).to include("unknown")
expect(report.occurrences.map(&:confidence)).to include("unknown") expect(report.findings.map(&:confidence)).to include("unknown")
expect(report.occurrences.map(&:severity)).not_to include("undefined") expect(report.findings.map(&:severity)).not_to include("undefined")
expect(report.occurrences.map(&:confidence)).not_to include("undefined") expect(report.findings.map(&:confidence)).not_to include("undefined")
end end
context 'parsing remediations' do context 'parsing remediations' do
...@@ -101,7 +101,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do ...@@ -101,7 +101,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
raw_json[:remediations] << fix_with_cve raw_json[:remediations] << fix_with_cve
parser.parse!(raw_json.to_json, report) parser.parse!(raw_json.to_json, report)
vulnerability = report.occurrences.find { |x| x.compare_key == "CVE-1020" } vulnerability = report.findings.find { |x| x.compare_key == "CVE-1020" }
expect(vulnerability.raw_metadata).to include fix_with_cve.to_json expect(vulnerability.raw_metadata).to include fix_with_cve.to_json
end end
...@@ -120,7 +120,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do ...@@ -120,7 +120,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
raw_json[:remediations] << fix_with_id raw_json[:remediations] << fix_with_id
parser.parse!(raw_json.to_json, report) parser.parse!(raw_json.to_json, report)
vulnerability = report.occurrences.find { |x| x.compare_key == "CVE-1030" } vulnerability = report.findings.find { |x| x.compare_key == "CVE-1030" }
expect(vulnerability.raw_metadata).to include fix_with_id.to_json expect(vulnerability.raw_metadata).to include fix_with_id.to_json
end end
...@@ -148,9 +148,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do ...@@ -148,9 +148,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
raw_json[:remediations] << fix_with_id << fix_with_cve raw_json[:remediations] << fix_with_id << fix_with_cve
parser.parse!(raw_json.to_json, report) parser.parse!(raw_json.to_json, report)
vulnerability_1030 = report.occurrences.find { |x| x.compare_key == "CVE-1030" } vulnerability_1030 = report.findings.find { |x| x.compare_key == "CVE-1030" }
expect(vulnerability_1030.raw_metadata).to include fix_with_id.to_json expect(vulnerability_1030.raw_metadata).to include fix_with_id.to_json
vulnerability_1020 = report.occurrences.find { |x| x.compare_key == "CVE-1020" } vulnerability_1020 = report.findings.find { |x| x.compare_key == "CVE-1020" }
expect(vulnerability_1020.raw_metadata).to include fix_with_cve.to_json expect(vulnerability_1020.raw_metadata).to include fix_with_cve.to_json
end end
...@@ -179,7 +179,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do ...@@ -179,7 +179,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
raw_json[:remediations] << fix_with_id << fix_with_id_2 raw_json[:remediations] << fix_with_id << fix_with_id_2
parser.parse!(raw_json.to_json, report) parser.parse!(raw_json.to_json, report)
report.occurrences.map do |vulnerability| report.findings.map do |vulnerability|
expect(vulnerability.raw_metadata).not_to include(fix_with_id.to_json) expect(vulnerability.raw_metadata).not_to include(fix_with_id.to_json)
end end
end end
...@@ -208,7 +208,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do ...@@ -208,7 +208,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
} }
end end
subject(:scanner) { report.occurrences.first.scanner } subject(:scanner) { report.findings.first.scanner }
before do before do
parser.parse!(raw_json.to_json, report) parser.parse!(raw_json.to_json, report)
......
...@@ -18,14 +18,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::ContainerScanning do ...@@ -18,14 +18,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::ContainerScanning do
let(:artifact) { create(:ee_ci_job_artifact, :container_scanning) } let(:artifact) { create(:ee_ci_job_artifact, :container_scanning) }
let(:image) { 'registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256:bc09fe2e0721dfaeee79364115aeedf2174cce0947b9ae5fe7c33312ee019a4e' } let(:image) { 'registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256:bc09fe2e0721dfaeee79364115aeedf2174cce0947b9ae5fe7c33312ee019a4e' }
it "parses all identifiers and occurrences for unapproved vulnerabilities" do it "parses all identifiers and findings for unapproved vulnerabilities" do
expect(report.occurrences.length).to eq(8) expect(report.findings.length).to eq(8)
expect(report.identifiers.length).to eq(8) expect(report.identifiers.length).to eq(8)
expect(report.scanners.length).to eq(1) expect(report.scanners.length).to eq(1)
end end
it 'generates expected location' do it 'generates expected location' do
location = report.occurrences.first.location location = report.findings.first.location
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::ContainerScanning) expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::ContainerScanning)
expect(location).to have_attributes( expect(location).to have_attributes(
...@@ -37,11 +37,11 @@ RSpec.describe Gitlab::Ci::Parsers::Security::ContainerScanning do ...@@ -37,11 +37,11 @@ RSpec.describe Gitlab::Ci::Parsers::Security::ContainerScanning do
end end
it "generates expected metadata_version" do it "generates expected metadata_version" do
expect(report.occurrences.first.metadata_version).to eq('2.3') expect(report.findings.first.metadata_version).to eq('2.3')
end end
it "adds report image's name to raw_metadata" do it "adds report image's name to raw_metadata" do
expect(Gitlab::Json.parse(report.occurrences.first.raw_metadata).dig('location', 'image')).to eq(image) expect(Gitlab::Json.parse(report.findings.first.raw_metadata).dig('location', 'image')).to eq(image)
end end
end end
end end
...@@ -16,13 +16,13 @@ RSpec.describe Gitlab::Ci::Parsers::Security::CoverageFuzzing do ...@@ -16,13 +16,13 @@ RSpec.describe Gitlab::Ci::Parsers::Security::CoverageFuzzing do
end end
end end
it 'parses all identifiers and occurrences' do it 'parses all identifiers and findings' do
expect(report.occurrences.length).to eq(1) expect(report.findings.length).to eq(1)
expect(report.scanners.length).to eq(1) expect(report.scanners.length).to eq(1)
end end
it 'generates expected location' do it 'generates expected location' do
location = report.occurrences.first.location location = report.findings.first.location
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::CoverageFuzzing) expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::CoverageFuzzing)
expect(location).to have_attributes( expect(location).to have_attributes(
......
...@@ -37,15 +37,15 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Dast do ...@@ -37,15 +37,15 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Dast do
end end
end end
it 'parses all identifiers, occurrences and scanned resources' do it 'parses all identifiers, findings and scanned resources' do
expect(report.occurrences.length).to eq(occurrence_count) expect(report.findings.length).to eq(occurrence_count)
expect(report.identifiers.length).to eq(identifier_count) expect(report.identifiers.length).to eq(identifier_count)
expect(report.scanners.length).to eq(scanner_count) expect(report.scanners.length).to eq(scanner_count)
expect(report.scanned_resources.length).to eq(scanned_resources_count) expect(report.scanned_resources.length).to eq(scanned_resources_count)
end end
it 'generates expected location' do it 'generates expected location' do
location = report.occurrences.last.location location = report.findings.last.location
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::Dast) expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::Dast)
expect(location).to have_attributes( expect(location).to have_attributes(
...@@ -64,7 +64,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Dast do ...@@ -64,7 +64,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Dast do
with_them do with_them do
it 'saves properly occurrence' do it 'saves properly occurrence' do
occurrence = report.occurrences.last occurrence = report.findings.last
expect(occurrence.public_send(attribute)).to eq(value) expect(occurrence.public_send(attribute)).to eq(value)
end end
......
...@@ -27,14 +27,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::DependencyScanning do ...@@ -27,14 +27,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::DependencyScanning do
end end
end end
it "parses all identifiers and occurrences" do it "parses all identifiers and findings" do
expect(report.occurrences.length).to eq(occurrence_count) expect(report.findings.length).to eq(occurrence_count)
expect(report.identifiers.length).to eq(identifier_count) expect(report.identifiers.length).to eq(identifier_count)
expect(report.scanners.length).to eq(scanner_count) expect(report.scanners.length).to eq(scanner_count)
end end
it 'generates expected location' do it 'generates expected location' do
location = report.occurrences.first.location location = report.findings.first.location
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::DependencyScanning) expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::DependencyScanning)
expect(location).to have_attributes( expect(location).to have_attributes(
...@@ -45,7 +45,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::DependencyScanning do ...@@ -45,7 +45,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::DependencyScanning do
end end
it "generates expected metadata_version" do it "generates expected metadata_version" do
expect(report.occurrences.first.metadata_version).to eq(version) expect(report.findings.first.metadata_version).to eq(version)
end end
end end
...@@ -79,7 +79,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::DependencyScanning do ...@@ -79,7 +79,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::DependencyScanning do
end end
it "generates occurrence with expected remediation" do it "generates occurrence with expected remediation" do
occurrence = report.occurrences.last occurrence = report.findings.last
raw_metadata = Gitlab::Json.parse!(occurrence.raw_metadata) raw_metadata = Gitlab::Json.parse!(occurrence.raw_metadata)
expect(occurrence.name).to eq("Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js") expect(occurrence.name).to eq("Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js")
......
...@@ -22,14 +22,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Sast do ...@@ -22,14 +22,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Sast do
end end
end end
it "parses all identifiers and occurrences" do it "parses all identifiers and findings" do
expect(report.occurrences.length).to eq(33) expect(report.findings.length).to eq(33)
expect(report.identifiers.length).to eq(17) expect(report.identifiers.length).to eq(17)
expect(report.scanners.length).to eq(3) expect(report.scanners.length).to eq(3)
end end
it 'generates expected location' do it 'generates expected location' do
location = report.occurrences.first.location location = report.findings.first.location
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::Sast) expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::Sast)
expect(location).to have_attributes( expect(location).to have_attributes(
...@@ -42,7 +42,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Sast do ...@@ -42,7 +42,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Sast do
end end
it "generates expected metadata_version" do it "generates expected metadata_version" do
expect(report.occurrences.first.metadata_version).to eq('1.2') expect(report.findings.first.metadata_version).to eq('1.2')
end end
end end
end end
......
...@@ -22,14 +22,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::SecretDetection do ...@@ -22,14 +22,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::SecretDetection do
end end
end end
it "parses all identifiers and occurrences" do it "parses all identifiers and findings" do
expect(report.occurrences.length).to eq(1) expect(report.findings.length).to eq(1)
expect(report.identifiers.length).to eq(1) expect(report.identifiers.length).to eq(1)
expect(report.scanners.length).to eq(1) expect(report.scanners.length).to eq(1)
end end
it 'generates expected location' do it 'generates expected location' do
location = report.occurrences.first.location location = report.findings.first.location
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::SecretDetection) expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::SecretDetection)
expect(location).to have_attributes( expect(location).to have_attributes(
...@@ -42,7 +42,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::SecretDetection do ...@@ -42,7 +42,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::SecretDetection do
end end
it "generates expected metadata_version" do it "generates expected metadata_version" do
expect(report.occurrences.first.metadata_version).to eq('3.0') expect(report.findings.first.metadata_version).to eq('3.0')
end end
end end
end end
......
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::Ci::Reports::Security::AggregatedReport do RSpec.describe Gitlab::Ci::Reports::Security::AggregatedReport do
subject { described_class.new(reports, occurrences) } subject { described_class.new(reports, findings) }
let(:reports) { build_list(:ci_reports_security_report, 1) } let(:reports) { build_list(:ci_reports_security_report, 1) }
let(:occurrences) { build_list(:ci_reports_security_occurrence, 1) } let(:findings) { build_list(:ci_reports_security_finding, 1) }
describe '#created_at' do describe '#created_at' do
context 'no reports' do context 'no reports' do
......
...@@ -62,7 +62,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Occurrence do ...@@ -62,7 +62,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Occurrence do
end end
describe "delegation" do describe "delegation" do
subject { create(:ci_reports_security_occurrence) } subject { create(:ci_reports_security_finding) }
%i[file_path start_line end_line].each do |attribute| %i[file_path start_line end_line].each do |attribute|
it "delegates attribute #{attribute} to location" do it "delegates attribute #{attribute} to location" do
...@@ -72,7 +72,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Occurrence do ...@@ -72,7 +72,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Occurrence do
end end
describe '#to_hash' do describe '#to_hash' do
let(:occurrence) { create(:ci_reports_security_occurrence) } let(:occurrence) { create(:ci_reports_security_finding) }
subject { occurrence.to_hash } subject { occurrence.to_hash }
...@@ -98,7 +98,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Occurrence do ...@@ -98,7 +98,7 @@ RSpec.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(:occurrence) { create(:ci_reports_security_occurrence, identifiers: [primary_identifier, other_identifier]) } let(:occurrence) { create(:ci_reports_security_finding, identifiers: [primary_identifier, other_identifier]) }
subject { occurrence.primary_identifier } subject { occurrence.primary_identifier }
...@@ -111,7 +111,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Occurrence do ...@@ -111,7 +111,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Occurrence do
let(:old_location) { create(:ci_reports_security_locations_sast, file_path: 'old_file.rb') } let(:old_location) { create(:ci_reports_security_locations_sast, file_path: 'old_file.rb') }
let(:new_location) { create(:ci_reports_security_locations_sast, file_path: 'new_file.rb') } let(:new_location) { create(:ci_reports_security_locations_sast, file_path: 'new_file.rb') }
let(:occurrence) { create(:ci_reports_security_occurrence, location: old_location) } let(:occurrence) { create(:ci_reports_security_finding, location: old_location) }
subject { occurrence.update_location(new_location) } subject { occurrence.update_location(new_location) }
......
...@@ -41,13 +41,13 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -41,13 +41,13 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
end end
end end
describe '#add_occurrence' do describe '#add_finding' do
let(:occurrence) { create(:ci_reports_security_occurrence) } let(:finding) { create(:ci_reports_security_finding) }
it 'enriches given occurrence and stores it in the collection' do it 'enriches given finding and stores it in the collection' do
report.add_occurrence(occurrence) report.add_finding(finding)
expect(report.occurrences).to eq([occurrence]) expect(report.findings).to eq([finding])
end end
end end
...@@ -55,7 +55,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -55,7 +55,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
let(:report) do let(:report) do
create( create(
:ci_reports_security_report, :ci_reports_security_report,
occurrences: [create(:ci_reports_security_occurrence)], findings: [create(:ci_reports_security_finding)],
scanners: [create(:ci_reports_security_scanner)], scanners: [create(:ci_reports_security_scanner)],
identifiers: [create(:ci_reports_security_identifier)] identifiers: [create(:ci_reports_security_identifier)]
) )
...@@ -67,7 +67,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -67,7 +67,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
expect(clone.type).to eq(report.type) expect(clone.type).to eq(report.type)
expect(clone.commit_sha).to eq(report.commit_sha) expect(clone.commit_sha).to eq(report.commit_sha)
expect(clone.created_at).to eq(report.created_at) expect(clone.created_at).to eq(report.created_at)
expect(clone.occurrences).to eq([]) expect(clone.findings).to eq([])
expect(clone.scanners).to eq({}) expect(clone.scanners).to eq({})
expect(clone.identifiers).to eq({}) expect(clone.identifiers).to eq({})
end end
...@@ -77,7 +77,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -77,7 +77,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
let(:report) do let(:report) do
create( create(
:ci_reports_security_report, :ci_reports_security_report,
occurrences: [create(:ci_reports_security_occurrence)], findings: [create(:ci_reports_security_finding)],
scanners: [create(:ci_reports_security_scanner)], scanners: [create(:ci_reports_security_scanner)],
identifiers: [create(:ci_reports_security_identifier)] identifiers: [create(:ci_reports_security_identifier)]
) )
...@@ -85,7 +85,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -85,7 +85,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
let(:other_report) do let(:other_report) do
create( create(
:ci_reports_security_report, :ci_reports_security_report,
occurrences: [create(:ci_reports_security_occurrence, compare_key: 'other_occurrence')], findings: [create(:ci_reports_security_finding, compare_key: 'other_finding')],
scanners: [create(:ci_reports_security_scanner, external_id: 'other_scanner', name: 'Other Scanner')], scanners: [create(:ci_reports_security_scanner, external_id: 'other_scanner', name: 'Other Scanner')],
identifiers: [create(:ci_reports_security_identifier, external_id: 'other_id', name: 'other_scanner')] identifiers: [create(:ci_reports_security_identifier, external_id: 'other_id', name: 'other_scanner')]
) )
...@@ -96,7 +96,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -96,7 +96,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
end end
it 'replaces report contents with other reports contents' do it 'replaces report contents with other reports contents' do
expect(report.occurrences).to eq(other_report.occurrences) expect(report.findings).to eq(other_report.findings)
expect(report.scanners).to eq(other_report.scanners) expect(report.scanners).to eq(other_report.scanners)
expect(report.identifiers).to eq(other_report.identifiers) expect(report.identifiers).to eq(other_report.identifiers)
end end
...@@ -128,10 +128,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -128,10 +128,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
context "when the sast report has an unsafe vulnerability" do context "when the sast report has an unsafe vulnerability" do
where(severity: %w[unknown Unknown high High critical Critical]) where(severity: %w[unknown Unknown high High critical Critical])
with_them do with_them do
let(:occurrence) { build(:ci_reports_security_occurrence, severity: severity) } let(:finding) { build(:ci_reports_security_finding, severity: severity) }
before do before do
subject.add_occurrence(occurrence) subject.add_finding(finding)
end end
it { expect(subject.unsafe_severity?).to be(true) } it { expect(subject.unsafe_severity?).to be(true) }
...@@ -142,10 +142,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -142,10 +142,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
context "when the sast report has a medium to low severity vulnerability" do context "when the sast report has a medium to low severity vulnerability" do
where(severity: %w[medium Medium low Low]) where(severity: %w[medium Medium low Low])
with_them do with_them do
let(:occurrence) { build(:ci_reports_security_occurrence, severity: severity) } let(:finding) { build(:ci_reports_security_finding, severity: severity) }
before do before do
subject.add_occurrence(occurrence) subject.add_finding(finding)
end end
it { expect(subject.unsafe_severity?).to be(false) } it { expect(subject.unsafe_severity?).to be(false) }
...@@ -154,10 +154,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -154,10 +154,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
end end
context "when the sast report has a vulnerability with a `nil` severity" do context "when the sast report has a vulnerability with a `nil` severity" do
let(:occurrence) { build(:ci_reports_security_occurrence, severity: nil) } let(:finding) { build(:ci_reports_security_finding, severity: nil) }
before do before do
subject.add_occurrence(occurrence) subject.add_finding(finding)
end end
it { expect(subject.unsafe_severity?).to be(false) } it { expect(subject.unsafe_severity?).to be(false) }
...@@ -165,10 +165,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do ...@@ -165,10 +165,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
end end
context "when the sast report has a vulnerability with a blank severity" do context "when the sast report has a vulnerability with a blank severity" do
let(:occurrence) { build(:ci_reports_security_occurrence, severity: '') } let(:finding) { build(:ci_reports_security_finding, severity: '') }
before do before do
subject.add_occurrence(occurrence) subject.add_finding(finding)
end end
it { expect(subject.unsafe_severity?).to be(false) } it { expect(subject.unsafe_severity?).to be(false) }
......
...@@ -41,13 +41,13 @@ RSpec.describe Gitlab::Ci::Reports::Security::Reports do ...@@ -41,13 +41,13 @@ RSpec.describe Gitlab::Ci::Reports::Security::Reports do
describe "#violates_default_policy?" do describe "#violates_default_policy?" do
subject { described_class.new(commit_sha) } subject { described_class.new(commit_sha) }
let(:low_severity) { build(:ci_reports_security_occurrence, severity: 'low') } let(:low_severity) { build(:ci_reports_security_finding, severity: 'low') }
let(:high_severity) { build(:ci_reports_security_occurrence, severity: 'high') } let(:high_severity) { build(:ci_reports_security_finding, severity: 'high') }
context "when a report has a high severity vulnerability" do context "when a report has a high severity vulnerability" do
before do before do
subject.get_report('sast', artifact).add_occurrence(high_severity) subject.get_report('sast', artifact).add_finding(high_severity)
subject.get_report('dependency_scanning', artifact).add_occurrence(low_severity) subject.get_report('dependency_scanning', artifact).add_finding(low_severity)
end end
it { expect(subject.violates_default_policy?).to be(true) } it { expect(subject.violates_default_policy?).to be(true) }
...@@ -55,8 +55,9 @@ RSpec.describe Gitlab::Ci::Reports::Security::Reports do ...@@ -55,8 +55,9 @@ RSpec.describe Gitlab::Ci::Reports::Security::Reports do
context "when none of the reports have a high severity vulnerability" do context "when none of the reports have a high severity vulnerability" do
before do before do
subject.get_report('sast', artifact).add_occurrence(low_severity) subject.get_report('sast', artifact).add_finding(low_severity)
subject.get_report('dependency_scanning', artifact).add_occurrence(low_severity) subject.get_report('sast', artifact).add_finding(low_severity)
subject.get_report('dependency_scanning', artifact).add_finding(low_severity)
end end
it { expect(subject.violates_default_policy?).to be(false) } it { expect(subject.violates_default_policy?).to be(false) }
......
...@@ -16,9 +16,9 @@ RSpec.describe MigrateVulnerabilityDismissalFeedback, :migration, :sidekiq do ...@@ -16,9 +16,9 @@ RSpec.describe MigrateVulnerabilityDismissalFeedback, :migration, :sidekiq do
let(:vulnerabilities) { table(:vulnerabilities) } let(:vulnerabilities) { table(:vulnerabilities) }
let(:dismissed_state) { Gitlab::BackgroundMigration::UpdateVulnerabilitiesFromDismissalFeedback::VULNERABILITY_DISMISSED_STATE } let(:dismissed_state) { Gitlab::BackgroundMigration::UpdateVulnerabilitiesFromDismissalFeedback::VULNERABILITY_DISMISSED_STATE }
let(:severity) { Vulnerabilities::Occurrence::SEVERITY_LEVELS[:unknown] } let(:severity) { Vulnerabilities::Finding::SEVERITY_LEVELS[:unknown] }
let(:confidence) { Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:medium] } let(:confidence) { Vulnerabilities::Finding::CONFIDENCE_LEVELS[:medium] }
let(:report_type) { Vulnerabilities::Occurrence::REPORT_TYPES[:sast] } let(:report_type) { Vulnerabilities::Finding::REPORT_TYPES[:sast] }
before do before do
stub_const("#{described_class.name}::BATCH_SIZE", 1) stub_const("#{described_class.name}::BATCH_SIZE", 1)
......
...@@ -16,9 +16,9 @@ RSpec.describe MigrateVulnerabilityDismissals, :migration, :sidekiq do ...@@ -16,9 +16,9 @@ RSpec.describe MigrateVulnerabilityDismissals, :migration, :sidekiq do
let(:vulnerabilities) { table(:vulnerabilities) } let(:vulnerabilities) { table(:vulnerabilities) }
let(:detected_state) { Gitlab::BackgroundMigration::UpdateVulnerabilitiesToDismissed::VULNERABILITY_DETECTED } let(:detected_state) { Gitlab::BackgroundMigration::UpdateVulnerabilitiesToDismissed::VULNERABILITY_DETECTED }
let(:severity) { Vulnerabilities::Occurrence::SEVERITY_LEVELS[:unknown] } let(:severity) { Vulnerabilities::Finding::SEVERITY_LEVELS[:unknown] }
let(:confidence) { Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:medium] } let(:confidence) { Vulnerabilities::Finding::CONFIDENCE_LEVELS[:medium] }
let(:report_type) { Vulnerabilities::Occurrence::REPORT_TYPES[:sast] } let(:report_type) { Vulnerabilities::Finding::REPORT_TYPES[:sast] }
before do before do
stub_const("#{described_class.name}::BATCH_SIZE", 1) stub_const("#{described_class.name}::BATCH_SIZE", 1)
......
...@@ -172,7 +172,7 @@ RSpec.describe Ci::Build do ...@@ -172,7 +172,7 @@ RSpec.describe Ci::Build do
it 'parses blobs and add the results to the report' do it 'parses blobs and add the results to the report' do
subject subject
expect(security_reports.get_report('sast', artifact).occurrences.size).to eq(33) expect(security_reports.get_report('sast', artifact).findings.size).to eq(33)
end end
it 'adds the created date to the report' do it 'adds the created date to the report' do
...@@ -191,10 +191,10 @@ RSpec.describe Ci::Build do ...@@ -191,10 +191,10 @@ RSpec.describe Ci::Build do
it 'parses blobs and adds the results to the reports' do it 'parses blobs and adds the results to the reports' do
subject subject
expect(security_reports.get_report('sast', sast_artifact).occurrences.size).to eq(33) expect(security_reports.get_report('sast', sast_artifact).findings.size).to eq(33)
expect(security_reports.get_report('dependency_scanning', ds_artifact).occurrences.size).to eq(4) expect(security_reports.get_report('dependency_scanning', ds_artifact).findings.size).to eq(4)
expect(security_reports.get_report('container_scanning', cs_artifact).occurrences.size).to eq(8) expect(security_reports.get_report('container_scanning', cs_artifact).findings.size).to eq(8)
expect(security_reports.get_report('dast', dast_artifact).occurrences.size).to eq(20) expect(security_reports.get_report('dast', dast_artifact).findings.size).to eq(20)
end end
end end
......
...@@ -14,7 +14,7 @@ RSpec.describe Ci::Pipeline do ...@@ -14,7 +14,7 @@ RSpec.describe Ci::Pipeline do
it { is_expected.to have_many(:security_scans).through(:builds).class_name('Security::Scan') } it { is_expected.to have_many(:security_scans).through(:builds).class_name('Security::Scan') }
it { is_expected.to have_many(:downstream_bridges) } it { is_expected.to have_many(:downstream_bridges) }
it { is_expected.to have_many(:vulnerability_findings).through(:vulnerabilities_finding_pipelines).class_name('Vulnerabilities::Occurrence') } it { is_expected.to have_many(:vulnerability_findings).through(:vulnerabilities_finding_pipelines).class_name('Vulnerabilities::Finding') }
it { is_expected.to have_many(:vulnerabilities_finding_pipelines).class_name('Vulnerabilities::FindingPipeline') } it { is_expected.to have_many(:vulnerabilities_finding_pipelines).class_name('Vulnerabilities::FindingPipeline') }
describe '.failure_reasons' do describe '.failure_reasons' do
...@@ -53,8 +53,8 @@ RSpec.describe Ci::Pipeline do ...@@ -53,8 +53,8 @@ RSpec.describe Ci::Pipeline do
let!(:pipeline_3) { create(:ci_pipeline, project: project) } let!(:pipeline_3) { create(:ci_pipeline, project: project) }
before do before do
create(:vulnerabilities_occurrence, pipelines: [pipeline_1], project: pipeline.project) create(:vulnerabilities_finding, pipelines: [pipeline_1], project: pipeline.project)
create(:vulnerabilities_occurrence, pipelines: [pipeline_2], project: pipeline.project) create(:vulnerabilities_finding, pipelines: [pipeline_2], project: pipeline.project)
end end
it "returns pipeline with vulnerabilities" do it "returns pipeline with vulnerabilities" do
...@@ -158,18 +158,18 @@ RSpec.describe Ci::Pipeline do ...@@ -158,18 +158,18 @@ RSpec.describe Ci::Pipeline do
expect(subject.reports.keys).to contain_exactly('sast', 'dependency_scanning', 'container_scanning') 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) # for each of report categories, we have merged 2 reports with the same data (fixture)
expect(subject.get_report('sast', sast1_artifact).occurrences.size).to eq(33) expect(subject.get_report('sast', sast1_artifact).findings.size).to eq(33)
expect(subject.get_report('dependency_scanning', ds1_artifact).occurrences.size).to eq(4) expect(subject.get_report('dependency_scanning', ds1_artifact).findings.size).to eq(4)
expect(subject.get_report('container_scanning', cs1_artifact).occurrences.size).to eq(8) expect(subject.get_report('container_scanning', cs1_artifact).findings.size).to eq(8)
end end
context 'when builds are retried' do context 'when builds are retried' do
let(:build_sast_1) { create(:ci_build, :retried, name: 'sast_1', pipeline: pipeline, project: project) } let(:build_sast_1) { create(:ci_build, :retried, name: 'sast_1', pipeline: pipeline, project: project) }
it 'does not take retried builds into account' do it 'does not take retried builds into account' do
expect(subject.get_report('sast', sast1_artifact).occurrences.size).to eq(33) expect(subject.get_report('sast', sast1_artifact).findings.size).to eq(33)
expect(subject.get_report('dependency_scanning', ds1_artifact).occurrences.size).to eq(4) expect(subject.get_report('dependency_scanning', ds1_artifact).findings.size).to eq(4)
expect(subject.get_report('container_scanning', cs1_artifact).occurrences.size).to eq(8) expect(subject.get_report('container_scanning', cs1_artifact).findings.size).to eq(8)
end end
end end
end end
......
...@@ -228,7 +228,7 @@ RSpec.describe Vulnerabilities::Feedback do ...@@ -228,7 +228,7 @@ RSpec.describe Vulnerabilities::Feedback do
let(:expected_occurrence_key) { { project_id: project_id, category: category, project_fingerprint: project_fingerprint } } let(:expected_occurrence_key) { { project_id: project_id, category: category, project_fingerprint: project_fingerprint } }
let(:feedback) { build(:vulnerability_feedback, expected_occurrence_key) } let(:feedback) { build(:vulnerability_feedback, expected_occurrence_key) }
subject { feedback.occurrence_key } subject { feedback.finding_key }
it { is_expected.to eq(expected_occurrence_key) } it { is_expected.to eq(expected_occurrence_key) }
end end
......
...@@ -4,14 +4,14 @@ require 'spec_helper' ...@@ -4,14 +4,14 @@ require 'spec_helper'
RSpec.describe Vulnerabilities::FindingIdentifier do RSpec.describe Vulnerabilities::FindingIdentifier do
describe 'associations' do describe 'associations' do
it { is_expected.to belong_to(:finding).class_name('Vulnerabilities::Finding').with_foreign_key('occurrence_id') }
it { is_expected.to belong_to(:identifier).class_name('Vulnerabilities::Identifier') } it { is_expected.to belong_to(:identifier).class_name('Vulnerabilities::Identifier') }
it { is_expected.to belong_to(:occurrence).class_name('Vulnerabilities::Occurrence') }
end end
describe 'validations' do describe 'validations' do
let!(:finding_identifier) { create(:vulnerabilities_finding_identifier) } let!(:finding_identifier) { create(:vulnerabilities_finding_identifier) }
it { is_expected.to validate_presence_of(:occurrence) } it { is_expected.to validate_presence_of(:finding) }
it { is_expected.to validate_presence_of(:identifier) } it { is_expected.to validate_presence_of(:identifier) }
it { is_expected.to validate_uniqueness_of(:identifier_id).scoped_to(:occurrence_id) } it { is_expected.to validate_uniqueness_of(:identifier_id).scoped_to(:occurrence_id) }
end end
......
...@@ -5,13 +5,13 @@ require 'spec_helper' ...@@ -5,13 +5,13 @@ require 'spec_helper'
RSpec.describe Vulnerabilities::FindingPipeline do RSpec.describe Vulnerabilities::FindingPipeline do
describe 'associations' do describe 'associations' do
it { is_expected.to belong_to(:pipeline).class_name('Ci::Pipeline') } it { is_expected.to belong_to(:pipeline).class_name('Ci::Pipeline') }
it { is_expected.to belong_to(:occurrence).class_name('Vulnerabilities::Occurrence') } it { is_expected.to belong_to(:finding).class_name('Vulnerabilities::Finding') }
end end
describe 'validations' do describe 'validations' do
let!(:finding_pipeline) { create(:vulnerabilities_finding_pipeline) } let!(:finding_pipeline) { create(:vulnerabilities_finding_pipeline) }
it { is_expected.to validate_presence_of(:occurrence) } it { is_expected.to validate_presence_of(:finding) }
it { is_expected.to validate_presence_of(:pipeline) } it { is_expected.to validate_presence_of(:pipeline) }
it { is_expected.to validate_uniqueness_of(:pipeline_id).scoped_to(:occurrence_id) } it { is_expected.to validate_uniqueness_of(:pipeline_id).scoped_to(:occurrence_id) }
end end
......
...@@ -5,8 +5,8 @@ require 'spec_helper' ...@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe Vulnerabilities::Identifier do RSpec.describe Vulnerabilities::Identifier do
describe 'associations' do describe 'associations' do
it { is_expected.to have_many(:finding_identifiers).class_name('Vulnerabilities::FindingIdentifier') } it { is_expected.to have_many(:finding_identifiers).class_name('Vulnerabilities::FindingIdentifier') }
it { is_expected.to have_many(:occurrences).class_name('Vulnerabilities::Occurrence') } it { is_expected.to have_many(:findings).class_name('Vulnerabilities::Finding') }
it { is_expected.to have_many(:primary_occurrences).class_name('Vulnerabilities::Occurrence') } it { is_expected.to have_many(:primary_findings).class_name('Vulnerabilities::Finding') }
it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:project) }
end end
......
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Vulnerabilities::Scanner do RSpec.describe Vulnerabilities::Scanner do
describe 'associations' do describe 'associations' do
it { is_expected.to have_many(:occurrences).class_name('Vulnerabilities::Occurrence') } it { is_expected.to have_many(:findings).class_name('Vulnerabilities::Finding') }
it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:project) }
end end
......
...@@ -31,7 +31,7 @@ RSpec.describe Vulnerability do ...@@ -31,7 +31,7 @@ RSpec.describe Vulnerability do
it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:milestone) } it { is_expected.to belong_to(:milestone) }
it { is_expected.to belong_to(:epic) } it { is_expected.to belong_to(:epic) }
it { is_expected.to have_many(:findings).class_name('Vulnerabilities::Occurrence').inverse_of(:vulnerability) } it { is_expected.to have_many(:findings).class_name('Vulnerabilities::Finding').inverse_of(:vulnerability) }
it { is_expected.to have_many(:issue_links).class_name('Vulnerabilities::IssueLink').inverse_of(:vulnerability) } it { is_expected.to have_many(:issue_links).class_name('Vulnerabilities::IssueLink').inverse_of(:vulnerability) }
it { is_expected.to have_many(:related_issues).through(:issue_links).source(:issue) } it { is_expected.to have_many(:related_issues).through(:issue_links).source(:issue) }
it { is_expected.to belong_to(:author).class_name('User') } it { is_expected.to belong_to(:author).class_name('User') }
...@@ -43,7 +43,7 @@ RSpec.describe Vulnerability do ...@@ -43,7 +43,7 @@ RSpec.describe Vulnerability do
it { is_expected.to have_one(:group).through(:project) } it { is_expected.to have_one(:group).through(:project) }
it { is_expected.to have_many(:findings).class_name('Vulnerabilities::Occurrence').dependent(false) } it { is_expected.to have_many(:findings).class_name('Vulnerabilities::Finding').dependent(false) }
it { is_expected.to have_many(:notes).dependent(:delete_all) } it { is_expected.to have_many(:notes).dependent(:delete_all) }
it { is_expected.to have_many(:user_mentions).class_name('VulnerabilityUserMention') } it { is_expected.to have_many(:user_mentions).class_name('VulnerabilityUserMention') }
end end
...@@ -274,11 +274,11 @@ RSpec.describe Vulnerability do ...@@ -274,11 +274,11 @@ RSpec.describe Vulnerability do
subject { vulnerability.resolved_on_default_branch } subject { vulnerability.resolved_on_default_branch }
context 'Vulnerability::Occurrence is present on the pipeline for default branch' do context 'Vulnerability::Finding is present on the pipeline for default branch' do
it { is_expected.to eq(false) } it { is_expected.to eq(false) }
end end
context 'Vulnerability::Occurrence is not present on the pipeline for default branch' do context 'Vulnerability::Finding is not present on the pipeline for default branch' do
before do before do
project.instance_variable_set(:@latest_successful_pipeline_for_default_branch, pipeline_without_vulnerability) project.instance_variable_set(:@latest_successful_pipeline_for_default_branch, pipeline_without_vulnerability)
end end
......
...@@ -6,7 +6,7 @@ RSpec.describe Security::VulnerableProjectPresenter do ...@@ -6,7 +6,7 @@ RSpec.describe Security::VulnerableProjectPresenter do
let(:project) { create(:project) } let(:project) { create(:project) }
before do before do
allow(::Vulnerabilities::Occurrence).to receive(:batch_count_by_project_and_severity).and_return(1) allow(::Vulnerabilities::Finding).to receive(:batch_count_by_project_and_severity).and_return(1)
end end
subject { described_class.new(project) } subject { described_class.new(project) }
...@@ -15,7 +15,7 @@ RSpec.describe Security::VulnerableProjectPresenter do ...@@ -15,7 +15,7 @@ RSpec.describe Security::VulnerableProjectPresenter do
expect(subject.id).to be(project.id) expect(subject.id).to be(project.id)
end end
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.each do |severity_level| ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.each do |severity_level|
it "exposes a vulnerability count attribute for #{severity_level} vulnerabilities" do it "exposes a vulnerability count attribute for #{severity_level} vulnerabilities" do
expect(subject.public_send("#{severity_level}_vulnerability_count")).to be(1) expect(subject.public_send("#{severity_level}_vulnerability_count")).to be(1)
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Vulnerabilities::OccurrencePresenter do RSpec.describe Vulnerabilities::FindingPresenter do
let(:presenter) { described_class.new(occurrence) } let(:presenter) { described_class.new(occurrence) }
let(:occurrence) { build_stubbed(:vulnerabilities_occurrence) } let(:occurrence) { build_stubbed(:vulnerabilities_occurrence) }
......
...@@ -37,13 +37,13 @@ RSpec.describe 'Query.vulnerabilities.identifiers' do ...@@ -37,13 +37,13 @@ RSpec.describe 'Query.vulnerabilities.identifiers' do
let_it_be(:finding) do let_it_be(:finding) do
create( create(
:vulnerabilities_occurrence, :vulnerabilities_finding,
vulnerability: vulnerability vulnerability: vulnerability
) )
end end
let_it_be(:vulnerabilities_finding_identifier) do let_it_be(:vulnerabilities_finding_identifier) do
create(:vulnerabilities_finding_identifier, identifier: finding_identifier, occurrence: finding) create(:vulnerabilities_finding_identifier, identifier: finding_identifier, finding: finding)
end end
subject { graphql_data.dig('vulnerabilities', 'nodes') } subject { graphql_data.dig('vulnerabilities', 'nodes') }
......
...@@ -32,8 +32,8 @@ RSpec.describe API::VulnerabilityFindings do ...@@ -32,8 +32,8 @@ RSpec.describe API::VulnerabilityFindings do
create(:vulnerability_feedback, :dismissal, :sast, create(:vulnerability_feedback, :dismissal, :sast,
project: project, project: project,
pipeline: pipeline, pipeline: pipeline,
project_fingerprint: sast_report.occurrences.first.project_fingerprint, project_fingerprint: sast_report.findings.first.project_fingerprint,
vulnerability_data: sast_report.occurrences.first.raw_metadata vulnerability_data: sast_report.findings.first.raw_metadata
) )
end end
...@@ -43,21 +43,21 @@ RSpec.describe API::VulnerabilityFindings do ...@@ -43,21 +43,21 @@ RSpec.describe API::VulnerabilityFindings do
end end
# Because fixture reports that power :ee_ci_job_artifact factory contain long report lists, # Because fixture reports that power :ee_ci_job_artifact factory contain long report lists,
# we need to make sure that all occurrences for both SAST and Dependency Scanning are included in the response. # we need to make sure that all findings for both SAST and Dependency Scanning are included in the response.
# That's why the page size is 40. # That's why the page size is 40.
let(:pagination) { { per_page: 40 } } let(:pagination) { { per_page: 40 } }
it 'returns all non-dismissed vulnerabilities' do it 'returns all non-dismissed vulnerabilities' do
# all occurrences except one that was dismissed # all findings except one that was dismissed
occurrence_count = (sast_report.occurrences.count + ds_report.occurrences.count - 1).to_s finding_count = (sast_report.findings.count + ds_report.findings.count - 1).to_s
get api(project_vulnerability_findings_path, user), params: pagination get api(project_vulnerability_findings_path, user), params: pagination
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(response).to match_response_schema('vulnerabilities/occurrence_list', dir: 'ee') expect(response).to match_response_schema('vulnerabilities/finding_list', dir: 'ee')
expect(response.headers['X-Total']).to eq occurrence_count expect(response.headers['X-Total']).to eq finding_count
expect(json_response.map { |v| v['report_type'] }.uniq).to match_array %w[dependency_scanning sast] expect(json_response.map { |v| v['report_type'] }.uniq).to match_array %w[dependency_scanning sast]
end end
...@@ -68,39 +68,39 @@ RSpec.describe API::VulnerabilityFindings do ...@@ -68,39 +68,39 @@ RSpec.describe API::VulnerabilityFindings do
end.count end.count
# Threshold is required for the extra query performed in Security::PipelineVulnerabilitiesFinder to load # Threshold is required for the extra query performed in Security::PipelineVulnerabilitiesFinder to load
# the Vulnerabilities providing computed states for the associated Vulnerability::Occurrences # the Vulnerabilities providing computed states for the associated Vulnerability::Findings
expect { get api(project_vulnerability_findings_path, user) }.not_to exceed_query_limit(control_count).with_threshold(1) expect { get api(project_vulnerability_findings_path, user) }.not_to exceed_query_limit(control_count).with_threshold(1)
end end
describe 'filtering' do describe 'filtering' do
it 'returns vulnerabilities with sast report_type' do it 'returns vulnerabilities with sast report_type' do
occurrence_count = (sast_report.occurrences.count - 1).to_s # all SAST occurrences except one that was dismissed finding_count = (sast_report.findings.count - 1).to_s # all SAST findings except one that was dismissed
get api(project_vulnerability_findings_path, user), params: { report_type: 'sast' } get api(project_vulnerability_findings_path, user), params: { report_type: 'sast' }
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['X-Total']).to eq occurrence_count expect(response.headers['X-Total']).to eq finding_count
expect(json_response.map { |v| v['report_type'] }.uniq).to match_array %w[sast] expect(json_response.map { |v| v['report_type'] }.uniq).to match_array %w[sast]
# occurrences are implicitly sorted by Security::PipelineVulnerabilitiesFinder and # findings are implicitly sorted by Security::PipelineVulnerabilitiesFinder and
# Security::MergeReportsService so their order differs from what is present in fixture file # Security::MergeReportsService so their order differs from what is present in fixture file
expect(json_response.first['name']).to eq 'ECB mode is insecure' expect(json_response.first['name']).to eq 'ECB mode is insecure'
end end
it 'returns vulnerabilities with dependency_scanning report_type' do it 'returns vulnerabilities with dependency_scanning report_type' do
occurrence_count = ds_report.occurrences.count.to_s finding_count = ds_report.findings.count.to_s
get api(project_vulnerability_findings_path, user), params: { report_type: 'dependency_scanning' } get api(project_vulnerability_findings_path, user), params: { report_type: 'dependency_scanning' }
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['X-Total']).to eq occurrence_count expect(response.headers['X-Total']).to eq finding_count
expect(json_response.map { |v| v['report_type'] }.uniq).to match_array %w[dependency_scanning] expect(json_response.map { |v| v['report_type'] }.uniq).to match_array %w[dependency_scanning]
# occurrences are implicitly sorted by Security::PipelineVulnerabilitiesFinder and # findings are implicitly sorted by Security::PipelineVulnerabilitiesFinder and
# Security::MergeReportsService so their order differs from what is present in fixture file # Security::MergeReportsService so their order differs from what is present in fixture file
expect(json_response.first['name']).to eq 'ruby-ffi DDL loading issue on Windows OS' expect(json_response.first['name']).to eq 'ruby-ffi DDL loading issue on Windows OS'
end end
...@@ -112,13 +112,13 @@ RSpec.describe API::VulnerabilityFindings do ...@@ -112,13 +112,13 @@ RSpec.describe API::VulnerabilityFindings do
end end
it 'returns dismissed vulnerabilities with `all` scope' do it 'returns dismissed vulnerabilities with `all` scope' do
occurrence_count = (sast_report.occurrences.count + ds_report.occurrences.count).to_s finding_count = (sast_report.findings.count + ds_report.findings.count).to_s
get api(project_vulnerability_findings_path, user), params: { scope: 'all' }.merge(pagination) get api(project_vulnerability_findings_path, user), params: { scope: 'all' }.merge(pagination)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['X-Total']).to eq occurrence_count expect(response.headers['X-Total']).to eq finding_count
end end
it 'returns vulnerabilities with low severity' do it 'returns vulnerabilities with low severity' do
...@@ -159,13 +159,13 @@ RSpec.describe API::VulnerabilityFindings do ...@@ -159,13 +159,13 @@ RSpec.describe API::VulnerabilityFindings do
context 'when pipeline_id is supplied' do context 'when pipeline_id is supplied' do
it 'returns vulnerabilities from supplied pipeline' do it 'returns vulnerabilities from supplied pipeline' do
occurrence_count = (sast_report.occurrences.count + ds_report.occurrences.count - 1).to_s finding_count = (sast_report.findings.count + ds_report.findings.count - 1).to_s
get api(project_vulnerability_findings_path, user), params: { pipeline_id: pipeline.id }.merge(pagination) get api(project_vulnerability_findings_path, user), params: { pipeline_id: pipeline.id }.merge(pagination)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['X-Total']).to eq occurrence_count expect(response.headers['X-Total']).to eq finding_count
end end
context 'pipeline has no reports' do context 'pipeline has no reports' do
......
...@@ -24,7 +24,7 @@ RSpec.describe 'GET /groups/*group_id/-/security/projects' do ...@@ -24,7 +24,7 @@ RSpec.describe 'GET /groups/*group_id/-/security/projects' do
projects = create_list(:project, 2, namespace: group) projects = create_list(:project, 2, namespace: group)
projects.each do |project| projects.each do |project|
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.each do |severity| ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.each do |severity|
create(:vulnerabilities_occurrence, severity: severity, project: project) create(:vulnerabilities_occurrence, severity: severity, project: project)
end end
end end
......
...@@ -40,14 +40,14 @@ RSpec.describe 'GET /-/security/vulnerability_findings' do ...@@ -40,14 +40,14 @@ RSpec.describe 'GET /-/security/vulnerability_findings' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(json_response.length).to eq 2 expect(json_response.length).to eq 2
expect(json_response.first['id']).to be(critical_vulnerability.id) expect(json_response.first['id']).to be(critical_vulnerability.id)
expect(response).to match_response_schema('vulnerabilities/occurrence_list', dir: 'ee') expect(response).to match_response_schema('vulnerabilities/finding_list', dir: 'ee')
end end
context 'when a specific page is requested' do context 'when a specific page is requested' do
let(:findings_request_params) { { page: 2 } } let(:findings_request_params) { { page: 2 } }
before do before do
Vulnerabilities::Occurrence.paginates_per 2 Vulnerabilities::Finding.paginates_per 2
create_list(:vulnerabilities_occurrence, 3, pipelines: [pipeline], project: project) create_list(:vulnerabilities_occurrence, 3, pipelines: [pipeline], project: project)
...@@ -55,7 +55,7 @@ RSpec.describe 'GET /-/security/vulnerability_findings' do ...@@ -55,7 +55,7 @@ RSpec.describe 'GET /-/security/vulnerability_findings' do
end end
after do after do
Vulnerabilities::Occurrence.paginates_per Vulnerabilities::Occurrence::OCCURRENCES_PER_PAGE Vulnerabilities::Finding.paginates_per Vulnerabilities::Finding::FINDINGS_PER_PAGE
end end
it 'returns the list of vulnerability findings that are on the requested page' do it 'returns the list of vulnerability findings that are on the requested page' do
......
...@@ -6,13 +6,13 @@ RSpec.describe Vulnerabilities::FindingReportsComparerEntity do ...@@ -6,13 +6,13 @@ RSpec.describe Vulnerabilities::FindingReportsComparerEntity do
describe 'container scanning report comparison' do describe 'container scanning report comparison' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:base_occurrences) { create_list(:vulnerabilities_occurrence, 2) } let(:base_findings) { create_list(:vulnerabilities_finding, 2) }
let(:base_combined_reports) { build_list(:ci_reports_security_report, 1, created_at: nil) } 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(:base_report) { build(:ci_reports_security_aggregated_reports, reports: base_combined_reports, findings: base_findings)}
let(:head_occurrences) { create_list(:vulnerabilities_occurrence, 1) } let(:head_findings) { create_list(:vulnerabilities_finding, 1) }
let(:head_combined_reports) { build_list(:ci_reports_security_report, 1, created_at: 2.days.ago) } 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(:head_report) { build(:ci_reports_security_aggregated_reports, reports: head_combined_reports, findings: head_findings)}
let(:scan) { create(:security_scan, scanned_resources_count: 10) } let(:scan) { create(:security_scan, scanned_resources_count: 10) }
let(:security_scans) { [scan] } let(:security_scans) { [scan] }
......
...@@ -7,12 +7,12 @@ RSpec.describe VulnerableProjectEntity do ...@@ -7,12 +7,12 @@ RSpec.describe VulnerableProjectEntity do
let(:vulnerable_project) { ::Security::VulnerableProjectPresenter.new(project) } let(:vulnerable_project) { ::Security::VulnerableProjectPresenter.new(project) }
before do before do
allow(::Vulnerabilities::Occurrence).to receive(:batch_count_by_project_and_severity).and_return(2) allow(::Vulnerabilities::Finding).to receive(:batch_count_by_project_and_severity).and_return(2)
end end
subject { described_class.new(vulnerable_project) } subject { described_class.new(vulnerable_project) }
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.each do |severity_level| ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.each do |severity_level|
it "exposes a vulnerability count attribute for #{severity_level} vulnerabilities" do it "exposes a vulnerability count attribute for #{severity_level} vulnerabilities" do
expect(subject.as_json["#{severity_level}_vulnerability_count".to_sym]).to be(2) expect(subject.as_json["#{severity_level}_vulnerability_count".to_sym]).to be(2)
end end
......
...@@ -11,14 +11,14 @@ RSpec.describe VulnerableProjectSerializer do ...@@ -11,14 +11,14 @@ RSpec.describe VulnerableProjectSerializer do
before do before do
project.add_developer(user) project.add_developer(user)
allow(::Vulnerabilities::Occurrence).to receive(:batch_count_by_project_and_severity) allow(::Vulnerabilities::Finding).to receive(:batch_count_by_project_and_severity)
end end
describe '#represent' do describe '#represent' do
subject { serializer.represent(vulnerable_project) } subject { serializer.represent(vulnerable_project) }
it 'includes counts for each severity of vulnerability' do it 'includes counts for each severity of vulnerability' do
::Vulnerabilities::Occurrence::SEVERITY_LEVELS.keys.each do |severity_level| ::Vulnerabilities::Finding::SEVERITY_LEVELS.keys.each do |severity_level|
expect(subject).to include("#{severity_level}_vulnerability_count".to_sym) expect(subject).to include("#{severity_level}_vulnerability_count".to_sym)
end end
end end
......
...@@ -14,24 +14,24 @@ RSpec.describe Security::MergeReportsService, '#execute' do ...@@ -14,24 +14,24 @@ RSpec.describe Security::MergeReportsService, '#execute' do
let(:identifier_cwe) { build(:ci_reports_security_identifier, external_id: '789', external_type: 'cwe') } let(:identifier_cwe) { build(:ci_reports_security_identifier, external_id: '789', external_type: 'cwe') }
let(:identifier_wasc) { build(:ci_reports_security_identifier, external_id: '13', external_type: 'wasc') } let(:identifier_wasc) { build(:ci_reports_security_identifier, external_id: '13', external_type: 'wasc') }
let(:occurrence_id_1) do let(:finding_id_1) do
build(:ci_reports_security_occurrence, build(:ci_reports_security_finding,
identifiers: [identifier_1_primary, identifier_1_cve], identifiers: [identifier_1_primary, identifier_1_cve],
scanner: scanner_1, scanner: scanner_1,
severity: :low severity: :low
) )
end end
let(:occurrence_id_1_extra) do let(:finding_id_1_extra) do
build(:ci_reports_security_occurrence, build(:ci_reports_security_finding,
identifiers: [identifier_1_primary, identifier_1_cve], identifiers: [identifier_1_primary, identifier_1_cve],
scanner: scanner_1, scanner: scanner_1,
severity: :low severity: :low
) )
end end
let(:occurrence_id_2_loc_1) do let(:finding_id_2_loc_1) do
build(:ci_reports_security_occurrence, build(:ci_reports_security_finding,
identifiers: [identifier_2_primary, identifier_2_cve], identifiers: [identifier_2_primary, identifier_2_cve],
location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34), location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34),
scanner: scanner_2, scanner: scanner_2,
...@@ -39,8 +39,8 @@ RSpec.describe Security::MergeReportsService, '#execute' do ...@@ -39,8 +39,8 @@ RSpec.describe Security::MergeReportsService, '#execute' do
) )
end end
let(:occurrence_id_2_loc_2) do let(:finding_id_2_loc_2) do
build(:ci_reports_security_occurrence, build(:ci_reports_security_finding,
identifiers: [identifier_2_primary, identifier_2_cve], identifiers: [identifier_2_primary, identifier_2_cve],
location: build(:ci_reports_security_locations_sast, start_line: 42, end_line: 44), location: build(:ci_reports_security_locations_sast, start_line: 42, end_line: 44),
scanner: scanner_2, scanner: scanner_2,
...@@ -48,70 +48,70 @@ RSpec.describe Security::MergeReportsService, '#execute' do ...@@ -48,70 +48,70 @@ RSpec.describe Security::MergeReportsService, '#execute' do
) )
end end
let(:occurrence_cwe_1) do let(:finding_cwe_1) do
build(:ci_reports_security_occurrence, build(:ci_reports_security_finding,
identifiers: [identifier_cwe], identifiers: [identifier_cwe],
scanner: scanner_3, scanner: scanner_3,
severity: :high severity: :high
) )
end end
let(:occurrence_cwe_2) do let(:finding_cwe_2) do
build(:ci_reports_security_occurrence, build(:ci_reports_security_finding,
identifiers: [identifier_cwe], identifiers: [identifier_cwe],
scanner: scanner_1, scanner: scanner_1,
severity: :critical severity: :critical
) )
end end
let(:occurrence_wasc_1) do let(:finding_wasc_1) do
build(:ci_reports_security_occurrence, build(:ci_reports_security_finding,
identifiers: [identifier_wasc], identifiers: [identifier_wasc],
scanner: scanner_1, scanner: scanner_1,
severity: :medium severity: :medium
) )
end end
let(:occurrence_wasc_2) do let(:finding_wasc_2) do
build(:ci_reports_security_occurrence, build(:ci_reports_security_finding,
identifiers: [identifier_wasc], identifiers: [identifier_wasc],
scanner: scanner_2, scanner: scanner_2,
severity: :critical severity: :critical
) )
end end
let(:report_1_occurrences) { [occurrence_id_1, occurrence_id_2_loc_1, occurrence_cwe_2, occurrence_wasc_1] } let(:report_1_findings) { [finding_id_1, finding_id_2_loc_1, finding_cwe_2, finding_wasc_1] }
let(:report_1) do let(:report_1) do
build( build(
:ci_reports_security_report, :ci_reports_security_report,
scanners: [scanner_1, scanner_2], scanners: [scanner_1, scanner_2],
occurrences: report_1_occurrences, findings: report_1_findings,
identifiers: report_1_occurrences.flat_map(&:identifiers), identifiers: report_1_findings.flat_map(&:identifiers),
scanned_resources: ['example.com', 'example.com/1', 'example.com/2'] scanned_resources: ['example.com', 'example.com/1', 'example.com/2']
) )
end end
let(:report_2_occurrences) { [occurrence_id_2_loc_2, occurrence_wasc_2] } let(:report_2_findings) { [finding_id_2_loc_2, finding_wasc_2] }
let(:report_2) do let(:report_2) do
build( build(
:ci_reports_security_report, :ci_reports_security_report,
scanners: [scanner_2], scanners: [scanner_2],
occurrences: report_2_occurrences, findings: report_2_findings,
identifiers: occurrence_id_2_loc_2.identifiers, identifiers: finding_id_2_loc_2.identifiers,
scanned_resources: ['example.com', 'example.com/3'] scanned_resources: ['example.com', 'example.com/3']
) )
end end
let(:report_3_occurrences) { [occurrence_id_1_extra, occurrence_cwe_1] } let(:report_3_findings) { [finding_id_1_extra, finding_cwe_1] }
let(:report_3) do let(:report_3) do
build( build(
:ci_reports_security_report, :ci_reports_security_report,
scanners: [scanner_1, scanner_3], scanners: [scanner_1, scanner_3],
occurrences: report_3_occurrences, findings: report_3_findings,
identifiers: report_3_occurrences.flat_map(&:identifiers) identifiers: report_3_findings.flat_map(&:identifiers)
) )
end end
...@@ -137,15 +137,15 @@ RSpec.describe Security::MergeReportsService, '#execute' do ...@@ -137,15 +137,15 @@ RSpec.describe Security::MergeReportsService, '#execute' do
end end
it 'deduplicates (except cwe and wasc) and sorts the vulnerabilities by severity (desc) then by compare key' do it 'deduplicates (except cwe and wasc) and sorts the vulnerabilities by severity (desc) then by compare key' do
expect(subject.occurrences).to( expect(subject.findings).to(
eq([ eq([
occurrence_cwe_2, finding_cwe_2,
occurrence_wasc_2, finding_wasc_2,
occurrence_cwe_1, finding_cwe_1,
occurrence_id_2_loc_2, finding_id_2_loc_2,
occurrence_id_2_loc_1, finding_id_2_loc_1,
occurrence_wasc_1, finding_wasc_1,
occurrence_id_1 finding_id_1
]) ])
) )
end end
...@@ -170,16 +170,16 @@ RSpec.describe Security::MergeReportsService, '#execute' do ...@@ -170,16 +170,16 @@ RSpec.describe Security::MergeReportsService, '#execute' do
let(:identifier_cve) { build(:ci_reports_security_identifier, external_id: 'CVE-2019-123', external_type: 'cve') } let(:identifier_cve) { build(:ci_reports_security_identifier, external_id: 'CVE-2019-123', external_type: 'cve') }
let(:identifier_npm) { build(:ci_reports_security_identifier, external_id: 'NPM-13', external_type: 'npm') } let(:identifier_npm) { build(:ci_reports_security_identifier, external_id: 'NPM-13', external_type: 'npm') }
let(:occurrence_id_1) { build(:ci_reports_security_occurrence, identifiers: [identifier_gemnasium, identifier_cve, identifier_npm], scanner: gemnasium_scanner, report_type: :dependency_scanning) } let(:finding_id_1) { build(:ci_reports_security_finding, identifiers: [identifier_gemnasium, identifier_cve, identifier_npm], scanner: gemnasium_scanner, report_type: :dependency_scanning) }
let(:occurrence_id_2) { build(:ci_reports_security_occurrence, identifiers: [identifier_cve], scanner: bundler_audit_scanner, report_type: :dependency_scanning) } let(:finding_id_2) { build(:ci_reports_security_finding, identifiers: [identifier_cve], scanner: bundler_audit_scanner, report_type: :dependency_scanning) }
let(:occurrence_id_3) { build(:ci_reports_security_occurrence, identifiers: [identifier_npm], scanner: retire_js_scaner, report_type: :dependency_scanning ) } let(:finding_id_3) { build(:ci_reports_security_finding, identifiers: [identifier_npm], scanner: retire_js_scaner, report_type: :dependency_scanning ) }
let(:gemnasium_report) do let(:gemnasium_report) do
build( :ci_reports_security_report, build( :ci_reports_security_report,
type: :dependency_scanning, type: :dependency_scanning,
scanners: [gemnasium_scanner], scanners: [gemnasium_scanner],
occurrences: [occurrence_id_1], findings: [finding_id_1],
identifiers: occurrence_id_1.identifiers identifiers: finding_id_1.identifiers
) )
end end
...@@ -188,8 +188,8 @@ RSpec.describe Security::MergeReportsService, '#execute' do ...@@ -188,8 +188,8 @@ RSpec.describe Security::MergeReportsService, '#execute' do
:ci_reports_security_report, :ci_reports_security_report,
type: :dependency_scanning, type: :dependency_scanning,
scanners: [bundler_audit_scanner], scanners: [bundler_audit_scanner],
occurrences: [occurrence_id_2], findings: [finding_id_2],
identifiers: occurrence_id_2.identifiers identifiers: finding_id_2.identifiers
) )
end end
...@@ -198,8 +198,8 @@ RSpec.describe Security::MergeReportsService, '#execute' do ...@@ -198,8 +198,8 @@ RSpec.describe Security::MergeReportsService, '#execute' do
:ci_reports_security_report, :ci_reports_security_report,
type: :dependency_scanning, type: :dependency_scanning,
scanners: [retire_js_scaner], scanners: [retire_js_scaner],
occurrences: [occurrence_id_3], findings: [finding_id_3],
identifiers: occurrence_id_3.identifiers identifiers: finding_id_3.identifiers
) )
end end
...@@ -208,8 +208,8 @@ RSpec.describe Security::MergeReportsService, '#execute' do ...@@ -208,8 +208,8 @@ RSpec.describe Security::MergeReportsService, '#execute' do
:ci_reports_security_report, :ci_reports_security_report,
type: :dependency_scanning, type: :dependency_scanning,
scanners: [scanner_2], scanners: [scanner_2],
occurrences: [occurrence_id_2_loc_1], findings: [finding_id_2_loc_1],
identifiers: occurrence_id_2_loc_1.identifiers identifiers: finding_id_2_loc_1.identifiers
) )
end end
...@@ -217,17 +217,17 @@ RSpec.describe Security::MergeReportsService, '#execute' do ...@@ -217,17 +217,17 @@ RSpec.describe Security::MergeReportsService, '#execute' do
subject { described_class.new(gemnasium_report, retirejs_report, bundler_audit_report).execute } subject { described_class.new(gemnasium_report, retirejs_report, bundler_audit_report).execute }
specify { expect(subject.scanners.values).to eql([bundler_audit_scanner, retire_js_scaner, gemnasium_scanner]) } specify { expect(subject.scanners.values).to eql([bundler_audit_scanner, retire_js_scaner, gemnasium_scanner]) }
specify { expect(subject.occurrences.count).to eq(2) } specify { expect(subject.findings.count).to eq(2) }
specify { expect(subject.occurrences.first.identifiers).to contain_exactly(identifier_cve) } specify { expect(subject.findings.first.identifiers).to contain_exactly(identifier_cve) }
specify { expect(subject.occurrences.last.identifiers).to contain_exactly(identifier_npm) } specify { expect(subject.findings.last.identifiers).to contain_exactly(identifier_npm) }
end end
context 'when a custom analyzer is completed before the known analyzers' do context 'when a custom analyzer is completed before the known analyzers' do
subject { described_class.new(custom_analyzer_report, retirejs_report, bundler_audit_report).execute } subject { described_class.new(custom_analyzer_report, retirejs_report, bundler_audit_report).execute }
specify { expect(subject.scanners.values).to eql([bundler_audit_scanner, retire_js_scaner, scanner_2]) } specify { expect(subject.scanners.values).to eql([bundler_audit_scanner, retire_js_scaner, scanner_2]) }
specify { expect(subject.occurrences.count).to eq(3) } specify { expect(subject.findings.count).to eq(3) }
specify { expect(subject.occurrences.last.identifiers).to match_array(occurrence_id_2_loc_1.identifiers) } specify { expect(subject.findings.last.identifiers).to match_array(finding_id_2_loc_1.identifiers) }
end end
end end
end end
...@@ -23,7 +23,7 @@ RSpec.describe Security::StoreReportService, '#execute' do ...@@ -23,7 +23,7 @@ RSpec.describe Security::StoreReportService, '#execute' do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
where(:case_name, :report_type, :scanners, :identifiers, :occurrences, :finding_identifiers, :finding_pipelines) do where(:case_name, :report_type, :scanners, :identifiers, :findings, :finding_identifiers, :finding_pipelines) do
'with SAST report' | :sast | 3 | 17 | 33 | 39 | 33 'with SAST report' | :sast | 3 | 17 | 33 | 39 | 33
'with Dependency Scanning report' | :dependency_scanning | 2 | 7 | 4 | 7 | 4 'with Dependency Scanning report' | :dependency_scanning | 2 | 7 | 4 | 7 | 4
'with Container Scanning report' | :container_scanning | 1 | 8 | 8 | 8 | 8 'with Container Scanning report' | :container_scanning | 1 | 8 | 8 | 8 | 8
...@@ -38,11 +38,11 @@ RSpec.describe Security::StoreReportService, '#execute' do ...@@ -38,11 +38,11 @@ RSpec.describe Security::StoreReportService, '#execute' do
expect { subject }.to change { Vulnerabilities::Identifier.count }.by(identifiers) expect { subject }.to change { Vulnerabilities::Identifier.count }.by(identifiers)
end end
it 'inserts all occurrences' do it 'inserts all findings' do
expect { subject }.to change { Vulnerabilities::Occurrence.count }.by(occurrences) expect { subject }.to change { Vulnerabilities::Finding.count }.by(findings)
end end
it 'inserts all occurrence identifiers (join model)' do it 'inserts all finding identifiers (join model)' do
expect { subject }.to change { Vulnerabilities::FindingIdentifier.count }.by(finding_identifiers) expect { subject }.to change { Vulnerabilities::FindingIdentifier.count }.by(finding_identifiers)
end end
...@@ -51,18 +51,18 @@ RSpec.describe Security::StoreReportService, '#execute' do ...@@ -51,18 +51,18 @@ RSpec.describe Security::StoreReportService, '#execute' do
end end
it 'inserts all vulnerabilties' do it 'inserts all vulnerabilties' do
expect { subject }.to change { Vulnerability.count }.by(occurrences) expect { subject }.to change { Vulnerability.count }.by(findings)
end end
end end
context 'invalid data' do context 'invalid data' do
let(:artifact) { create(:ee_ci_job_artifact, :sast) } let(:artifact) { create(:ee_ci_job_artifact, :sast) }
let(:occurrence_without_name) { build(:ci_reports_security_occurrence, name: nil) } let(:finding_without_name) { build(:ci_reports_security_finding, name: nil) }
let(:report) { Gitlab::Ci::Reports::Security::Report.new('container_scanning', nil, nil) } let(:report) { Gitlab::Ci::Reports::Security::Report.new('container_scanning', nil, nil) }
before do before do
allow(Gitlab::ErrorTracking).to receive(:track_and_raise_exception).and_call_original allow(Gitlab::ErrorTracking).to receive(:track_and_raise_exception).and_call_original
report.add_occurrence(occurrence_without_name) report.add_finding(finding_without_name)
end end
it 'raises invalid record error' do it 'raises invalid record error' do
...@@ -70,7 +70,7 @@ RSpec.describe Security::StoreReportService, '#execute' do ...@@ -70,7 +70,7 @@ RSpec.describe Security::StoreReportService, '#execute' do
end end
it 'reports the error correctly' do it 'reports the error correctly' do
expected_params = occurrence_without_name.to_hash.dig(:raw_metadata) expected_params = finding_without_name.to_hash.dig(:raw_metadata)
expect { subject.execute }.to raise_error { |error| expect { subject.execute }.to raise_error { |error|
expect(Gitlab::ErrorTracking).to have_received(:track_and_raise_exception).with(error, create_params: expected_params) expect(Gitlab::ErrorTracking).to have_received(:track_and_raise_exception).with(error, create_params: expected_params)
} }
...@@ -87,8 +87,8 @@ RSpec.describe Security::StoreReportService, '#execute' do ...@@ -87,8 +87,8 @@ RSpec.describe Security::StoreReportService, '#execute' do
let(:new_report) { new_pipeline.security_reports.get_report(report_type.to_s, artifact) } let(:new_report) { new_pipeline.security_reports.get_report(report_type.to_s, artifact) }
let(:report_type) { :sast } let(:report_type) { :sast }
let!(:occurrence) do let!(:finding) do
create(:vulnerabilities_occurrence, create(:vulnerabilities_finding,
pipelines: [pipeline], pipelines: [pipeline],
identifiers: [identifier], identifiers: [identifier],
primary_identifier: identifier, primary_identifier: identifier,
...@@ -97,7 +97,7 @@ RSpec.describe Security::StoreReportService, '#execute' do ...@@ -97,7 +97,7 @@ RSpec.describe Security::StoreReportService, '#execute' do
location_fingerprint: 'd869ba3f0b3347eb2749135a437dc07c8ae0f420') location_fingerprint: 'd869ba3f0b3347eb2749135a437dc07c8ae0f420')
end end
let!(:vulnerability) { create(:vulnerability, findings: [occurrence], project: project) } let!(:vulnerability) { create(:vulnerability, findings: [finding], project: project) }
before do before do
project.add_developer(user) project.add_developer(user)
...@@ -114,11 +114,11 @@ RSpec.describe Security::StoreReportService, '#execute' do ...@@ -114,11 +114,11 @@ RSpec.describe Security::StoreReportService, '#execute' do
expect { subject }.to change { Vulnerabilities::Identifier.count }.by(16) expect { subject }.to change { Vulnerabilities::Identifier.count }.by(16)
end end
it 'inserts only new occurrences and reuse existing ones' do it 'inserts only new findings and reuse existing ones' do
expect { subject }.to change { Vulnerabilities::Occurrence.count }.by(32) expect { subject }.to change { Vulnerabilities::Finding.count }.by(32)
end end
it 'inserts all occurrence pipelines (join model) for this new pipeline' do it 'inserts all finding pipelines (join model) for this new pipeline' do
expect { subject }.to change { Vulnerabilities::FindingPipeline.where(pipeline: new_pipeline).count }.by(33) expect { subject }.to change { Vulnerabilities::FindingPipeline.where(pipeline: new_pipeline).count }.by(33)
end end
...@@ -126,9 +126,9 @@ RSpec.describe Security::StoreReportService, '#execute' do ...@@ -126,9 +126,9 @@ RSpec.describe Security::StoreReportService, '#execute' do
expect { subject }.to change { Vulnerability.count }.by(32) expect { subject }.to change { Vulnerability.count }.by(32)
end end
it 'updates existing occurrences with new data' do it 'updates existing findings with new data' do
subject subject
expect(occurrence.reload).to have_attributes(severity: 'medium', name: 'Probable insecure usage of temp file/directory.') expect(finding.reload).to have_attributes(severity: 'medium', name: 'Probable insecure usage of temp file/directory.')
end end
it 'updates existing vulnerability with new data' do it 'updates existing vulnerability with new data' do
...@@ -138,7 +138,7 @@ RSpec.describe Security::StoreReportService, '#execute' do ...@@ -138,7 +138,7 @@ RSpec.describe Security::StoreReportService, '#execute' do
end end
context 'with existing data from same pipeline' do context 'with existing data from same pipeline' do
let!(:occurrence) { create(:vulnerabilities_occurrence, project: project, pipelines: [pipeline]) } let!(:finding) { create(:vulnerabilities_finding, project: project, pipelines: [pipeline]) }
let(:report_type) { :sast } let(:report_type) { :sast }
it 'skips report' do it 'skips report' do
......
...@@ -48,10 +48,10 @@ RSpec.describe Vulnerabilities::CreateService do ...@@ -48,10 +48,10 @@ RSpec.describe Vulnerabilities::CreateService do
end end
it 'starts a new transaction for the create sequence' do it 'starts a new transaction for the create sequence' do
allow(Vulnerabilities::Occurrence).to receive(:transaction).and_call_original allow(Vulnerabilities::Finding).to receive(:transaction).and_call_original
subject subject
expect(Vulnerabilities::Occurrence).to have_received(:transaction).with(requires_new: true).once expect(Vulnerabilities::Finding).to have_received(:transaction).with(requires_new: true).once
end end
context 'when finding id is unknown' do context 'when finding id is unknown' do
......
...@@ -40,14 +40,14 @@ RSpec.shared_examples ProjectVulnerabilityFindingsActions do ...@@ -40,14 +40,14 @@ RSpec.shared_examples ProjectVulnerabilityFindingsActions do
end end
expect(json_response.first['blob_path']).to eq(blob_path) expect(json_response.first['blob_path']).to eq(blob_path)
expect(response).to match_response_schema('vulnerabilities/occurrence_list', dir: 'ee') expect(response).to match_response_schema('vulnerabilities/finding_list', dir: 'ee')
end end
context 'when a specific page is requested' do context 'when a specific page is requested' do
let(:action_params) { vulnerable_params.merge(page: 2) } let(:action_params) { vulnerable_params.merge(page: 2) }
before do before do
Vulnerabilities::Occurrence.paginates_per 2 Vulnerabilities::Finding.paginates_per 2
create_list(:vulnerabilities_occurrence, 3, pipelines: [pipeline], project: vulnerable_project) create_list(:vulnerabilities_occurrence, 3, pipelines: [pipeline], project: vulnerable_project)
...@@ -55,7 +55,7 @@ RSpec.shared_examples ProjectVulnerabilityFindingsActions do ...@@ -55,7 +55,7 @@ RSpec.shared_examples ProjectVulnerabilityFindingsActions do
end end
after do after do
Vulnerabilities::Occurrence.paginates_per Vulnerabilities::Occurrence::OCCURRENCES_PER_PAGE Vulnerabilities::Finding.paginates_per Vulnerabilities::Finding::FINDINGS_PER_PAGE
end end
it 'returns the list of vulnerability findings that are on the requested page' do it 'returns the list of vulnerability findings that are on the requested page' do
......
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