Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
5fe4b7d0
Commit
5fe4b7d0
authored
Dec 17, 2019
by
Cameron Swords
Committed by
Thong Kuah
Dec 17, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Parsers have access to JobArtifacts
The JobArtifact is required to retrieve the creation date
parent
d9d063b9
Changes
27
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
342 additions
and
184 deletions
+342
-184
app/models/ci/build.rb
app/models/ci/build.rb
+1
-1
ee/app/finders/security/pipeline_vulnerabilities_finder.rb
ee/app/finders/security/pipeline_vulnerabilities_finder.rb
+4
-8
ee/app/models/ee/ci/build.rb
ee/app/models/ee/ci/build.rb
+4
-4
ee/app/serializers/vulnerabilities/occurrence_reports_comparer_entity.rb
...ers/vulnerabilities/occurrence_reports_comparer_entity.rb
+3
-0
ee/app/services/security/merge_reports_service.rb
ee/app/services/security/merge_reports_service.rb
+2
-1
ee/lib/api/vulnerability_findings.rb
ee/lib/api/vulnerability_findings.rb
+2
-1
ee/lib/gitlab/ci/parsers/security/concerns/deprecated_syntax.rb
.../gitlab/ci/parsers/security/concerns/deprecated_syntax.rb
+0
-1
ee/lib/gitlab/ci/reports/security/aggregated_report.rb
ee/lib/gitlab/ci/reports/security/aggregated_report.rb
+24
-0
ee/lib/gitlab/ci/reports/security/report.rb
ee/lib/gitlab/ci/reports/security/report.rb
+4
-2
ee/lib/gitlab/ci/reports/security/reports.rb
ee/lib/gitlab/ci/reports/security/reports.rb
+2
-2
ee/lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb
...lab/ci/reports/security/vulnerability_reports_comparer.rb
+21
-5
ee/spec/factories/ci/reports/security/aggregated_reports.rb
ee/spec/factories/ci/reports/security/aggregated_reports.rb
+12
-0
ee/spec/factories/ci/reports/security/reports.rb
ee/spec/factories/ci/reports/security/reports.rb
+2
-1
ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb
.../finders/security/pipeline_vulnerabilities_finder_spec.rb
+54
-51
ee/spec/lib/gitlab/ci/parsers/security/container_scanning_spec.rb
...lib/gitlab/ci/parsers/security/container_scanning_spec.rb
+1
-1
ee/spec/lib/gitlab/ci/parsers/security/dast_spec.rb
ee/spec/lib/gitlab/ci/parsers/security/dast_spec.rb
+1
-1
ee/spec/lib/gitlab/ci/parsers/security/dependency_scanning_spec.rb
...ib/gitlab/ci/parsers/security/dependency_scanning_spec.rb
+1
-1
ee/spec/lib/gitlab/ci/parsers/security/sast_spec.rb
ee/spec/lib/gitlab/ci/parsers/security/sast_spec.rb
+3
-2
ee/spec/lib/gitlab/ci/reports/security/aggregated_report_spec.rb
.../lib/gitlab/ci/reports/security/aggregated_report_spec.rb
+45
-0
ee/spec/lib/gitlab/ci/reports/security/report_spec.rb
ee/spec/lib/gitlab/ci/reports/security/report_spec.rb
+5
-3
ee/spec/lib/gitlab/ci/reports/security/reports_spec.rb
ee/spec/lib/gitlab/ci/reports/security/reports_spec.rb
+8
-6
ee/spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb
...i/reports/security/vulnerability_reports_comparer_spec.rb
+87
-54
ee/spec/models/ci/build_spec.rb
ee/spec/models/ci/build_spec.rb
+22
-20
ee/spec/models/ci/pipeline_spec.rb
ee/spec/models/ci/pipeline_spec.rb
+12
-12
ee/spec/serializers/vulnerabilities/occurrence_reports_comparer_entity_spec.rb
...ulnerabilities/occurrence_reports_comparer_entity_spec.rb
+16
-3
ee/spec/services/security/store_report_service_spec.rb
ee/spec/services/security/store_report_service_spec.rb
+2
-2
ee/spec/services/security/store_reports_service_spec.rb
ee/spec/services/security/store_reports_service_spec.rb
+4
-2
No files found.
app/models/ci/build.rb
View file @
5fe4b7d0
...
...
@@ -887,7 +887,7 @@ module Ci
def
each_report
(
report_types
)
job_artifacts_for_types
(
report_types
).
each
do
|
report_artifact
|
report_artifact
.
each_blob
do
|
blob
|
yield
report_artifact
.
file_type
,
blob
yield
report_artifact
.
file_type
,
blob
,
report_artifact
end
end
end
...
...
ee/app/finders/security/pipeline_vulnerabilities_finder.rb
View file @
5fe4b7d0
...
...
@@ -24,13 +24,9 @@ module Security
end
def
execute
reports
=
pipeline_reports
return
[]
if
reports
.
nil?
occurrences
=
reports
.
each_with_object
([])
do
|
(
type
,
report
),
occurrences
|
next
unless
requested_type?
(
type
)
requested_reports
=
pipeline_reports
.
select
{
|
report_type
|
requested_type?
(
report_type
)
}
occurrences
=
requested_reports
.
each_with_object
([])
do
|
(
type
,
report
),
occurrences
|
raise
ParseError
,
'JSON parsing failed'
if
report
.
error
.
is_a?
(
Gitlab
::
Ci
::
Parsers
::
Security
::
Common
::
SecurityReportParserError
)
normalized_occurrences
=
normalize_report_occurrences
(
...
...
@@ -41,7 +37,7 @@ module Security
occurrences
.
concat
(
filtered_occurrences
)
end
sort_occurrences
(
occurrences
)
Gitlab
::
Ci
::
Reports
::
Security
::
AggregatedReport
.
new
(
requested_reports
.
values
,
sort_occurrences
(
occurrences
)
)
end
private
...
...
@@ -63,7 +59,7 @@ module Security
end
def
pipeline_reports
pipeline
&
.
security_reports
&
.
reports
pipeline
&
.
security_reports
&
.
reports
||
{}
end
def
vulnerabilities_by_finding_fingerprint
(
report_type
,
report
)
...
...
ee/app/models/ee/ci/build.rb
View file @
5fe4b7d0
...
...
@@ -48,8 +48,8 @@ module EE
end
def
collect_security_reports!
(
security_reports
)
each_report
(
::
Ci
::
JobArtifact
::
SECURITY_REPORT_FILE_TYPES
)
do
|
file_type
,
blob
|
security_reports
.
get_report
(
file_type
).
tap
do
|
security_report
|
each_report
(
::
Ci
::
JobArtifact
::
SECURITY_REPORT_FILE_TYPES
)
do
|
file_type
,
blob
,
report_artifact
|
security_reports
.
get_report
(
file_type
,
report_artifact
).
tap
do
|
security_report
|
next
unless
project
.
feature_available?
(
LICENSED_PARSER_FEATURES
.
fetch
(
file_type
))
parse_security_artifact_blob
(
security_report
,
blob
)
...
...
@@ -75,7 +75,7 @@ module EE
if
project
.
feature_available?
(
:dependency_scanning
)
dependency_list
=
::
Gitlab
::
Ci
::
Parsers
::
Security
::
DependencyList
.
new
(
project
,
sha
)
each_report
(
::
Ci
::
JobArtifact
::
DEPENDENCY_LIST_REPORT_FILE_TYPES
)
do
|
file_type
,
blob
|
each_report
(
::
Ci
::
JobArtifact
::
DEPENDENCY_LIST_REPORT_FILE_TYPES
)
do
|
_
,
blob
|
dependency_list
.
parse!
(
blob
,
dependency_list_report
)
end
end
...
...
@@ -87,7 +87,7 @@ module EE
if
project
.
feature_available?
(
:dependency_scanning
)
dependency_list
=
::
Gitlab
::
Ci
::
Parsers
::
Security
::
DependencyList
.
new
(
project
,
sha
)
each_report
(
::
Ci
::
JobArtifact
::
LICENSE_MANAGEMENT_REPORT_FILE_TYPES
)
do
|
file_type
,
blob
|
each_report
(
::
Ci
::
JobArtifact
::
LICENSE_MANAGEMENT_REPORT_FILE_TYPES
)
do
|
_
,
blob
|
dependency_list
.
parse_licenses!
(
blob
,
dependency_list_report
)
end
end
...
...
ee/app/serializers/vulnerabilities/occurence_reports_comparer_entity.rb
→
ee/app/serializers/vulnerabilities/occur
r
ence_reports_comparer_entity.rb
View file @
5fe4b7d0
# frozen_string_literal: true
class
Vulnerabilities::OccurrenceReportsComparerEntity
<
Grape
::
Entity
expose
:base_report_created_at
expose
:base_report_out_of_date
expose
:head_report_created_at
expose
:added
,
using:
Vulnerabilities
::
OccurrenceEntity
expose
:fixed
,
using:
Vulnerabilities
::
OccurrenceEntity
expose
:existing
,
using:
Vulnerabilities
::
OccurrenceEntity
...
...
ee/app/services/security/merge_reports_service.rb
View file @
5fe4b7d0
...
...
@@ -20,7 +20,8 @@ module Security
@source_reports
=
source_reports
@target_report
=
::
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
@source_reports
.
first
.
type
,
@source_reports
.
first
.
commit_sha
@source_reports
.
first
.
commit_sha
,
@source_reports
.
first
.
created_at
)
@occurrences
=
[]
end
...
...
ee/lib/api/vulnerability_findings.rb
View file @
5fe4b7d0
...
...
@@ -14,7 +14,8 @@ module API
return
[]
unless
pipeline
Security
::
PipelineVulnerabilitiesFinder
.
new
(
pipeline:
pipeline
,
params:
params
).
execute
aggregated_report
=
Security
::
PipelineVulnerabilitiesFinder
.
new
(
pipeline:
pipeline
,
params:
params
).
execute
aggregated_report
.
occurrences
end
end
...
...
ee/lib/gitlab/ci/parsers/security/concerns/deprecated_syntax.rb
View file @
5fe4b7d0
...
...
@@ -18,7 +18,6 @@ module Gitlab
report
=
super
if
report
.
is_a?
(
Array
)
puts
self
.
class
report
=
{
"version"
=>
self
.
class
::
DEPRECATED_REPORT_VERSION
,
"vulnerabilities"
=>
report
...
...
ee/lib/gitlab/ci/reports/security/aggregated_report.rb
0 → 100644
View file @
5fe4b7d0
# frozen_string_literal: true
# Used to represent combined Security Reports. This is typically done for vulnerability deduplication purposes.
module
Gitlab
module
Ci
module
Reports
module
Security
class
AggregatedReport
attr_reader
:occurrences
def
initialize
(
reports
,
occurrences
)
@reports
=
reports
@occurrences
=
occurrences
end
def
created_at
@reports
.
map
(
&
:created_at
).
compact
.
min
end
end
end
end
end
end
ee/lib/gitlab/ci/reports/security/report.rb
View file @
5fe4b7d0
...
...
@@ -7,6 +7,7 @@ module Gitlab
class
Report
UNSAFE_SEVERITIES
=
%w[unknown high critical]
.
freeze
attr_reader
:created_at
attr_reader
:type
attr_reader
:commit_sha
attr_reader
:occurrences
...
...
@@ -15,9 +16,10 @@ module Gitlab
attr_accessor
:error
def
initialize
(
type
,
commit_sha
)
def
initialize
(
type
,
commit_sha
,
created_at
)
@type
=
type
@commit_sha
=
commit_sha
@created_at
=
created_at
@occurrences
=
[]
@scanners
=
{}
@identifiers
=
{}
...
...
@@ -40,7 +42,7 @@ module Gitlab
end
def
clone_as_blank
Report
.
new
(
type
,
commit_sha
)
Report
.
new
(
type
,
commit_sha
,
created_at
)
end
def
replace_with!
(
other
)
...
...
ee/lib/gitlab/ci/reports/security/reports.rb
View file @
5fe4b7d0
...
...
@@ -14,8 +14,8 @@ module Gitlab
@commit_sha
=
commit_sha
end
def
get_report
(
report_type
)
reports
[
report_type
]
||=
Report
.
new
(
report_type
,
commit_sha
)
def
get_report
(
report_type
,
report_artifact
)
reports
[
report_type
]
||=
Report
.
new
(
report_type
,
commit_sha
,
report_artifact
.
created_at
)
end
def
violates_default_policy?
...
...
ee/lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb
View file @
5fe4b7d0
...
...
@@ -9,27 +9,43 @@ module Gitlab
attr_reader
:base_report
,
:head_report
ACCEPTABLE_REPORT_AGE
=
1
.
week
def
initialize
(
base_report
,
head_report
)
@base_report
=
base_report
||
[]
@head_report
=
head_report
||
[]
@base_report
=
base_report
@head_report
=
head_report
end
def
base_report_created_at
@base_report
.
created_at
end
def
head_report_created_at
@head_report
.
created_at
end
def
base_report_out_of_date
return
false
unless
@base_report
.
created_at
ACCEPTABLE_REPORT_AGE
.
ago
>
@base_report
.
created_at
end
def
added
strong_memoize
(
:added
)
do
head_report
-
base_report
head_report
.
occurrences
-
base_report
.
occurrences
end
end
def
fixed
strong_memoize
(
:fixed
)
do
base_report
-
head_report
base_report
.
occurrences
-
head_report
.
occurrences
end
end
def
existing
strong_memoize
(
:existing
)
do
# Existing vulnerabilities should point to source report for most recent information
head_report
&
base_report
head_report
.
occurrences
&
base_report
.
occurrences
end
end
end
...
...
ee/spec/factories/ci/reports/security/aggregated_reports.rb
0 → 100644
View file @
5fe4b7d0
# frozen_string_literal: true
FactoryBot
.
define
do
factory
:ci_reports_security_aggregated_reports
,
class:
::
Gitlab
::
Ci
::
Reports
::
Security
::
AggregatedReport
do
reports
{
FactoryBot
.
build_list
(
:ci_reports_security_report
,
1
)
}
occurrences
{
FactoryBot
.
build_list
(
:ci_reports_security_occurrence
,
1
)
}
initialize_with
do
::
Gitlab
::
Ci
::
Reports
::
Security
::
AggregatedReport
.
new
(
reports
,
occurrences
)
end
end
end
ee/spec/factories/ci/reports/security/reports.rb
View file @
5fe4b7d0
...
...
@@ -4,6 +4,7 @@ FactoryBot.define do
factory
:ci_reports_security_report
,
class:
::
Gitlab
::
Ci
::
Reports
::
Security
::
Report
do
type
{
:sast
}
commit_sha
{
Digest
::
SHA1
.
hexdigest
(
SecureRandom
.
hex
)
}
created_at
{
2
.
weeks
.
ago
}
transient
do
occurrences
{
[]
}
...
...
@@ -20,7 +21,7 @@ FactoryBot.define do
skip_create
initialize_with
do
::
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
type
,
commit_sha
)
::
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
type
,
commit_sha
,
created_at
)
end
end
end
ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb
View file @
5fe4b7d0
...
...
@@ -53,31 +53,33 @@ describe Security::PipelineVulnerabilitiesFinder do
subject
{
described_class
.
new
(
pipeline:
pipeline
,
params:
params
).
execute
}
it
'assigns commit sha to findings'
do
expect
(
subject
.
map
(
&
:sha
).
uniq
).
to
eq
[
pipeline
.
sha
]
end
context
'occurrences'
do
it
'assigns commit sha to findings'
do
expect
(
subject
.
occurrences
.
map
(
&
:sha
).
uniq
).
to
eq
([
pipeline
.
sha
])
end
context
'by order'
do
let
(
:params
)
{
{
report_type:
%w[sast]
}
}
let!
(
:high_high
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :high
,
severity: :high
)
}
let!
(
:critical_medium
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :medium
,
severity: :critical
)
}
let!
(
:critical_high
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :high
,
severity: :critical
)
}
let!
(
:unknown_high
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :high
,
severity: :unknown
)
}
let!
(
:unknown_medium
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :medium
,
severity: :unknown
)
}
let!
(
:unknown_low
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :low
,
severity: :unknown
)
}
it
'orders by severity and confidence'
do
allow_next_instance_of
(
described_class
)
do
|
pipeline_vulnerabilities_finder
|
allow
(
pipeline_vulnerabilities_finder
).
to
receive
(
:filter
).
and_return
([
unknown_low
,
unknown_medium
,
critical_high
,
unknown_high
,
critical_medium
,
high_high
])
expect
(
subject
).
to
eq
([
critical_high
,
critical_medium
,
high_high
,
unknown_high
,
unknown_medium
,
unknown_low
])
context
'by order'
do
let
(
:params
)
{
{
report_type:
%w[sast]
}
}
let!
(
:high_high
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :high
,
severity: :high
)
}
let!
(
:critical_medium
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :medium
,
severity: :critical
)
}
let!
(
:critical_high
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :high
,
severity: :critical
)
}
let!
(
:unknown_high
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :high
,
severity: :unknown
)
}
let!
(
:unknown_medium
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :medium
,
severity: :unknown
)
}
let!
(
:unknown_low
)
{
build
(
:vulnerabilities_occurrence
,
confidence: :low
,
severity: :unknown
)
}
it
'orders by severity and confidence'
do
allow_next_instance_of
(
described_class
)
do
|
pipeline_vulnerabilities_finder
|
allow
(
pipeline_vulnerabilities_finder
).
to
receive
(
:filter
).
and_return
([
unknown_low
,
unknown_medium
,
critical_high
,
unknown_high
,
critical_medium
,
high_high
])
expect
(
subject
.
occurrences
).
to
eq
([
critical_high
,
critical_medium
,
high_high
,
unknown_high
,
unknown_medium
,
unknown_low
])
end
end
end
end
...
...
@@ -88,8 +90,8 @@ describe Security::PipelineVulnerabilitiesFinder do
let
(
:sast_report_fingerprints
)
{
pipeline
.
security_reports
.
reports
[
'sast'
].
occurrences
.
map
(
&
:location
).
map
(
&
:fingerprint
)
}
it
'includes only sast'
do
expect
(
subject
.
map
(
&
:location_fingerprint
)).
to
match_array
(
sast_report_fingerprints
)
expect
(
subject
.
count
).
to
eq
sast_count
expect
(
subject
.
occurrences
.
map
(
&
:location_fingerprint
)).
to
match_array
(
sast_report_fingerprints
)
expect
(
subject
.
occurrences
.
count
).
to
eq
(
sast_count
)
end
end
...
...
@@ -98,8 +100,8 @@ describe Security::PipelineVulnerabilitiesFinder do
let
(
:ds_report_fingerprints
)
{
pipeline
.
security_reports
.
reports
[
'dependency_scanning'
].
occurrences
.
map
(
&
:location
).
map
(
&
:fingerprint
)
}
it
'includes only dependency_scanning'
do
expect
(
subject
.
map
(
&
:location_fingerprint
)).
to
match_array
(
ds_report_fingerprints
)
expect
(
subject
.
count
).
to
eq
ds_count
expect
(
subject
.
occurrences
.
map
(
&
:location_fingerprint
)).
to
match_array
(
ds_report_fingerprints
)
expect
(
subject
.
occurrences
.
count
).
to
eq
(
ds_count
)
end
end
...
...
@@ -108,8 +110,8 @@ describe Security::PipelineVulnerabilitiesFinder do
let
(
:dast_report_fingerprints
)
{
pipeline
.
security_reports
.
reports
[
'dast'
].
occurrences
.
map
(
&
:location
).
map
(
&
:fingerprint
)
}
it
'includes only dast'
do
expect
(
subject
.
map
(
&
:location_fingerprint
)).
to
match_array
(
dast_report_fingerprints
)
expect
(
subject
.
count
).
to
eq
dast_count
expect
(
subject
.
occurrences
.
map
(
&
:location_fingerprint
)).
to
match_array
(
dast_report_fingerprints
)
expect
(
subject
.
occurrences
.
count
).
to
eq
(
dast_count
)
end
end
...
...
@@ -118,8 +120,8 @@ describe Security::PipelineVulnerabilitiesFinder do
it
'includes only container_scanning'
do
fingerprints
=
pipeline
.
security_reports
.
reports
[
'container_scanning'
].
occurrences
.
map
(
&
:location
).
map
(
&
:fingerprint
)
expect
(
subject
.
map
(
&
:location_fingerprint
)).
to
match_array
(
fingerprints
)
expect
(
subject
.
count
).
to
eq
cs_count
expect
(
subject
.
occurrences
.
map
(
&
:location_fingerprint
)).
to
match_array
(
fingerprints
)
expect
(
subject
.
occurrences
.
count
).
to
eq
(
cs_count
)
end
end
end
...
...
@@ -155,8 +157,8 @@ describe Security::PipelineVulnerabilitiesFinder do
subject
{
described_class
.
new
(
pipeline:
pipeline
).
execute
}
it
'returns non-dismissed vulnerabilities'
do
expect
(
subject
.
count
).
to
eq
cs_count
+
dast_count
+
ds_count
+
sast_count
-
feedback
.
count
expect
(
subject
.
map
(
&
:project_fingerprint
)).
not_to
include
(
*
feedback
.
map
(
&
:project_fingerprint
))
expect
(
subject
.
occurrences
.
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
))
end
end
...
...
@@ -164,8 +166,8 @@ describe Security::PipelineVulnerabilitiesFinder do
subject
{
described_class
.
new
(
pipeline:
pipeline
,
params:
{
report_type:
%w[dependency_scanning]
,
scope:
'dismissed'
}
).
execute
}
it
'returns non-dismissed vulnerabilities'
do
expect
(
subject
.
count
).
to
eq
(
ds_count
-
1
)
expect
(
subject
.
map
(
&
:project_fingerprint
)).
not_to
include
(
ds_occurrence
.
project_fingerprint
)
expect
(
subject
.
occurrences
.
count
).
to
eq
(
ds_count
-
1
)
expect
(
subject
.
occurrences
.
map
(
&
:project_fingerprint
)).
not_to
include
(
ds_occurrence
.
project_fingerprint
)
end
end
...
...
@@ -173,7 +175,7 @@ describe Security::PipelineVulnerabilitiesFinder do
let
(
:params
)
{
{
report_type:
%w[sast dast container_scanning dependency_scanning]
,
scope:
'all'
}
}
it
'returns all vulnerabilities'
do
expect
(
subject
.
count
).
to
eq
cs_count
+
dast_count
+
ds_count
+
sast_count
expect
(
subject
.
occurrences
.
count
).
to
eq
(
cs_count
+
dast_count
+
ds_count
+
sast_count
)
end
end
end
...
...
@@ -183,7 +185,7 @@ describe Security::PipelineVulnerabilitiesFinder do
subject
{
described_class
.
new
(
pipeline:
pipeline
).
execute
}
it
'returns all vulnerability severity levels'
do
expect
(
subject
.
map
(
&
:severity
).
uniq
).
to
match_array
%w[undefined unknown low medium high critical info]
expect
(
subject
.
occurrences
.
map
(
&
:severity
).
uniq
).
to
match_array
(
%w[undefined unknown low medium high critical info]
)
end
end
...
...
@@ -191,7 +193,7 @@ describe Security::PipelineVulnerabilitiesFinder do
subject
{
described_class
.
new
(
pipeline:
pipeline
,
params:
{
severity:
'low'
}
).
execute
}
it
'returns only low-severity vulnerabilities'
do
expect
(
subject
.
map
(
&
:severity
).
uniq
).
to
match_array
%w[low]
expect
(
subject
.
occurrences
.
map
(
&
:severity
).
uniq
).
to
match_array
(
%w[low]
)
end
end
end
...
...
@@ -201,7 +203,7 @@ describe Security::PipelineVulnerabilitiesFinder do
subject
{
described_class
.
new
(
pipeline:
pipeline
).
execute
}
it
'returns all vulnerability confidence levels'
do
expect
(
subject
.
map
(
&
:confidence
).
uniq
).
to
match_array
%w[undefined unknown low medium high]
expect
(
subject
.
occurrences
.
map
(
&
:confidence
).
uniq
).
to
match_array
%w[undefined unknown low medium high]
end
end
...
...
@@ -209,7 +211,7 @@ describe Security::PipelineVulnerabilitiesFinder do
subject
{
described_class
.
new
(
pipeline:
pipeline
,
params:
{
confidence:
'medium'
}
).
execute
}
it
'returns only medium-confidence vulnerabilities'
do
expect
(
subject
.
map
(
&
:confidence
).
uniq
).
to
match_array
%w[medium]
expect
(
subject
.
occurrences
.
map
(
&
:confidence
).
uniq
).
to
match_array
(
%w[medium]
)
end
end
end
...
...
@@ -219,9 +221,9 @@ describe Security::PipelineVulnerabilitiesFinder do
let
(
:params
)
{
{
report_type:
%w[sast dast container_scanning dependency_scanning]
,
scope:
'all'
}
}
it
'filters by all params'
do
expect
(
subject
.
count
).
to
eq
cs_count
+
dast_count
+
ds_count
+
sast_count
expect
(
subject
.
map
(
&
:confidence
).
uniq
).
to
match_array
%w[undefined unknown low medium high]
expect
(
subject
.
map
(
&
:severity
).
uniq
).
to
match_array
%w[undefined unknown low medium high critical info]
expect
(
subject
.
occurrences
.
count
).
to
eq
(
cs_count
+
dast_count
+
ds_count
+
sast_count
)
expect
(
subject
.
occurrences
.
map
(
&
:confidence
).
uniq
).
to
match_array
(
%w[undefined unknown low medium high]
)
expect
(
subject
.
occurrences
.
map
(
&
:severity
).
uniq
).
to
match_array
(
%w[undefined unknown low medium high critical info]
)
end
end
...
...
@@ -229,7 +231,8 @@ describe Security::PipelineVulnerabilitiesFinder do
let
(
:params
)
{
{
report_type:
%w[code_quality]
}
}
it
'did not find anything'
do
is_expected
.
to
be_empty
expect
(
subject
.
created_at
).
to
be_nil
expect
(
subject
.
occurrences
).
to
be_empty
end
end
end
...
...
@@ -238,7 +241,7 @@ describe Security::PipelineVulnerabilitiesFinder do
subject
{
described_class
.
new
(
pipeline:
pipeline
).
execute
}
it
'returns all report_types'
do
expect
(
subject
.
count
).
to
eq
cs_count
+
dast_count
+
ds_count
+
sast_count
expect
(
subject
.
occurrences
.
count
).
to
eq
(
cs_count
+
dast_count
+
ds_count
+
sast_count
)
end
end
...
...
@@ -279,14 +282,14 @@ describe Security::PipelineVulnerabilitiesFinder do
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
confirmed
=
subject
.
find
{
|
f
|
f
.
project_fingerprint
==
confirmed_fingerprint
}
resolved
=
subject
.
find
{
|
f
|
f
.
project_fingerprint
==
resolved_fingerprint
}
dismissed
=
subject
.
find
{
|
f
|
f
.
project_fingerprint
==
dismissed_fingerprint
}
confirmed
=
subject
.
occurrences
.
find
{
|
f
|
f
.
project_fingerprint
==
confirmed_fingerprint
}
resolved
=
subject
.
occurrences
.
find
{
|
f
|
f
.
project_fingerprint
==
resolved_fingerprint
}
dismissed
=
subject
.
occurrences
.
find
{
|
f
|
f
.
project_fingerprint
==
dismissed_fingerprint
}
expect
(
confirmed
.
state
).
to
eq
'confirmed'
expect
(
resolved
.
state
).
to
eq
'resolved'
expect
(
dismissed
.
state
).
to
eq
'dismissed'
expect
(
subject
-
[
confirmed
,
resolved
,
dismissed
]).
to
all
have_attributes
(
state:
'opened'
)
expect
(
subject
.
occurrences
-
[
confirmed
,
resolved
,
dismissed
]).
to
all
(
have_attributes
(
state:
'opened'
)
)
end
end
...
...
@@ -297,7 +300,7 @@ describe Security::PipelineVulnerabilitiesFinder do
select_proc
=
proc
{
|
o
|
o
.
severity
==
'medium'
&&
o
.
confidence
==
'high'
}
report_occurrences
=
pipeline
.
security_reports
.
reports
[
'sast'
].
occurrences
.
select
(
&
select_proc
)
found_occurrences
=
subject
.
select
(
&
select_proc
)
found_occurrences
=
subject
.
occurrences
.
select
(
&
select_proc
)
found_occurrences
.
each_with_index
do
|
found
,
i
|
expect
(
found
.
metadata
[
'cve'
]).
to
eq
(
report_occurrences
[
i
].
compare_key
)
...
...
ee/spec/lib/gitlab/ci/parsers/security/container_scanning_spec.rb
View file @
5fe4b7d0
...
...
@@ -6,7 +6,7 @@ describe Gitlab::Ci::Parsers::Security::ContainerScanning do
let
(
:parser
)
{
described_class
.
new
}
let
(
:project
)
{
artifact
.
project
}
let
(
:pipeline
)
{
artifact
.
job
.
pipeline
}
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
artifact
.
file_type
,
pipeline
.
sha
)
}
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
artifact
.
file_type
,
pipeline
.
sha
,
2
.
weeks
.
ago
)
}
before
do
artifact
.
each_blob
do
|
blob
|
...
...
ee/spec/lib/gitlab/ci/parsers/security/dast_spec.rb
View file @
5fe4b7d0
...
...
@@ -9,7 +9,7 @@ describe Gitlab::Ci::Parsers::Security::Dast do
let
(
:project
)
{
artifact
.
project
}
let
(
:pipeline
)
{
artifact
.
job
.
pipeline
}
let
(
:artifact
)
{
create
(
:ee_ci_job_artifact
,
:dast
)
}
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
artifact
.
file_type
,
pipeline
.
sha
)
}
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
artifact
.
file_type
,
pipeline
.
sha
,
2
.
weeks
.
ago
)
}
let
(
:parser
)
{
described_class
.
new
}
where
(
:report_format
,
...
...
ee/spec/lib/gitlab/ci/parsers/security/dependency_scanning_spec.rb
View file @
5fe4b7d0
...
...
@@ -9,7 +9,7 @@ describe Gitlab::Ci::Parsers::Security::DependencyScanning do
let
(
:project
)
{
artifact
.
project
}
let
(
:pipeline
)
{
artifact
.
job
.
pipeline
}
let
(
:artifact
)
{
create
(
:ee_ci_job_artifact
,
:dependency_scanning
)
}
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
artifact
.
file_type
,
pipeline
.
sha
)
}
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
artifact
.
file_type
,
pipeline
.
sha
,
2
.
weeks
.
ago
)
}
let
(
:parser
)
{
described_class
.
new
}
where
(
:report_format
,
:occurrence_count
,
:identifier_count
,
:scanner_count
,
:file_path
,
:package_name
,
:package_version
,
:version
)
do
...
...
ee/spec/lib/gitlab/ci/parsers/security/sast_spec.rb
View file @
5fe4b7d0
...
...
@@ -7,12 +7,13 @@ describe Gitlab::Ci::Parsers::Security::Sast do
subject
(
:parser
)
{
described_class
.
new
}
let
(
:commit_sha
)
{
"d8978e74745e18ce44d88814004d4255ac6a65bb"
}
let
(
:created_at
)
{
2
.
weeks
.
ago
}
context
"when parsing valid reports"
do
where
(
report_format:
%i(sast sast_deprecated)
)
with_them
do
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
artifact
.
file_type
,
commit_sha
)
}
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
artifact
.
file_type
,
commit_sha
,
created_at
)
}
let
(
:artifact
)
{
create
(
:ee_ci_job_artifact
,
report_format
)
}
before
do
...
...
@@ -47,7 +48,7 @@ describe Gitlab::Ci::Parsers::Security::Sast do
end
context
"when parsing an empty report"
do
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
'sast'
,
commit_sha
)
}
let
(
:report
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Report
.
new
(
'sast'
,
commit_sha
,
created_at
)
}
let
(
:blob
)
{
JSON
.
generate
({})
}
it
{
expect
(
parser
.
parse!
(
blob
,
report
)).
to
be_empty
}
...
...
ee/spec/lib/gitlab/ci/reports/security/aggregated_report_spec.rb
0 → 100644
View file @
5fe4b7d0
# frozen_string_literal: true
require
'spec_helper'
describe
Gitlab
::
Ci
::
Reports
::
Security
::
AggregatedReport
do
subject
{
described_class
.
new
(
reports
,
occurrences
)
}
let
(
:reports
)
{
build_list
(
:ci_reports_security_report
,
1
)
}
let
(
:occurrences
)
{
build_list
(
:ci_reports_security_occurrence
,
1
)
}
describe
'#created_at'
do
context
'no reports'
do
let
(
:reports
)
{
[]
}
it
'has no created date'
do
expect
(
subject
.
created_at
).
to
be_nil
end
end
context
'report with no created date'
do
let
(
:reports
)
{
build_list
(
:ci_reports_security_report
,
1
,
created_at:
nil
)
}
it
'has no created date'
do
expect
(
subject
.
created_at
).
to
be_nil
end
end
context
'has reports'
do
let
(
:a_long_time_ago
)
{
2
.
months
.
ago
}
let
(
:a_while_ago
)
{
2
.
weeks
.
ago
}
let
(
:yesterday
)
{
1
.
day
.
ago
}
let
(
:reports
)
do
[
build
(
:ci_reports_security_report
,
created_at:
a_while_ago
),
build
(
:ci_reports_security_report
,
created_at:
a_long_time_ago
),
build
(
:ci_reports_security_report
,
created_at:
nil
),
build
(
:ci_reports_security_report
,
created_at:
yesterday
)]
end
it
'has oldest created date'
do
expect
(
subject
.
created_at
).
to
eq
(
a_long_time_ago
)
end
end
end
end
ee/spec/lib/gitlab/ci/reports/security/report_spec.rb
View file @
5fe4b7d0
...
...
@@ -3,8 +3,9 @@
require
'spec_helper'
describe
Gitlab
::
Ci
::
Reports
::
Security
::
Report
do
let
(
:report
)
{
described_class
.
new
(
'sast'
,
commit_sha
)
}
let
(
:report
)
{
described_class
.
new
(
'sast'
,
commit_sha
,
created_at
)
}
let
(
:commit_sha
)
{
"d8978e74745e18ce44d88814004d4255ac6a65bb"
}
let
(
:created_at
)
{
2
.
weeks
.
ago
}
it
{
expect
(
report
.
type
).
to
eq
(
'sast'
)
}
...
...
@@ -65,6 +66,7 @@ describe Gitlab::Ci::Reports::Security::Report do
expect
(
clone
.
type
).
to
eq
(
report
.
type
)
expect
(
clone
.
commit_sha
).
to
eq
(
report
.
commit_sha
)
expect
(
clone
.
created_at
).
to
eq
(
report
.
created_at
)
expect
(
clone
.
occurrences
).
to
eq
([])
expect
(
clone
.
scanners
).
to
eq
({})
expect
(
clone
.
identifiers
).
to
eq
({})
...
...
@@ -111,7 +113,7 @@ describe Gitlab::Ci::Reports::Security::Report do
allow
(
report
).
to
receive
(
:replace_with!
)
end
subject
{
report
.
merge!
(
described_class
.
new
(
'sast'
,
commit_sha
))
}
subject
{
report
.
merge!
(
described_class
.
new
(
'sast'
,
commit_sha
,
created_at
))
}
it
'invokes the merge with other report and then replaces this report contents by merge result'
do
subject
...
...
@@ -121,7 +123,7 @@ describe Gitlab::Ci::Reports::Security::Report do
end
describe
"#safe?"
do
subject
{
described_class
.
new
(
'sast'
,
commit_sha
)
}
subject
{
described_class
.
new
(
'sast'
,
commit_sha
,
created_at
)
}
context
"when the sast report has an unsafe vulnerability"
do
where
(
severity:
%w[unknown Unknown high High critical Critical]
)
...
...
ee/spec/lib/gitlab/ci/reports/security/reports_spec.rb
View file @
5fe4b7d0
...
...
@@ -5,19 +5,21 @@ require 'spec_helper'
describe
Gitlab
::
Ci
::
Reports
::
Security
::
Reports
do
let
(
:commit_sha
)
{
'20410773a37f49d599e5f0d45219b39304763538'
}
let
(
:security_reports
)
{
described_class
.
new
(
commit_sha
)
}
let
(
:artifact
)
{
create
(
:ee_ci_job_artifact
,
:sast
)
}
describe
'#get_report'
do
subject
{
security_reports
.
get_report
(
report_type
)
}
subject
{
security_reports
.
get_report
(
report_type
,
artifact
)
}
context
'when report type is sast'
do
let
(
:report_type
)
{
'sast'
}
it
{
expect
(
subject
.
type
).
to
eq
(
'sast'
)
}
it
{
expect
(
subject
.
commit_sha
).
to
eq
(
commit_sha
)
}
it
{
expect
(
subject
.
created_at
).
to
eq
(
artifact
.
created_at
)
}
it
'initializes a new report and returns it'
do
expect
(
Gitlab
::
Ci
::
Reports
::
Security
::
Report
).
to
receive
(
:new
)
.
with
(
'sast'
,
commit_sha
).
and_call_original
.
with
(
'sast'
,
commit_sha
,
artifact
.
created_at
).
and_call_original
is_expected
.
to
be_a
(
Gitlab
::
Ci
::
Reports
::
Security
::
Report
)
end
...
...
@@ -44,8 +46,8 @@ describe Gitlab::Ci::Reports::Security::Reports do
context
"when a report has a high severity vulnerability"
do
before
do
subject
.
get_report
(
'sast'
).
add_occurrence
(
high_severity
)
subject
.
get_report
(
'dependency_scanning'
).
add_occurrence
(
low_severity
)
subject
.
get_report
(
'sast'
,
artifact
).
add_occurrence
(
high_severity
)
subject
.
get_report
(
'dependency_scanning'
,
artifact
).
add_occurrence
(
low_severity
)
end
it
{
expect
(
subject
.
violates_default_policy?
).
to
be
(
true
)
}
...
...
@@ -53,8 +55,8 @@ describe Gitlab::Ci::Reports::Security::Reports do
context
"when none of the reports have a high severity vulnerability"
do
before
do
subject
.
get_report
(
'sast'
).
add_occurrence
(
low_severity
)
subject
.
get_report
(
'dependency_scanning'
).
add_occurrence
(
low_severity
)
subject
.
get_report
(
'sast'
,
artifact
).
add_occurrence
(
low_severity
)
subject
.
get_report
(
'dependency_scanning'
,
artifact
).
add_occurrence
(
low_severity
)
end
it
{
expect
(
subject
.
violates_default_policy?
).
to
be
(
false
)
}
...
...
ee/spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb
View file @
5fe4b7d0
...
...
@@ -3,41 +3,73 @@
require
'spec_helper'
describe
Gitlab
::
Ci
::
Reports
::
Security
::
VulnerabilityReportsComparer
do
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!
(
: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
(
: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_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
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_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
head_vulnerability
])}
before
do
allow
(
base_vulnerability
).
to
receive
(
:location
).
and_return
({})
allow
(
head_vulnerability
).
to
receive
(
:location
).
and_return
({})
end
subject
{
described_class
.
new
(
base_report
,
head_report
)
}
describe
'#base_report_out_of_date'
do
context
'no base report'
do
let
(
:base_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
reports:
[],
occurrences:
[])}
it
'is not out of date'
do
expect
(
subject
.
base_report_out_of_date
).
to
be
false
end
end
context
'base report older than one week'
do
let
(
:report
)
{
build
(
:ci_reports_security_report
,
created_at:
1
.
week
.
ago
-
60
.
seconds
)
}
let
(
:base_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
reports:
[
report
])}
it
'is not out of date'
do
expect
(
subject
.
base_report_out_of_date
).
to
be
true
end
end
context
'base report less than one week old'
do
let
(
:report
)
{
build
(
:ci_reports_security_report
,
created_at:
1
.
week
.
ago
+
60
.
seconds
)
}
let
(
:base_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
reports:
[
report
])}
it
'is not out of date'
do
expect
(
subject
.
base_report_out_of_date
).
to
be
false
end
end
end
describe
'#existing'
do
context
'with existing reports'
do
let
(
:vuln
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'888'
,
confidence:
Vulnerabilities
::
Occurrence
::
CONFIDENCE_LEVELS
[
:medium
])
}
let
(
:low_vuln
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'888'
,
confidence:
Vulnerabilities
::
Occurrence
::
CONFIDENCE_LEVELS
[
:low
])
}
let
(
:comparer
)
{
described_class
.
new
([
base_vulnerability
],
[
head_vulnerability
])
}
it
'points to source tree'
do
comparer
=
described_class
.
new
([
base_vulnerability
],
[
head_vulnerability
])
expect
(
comparer
.
existing
).
to
eq
([
head_vulnerability
])
expect
(
subject
.
existing
).
to
eq
([
head_vulnerability
])
end
context
"when comparing reports with different fingerprints"
do
let
!
(
:base_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'A'
)
}
let
!
(
:head_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'B'
)
}
context
'when comparing reports with different fingerprints'
do
let
(
:base_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'A'
)
}
let
(
:head_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'B'
)
}
it
"does not find any overlap"
do
comparer
=
described_class
.
new
([
base_vulnerability
],
[
head_vulnerability
])
expect
(
comparer
.
existing
).
to
eq
([])
it
'does not find any overlap'
do
expect
(
subject
.
existing
).
to
eq
([])
end
end
it
'does not change order'
do
comparer
=
described_class
.
new
([
base_vulnerability
,
vuln
],
[
head_vulnerability
,
vuln
,
low_vuln
])
context
'new vulnerabilities'
do
let
(
:vuln
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'888'
,
confidence:
Vulnerabilities
::
Occurrence
::
CONFIDENCE_LEVELS
[
:medium
])
}
let
(
:low_vuln
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'888'
,
confidence:
Vulnerabilities
::
Occurrence
::
CONFIDENCE_LEVELS
[
:low
])
}
let
(
:base_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
base_vulnerability
,
vuln
])}
let
(
:head_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
head_vulnerability
,
vuln
,
low_vuln
])}
expect
(
comparer
.
existing
).
to
eq
([
head_vulnerability
,
vuln
])
it
'does not change order'
do
expect
(
subject
.
existing
).
to
eq
([
head_vulnerability
,
vuln
])
end
end
end
end
...
...
@@ -47,28 +79,28 @@ describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
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
])
}
context
'with new vulnerability'
do
let
(
:
comparer
)
{
described_class
.
new
([
base_vulnerability
],
[
vuln
,
low
,
head_vulnerability
])
}
let
(
:
head_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
head_vulnerability
,
vuln
])
}
it
'points to source tree'
do
comparer
=
described_class
.
new
([
base_vulnerability
],
[
head_vulnerability
,
vuln
])
expect
(
comparer
.
added
).
to
eq
([
vuln
])
expect
(
subject
.
added
).
to
eq
([
vuln
])
end
end
context
"when comparing reports with different fingerprints"
do
let!
(
:base_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'A'
)
}
let!
(
:head_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'B'
)
}
context
'when comparing reports with different fingerprints'
do
let
(
:base_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'A'
)
}
let
(
:head_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'B'
)
}
let
(
:head_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
head_vulnerability
,
vuln
])}
it
"does not find any overlap"
do
comparer
=
described_class
.
new
([
base_vulnerability
],
[
head_vulnerability
,
vuln
])
expect
(
comparer
.
added
).
to
eq
([
head_vulnerability
,
vuln
])
end
it
'does not find any overlap'
do
expect
(
subject
.
added
).
to
eq
([
head_vulnerability
,
vuln
])
end
end
it
'does not change
order'
do
comparer
=
described_class
.
new
([
base_vulnerability
],
[
head_vulnerability
,
vuln
,
low_vuln
])
context
'
order'
do
let
(
:head_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
head_vulnerability
,
vuln
,
low_vuln
])}
expect
(
comparer
.
added
).
to
eq
([
vuln
,
low_vuln
])
it
'does not change'
do
expect
(
subject
.
added
).
to
eq
([
vuln
,
low_vuln
])
end
end
end
...
...
@@ -78,34 +110,37 @@ describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
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
])
}
context
'with fixed vulnerability'
do
it
'points to base tree'
do
comparer
=
described_class
.
new
([
base_vulnerability
,
vuln
],
[
head_vulnerability
])
let
(
:base_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
base_vulnerability
,
vuln
])}
expect
(
comparer
.
fixed
).
to
eq
([
vuln
])
it
'points to base tree'
do
expect
(
subject
.
fixed
).
to
eq
([
vuln
])
end
end
context
"when comparing reports with different fingerprints"
do
let!
(
:base_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'A'
)
}
let!
(
:head_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'B'
)
}
it
"does not find any overlap"
do
comparer
=
described_class
.
new
([
base_vulnerability
,
vuln
],
[
head_vulnerability
])
context
'when comparing reports with different fingerprints'
do
let
(
:base_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'A'
)
}
let
(
:head_vulnerability
)
{
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'B'
)
}
let
(
:base_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
base_vulnerability
,
vuln
])}
expect
(
comparer
.
fixed
).
to
eq
([
base_vulnerability
,
vuln
])
e
nd
it
'does not find any overlap'
do
e
xpect
(
subject
.
fixed
).
to
eq
([
base_vulnerability
,
vuln
])
end
end
it
'does not change
order'
do
comparer
=
described_class
.
new
([
vuln
,
medium_vuln
,
base_vulnerability
],
[
head_vulnerability
])
context
'
order'
do
let
(
:base_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
occurrences:
[
vuln
,
medium_vuln
,
base_vulnerability
])}
expect
(
comparer
.
fixed
).
to
eq
([
vuln
,
medium_vuln
])
it
'does not change'
do
expect
(
subject
.
fixed
).
to
eq
([
vuln
,
medium_vuln
])
end
end
end
describe
'with empty vulnerabilities'
do
let
(
:empty_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
reports:
[],
occurrences:
[])}
it
'returns empty array when reports are not present'
do
comparer
=
described_class
.
new
(
nil
,
nil
)
comparer
=
described_class
.
new
(
empty_report
,
empty_report
)
expect
(
comparer
.
existing
).
to
eq
([])
expect
(
comparer
.
fixed
).
to
eq
([])
...
...
@@ -113,20 +148,18 @@ describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
end
it
'returns added vulnerability when base is empty and head is not empty'
do
vuln
=
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'888'
)
comparer
=
described_class
.
new
(
nil
,
[
vuln
])
comparer
=
described_class
.
new
(
empty_report
,
head_report
)
expect
(
comparer
.
existing
).
to
eq
([])
expect
(
comparer
.
fixed
).
to
eq
([])
expect
(
comparer
.
added
).
to
eq
([
vuln
])
expect
(
comparer
.
added
).
to
eq
([
head_vulnerability
])
end
it
'returns fixed vulnerability when head is empty and base is not empty'
do
vuln
=
build
(
:vulnerabilities_occurrence
,
report_type: :sast
,
identifiers:
[
identifier
],
location_fingerprint:
'888'
)
comparer
=
described_class
.
new
([
vuln
],
nil
)
comparer
=
described_class
.
new
(
base_report
,
empty_report
)
expect
(
comparer
.
existing
).
to
eq
([])
expect
(
comparer
.
fixed
).
to
eq
([
vuln
])
expect
(
comparer
.
fixed
).
to
eq
([
base_vulnerability
])
expect
(
comparer
.
added
).
to
eq
([])
end
end
...
...
ee/spec/models/ci/build_spec.rb
View file @
5fe4b7d0
...
...
@@ -14,6 +14,7 @@ describe Ci::Build do
end
let
(
:job
)
{
create
(
:ci_build
,
pipeline:
pipeline
)
}
let
(
:artifact
)
{
create
(
:ee_ci_job_artifact
,
:sast
,
job:
job
,
project:
job
.
project
)
}
describe
'#shared_runners_minutes_limit_enabled?'
do
subject
{
job
.
shared_runners_minutes_limit_enabled?
}
...
...
@@ -112,58 +113,59 @@ describe Ci::Build do
context
'when build has a security report'
do
context
'when there is a sast report'
do
before
do
create
(
:ee_ci_job_artifact
,
:sast
,
job:
job
,
project:
job
.
project
)
end
let!
(
:artifact
)
{
create
(
:ee_ci_job_artifact
,
:sast
,
job:
job
,
project:
job
.
project
)
}
it
'parses blobs and add the results to the report'
do
subject
expect
(
security_reports
.
get_report
(
'sast'
).
occurrences
.
size
).
to
eq
(
33
)
expect
(
security_reports
.
get_report
(
'sast'
,
artifact
).
occurrences
.
size
).
to
eq
(
33
)
end
it
'adds the created date to the report'
do
subject
expect
(
security_reports
.
get_report
(
'sast'
,
artifact
).
created_at
.
to_s
).
to
eq
(
artifact
.
created_at
.
to_s
)
end
end
context
'when there are multiple reports'
do
before
do
create
(
:ee_ci_job_artifact
,
:sast
,
job:
job
,
project:
job
.
project
)
create
(
:ee_ci_job_artifact
,
:dependency_scanning
,
job:
job
,
project:
job
.
project
)
create
(
:ee_ci_job_artifact
,
:container_scanning
,
job:
job
,
project:
job
.
project
)
create
(
:ee_ci_job_artifact
,
:dast
,
job:
job
,
project:
job
.
project
)
end
let!
(
:sast_artifact
)
{
create
(
:ee_ci_job_artifact
,
:sast
,
job:
job
,
project:
job
.
project
)
}
let!
(
:ds_artifact
)
{
create
(
:ee_ci_job_artifact
,
:dependency_scanning
,
job:
job
,
project:
job
.
project
)
}
let!
(
:cs_artifact
)
{
create
(
:ee_ci_job_artifact
,
:container_scanning
,
job:
job
,
project:
job
.
project
)
}
let!
(
:dast_artifact
)
{
create
(
:ee_ci_job_artifact
,
:dast
,
job:
job
,
project:
job
.
project
)
}
it
'parses blobs and adds the results to the reports'
do
subject
expect
(
security_reports
.
get_report
(
'sast'
).
occurrences
.
size
).
to
eq
(
33
)
expect
(
security_reports
.
get_report
(
'dependency_scanning'
).
occurrences
.
size
).
to
eq
(
4
)
expect
(
security_reports
.
get_report
(
'container_scanning'
).
occurrences
.
size
).
to
eq
(
8
)
expect
(
security_reports
.
get_report
(
'dast'
).
occurrences
.
size
).
to
eq
(
20
)
expect
(
security_reports
.
get_report
(
'sast'
,
sast_artifact
).
occurrences
.
size
).
to
eq
(
33
)
expect
(
security_reports
.
get_report
(
'dependency_scanning'
,
ds_artifact
).
occurrences
.
size
).
to
eq
(
4
)
expect
(
security_reports
.
get_report
(
'container_scanning'
,
cs_artifact
).
occurrences
.
size
).
to
eq
(
8
)
expect
(
security_reports
.
get_report
(
'dast'
,
dast_artifact
).
occurrences
.
size
).
to
eq
(
20
)
end
end
context
'when there is a corrupted sast report'
do
before
do
create
(
:ee_ci_job_artifact
,
:sast_with_corrupted_data
,
job:
job
,
project:
job
.
project
)
end
let!
(
:artifact
)
{
create
(
:ee_ci_job_artifact
,
:sast_with_corrupted_data
,
job:
job
,
project:
job
.
project
)
}
it
'stores an error'
do
subject
expect
(
security_reports
.
get_report
(
'sast'
)).
to
be_errored
expect
(
security_reports
.
get_report
(
'sast'
,
artifact
)).
to
be_errored
end
end
end
context
'when there is unsupported file type'
do
let!
(
:artifact
)
{
create
(
:ee_ci_job_artifact
,
:codequality
,
job:
job
,
project:
job
.
project
)
}
before
do
stub_const
(
"Ci::JobArtifact::SECURITY_REPORT_FILE_TYPES"
,
%w[codequality]
)
create
(
:ee_ci_job_artifact
,
:codequality
,
job:
job
,
project:
job
.
project
)
end
it
'stores an error'
do
subject
expect
(
security_reports
.
get_report
(
'codequality'
)).
to
be_errored
expect
(
security_reports
.
get_report
(
'codequality'
,
artifact
)).
to
be_errored
end
end
end
...
...
ee/spec/models/ci/pipeline_spec.rb
View file @
5fe4b7d0
...
...
@@ -159,14 +159,14 @@ describe Ci::Pipeline do
let
(
:build_ds_2
)
{
create
(
:ci_build
,
:success
,
name:
'ds_2'
,
pipeline:
pipeline
,
project:
project
)
}
let
(
:build_cs_1
)
{
create
(
:ci_build
,
:success
,
name:
'cs_1'
,
pipeline:
pipeline
,
project:
project
)
}
let
(
:build_cs_2
)
{
create
(
:ci_build
,
:success
,
name:
'cs_2'
,
pipeline:
pipeline
,
project:
project
)
}
let!
(
:sast1_artifact
)
{
create
(
:ee_ci_job_artifact
,
:sast
,
job:
build_sast_1
,
project:
project
)
}
let!
(
:sast2_artifact
)
{
create
(
:ee_ci_job_artifact
,
:sast
,
job:
build_sast_2
,
project:
project
)
}
let!
(
:ds1_artifact
)
{
create
(
:ee_ci_job_artifact
,
:dependency_scanning
,
job:
build_ds_1
,
project:
project
)
}
let!
(
:ds2_artifact
)
{
create
(
:ee_ci_job_artifact
,
:dependency_scanning
,
job:
build_ds_2
,
project:
project
)
}
let!
(
:cs1_artifact
)
{
create
(
:ee_ci_job_artifact
,
:container_scanning
,
job:
build_cs_1
,
project:
project
)
}
let!
(
:cs2_artifact
)
{
create
(
:ee_ci_job_artifact
,
:container_scanning
,
job:
build_cs_2
,
project:
project
)
}
before
do
create
(
:ee_ci_job_artifact
,
:sast
,
job:
build_sast_1
,
project:
project
)
create
(
:ee_ci_job_artifact
,
:sast
,
job:
build_sast_2
,
project:
project
)
create
(
:ee_ci_job_artifact
,
:dependency_scanning
,
job:
build_ds_1
,
project:
project
)
create
(
:ee_ci_job_artifact
,
:dependency_scanning
,
job:
build_ds_2
,
project:
project
)
create
(
:ee_ci_job_artifact
,
:container_scanning
,
job:
build_cs_1
,
project:
project
)
create
(
:ee_ci_job_artifact
,
:container_scanning
,
job:
build_cs_2
,
project:
project
)
end
it
'assigns pipeline commit_sha to the reports'
do
...
...
@@ -178,18 +178,18 @@ describe Ci::Pipeline do
expect
(
subject
.
reports
.
keys
).
to
contain_exactly
(
'sast'
,
'dependency_scanning'
,
'container_scanning'
)
# for each of report categories, we have merged 2 reports with the same data (fixture)
expect
(
subject
.
get_report
(
'sast'
).
occurrences
.
size
).
to
eq
(
33
)
expect
(
subject
.
get_report
(
'dependency_scanning'
).
occurrences
.
size
).
to
eq
(
4
)
expect
(
subject
.
get_report
(
'container_scanning'
).
occurrences
.
size
).
to
eq
(
8
)
expect
(
subject
.
get_report
(
'sast'
,
sast1_artifact
).
occurrences
.
size
).
to
eq
(
33
)
expect
(
subject
.
get_report
(
'dependency_scanning'
,
ds1_artifact
).
occurrences
.
size
).
to
eq
(
4
)
expect
(
subject
.
get_report
(
'container_scanning'
,
cs1_artifact
).
occurrences
.
size
).
to
eq
(
8
)
end
context
'when builds are retried'
do
let
(
:build_sast_1
)
{
create
(
:ci_build
,
:retried
,
name:
'sast_1'
,
pipeline:
pipeline
,
project:
project
)
}
it
'does not take retried builds into account'
do
expect
(
subject
.
get_report
(
'sast'
).
occurrences
.
size
).
to
eq
(
33
)
expect
(
subject
.
get_report
(
'dependency_scanning'
).
occurrences
.
size
).
to
eq
(
4
)
expect
(
subject
.
get_report
(
'container_scanning'
).
occurrences
.
size
).
to
eq
(
8
)
expect
(
subject
.
get_report
(
'sast'
,
sast1_artifact
).
occurrences
.
size
).
to
eq
(
33
)
expect
(
subject
.
get_report
(
'dependency_scanning'
,
ds1_artifact
).
occurrences
.
size
).
to
eq
(
4
)
expect
(
subject
.
get_report
(
'container_scanning'
,
cs1_artifact
).
occurrences
.
size
).
to
eq
(
8
)
end
end
end
...
...
ee/spec/serializers/vulnerabilities/occurrence_reports_comparer_entity_spec.rb
View file @
5fe4b7d0
...
...
@@ -6,8 +6,13 @@ describe Vulnerabilities::OccurrenceReportsComparerEntity do
describe
'container scanning report comparison'
do
set
(
:user
)
{
create
(
:user
)
}
let
(
:base_report
)
{
create_list
(
:vulnerabilities_occurrence
,
2
)
}
let
(
:head_report
)
{
create_list
(
:vulnerabilities_occurrence
,
1
)
}
let
(
:base_occurrences
)
{
create_list
(
:vulnerabilities_occurrence
,
2
)
}
let
(
:base_combined_reports
)
{
build_list
(
:ci_reports_security_report
,
1
,
created_at:
nil
)
}
let
(
:base_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
reports:
base_combined_reports
,
occurrences:
base_occurrences
)}
let
(
:head_occurrences
)
{
create_list
(
:vulnerabilities_occurrence
,
1
)
}
let
(
:head_combined_reports
)
{
build_list
(
:ci_reports_security_report
,
1
,
created_at:
2
.
days
.
ago
)
}
let
(
:head_report
)
{
build
(
:ci_reports_security_aggregated_reports
,
reports:
head_combined_reports
,
occurrences:
head_occurrences
)}
let
(
:comparer
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
VulnerabilityReportsComparer
.
new
(
base_report
,
head_report
)
}
...
...
@@ -27,7 +32,15 @@ describe Vulnerabilities::OccurrenceReportsComparerEntity do
end
it
'contains the added existing and fixed vulnerabilities for container scanning'
do
expect
(
subject
.
keys
).
to
match_array
([
:added
,
:existing
,
:fixed
])
expect
(
subject
.
keys
).
to
include
(
:added
)
expect
(
subject
.
keys
).
to
include
(
:existing
)
expect
(
subject
.
keys
).
to
include
(
:fixed
)
end
it
'contains the report out of date fields'
do
expect
(
subject
.
keys
).
to
include
(
:base_report_created_at
)
expect
(
subject
.
keys
).
to
include
(
:base_report_out_of_date
)
expect
(
subject
.
keys
).
to
include
(
:head_report_created_at
)
end
end
end
...
...
ee/spec/services/security/store_report_service_spec.rb
View file @
5fe4b7d0
...
...
@@ -6,7 +6,7 @@ describe Security::StoreReportService, '#execute' do
let
(
:artifact
)
{
create
(
:ee_ci_job_artifact
,
report_type
)
}
let
(
:project
)
{
artifact
.
project
}
let
(
:pipeline
)
{
artifact
.
job
.
pipeline
}
let
(
:report
)
{
pipeline
.
security_reports
.
get_report
(
report_type
.
to_s
)
}
let
(
:report
)
{
pipeline
.
security_reports
.
get_report
(
report_type
.
to_s
,
artifact
)
}
before
do
stub_licensed_features
(
sast:
true
,
dependency_scanning:
true
,
container_scanning:
true
)
...
...
@@ -52,7 +52,7 @@ describe Security::StoreReportService, '#execute' do
let!
(
:new_artifact
)
{
create
(
:ee_ci_job_artifact
,
:sast
,
job:
new_build
)
}
let
(
:new_build
)
{
create
(
:ci_build
,
pipeline:
new_pipeline
)
}
let
(
:new_pipeline
)
{
create
(
:ci_pipeline
,
project:
project
)
}
let
(
:new_report
)
{
new_pipeline
.
security_reports
.
get_report
(
report_type
.
to_s
)
}
let
(
:new_report
)
{
new_pipeline
.
security_reports
.
get_report
(
report_type
.
to_s
,
artifact
)
}
let
(
:report_type
)
{
:sast
}
let!
(
:occurrence
)
do
...
...
ee/spec/services/security/store_reports_service_spec.rb
View file @
5fe4b7d0
...
...
@@ -32,10 +32,12 @@ describe Security::StoreReportsService do
context
'when StoreReportService returns an error for a report'
do
let
(
:reports
)
{
Gitlab
::
Ci
::
Reports
::
Security
::
Reports
.
new
(
pipeline
.
sha
)
}
let
(
:sast_report
)
{
reports
.
get_report
(
'sast'
)
}
let
(
:dast_report
)
{
reports
.
get_report
(
'dast'
)
}
let
(
:sast_report
)
{
reports
.
get_report
(
'sast'
,
sast_artifact
)
}
let
(
:dast_report
)
{
reports
.
get_report
(
'dast'
,
dast_artifact
)
}
let
(
:success
)
{
{
status: :success
}
}
let
(
:error
)
{
{
status: :error
,
message:
"something went wrong"
}
}
let
(
:sast_artifact
)
{
create
(
:ee_ci_job_artifact
,
:sast
)
}
let
(
:dast_artifact
)
{
create
(
:ee_ci_job_artifact
,
:dast
)
}
before
do
allow
(
pipeline
).
to
receive
(
:security_reports
).
and_return
(
reports
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment