Commit c1a794aa authored by Michał Zając's avatar Michał Zając

Rename Occurrence to Finding

After introducing the first-class vulnerabilities, only the REST API
endpoints, model associations, and controller endpoints were renamed:
former Vulnerabilities became Vulnerability Findings.

https://gitlab.com/gitlab-org/gitlab/issues/10252#terminology
parent e30e95e9
...@@ -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) }
......
# 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
...@@ -15,14 +15,15 @@ module Vulnerabilities ...@@ -15,14 +15,15 @@ module Vulnerabilities
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 +123,7 @@ module Vulnerabilities ...@@ -122,7 +123,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,
......
...@@ -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,12 +8,12 @@ module Vulnerabilities ...@@ -8,12 +8,12 @@ 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, foreign_key: 'project_id'
validates :project, presence: true validates :project, presence: true
validates :external_type, presence: true validates :external_type, presence: true
......
...@@ -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
......
...@@ -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.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,7 +6,7 @@ module Security ...@@ -6,7 +6,7 @@ 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
...@@ -14,7 +14,7 @@ module Security ...@@ -14,7 +14,7 @@ module Security
def execute def execute
findings = ::Security::PipelineVulnerabilitiesFinder.new(pipeline: @pipeline, params: { report_type: @report_types }).execute findings = ::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) findings.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.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 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.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
......
...@@ -44,19 +44,19 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -44,19 +44,19 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline, params: params).execute } subject { described_class.new(pipeline: pipeline, params: params).execute }
context 'occurrences' do context 'findings' do
it 'assigns commit sha to findings' do it 'assigns commit sha to findings' do
expect(subject.occurrences.map(&:sha).uniq).to eq([pipeline.sha]) expect(subject.findings.map(&:sha).uniq).to eq([pipeline.sha])
end end
context 'by order' do context 'by order' do
let(:params) { { report_type: %w[sast] } } let(:params) { { report_type: %w[sast] } }
let!(:high_high) { build(:vulnerabilities_occurrence, confidence: :high, severity: :high) } let!(:high_high) { build(:vulnerabilities_finding, confidence: :high, severity: :high) }
let!(:critical_medium) { build(:vulnerabilities_occurrence, confidence: :medium, severity: :critical) } let!(:critical_medium) { build(:vulnerabilities_finding, confidence: :medium, severity: :critical) }
let!(:critical_high) { build(:vulnerabilities_occurrence, confidence: :high, severity: :critical) } let!(:critical_high) { build(:vulnerabilities_finding, confidence: :high, severity: :critical) }
let!(:unknown_high) { build(:vulnerabilities_occurrence, confidence: :high, severity: :unknown) } let!(:unknown_high) { build(:vulnerabilities_finding, confidence: :high, severity: :unknown) }
let!(:unknown_medium) { build(:vulnerabilities_occurrence, confidence: :medium, severity: :unknown) } let!(:unknown_medium) { build(:vulnerabilities_finding, confidence: :medium, severity: :unknown) }
let!(:unknown_low) { build(:vulnerabilities_occurrence, confidence: :low, severity: :unknown) } let!(:unknown_low) { build(:vulnerabilities_finding, confidence: :low, severity: :unknown) }
it 'orders by severity and confidence' do it 'orders by severity and confidence' do
allow_next_instance_of(described_class) do |pipeline_vulnerabilities_finder| allow_next_instance_of(described_class) do |pipeline_vulnerabilities_finder|
...@@ -69,7 +69,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -69,7 +69,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
high_high high_high
]) ])
expect(subject.occurrences).to eq([critical_high, critical_medium, high_high, unknown_high, unknown_medium, unknown_low]) expect(subject.findings).to eq([critical_high, critical_medium, high_high, unknown_high, unknown_medium, unknown_low])
end end
end end
end end
...@@ -78,31 +78,31 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -78,31 +78,31 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
context 'by report type' do context 'by report type' do
context 'when sast' do context 'when sast' do
let(:params) { { report_type: %w[sast] } } let(:params) { { report_type: %w[sast] } }
let(:sast_report_fingerprints) {pipeline.security_reports.reports['sast'].occurrences.map(&:location).map(&:fingerprint) } let(:sast_report_fingerprints) {pipeline.security_reports.reports['sast'].findings.map(&:location).map(&:fingerprint) }
it 'includes only sast' do it 'includes only sast' do
expect(subject.occurrences.map(&:location_fingerprint)).to match_array(sast_report_fingerprints) expect(subject.findings.map(&:location_fingerprint)).to match_array(sast_report_fingerprints)
expect(subject.occurrences.count).to eq(sast_count) expect(subject.findings.count).to eq(sast_count)
end end
end end
context 'when dependency_scanning' do context 'when dependency_scanning' do
let(:params) { { report_type: %w[dependency_scanning] } } let(:params) { { report_type: %w[dependency_scanning] } }
let(:ds_report_fingerprints) {pipeline.security_reports.reports['dependency_scanning'].occurrences.map(&:location).map(&:fingerprint) } let(:ds_report_fingerprints) {pipeline.security_reports.reports['dependency_scanning'].findings.map(&:location).map(&:fingerprint) }
it 'includes only dependency_scanning' do it 'includes only dependency_scanning' do
expect(subject.occurrences.map(&:location_fingerprint)).to match_array(ds_report_fingerprints) expect(subject.findings.map(&:location_fingerprint)).to match_array(ds_report_fingerprints)
expect(subject.occurrences.count).to eq(ds_count) expect(subject.findings.count).to eq(ds_count)
end end
end end
context 'when dast' do context 'when dast' do
let(:params) { { report_type: %w[dast] } } let(:params) { { report_type: %w[dast] } }
let(:dast_report_fingerprints) {pipeline.security_reports.reports['dast'].occurrences.map(&:location).map(&:fingerprint) } let(:dast_report_fingerprints) {pipeline.security_reports.reports['dast'].findings.map(&:location).map(&:fingerprint) }
it 'includes only dast' do it 'includes only dast' do
expect(subject.occurrences.map(&:location_fingerprint)).to match_array(dast_report_fingerprints) expect(subject.findings.map(&:location_fingerprint)).to match_array(dast_report_fingerprints)
expect(subject.occurrences.count).to eq(dast_count) expect(subject.findings.count).to eq(dast_count)
end end
end end
...@@ -110,16 +110,16 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -110,16 +110,16 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
let(:params) { { report_type: %w[container_scanning] } } let(:params) { { report_type: %w[container_scanning] } }
it 'includes only container_scanning' do it 'includes only container_scanning' do
fingerprints = pipeline.security_reports.reports['container_scanning'].occurrences.map(&:location).map(&:fingerprint) fingerprints = pipeline.security_reports.reports['container_scanning'].findings.map(&:location).map(&:fingerprint)
expect(subject.occurrences.map(&:location_fingerprint)).to match_array(fingerprints) expect(subject.findings.map(&:location_fingerprint)).to match_array(fingerprints)
expect(subject.occurrences.count).to eq(cs_count) expect(subject.findings.count).to eq(cs_count)
end end
end end
end end
context 'by scope' do context 'by scope' do
let(:ds_occurrence) { pipeline.security_reports.reports["dependency_scanning"].occurrences.first } let(:ds_finding) { pipeline.security_reports.reports["dependency_scanning"].findings.first }
let(:sast_occurrence) { pipeline.security_reports.reports["sast"].occurrences.first } let(:sast_finding) { pipeline.security_reports.reports["sast"].findings.first }
let!(:feedback) do let!(:feedback) do
[ [
...@@ -129,8 +129,8 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -129,8 +129,8 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
:dependency_scanning, :dependency_scanning,
project: project, project: project,
pipeline: pipeline, pipeline: pipeline,
project_fingerprint: ds_occurrence.project_fingerprint, project_fingerprint: ds_finding.project_fingerprint,
vulnerability_data: ds_occurrence.raw_metadata vulnerability_data: ds_finding.raw_metadata
), ),
create( create(
:vulnerability_feedback, :vulnerability_feedback,
...@@ -138,8 +138,8 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -138,8 +138,8 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
:sast, :sast,
project: project, project: project,
pipeline: pipeline, pipeline: pipeline,
project_fingerprint: sast_occurrence.project_fingerprint, project_fingerprint: sast_finding.project_fingerprint,
vulnerability_data: sast_occurrence.raw_metadata vulnerability_data: sast_finding.raw_metadata
) )
] ]
end end
...@@ -148,8 +148,8 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -148,8 +148,8 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline).execute } subject { described_class.new(pipeline: pipeline).execute }
it 'returns non-dismissed vulnerabilities' do it 'returns non-dismissed vulnerabilities' do
expect(subject.occurrences.count).to eq(cs_count + dast_count + ds_count + sast_count - feedback.count) expect(subject.findings.count).to eq(cs_count + dast_count + ds_count + sast_count - feedback.count)
expect(subject.occurrences.map(&:project_fingerprint)).not_to include(*feedback.map(&:project_fingerprint)) expect(subject.findings.map(&:project_fingerprint)).not_to include(*feedback.map(&:project_fingerprint))
end end
end end
...@@ -157,8 +157,8 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -157,8 +157,8 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline, params: { report_type: %w[dependency_scanning], scope: 'dismissed' } ).execute } subject { described_class.new(pipeline: pipeline, params: { report_type: %w[dependency_scanning], scope: 'dismissed' } ).execute }
it 'returns non-dismissed vulnerabilities' do it 'returns non-dismissed vulnerabilities' do
expect(subject.occurrences.count).to eq(ds_count - 1) expect(subject.findings.count).to eq(ds_count - 1)
expect(subject.occurrences.map(&:project_fingerprint)).not_to include(ds_occurrence.project_fingerprint) expect(subject.findings.map(&:project_fingerprint)).not_to include(ds_finding.project_fingerprint)
end end
end end
...@@ -166,7 +166,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -166,7 +166,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
let(:params) { { report_type: %w[sast dast container_scanning dependency_scanning], scope: 'all' } } let(:params) { { report_type: %w[sast dast container_scanning dependency_scanning], scope: 'all' } }
it 'returns all vulnerabilities' do it 'returns all vulnerabilities' do
expect(subject.occurrences.count).to eq(cs_count + dast_count + ds_count + sast_count) expect(subject.findings.count).to eq(cs_count + dast_count + ds_count + sast_count)
end end
end end
end end
...@@ -176,7 +176,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -176,7 +176,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline).execute } subject { described_class.new(pipeline: pipeline).execute }
it 'returns all vulnerability severity levels' do it 'returns all vulnerability severity levels' do
expect(subject.occurrences.map(&:severity).uniq).to match_array(%w[unknown low medium high critical info]) expect(subject.findings.map(&:severity).uniq).to match_array(%w[unknown low medium high critical info])
end end
end end
...@@ -184,7 +184,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -184,7 +184,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline, params: { severity: 'low' } ).execute } subject { described_class.new(pipeline: pipeline, params: { severity: 'low' } ).execute }
it 'returns only low-severity vulnerabilities' do it 'returns only low-severity vulnerabilities' do
expect(subject.occurrences.map(&:severity).uniq).to match_array(%w[low]) expect(subject.findings.map(&:severity).uniq).to match_array(%w[low])
end end
end end
end end
...@@ -194,7 +194,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -194,7 +194,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline).execute } subject { described_class.new(pipeline: pipeline).execute }
it 'returns all vulnerability confidence levels' do it 'returns all vulnerability confidence levels' do
expect(subject.occurrences.map(&:confidence).uniq).to match_array %w[unknown low medium high] expect(subject.findings.map(&:confidence).uniq).to match_array %w[unknown low medium high]
end end
end end
...@@ -202,7 +202,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -202,7 +202,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline, params: { confidence: 'medium' } ).execute } subject { described_class.new(pipeline: pipeline, params: { confidence: 'medium' } ).execute }
it 'returns only medium-confidence vulnerabilities' do it 'returns only medium-confidence vulnerabilities' do
expect(subject.occurrences.map(&:confidence).uniq).to match_array(%w[medium]) expect(subject.findings.map(&:confidence).uniq).to match_array(%w[medium])
end end
end end
end end
...@@ -212,7 +212,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -212,7 +212,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline).execute } subject { described_class.new(pipeline: pipeline).execute }
it 'returns all vulnerabilities with all scanners available' do it 'returns all vulnerabilities with all scanners available' do
expect(subject.occurrences.map(&:scanner).map(&:external_id).uniq).to match_array %w[bandit bundler_audit find_sec_bugs flawfinder gemnasium klar zaproxy] expect(subject.findings.map(&:scanner).map(&:external_id).uniq).to match_array %w[bandit bundler_audit find_sec_bugs flawfinder gemnasium klar zaproxy]
end end
end end
...@@ -220,7 +220,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -220,7 +220,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline, params: { scanner: 'zaproxy' } ).execute } subject { described_class.new(pipeline: pipeline, params: { scanner: 'zaproxy' } ).execute }
it 'returns only vulnerabilities with selected scanner external id' do it 'returns only vulnerabilities with selected scanner external id' do
expect(subject.occurrences.map(&:scanner).map(&:external_id).uniq).to match_array(%w[zaproxy]) expect(subject.findings.map(&:scanner).map(&:external_id).uniq).to match_array(%w[zaproxy])
end end
end end
end end
...@@ -230,10 +230,10 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -230,10 +230,10 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
let(:params) { { report_type: %w[sast dast container_scanning dependency_scanning], scanner: %w[bandit bundler_audit find_sec_bugs flawfinder gemnasium klar zaproxy], scope: 'all' } } let(:params) { { report_type: %w[sast dast container_scanning dependency_scanning], scanner: %w[bandit bundler_audit find_sec_bugs flawfinder gemnasium klar zaproxy], scope: 'all' } }
it 'filters by all params' do it 'filters by all params' do
expect(subject.occurrences.count).to eq(cs_count + dast_count + ds_count + sast_count) expect(subject.findings.count).to eq(cs_count + dast_count + ds_count + sast_count)
expect(subject.occurrences.map(&:scanner).map(&:external_id).uniq).to match_array %w[bandit bundler_audit find_sec_bugs flawfinder gemnasium klar zaproxy] expect(subject.findings.map(&:scanner).map(&:external_id).uniq).to match_array %w[bandit bundler_audit find_sec_bugs flawfinder gemnasium klar zaproxy]
expect(subject.occurrences.map(&:confidence).uniq).to match_array(%w[unknown low medium high]) expect(subject.findings.map(&:confidence).uniq).to match_array(%w[unknown low medium high])
expect(subject.occurrences.map(&:severity).uniq).to match_array(%w[unknown low medium high critical info]) expect(subject.findings.map(&:severity).uniq).to match_array(%w[unknown low medium high critical info])
end end
end end
...@@ -242,7 +242,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -242,7 +242,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
it 'did not find anything' do it 'did not find anything' do
expect(subject.created_at).to be_nil expect(subject.created_at).to be_nil
expect(subject.occurrences).to be_empty expect(subject.findings).to be_empty
end end
end end
end end
...@@ -251,7 +251,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -251,7 +251,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline).execute } subject { described_class.new(pipeline: pipeline).execute }
it 'returns all report_types' do it 'returns all report_types' do
expect(subject.occurrences.count).to eq(cs_count + dast_count + ds_count + sast_count) expect(subject.findings.count).to eq(cs_count + dast_count + ds_count + sast_count)
end end
end end
...@@ -292,37 +292,37 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do ...@@ -292,37 +292,37 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline, params: { report_type: %w[sast], scope: 'all' }).execute } subject { described_class.new(pipeline: pipeline, params: { report_type: %w[sast], scope: 'all' }).execute }
it 'assigns vulnerability records to findings providing them with computed state' do it 'assigns vulnerability records to findings providing them with computed state' do
confirmed = subject.occurrences.find { |f| f.project_fingerprint == confirmed_fingerprint } confirmed = subject.findings.find { |f| f.project_fingerprint == confirmed_fingerprint }
resolved = subject.occurrences.find { |f| f.project_fingerprint == resolved_fingerprint } resolved = subject.findings.find { |f| f.project_fingerprint == resolved_fingerprint }
dismissed = subject.occurrences.find { |f| f.project_fingerprint == dismissed_fingerprint } dismissed = subject.findings.find { |f| f.project_fingerprint == dismissed_fingerprint }
expect(confirmed.state).to eq 'confirmed' expect(confirmed.state).to eq 'confirmed'
expect(resolved.state).to eq 'resolved' expect(resolved.state).to eq 'resolved'
expect(dismissed.state).to eq 'dismissed' expect(dismissed.state).to eq 'dismissed'
expect(subject.occurrences - [confirmed, resolved, dismissed]).to all(have_attributes(state: 'detected')) expect(subject.findings - [confirmed, resolved, dismissed]).to all(have_attributes(state: 'detected'))
end end
end end
context 'when being tested for sort stability' do context 'when being tested for sort stability' do
let(:params) { { report_type: %w[sast] } } let(:params) { { report_type: %w[sast] } }
it 'maintains the order of the occurrences having the same severity and confidence' do it 'maintains the order of the findings having the same severity and confidence' do
select_proc = proc { |o| o.severity == 'medium' && o.confidence == 'high' } select_proc = proc { |o| o.severity == 'medium' && o.confidence == 'high' }
report_occurrences = pipeline.security_reports.reports['sast'].occurrences.select(&select_proc) report_findings = pipeline.security_reports.reports['sast'].findings.select(&select_proc)
found_occurrences = subject.occurrences.select(&select_proc) found_findings = subject.findings.select(&select_proc)
found_occurrences.each_with_index do |found, i| found_findings.each_with_index do |found, i|
expect(found.metadata['cve']).to eq(report_occurrences[i].compare_key) expect(found.metadata['cve']).to eq(report_findings[i].compare_key)
end end
end end
end end
context 'when scanner is not provided in the report occurrences' do context 'when scanner is not provided in the report findings' do
let!(:artifact_sast) { create(:ee_ci_job_artifact, :sast_with_missing_scanner, job: build_sast, project: project) } let!(:artifact_sast) { create(:ee_ci_job_artifact, :sast_with_missing_scanner, job: build_sast, project: project) }
it 'sets empty scanner' do it 'sets empty scanner' do
sast_scanners = subject.occurrences.select(&:sast?).map(&:scanner) sast_scanners = subject.findings.select(&:sast?).map(&:scanner)
expect(sast_scanners).to all(have_attributes(project_id: nil, external_id: nil, name: nil)) expect(sast_scanners).to all(have_attributes(project_id: nil, external_id: nil, name: nil))
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.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.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.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.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.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).finding(high_severity)
subject.get_report('dependency_scanning', artifact).add_occurrence(low_severity) subject.get_report('dependency_scanning', artifact).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,8 @@ RSpec.describe Gitlab::Ci::Reports::Security::Reports do ...@@ -55,8 +55,8 @@ 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).finding(low_severity)
subject.get_report('dependency_scanning', artifact).add_occurrence(low_severity) subject.get_report('dependency_scanning', artifact).finding(low_severity)
end end
it { expect(subject.violates_default_policy?).to be(false) } it { expect(subject.violates_default_policy?).to be(false) }
......
...@@ -5,11 +5,11 @@ require 'spec_helper' ...@@ -5,11 +5,11 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
let(:identifier) { build(:vulnerabilities_identifier) } let(:identifier) { build(:vulnerabilities_identifier) }
let(:base_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '123', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:critical]) } let(:base_vulnerability) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: '123', confidence: Vulnerabilities::Finding::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Finding::SEVERITY_LEVELS[:critical]) }
let(:base_report) { build(:ci_reports_security_aggregated_reports, occurrences: [base_vulnerability])} let(:base_report) { build(:ci_reports_security_aggregated_reports, findings: [base_vulnerability])}
let(:head_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '123', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:critical]) } let(:head_vulnerability) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: '123', confidence: Vulnerabilities::Finding::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Finding::SEVERITY_LEVELS[:critical]) }
let(:head_report) { build(:ci_reports_security_aggregated_reports, occurrences: [head_vulnerability])} let(:head_report) { build(:ci_reports_security_aggregated_reports, findings: [head_vulnerability])}
before do before do
allow(base_vulnerability).to receive(:location).and_return({}) allow(base_vulnerability).to receive(:location).and_return({})
...@@ -20,7 +20,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -20,7 +20,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
describe '#base_report_out_of_date' do describe '#base_report_out_of_date' do
context 'no base report' do context 'no base report' do
let(:base_report) { build(:ci_reports_security_aggregated_reports, reports: [], occurrences: [])} let(:base_report) { build(:ci_reports_security_aggregated_reports, reports: [], findings: [])}
it 'is not out of date' do it 'is not out of date' do
expect(subject.base_report_out_of_date).to be false expect(subject.base_report_out_of_date).to be false
...@@ -53,8 +53,8 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -53,8 +53,8 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end end
context 'when comparing reports with different fingerprints' do context 'when comparing reports with different fingerprints' do
let(:base_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: 'A') } let(:base_vulnerability) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: 'A') }
let(:head_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: 'B') } let(:head_vulnerability) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: 'B') }
it 'does not find any overlap' do it 'does not find any overlap' do
expect(subject.existing).to eq([]) expect(subject.existing).to eq([])
...@@ -62,10 +62,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -62,10 +62,10 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end end
context 'new vulnerabilities' do context 'new vulnerabilities' do
let(:vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:medium]) } let(:vuln) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Finding::CONFIDENCE_LEVELS[:medium]) }
let(:low_vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:low]) } let(:low_vuln) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Finding::CONFIDENCE_LEVELS[:low]) }
let(:base_report) { build(:ci_reports_security_aggregated_reports, occurrences: [base_vulnerability, vuln])} let(:base_report) { build(:ci_reports_security_aggregated_reports, findings: [base_vulnerability, vuln])}
let(:head_report) { build(:ci_reports_security_aggregated_reports, occurrences: [head_vulnerability, vuln, low_vuln])} let(:head_report) { build(:ci_reports_security_aggregated_reports, findings: [head_vulnerability, vuln, low_vuln])}
it 'does not change order' do it 'does not change order' do
expect(subject.existing).to eq([head_vulnerability, vuln]) expect(subject.existing).to eq([head_vulnerability, vuln])
...@@ -75,11 +75,11 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -75,11 +75,11 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end end
describe '#added' do describe '#added' do
let(:vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:critical]) } let(:vuln) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Finding::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Finding::SEVERITY_LEVELS[:critical]) }
let(:low_vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:low]) } let(:low_vuln) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Finding::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Finding::SEVERITY_LEVELS[:low]) }
context 'with new vulnerability' do context 'with new vulnerability' do
let(:head_report) { build(:ci_reports_security_aggregated_reports, occurrences: [head_vulnerability, vuln])} let(:head_report) { build(:ci_reports_security_aggregated_reports, findings: [head_vulnerability, vuln])}
it 'points to source tree' do it 'points to source tree' do
expect(subject.added).to eq([vuln]) expect(subject.added).to eq([vuln])
...@@ -87,9 +87,9 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -87,9 +87,9 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end end
context 'when comparing reports with different fingerprints' do context 'when comparing reports with different fingerprints' do
let(:base_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: 'A') } let(:base_vulnerability) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: 'A') }
let(:head_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: 'B') } let(:head_vulnerability) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: 'B') }
let(:head_report) { build(:ci_reports_security_aggregated_reports, occurrences: [head_vulnerability, vuln])} let(:head_report) { build(:ci_reports_security_aggregated_reports, findings: [head_vulnerability, vuln])}
it 'does not find any overlap' do it 'does not find any overlap' do
expect(subject.added).to eq([head_vulnerability, vuln]) expect(subject.added).to eq([head_vulnerability, vuln])
...@@ -97,7 +97,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -97,7 +97,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end end
context 'order' do context 'order' do
let(:head_report) { build(:ci_reports_security_aggregated_reports, occurrences: [head_vulnerability, vuln, low_vuln])} let(:head_report) { build(:ci_reports_security_aggregated_reports, findings: [head_vulnerability, vuln, low_vuln])}
it 'does not change' do it 'does not change' do
expect(subject.added).to eq([vuln, low_vuln]) expect(subject.added).to eq([vuln, low_vuln])
...@@ -106,11 +106,11 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -106,11 +106,11 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end end
describe '#fixed' do describe '#fixed' do
let(:vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888') } let(:vuln) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: '888') }
let(:medium_vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Occurrence::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Occurrence::SEVERITY_LEVELS[:medium]) } let(:medium_vuln) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: '888', confidence: Vulnerabilities::Finding::CONFIDENCE_LEVELS[:high], severity: Vulnerabilities::Finding::SEVERITY_LEVELS[:medium]) }
context 'with fixed vulnerability' do context 'with fixed vulnerability' do
let(:base_report) { build(:ci_reports_security_aggregated_reports, occurrences: [base_vulnerability, vuln])} let(:base_report) { build(:ci_reports_security_aggregated_reports, findings: [base_vulnerability, vuln])}
it 'points to base tree' do it 'points to base tree' do
expect(subject.fixed).to eq([vuln]) expect(subject.fixed).to eq([vuln])
...@@ -118,9 +118,9 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -118,9 +118,9 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end end
context 'when comparing reports with different fingerprints' do context 'when comparing reports with different fingerprints' do
let(:base_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: 'A') } let(:base_vulnerability) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: 'A') }
let(:head_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: 'B') } let(:head_vulnerability) { build(:vulnerabilities_finding, report_type: :sast, identifiers: [identifier], location_fingerprint: 'B') }
let(:base_report) { build(:ci_reports_security_aggregated_reports, occurrences: [base_vulnerability, vuln])} let(:base_report) { build(:ci_reports_security_aggregated_reports, findings: [base_vulnerability, vuln])}
it 'does not find any overlap' do it 'does not find any overlap' do
expect(subject.fixed).to eq([base_vulnerability, vuln]) expect(subject.fixed).to eq([base_vulnerability, vuln])
...@@ -128,7 +128,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -128,7 +128,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end end
context 'order' do context 'order' do
let(:base_report) { build(:ci_reports_security_aggregated_reports, occurrences: [vuln, medium_vuln, base_vulnerability])} let(:base_report) { build(:ci_reports_security_aggregated_reports, findings: [vuln, medium_vuln, base_vulnerability])}
it 'does not change' do it 'does not change' do
expect(subject.fixed).to eq([vuln, medium_vuln]) expect(subject.fixed).to eq([vuln, medium_vuln])
...@@ -137,7 +137,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do ...@@ -137,7 +137,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end end
describe 'with empty vulnerabilities' do describe 'with empty vulnerabilities' do
let(:empty_report) { build(:ci_reports_security_aggregated_reports, reports: [], occurrences: [])} let(:empty_report) { build(:ci_reports_security_aggregated_reports, reports: [], findings: [])}
it 'returns empty array when reports are not present' do it 'returns empty array when reports are not present' do
comparer = described_class.new(empty_report, empty_report, head_security_scans: []) comparer = described_class.new(empty_report, empty_report, head_security_scans: [])
......
...@@ -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
......
...@@ -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
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Vulnerabilities::Occurrence do RSpec.describe Vulnerabilities::Finding do
it { is_expected.to define_enum_for(:confidence) } it { is_expected.to define_enum_for(:confidence) }
it { is_expected.to define_enum_for(:report_type) } it { is_expected.to define_enum_for(:report_type) }
it { is_expected.to define_enum_for(:severity) } it { is_expected.to define_enum_for(:severity) }
...@@ -13,13 +13,13 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -13,13 +13,13 @@ RSpec.describe Vulnerabilities::Occurrence do
it { is_expected.to belong_to(:scanner).class_name('Vulnerabilities::Scanner') } it { is_expected.to belong_to(:scanner).class_name('Vulnerabilities::Scanner') }
it { is_expected.to belong_to(:vulnerability).inverse_of(:findings) } it { is_expected.to belong_to(:vulnerability).inverse_of(:findings) }
it { is_expected.to have_many(:pipelines).class_name('Ci::Pipeline') } it { is_expected.to have_many(:pipelines).class_name('Ci::Pipeline') }
it { is_expected.to have_many(:finding_pipelines).class_name('Vulnerabilities::FindingPipeline') } it { is_expected.to have_many(:finding_pipelines).class_name('Vulnerabilities::FindingPipeline').with_foreign_key('occurrence_id') }
it { is_expected.to have_many(:identifiers).class_name('Vulnerabilities::Identifier') } it { is_expected.to have_many(:identifiers).class_name('Vulnerabilities::Identifier') }
it { is_expected.to have_many(:finding_identifiers).class_name('Vulnerabilities::FindingIdentifier') } it { is_expected.to have_many(:finding_identifiers).class_name('Vulnerabilities::FindingIdentifier').with_foreign_key('occurrence_id') }
end end
describe 'validations' do describe 'validations' do
let(:occurrence) { build(:vulnerabilities_occurrence) } let(:finding) { build(:vulnerabilities_finding) }
it { is_expected.to validate_presence_of(:scanner) } it { is_expected.to validate_presence_of(:scanner) }
it { is_expected.to validate_presence_of(:project) } it { is_expected.to validate_presence_of(:project) }
...@@ -36,11 +36,11 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -36,11 +36,11 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
context 'database uniqueness' do context 'database uniqueness' do
let(:occurrence) { create(:vulnerabilities_occurrence) } let(:finding) { create(:vulnerabilities_finding) }
let(:new_occurrence) { occurrence.dup.tap { |o| o.uuid = SecureRandom.uuid } } let(:new_finding) { finding.dup.tap { |o| o.uuid = SecureRandom.uuid } }
it "when all index attributes are identical" do it "when all index attributes are identical" do
expect { new_occurrence.save! }.to raise_error(ActiveRecord::RecordNotUnique) expect { new_finding.save! }.to raise_error(ActiveRecord::RecordNotUnique)
end end
describe 'when some parameters are changed' do describe 'when some parameters are changed' do
...@@ -55,19 +55,19 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -55,19 +55,19 @@ RSpec.describe Vulnerabilities::Occurrence do
with_them do with_them do
it "is valid" do it "is valid" do
expect { new_occurrence.update!({ key => create(factory_name) }) }.not_to raise_error expect { new_finding.update!({ key => create(factory_name) }) }.not_to raise_error
end end
end end
end end
end end
context 'order' do context 'order' do
let!(:occurrence1) { create(:vulnerabilities_occurrence, confidence: described_class::CONFIDENCE_LEVELS[:high], severity: described_class::SEVERITY_LEVELS[:high]) } let!(:finding1) { create(:vulnerabilities_finding, confidence: described_class::CONFIDENCE_LEVELS[:high], severity: described_class::SEVERITY_LEVELS[:high]) }
let!(:occurrence2) { create(:vulnerabilities_occurrence, confidence: described_class::CONFIDENCE_LEVELS[:medium], severity: described_class::SEVERITY_LEVELS[:critical]) } let!(:finding2) { create(:vulnerabilities_finding, confidence: described_class::CONFIDENCE_LEVELS[:medium], severity: described_class::SEVERITY_LEVELS[:critical]) }
let!(:occurrence3) { create(:vulnerabilities_occurrence, confidence: described_class::CONFIDENCE_LEVELS[:high], severity: described_class::SEVERITY_LEVELS[:critical]) } let!(:finding3) { create(:vulnerabilities_finding, confidence: described_class::CONFIDENCE_LEVELS[:high], severity: described_class::SEVERITY_LEVELS[:critical]) }
it 'orders by severity and confidence' do it 'orders by severity and confidence' do
expect(described_class.all.ordered).to eq([occurrence3, occurrence2, occurrence1]) expect(described_class.all.ordered).to eq([finding3, finding2, finding1])
end end
end end
...@@ -76,18 +76,18 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -76,18 +76,18 @@ RSpec.describe Vulnerabilities::Occurrence do
subject { described_class.report_type(report_type) } subject { described_class.report_type(report_type) }
context 'when occurrence has the corresponding report type' do context 'when finding has the corresponding report type' do
let!(:occurrence) { create(:vulnerabilities_occurrence, report_type: report_type) } let!(:finding) { create(:vulnerabilities_finding, report_type: report_type) }
it 'selects the occurrence' do it 'selects the finding' do
is_expected.to eq([occurrence]) is_expected.to eq([finding])
end end
end end
context 'when occurrence does not have security reports' do context 'when finding does not have security reports' do
let!(:occurrence) { create(:vulnerabilities_occurrence, report_type: :dependency_scanning) } let!(:finding) { create(:vulnerabilities_finding, report_type: :dependency_scanning) }
it 'does not select the occurrence' do it 'does not select the finding' do
is_expected.to be_empty is_expected.to be_empty
end end
end end
...@@ -98,13 +98,13 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -98,13 +98,13 @@ RSpec.describe Vulnerabilities::Occurrence do
let(:pipeline) { create(:ci_pipeline, :success, project: project) } let(:pipeline) { create(:ci_pipeline, :success, project: project) }
before do before do
create(:vulnerabilities_occurrence, pipelines: [pipeline], project: project) create(:vulnerabilities_finding, pipelines: [pipeline], project: project)
end end
subject(:occurrences) { described_class.for_pipelines_with_sha([pipeline]) } subject(:findings) { described_class.for_pipelines_with_sha([pipeline]) }
it 'sets the sha' do it 'sets the sha' do
expect(occurrences.first.sha).to eq(pipeline.sha) expect(findings.first.sha).to eq(pipeline.sha)
end end
end end
...@@ -117,23 +117,23 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -117,23 +117,23 @@ RSpec.describe Vulnerabilities::Occurrence do
travel_to(date_1) do travel_to(date_1) do
pipeline = create(:ci_pipeline, :success, project: project) pipeline = create(:ci_pipeline, :success, project: project)
create_list(:vulnerabilities_occurrence, 2, create_list(:vulnerabilities_finding, 2,
pipelines: [pipeline], project: project, report_type: :sast, severity: :high) pipelines: [pipeline], project: project, report_type: :sast, severity: :high)
end end
travel_to(date_2) do travel_to(date_2) do
pipeline = create(:ci_pipeline, :success, project: project) pipeline = create(:ci_pipeline, :success, project: project)
create_list(:vulnerabilities_occurrence, 2, create_list(:vulnerabilities_finding, 2,
pipelines: [pipeline], project: project, report_type: :dependency_scanning, severity: :low) pipelines: [pipeline], project: project, report_type: :dependency_scanning, severity: :low)
create_list(:vulnerabilities_occurrence, 1, create_list(:vulnerabilities_finding, 1,
pipelines: [pipeline], project: project, report_type: :dast, severity: :medium) pipelines: [pipeline], project: project, report_type: :dast, severity: :medium)
create_list(:vulnerabilities_occurrence, 1, create_list(:vulnerabilities_finding, 1,
pipelines: [pipeline], project: project, report_type: :dast, severity: :low) pipelines: [pipeline], project: project, report_type: :dast, severity: :low)
create_list(:vulnerabilities_occurrence, 2, create_list(:vulnerabilities_finding, 2,
pipelines: [pipeline], project: project, report_type: :secret_detection, severity: :critical) pipelines: [pipeline], project: project, report_type: :secret_detection, severity: :critical)
end end
end end
...@@ -147,7 +147,7 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -147,7 +147,7 @@ RSpec.describe Vulnerabilities::Occurrence do
context 'within 3-day period' do context 'within 3-day period' do
let(:range) { 3.days } let(:range) { 3.days }
it 'returns expected counts for occurrences' do it 'returns expected counts for findings' do
first, second, third = subject first, second, third = subject
expect(first.day).to eq(date_2) expect(first.day).to eq(date_2)
...@@ -165,7 +165,7 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -165,7 +165,7 @@ RSpec.describe Vulnerabilities::Occurrence do
context 'within 4-day period' do context 'within 4-day period' do
let(:range) { 4.days } let(:range) { 4.days }
it 'returns expected counts for occurrences' do it 'returns expected counts for findings' do
first, second, third, forth = subject first, second, third, forth = subject
expect(first.day).to eq(date_1) expect(first.day).to eq(date_1)
...@@ -185,10 +185,10 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -185,10 +185,10 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
describe '.by_report_types' do describe '.by_report_types' do
let!(:vulnerability_sast) { create(:vulnerabilities_occurrence, report_type: :sast) } let!(:vulnerability_sast) { create(:vulnerabilities_finding, report_type: :sast) }
let!(:vulnerability_secret_detection) { create(:vulnerabilities_occurrence, report_type: :secret_detection) } let!(:vulnerability_secret_detection) { create(:vulnerabilities_finding, report_type: :secret_detection) }
let!(:vulnerability_dast) { create(:vulnerabilities_occurrence, report_type: :dast) } let!(:vulnerability_dast) { create(:vulnerabilities_finding, report_type: :dast) }
let!(:vulnerability_depscan) { create(:vulnerabilities_occurrence, report_type: :dependency_scanning) } let!(:vulnerability_depscan) { create(:vulnerabilities_finding, report_type: :dependency_scanning) }
subject { described_class.by_report_types(param) } subject { described_class.by_report_types(param) }
...@@ -218,8 +218,8 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -218,8 +218,8 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
describe '.by_projects' do describe '.by_projects' do
let!(:vulnerability1) { create(:vulnerabilities_occurrence) } let!(:vulnerability1) { create(:vulnerabilities_finding) }
let!(:vulnerability2) { create(:vulnerabilities_occurrence) } let!(:vulnerability2) { create(:vulnerabilities_finding) }
subject { described_class.by_projects(param) } subject { described_class.by_projects(param) }
...@@ -233,8 +233,8 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -233,8 +233,8 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
describe '.by_severities' do describe '.by_severities' do
let!(:vulnerability_high) { create(:vulnerabilities_occurrence, severity: :high) } let!(:vulnerability_high) { create(:vulnerabilities_finding, severity: :high) }
let!(:vulnerability_low) { create(:vulnerabilities_occurrence, severity: :low) } let!(:vulnerability_low) { create(:vulnerabilities_finding, severity: :low) }
subject { described_class.by_severities(param) } subject { described_class.by_severities(param) }
...@@ -256,8 +256,8 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -256,8 +256,8 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
describe '.by_confidences' do describe '.by_confidences' do
let!(:vulnerability_high) { create(:vulnerabilities_occurrence, confidence: :high) } let!(:vulnerability_high) { create(:vulnerabilities_finding, confidence: :high) }
let!(:vulnerability_low) { create(:vulnerabilities_occurrence, confidence: :low) } let!(:vulnerability_low) { create(:vulnerabilities_finding, confidence: :low) }
subject { described_class.by_confidences(param) } subject { described_class.by_confidences(param) }
...@@ -279,9 +279,9 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -279,9 +279,9 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
describe '.counted_by_severity' do describe '.counted_by_severity' do
let!(:high_vulnerabilities) { create_list(:vulnerabilities_occurrence, 3, severity: :high) } let!(:high_vulnerabilities) { create_list(:vulnerabilities_finding, 3, severity: :high) }
let!(:medium_vulnerabilities) { create_list(:vulnerabilities_occurrence, 2, severity: :medium) } let!(:medium_vulnerabilities) { create_list(:vulnerabilities_finding, 2, severity: :medium) }
let!(:low_vulnerabilities) { create_list(:vulnerabilities_occurrence, 1, severity: :low) } let!(:low_vulnerabilities) { create_list(:vulnerabilities_finding, 1, severity: :low) }
subject { described_class.counted_by_severity } subject { described_class.counted_by_severity }
...@@ -293,9 +293,9 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -293,9 +293,9 @@ RSpec.describe Vulnerabilities::Occurrence do
describe '.undismissed' do describe '.undismissed' do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:project2) { create(:project) } let_it_be(:project2) { create(:project) }
let!(:finding1) { create(:vulnerabilities_occurrence, project: project) } let!(:finding1) { create(:vulnerabilities_finding, project: project) }
let!(:finding2) { create(:vulnerabilities_occurrence, project: project, report_type: :dast) } let!(:finding2) { create(:vulnerabilities_finding, project: project, report_type: :dast) }
let!(:finding3) { create(:vulnerabilities_occurrence, project: project2) } let!(:finding3) { create(:vulnerabilities_finding, project: project2) }
before do before do
create( create(
...@@ -319,11 +319,11 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -319,11 +319,11 @@ RSpec.describe Vulnerabilities::Occurrence do
) )
end end
it 'returns all non-dismissed occurrences' do it 'returns all non-dismissed findings' do
expect(described_class.undismissed).to contain_exactly(finding2, finding3) expect(described_class.undismissed).to contain_exactly(finding2, finding3)
end end
it 'returns non-dismissed occurrences for project' do it 'returns non-dismissed findings for project' do
expect(project2.vulnerability_findings.undismissed).to contain_exactly(finding3) expect(project2.vulnerability_findings.undismissed).to contain_exactly(finding3)
end end
end end
...@@ -333,7 +333,7 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -333,7 +333,7 @@ RSpec.describe Vulnerabilities::Occurrence do
let(:project) { create(:project) } let(:project) { create(:project) }
it 'fetches a vulnerability count for the given project and severity' do it 'fetches a vulnerability count for the given project and severity' do
create(:vulnerabilities_occurrence, pipelines: [pipeline], project: project, severity: :high) create(:vulnerabilities_finding, pipelines: [pipeline], project: project, severity: :high)
count = described_class.batch_count_by_project_and_severity(project.id, 'high') count = described_class.batch_count_by_project_and_severity(project.id, 'high')
...@@ -344,15 +344,15 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -344,15 +344,15 @@ RSpec.describe Vulnerabilities::Occurrence do
old_pipeline = create(:ci_pipeline, :success, project: project) old_pipeline = create(:ci_pipeline, :success, project: project)
latest_pipeline = create(:ci_pipeline, :success, project: project) latest_pipeline = create(:ci_pipeline, :success, project: project)
latest_failed_pipeline = create(:ci_pipeline, :failed, project: project) latest_failed_pipeline = create(:ci_pipeline, :failed, project: project)
create(:vulnerabilities_occurrence, pipelines: [old_pipeline], project: project, severity: :critical) create(:vulnerabilities_finding, pipelines: [old_pipeline], project: project, severity: :critical)
create( create(
:vulnerabilities_occurrence, :vulnerabilities_finding,
pipelines: [latest_failed_pipeline], pipelines: [latest_failed_pipeline],
project: project, project: project,
severity: :critical severity: :critical
) )
create_list( create_list(
:vulnerabilities_occurrence, 2, :vulnerabilities_finding, 2,
pipelines: [latest_pipeline], pipelines: [latest_pipeline],
project: project, project: project,
severity: :critical severity: :critical
...@@ -375,8 +375,8 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -375,8 +375,8 @@ RSpec.describe Vulnerabilities::Occurrence do
projects.each do |project| projects.each do |project|
pipeline = create(:ci_pipeline, :success, project: project) pipeline = create(:ci_pipeline, :success, project: project)
create(:vulnerabilities_occurrence, pipelines: [pipeline], project: project, severity: :high) create(:vulnerabilities_finding, pipelines: [pipeline], project: project, severity: :high)
create(:vulnerabilities_occurrence, pipelines: [pipeline], project: project, severity: :low) create(:vulnerabilities_finding, pipelines: [pipeline], project: project, severity: :low)
end end
projects_and_severities = [ projects_and_severities = [
...@@ -394,8 +394,8 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -394,8 +394,8 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
it 'does not include dismissed vulnerabilities in the counts' do it 'does not include dismissed vulnerabilities in the counts' do
create(:vulnerabilities_occurrence, pipelines: [pipeline], project: project, severity: :high) create(:vulnerabilities_finding, pipelines: [pipeline], project: project, severity: :high)
dismissed_vulnerability = create(:vulnerabilities_occurrence, pipelines: [pipeline], project: project, severity: :high) dismissed_vulnerability = create(:vulnerabilities_finding, pipelines: [pipeline], project: project, severity: :high)
create( create(
:vulnerability_feedback, :vulnerability_feedback,
project: project, project: project,
...@@ -413,8 +413,8 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -413,8 +413,8 @@ RSpec.describe Vulnerabilities::Occurrence do
project2 = create(:project) project2 = create(:project)
pipeline1 = create(:ci_pipeline, :success, project: project1) pipeline1 = create(:ci_pipeline, :success, project: project1)
pipeline2 = create(:ci_pipeline, :success, project: project2) pipeline2 = create(:ci_pipeline, :success, project: project2)
create(:vulnerabilities_occurrence, pipelines: [pipeline1], project: project1, severity: :critical) create(:vulnerabilities_finding, pipelines: [pipeline1], project: project1, severity: :critical)
create(:vulnerabilities_occurrence, pipelines: [pipeline2], project: project2, severity: :high) create(:vulnerabilities_finding, pipelines: [pipeline2], project: project2, severity: :high)
project1_critical_count = described_class.batch_count_by_project_and_severity(project1.id, 'critical') project1_critical_count = described_class.batch_count_by_project_and_severity(project1.id, 'critical')
project1_high_count = described_class.batch_count_by_project_and_severity(project1.id, 'high') project1_high_count = described_class.batch_count_by_project_and_severity(project1.id, 'high')
...@@ -430,9 +430,9 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -430,9 +430,9 @@ RSpec.describe Vulnerabilities::Occurrence do
describe 'feedback' do describe 'feedback' do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let(:occurrence) do let(:finding) do
create( create(
:vulnerabilities_occurrence, :vulnerabilities_finding,
report_type: :dependency_scanning, report_type: :dependency_scanning,
project: project project: project
) )
...@@ -447,12 +447,12 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -447,12 +447,12 @@ RSpec.describe Vulnerabilities::Occurrence do
:issue, :issue,
issue: issue, issue: issue,
project: project, project: project,
project_fingerprint: occurrence.project_fingerprint project_fingerprint: finding.project_fingerprint
) )
end end
it 'returns associated feedback' do it 'returns associated feedback' do
feedback = occurrence.issue_feedback feedback = finding.issue_feedback
expect(feedback).to be_present expect(feedback).to be_present
expect(feedback[:project_id]).to eq project.id expect(feedback[:project_id]).to eq project.id
...@@ -468,12 +468,12 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -468,12 +468,12 @@ RSpec.describe Vulnerabilities::Occurrence do
:dependency_scanning, :dependency_scanning,
:dismissal, :dismissal,
project: project, project: project,
project_fingerprint: occurrence.project_fingerprint project_fingerprint: finding.project_fingerprint
) )
end end
it 'returns associated feedback' do it 'returns associated feedback' do
feedback = occurrence.dismissal_feedback feedback = finding.dismissal_feedback
expect(feedback).to be_present expect(feedback).to be_present
expect(feedback[:project_id]).to eq project.id expect(feedback[:project_id]).to eq project.id
...@@ -490,12 +490,12 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -490,12 +490,12 @@ RSpec.describe Vulnerabilities::Occurrence do
:merge_request, :merge_request,
merge_request: merge_request, merge_request: merge_request,
project: project, project: project,
project_fingerprint: occurrence.project_fingerprint project_fingerprint: finding.project_fingerprint
) )
end end
it 'returns associated feedback' do it 'returns associated feedback' do
feedback = occurrence.merge_request_feedback feedback = finding.merge_request_feedback
expect(feedback).to be_present expect(feedback).to be_present
expect(feedback[:project_id]).to eq project.id expect(feedback[:project_id]).to eq project.id
...@@ -507,9 +507,9 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -507,9 +507,9 @@ RSpec.describe Vulnerabilities::Occurrence do
describe '#load_feedback' do describe '#load_feedback' do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:occurrence) do let_it_be(:finding) do
create( create(
:vulnerabilities_occurrence, :vulnerabilities_finding,
report_type: :dependency_scanning, report_type: :dependency_scanning,
project: project project: project
) )
...@@ -520,20 +520,20 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -520,20 +520,20 @@ RSpec.describe Vulnerabilities::Occurrence do
:dependency_scanning, :dependency_scanning,
:dismissal, :dismissal,
project: project, project: project,
project_fingerprint: occurrence.project_fingerprint project_fingerprint: finding.project_fingerprint
) )
end end
let(:expected_feedback) { [feedback] } let(:expected_feedback) { [feedback] }
subject(:load_feedback) { occurrence.load_feedback.to_a } subject(:load_feedback) { finding.load_feedback.to_a }
it { is_expected.to eq(expected_feedback) } it { is_expected.to eq(expected_feedback) }
context 'when you have multiple occurrences' do context 'when you have multiple findings' do
let_it_be(:occurrence_2) do let_it_be(:finding_2) do
create( create(
:vulnerabilities_occurrence, :vulnerabilities_finding,
report_type: :dependency_scanning, report_type: :dependency_scanning,
project: project project: project
) )
...@@ -545,13 +545,13 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -545,13 +545,13 @@ RSpec.describe Vulnerabilities::Occurrence do
:dependency_scanning, :dependency_scanning,
:dismissal, :dismissal,
project: project, project: project,
project_fingerprint: occurrence_2.project_fingerprint project_fingerprint: finding_2.project_fingerprint
) )
end end
let(:expected_feedback) { [[feedback], [feedback_2]] } let(:expected_feedback) { [[feedback], [feedback_2]] }
subject(:load_feedback) { [occurrence, occurrence_2].map(&:load_feedback) } subject(:load_feedback) { [finding, finding_2].map(&:load_feedback) }
it { is_expected.to eq(expected_feedback) } it { is_expected.to eq(expected_feedback) }
end end
...@@ -606,37 +606,37 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -606,37 +606,37 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
describe '#scanner_name' do describe '#scanner_name' do
let(:vulnerabilities_occurrence) { create(:vulnerabilities_occurrence) } let(:vulnerabilities_finding) { create(:vulnerabilities_finding) }
subject(:scanner_name) { vulnerabilities_occurrence.scanner_name } subject(:scanner_name) { vulnerabilities_finding.scanner_name }
it { is_expected.to eq(vulnerabilities_occurrence.scanner.name) } it { is_expected.to eq(vulnerabilities_finding.scanner.name) }
end end
describe '#solution' do describe '#solution' do
subject { vulnerabilities_occurrence.solution } subject { vulnerabilities_finding.solution }
context 'when solution metadata key is present' do context 'when solution metadata key is present' do
let(:vulnerabilities_occurrence) { build(:vulnerabilities_occurrence) } let(:vulnerabilities_finding) { build(:vulnerabilities_finding) }
it { is_expected.to eq(vulnerabilities_occurrence.metadata['solution']) } it { is_expected.to eq(vulnerabilities_finding.metadata['solution']) }
end end
context 'when remediations key is present' do context 'when remediations key is present' do
let(:vulnerabilities_occurrence) do let(:vulnerabilities_finding) do
build(:vulnerabilities_occurrence_with_remediation, summary: "Test remediation") build(:vulnerabilities_finding_with_remediation, summary: "Test remediation")
end end
it { is_expected.to eq(vulnerabilities_occurrence.remediations.dig(0, 'summary')) } it { is_expected.to eq(vulnerabilities_finding.remediations.dig(0, 'summary')) }
end end
end end
describe '#evidence' do describe '#evidence' do
subject { occurrence.evidence } subject { finding.evidence }
context 'has an evidence fields' do context 'has an evidence fields' do
let(:occurrence) { create(:vulnerabilities_occurrence) } let(:finding) { create(:vulnerabilities_finding) }
let(:evidence) { occurrence.metadata['evidence'] } let(:evidence) { finding.metadata['evidence'] }
it do it do
is_expected.to match a_hash_including( is_expected.to match a_hash_including(
...@@ -655,7 +655,7 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -655,7 +655,7 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
context 'has no evidence summary when evidence is present, summary is not' do context 'has no evidence summary when evidence is present, summary is not' do
let(:occurrence) { create(:vulnerabilities_occurrence, raw_metadata: { evidence: {} }) } let(:finding) { create(:vulnerabilities_finding, raw_metadata: { evidence: {} }) }
it do it do
is_expected.to match a_hash_including( is_expected.to match a_hash_including(
...@@ -675,42 +675,42 @@ RSpec.describe Vulnerabilities::Occurrence do ...@@ -675,42 +675,42 @@ RSpec.describe Vulnerabilities::Occurrence do
end end
describe '#message' do describe '#message' do
let(:occurrence) { build(:vulnerabilities_occurrence) } let(:finding) { build(:vulnerabilities_finding) }
let(:expected_message) { occurrence.metadata['message'] } let(:expected_message) { finding.metadata['message'] }
subject { occurrence.message } subject { finding.message }
it { is_expected.to eql(expected_message) } it { is_expected.to eql(expected_message) }
end end
describe '#cve' do describe '#cve' do
let(:occurrence) { build(:vulnerabilities_occurrence) } let(:finding) { build(:vulnerabilities_finding) }
let(:expected_cve) { occurrence.metadata['cve'] } let(:expected_cve) { finding.metadata['cve'] }
subject { occurrence.cve } subject { finding.cve }
it { is_expected.to eql(expected_cve) } it { is_expected.to eql(expected_cve) }
end end
describe "#metadata" do describe "#metadata" do
let(:occurrence) { build(:vulnerabilities_occurrence) } let(:finding) { build(:vulnerabilities_finding) }
subject { occurrence.metadata } subject { finding.metadata }
it "handles bool JSON data" do it "handles bool JSON data" do
allow(occurrence).to receive(:raw_metadata) { "true" } allow(finding).to receive(:raw_metadata) { "true" }
expect(subject).to eq({}) expect(subject).to eq({})
end end
it "handles string JSON data" do it "handles string JSON data" do
allow(occurrence).to receive(:raw_metadata) { '"test"' } allow(finding).to receive(:raw_metadata) { '"test"' }
expect(subject).to eq({}) expect(subject).to eq({})
end end
it "parses JSON data" do it "parses JSON data" do
allow(occurrence).to receive(:raw_metadata) { '{ "test": true }' } allow(finding).to receive(:raw_metadata) { '{ "test": true }' }
expect(subject).to eq({ "test" => true }) expect(subject).to eq({ "test" => true })
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').with_foreign_key('occurrence_id') }
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
......
...@@ -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
......
...@@ -47,7 +47,7 @@ RSpec.describe 'GET /-/security/vulnerability_findings' do ...@@ -47,7 +47,7 @@ RSpec.describe 'GET /-/security/vulnerability_findings' 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::OCCURRENCES_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.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
......
...@@ -47,7 +47,7 @@ RSpec.shared_examples ProjectVulnerabilityFindingsActions do ...@@ -47,7 +47,7 @@ RSpec.shared_examples ProjectVulnerabilityFindingsActions 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::OCCURRENCES_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