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
057fef27
Commit
057fef27
authored
Jul 23, 2021
by
Saikat Sarkar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add vulnerability flags in Vulnerability Findings API
parent
d5aba68e
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
165 additions
and
7 deletions
+165
-7
ee/app/finders/security/findings_finder.rb
ee/app/finders/security/findings_finder.rb
+13
-0
ee/app/finders/security/pipeline_vulnerabilities_finder.rb
ee/app/finders/security/pipeline_vulnerabilities_finder.rb
+17
-2
ee/app/models/concerns/ee/vulnerability_flag_helpers.rb
ee/app/models/concerns/ee/vulnerability_flag_helpers.rb
+12
-0
ee/app/models/ee/project.rb
ee/app/models/ee/project.rb
+1
-0
ee/app/models/vulnerabilities/finding.rb
ee/app/models/vulnerabilities/finding.rb
+1
-0
ee/app/serializers/vulnerabilities/finding_entity.rb
ee/app/serializers/vulnerabilities/finding_entity.rb
+10
-0
ee/config/feature_flags/development/vulnerability_flags.yml
ee/config/feature_flags/development/vulnerability_flags.yml
+8
-0
ee/spec/finders/security/findings_finder_spec.rb
ee/spec/finders/security/findings_finder_spec.rb
+45
-2
ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb
.../finders/security/pipeline_vulnerabilities_finder_spec.rb
+28
-1
ee/spec/requests/api/vulnerability_findings_spec.rb
ee/spec/requests/api/vulnerability_findings_spec.rb
+2
-1
ee/spec/serializers/vulnerabilities/finding_entity_spec.rb
ee/spec/serializers/vulnerabilities/finding_entity_spec.rb
+28
-1
No files found.
ee/app/finders/security/findings_finder.rb
View file @
057fef27
...
@@ -61,6 +61,11 @@ module Security
...
@@ -61,6 +61,11 @@ module Security
finding
.
project
=
project
finding
.
project
=
project
finding
.
sha
=
pipeline
.
sha
finding
.
sha
=
pipeline
.
sha
finding
.
scanner
=
security_finding
.
scanner
finding
.
scanner
=
security_finding
.
scanner
if
calculate_false_positive?
finding
.
vulnerability_flags
=
existing_vulnerability_flags
.
fetch
(
security_finding
.
uuid
,
[])
end
finding
.
identifiers
=
identifiers
finding
.
identifiers
=
identifiers
finding
.
signatures
=
signatures
finding
.
signatures
=
signatures
end
end
...
@@ -74,6 +79,14 @@ module Security
...
@@ -74,6 +79,14 @@ module Security
existing_vulnerabilities
.
dig
(
security_finding
.
scan
.
scan_type
,
security_finding
.
project_fingerprint
)
&
.
first
existing_vulnerabilities
.
dig
(
security_finding
.
scan
.
scan_type
,
security_finding
.
project_fingerprint
)
&
.
first
end
end
def
existing_vulnerability_flags
@existing_vulnerability_flags
||=
project
.
vulnerability_flags_for
(
security_findings
.
map
(
&
:uuid
))
end
def
calculate_false_positive?
::
Feature
.
enabled?
(
:vulnerability_flags
,
project
)
&&
project
.
licensed_feature_available?
(
:sast_fp_reduction
)
end
def
existing_vulnerabilities
def
existing_vulnerabilities
@existing_vulnerabilities
||=
begin
@existing_vulnerabilities
||=
begin
project
.
vulnerabilities
project
.
vulnerabilities
...
...
ee/app/finders/security/pipeline_vulnerabilities_finder.rb
View file @
057fef27
...
@@ -33,7 +33,9 @@ module Security
...
@@ -33,7 +33,9 @@ module Security
normalized_findings
=
normalize_report_findings
(
normalized_findings
=
normalize_report_findings
(
report
.
findings
,
report
.
findings
,
vulnerabilities_by_finding_fingerprint
(
report
))
vulnerabilities_by_finding_fingerprint
(
report
),
existing_vulnerability_flags_for
(
report
))
filtered_findings
=
filter
(
normalized_findings
)
filtered_findings
=
filter
(
normalized_findings
)
findings
.
concat
(
filtered_findings
)
findings
.
concat
(
filtered_findings
)
...
@@ -74,12 +76,16 @@ module Security
...
@@ -74,12 +76,16 @@ module Security
.
select
(
:vulnerability_id
,
:project_fingerprint
)
.
select
(
:vulnerability_id
,
:project_fingerprint
)
end
end
def
existing_vulnerability_flags_for
(
report
)
pipeline
.
project
.
vulnerability_flags_for
(
report
.
findings
.
map
(
&
:uuid
))
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 findings 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_findings
(
report_findings
,
vulnerabilities
)
def
normalize_report_findings
(
report_findings
,
vulnerabilities
,
vulnerability_flags
)
report_findings
.
map
do
|
report_finding
|
report_findings
.
map
do
|
report_finding
|
finding_hash
=
report_finding
.
to_hash
finding_hash
=
report_finding
.
to_hash
.
except
(
:compare_key
,
:identifiers
,
:location
,
:scanner
,
:links
,
:signatures
)
.
except
(
:compare_key
,
:identifiers
,
:location
,
:scanner
,
:links
,
:signatures
)
...
@@ -101,10 +107,19 @@ module Security
...
@@ -101,10 +107,19 @@ module Security
Vulnerabilities
::
FindingSignature
.
new
(
signature
.
to_hash
)
Vulnerabilities
::
FindingSignature
.
new
(
signature
.
to_hash
)
end
end
if
calculate_false_positive?
finding
.
vulnerability_flags
=
vulnerability_flags
.
fetch
(
finding
.
uuid
,
[])
end
finding
finding
end
end
end
end
def
calculate_false_positive?
project
=
pipeline
.
project
::
Feature
.
enabled?
(
:vulnerability_flags
,
project
)
&&
project
.
licensed_feature_available?
(
:sast_fp_reduction
)
end
def
filter
(
findings
)
def
filter
(
findings
)
findings
.
select
do
|
finding
|
findings
.
select
do
|
finding
|
next
unless
in_selected_state?
(
finding
)
next
unless
in_selected_state?
(
finding
)
...
...
ee/app/models/concerns/ee/vulnerability_flag_helpers.rb
0 → 100644
View file @
057fef27
# frozen_string_literal: true
module
EE
module
VulnerabilityFlagHelpers
def
vulnerability_flags_for
(
uuids
)
vulnerability_findings
.
by_uuid
(
uuids
)
.
eager_load_vulnerability_flags
.
to_h
{
|
finding
|
[
finding
.
uuid
,
finding
.
vulnerability_flags
]
}
end
end
end
ee/app/models/ee/project.rb
View file @
057fef27
...
@@ -21,6 +21,7 @@ module EE
...
@@ -21,6 +21,7 @@ module EE
include
DeprecatedApprovalsBeforeMerge
include
DeprecatedApprovalsBeforeMerge
include
UsageStatistics
include
UsageStatistics
include
ProjectSecurityScannersInformation
include
ProjectSecurityScannersInformation
include
VulnerabilityFlagHelpers
before_save
:set_override_pull_mirror_available
,
unless:
->
{
::
Gitlab
::
CurrentSettings
.
mirror_available
}
before_save
:set_override_pull_mirror_available
,
unless:
->
{
::
Gitlab
::
CurrentSettings
.
mirror_available
}
before_save
:set_next_execution_timestamp_to_now
,
if:
->
(
project
)
{
project
.
mirror?
&&
project
.
mirror_changed?
&&
project
.
import_state
}
before_save
:set_next_execution_timestamp_to_now
,
if:
->
(
project
)
{
project
.
mirror?
&&
project
.
mirror_changed?
&&
project
.
import_state
}
...
...
ee/app/models/vulnerabilities/finding.rb
View file @
057fef27
...
@@ -87,6 +87,7 @@ module Vulnerabilities
...
@@ -87,6 +87,7 @@ module Vulnerabilities
scope
:by_severities
,
->
(
values
)
{
where
(
severity:
values
)
}
scope
:by_severities
,
->
(
values
)
{
where
(
severity:
values
)
}
scope
:by_confidences
,
->
(
values
)
{
where
(
confidence:
values
)
}
scope
:by_confidences
,
->
(
values
)
{
where
(
confidence:
values
)
}
scope
:by_project_fingerprints
,
->
(
values
)
{
where
(
project_fingerprint:
values
)
}
scope
:by_project_fingerprints
,
->
(
values
)
{
where
(
project_fingerprint:
values
)
}
scope
:by_uuid
,
->
(
uuids
)
{
where
(
uuid:
uuids
)
}
scope
:all_preloaded
,
->
do
scope
:all_preloaded
,
->
do
preload
(
:scanner
,
:identifiers
,
project:
[
:namespace
,
:project_feature
])
preload
(
:scanner
,
:identifiers
,
project:
[
:namespace
,
:project_feature
])
...
...
ee/app/serializers/vulnerabilities/finding_entity.rb
View file @
057fef27
...
@@ -12,6 +12,9 @@ class Vulnerabilities::FindingEntity < Grape::Entity
...
@@ -12,6 +12,9 @@ class Vulnerabilities::FindingEntity < Grape::Entity
expose
:create_jira_issue_url
do
|
occurrence
|
expose
:create_jira_issue_url
do
|
occurrence
|
create_jira_issue_url_for
(
occurrence
)
create_jira_issue_url_for
(
occurrence
)
end
end
expose
:false_positive
,
if:
->
(
_
,
_
)
{
expose_false_positive?
}
do
|
occurrence
|
occurrence
.
vulnerability_flags
.
any?
(
&
:false_positive?
)
end
expose
:create_vulnerability_feedback_issue_path
do
|
occurrence
|
expose
:create_vulnerability_feedback_issue_path
do
|
occurrence
|
create_vulnerability_feedback_issue_path
(
occurrence
.
project
)
create_vulnerability_feedback_issue_path
(
occurrence
.
project
)
end
end
...
@@ -54,6 +57,13 @@ class Vulnerabilities::FindingEntity < Grape::Entity
...
@@ -54,6 +57,13 @@ class Vulnerabilities::FindingEntity < Grape::Entity
def
current_user
def
current_user
return
request
.
current_user
if
request
.
respond_to?
(
:current_user
)
return
request
.
current_user
if
request
.
respond_to?
(
:current_user
)
end
end
private
def
expose_false_positive?
project
=
occurrence
.
project
::
Feature
.
enabled?
(
:vulnerability_flags
,
project
)
&&
project
.
licensed_feature_available?
(
:sast_fp_reduction
)
end
end
end
Vulnerabilities
::
FindingEntity
.
include_mod_with
(
'ProjectsHelper'
)
Vulnerabilities
::
FindingEntity
.
include_mod_with
(
'ProjectsHelper'
)
ee/config/feature_flags/development/vulnerability_flags.yml
0 → 100644
View file @
057fef27
---
name
:
vulnerability_flags
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66775
rollout_issue_url
:
https://gitlab.com/gitlab-org/gitlab/-/issues/336630
milestone
:
'
14.2'
type
:
development
group
:
group::static analysis
default_enabled
:
false
ee/spec/finders/security/findings_finder_spec.rb
View file @
057fef27
...
@@ -59,6 +59,8 @@ RSpec.describe Security::FindingsFinder do
...
@@ -59,6 +59,8 @@ RSpec.describe Security::FindingsFinder do
deduplicated:
true
,
deduplicated:
true
,
position:
index
,
position:
index
,
scan:
scan
)
scan:
scan
)
create
(
:vulnerabilities_finding
,
uuid:
finding
.
uuid
,
project:
pipeline
.
project
)
end
end
end
end
...
@@ -76,9 +78,21 @@ RSpec.describe Security::FindingsFinder do
...
@@ -76,9 +78,21 @@ RSpec.describe Security::FindingsFinder do
stub_licensed_features
(
sast:
true
,
dependency_scanning:
true
)
stub_licensed_features
(
sast:
true
,
dependency_scanning:
true
)
end
end
context
'N+1 queries'
do
it
'does not cause N+1 queries'
do
expect
{
finder_result
}.
not_to
exceed_query_limit
(
10
)
end
context
'with vulnerability_flags disabled'
do
before
do
stub_feature_flags
(
vulnerability_flags:
false
)
end
it
'does not cause N+1 queries'
do
it
'does not cause N+1 queries'
do
expect
{
finder_result
}.
not_to
exceed_query_limit
(
8
)
expect
{
finder_result
}.
not_to
exceed_query_limit
(
8
)
end
end
end
end
describe
'#current_page'
do
describe
'#current_page'
do
subject
{
finder_result
.
current_page
}
subject
{
finder_result
.
current_page
}
...
@@ -169,6 +183,35 @@ RSpec.describe Security::FindingsFinder do
...
@@ -169,6 +183,35 @@ RSpec.describe Security::FindingsFinder do
end
end
end
end
describe
'#vulnerability_flags'
do
before
do
stub_licensed_features
(
sast_fp_reduction:
true
)
end
context
'with no vulnerability flags present'
do
it
'does not have any vulnerability flag'
do
expect
(
finder_result
.
findings
).
to
all
(
have_attributes
(
vulnerability_flags:
be_empty
))
end
end
context
'with some vulnerability flags present'
do
before
do
create
(
:vulnerabilities_flag
,
finding:
pipeline
.
project
.
vulnerability_findings
.
first
)
create
(
:vulnerabilities_flag
,
finding:
pipeline
.
project
.
vulnerability_findings
.
last
)
end
it
'has some vulnerability_findings with vulnerability flag'
do
expect
(
finder_result
.
findings
).
to
include
(
have_attributes
(
vulnerability_flags:
be_present
))
end
it
'does not have any vulnerability_flag if license is not available'
do
stub_licensed_features
(
sast_fp_reduction:
false
)
expect
(
finder_result
.
findings
).
to
all
(
have_attributes
(
vulnerability_flags:
be_empty
))
end
end
end
describe
'#findings'
do
describe
'#findings'
do
subject
{
finder_result
.
findings
.
map
(
&
:project_fingerprint
)
}
subject
{
finder_result
.
findings
.
map
(
&
:project_fingerprint
)
}
...
...
ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb
View file @
057fef27
...
@@ -38,7 +38,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
...
@@ -38,7 +38,7 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
end
end
before
do
before
do
stub_licensed_features
(
sast:
true
,
dependency_scanning:
true
,
container_scanning:
true
,
dast:
true
)
stub_licensed_features
(
sast:
true
,
dependency_scanning:
true
,
container_scanning:
true
,
dast:
true
,
sast_fp_reduction:
true
)
# Stub out deduplication, if not done the expectations will vary based on the fixtures (which may/may not have duplicates)
# Stub out deduplication, if not done the expectations will vary based on the fixtures (which may/may not have duplicates)
disable_deduplication
disable_deduplication
end
end
...
@@ -137,6 +137,33 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
...
@@ -137,6 +137,33 @@ RSpec.describe Security::PipelineVulnerabilitiesFinder do
expect
(
subject
.
findings
.
map
(
&
:uuid
)).
to
match_array
(
sast_report_uuids
)
expect
(
subject
.
findings
.
map
(
&
:uuid
)).
to
match_array
(
sast_report_uuids
)
expect
(
subject
.
findings
.
count
).
to
eq
(
sast_count
)
expect
(
subject
.
findings
.
count
).
to
eq
(
sast_count
)
end
end
context
"false-positive"
do
before
do
vulnerability_finding
=
create
(
:vulnerabilities_finding
,
uuid:
sast_report_uuids
.
first
,
project:
pipeline
.
project
)
create
(
:vulnerabilities_flag
,
finding:
vulnerability_finding
)
end
it
'includes findings with false-positive'
do
expect
(
subject
.
findings
.
flat_map
(
&
:vulnerability_flags
)).
to
be_present
end
it
'does not include findings with false-positive if license is not available'
do
stub_licensed_features
(
sast_fp_reduction:
false
)
expect
(
subject
.
findings
).
to
all
(
have_attributes
(
vulnerability_flags:
be_empty
))
end
context
'with vulnerability_flags FF disabled'
do
before
do
stub_feature_flags
(
vulnerability_flags:
false
)
end
it
'does not include findings with false-positive'
do
expect
(
subject
.
findings
).
to
all
(
have_attributes
(
vulnerability_flags:
be_empty
))
end
end
end
end
end
context
'when dependency_scanning'
do
context
'when dependency_scanning'
do
...
...
ee/spec/requests/api/vulnerability_findings_spec.rb
View file @
057fef27
...
@@ -69,7 +69,8 @@ RSpec.describe API::VulnerabilityFindings do
...
@@ -69,7 +69,8 @@ RSpec.describe API::VulnerabilityFindings do
# 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::Findings
# 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
)
# and all associated vulnerability_flags
expect
{
get
api
(
project_vulnerability_findings_path
,
user
)
}.
not_to
exceed_query_limit
(
control_count
).
with_threshold
(
3
)
end
end
describe
'using different finders'
do
describe
'using different finders'
do
...
...
ee/spec/serializers/vulnerabilities/finding_entity_spec.rb
View file @
057fef27
...
@@ -23,10 +23,17 @@ RSpec.describe Vulnerabilities::FindingEntity do
...
@@ -23,10 +23,17 @@ RSpec.describe Vulnerabilities::FindingEntity do
scanner:
scanner
,
scanner:
scanner
,
scan:
scan
,
scan:
scan
,
project:
project
,
project:
project
,
identifiers:
identifiers
identifiers:
identifiers
,
vulnerability_flags:
flags
)
)
end
end
let
(
:flags
)
do
[
build
(
:vulnerabilities_flag
)
]
end
let
(
:dismiss_feedback
)
do
let
(
:dismiss_feedback
)
do
build
(
:vulnerability_feedback
,
:sast
,
:dismissal
,
build
(
:vulnerability_feedback
,
:sast
,
:dismissal
,
project:
project
,
project_fingerprint:
occurrence
.
project_fingerprint
)
project:
project
,
project_fingerprint:
occurrence
.
project_fingerprint
)
...
@@ -47,6 +54,7 @@ RSpec.describe Vulnerabilities::FindingEntity do
...
@@ -47,6 +54,7 @@ RSpec.describe Vulnerabilities::FindingEntity do
subject
{
entity
.
as_json
}
subject
{
entity
.
as_json
}
before
do
before
do
stub_licensed_features
(
sast_fp_reduction:
true
)
allow
(
request
).
to
receive
(
:current_user
).
and_return
(
user
)
allow
(
request
).
to
receive
(
:current_user
).
and_return
(
user
)
end
end
...
@@ -58,11 +66,30 @@ RSpec.describe Vulnerabilities::FindingEntity do
...
@@ -58,11 +66,30 @@ RSpec.describe Vulnerabilities::FindingEntity do
expect
(
subject
).
to
include
(
:description
,
:links
,
:location
,
:remediations
,
:solution
,
:evidence
)
expect
(
subject
).
to
include
(
:description
,
:links
,
:location
,
:remediations
,
:solution
,
:evidence
)
expect
(
subject
).
to
include
(
:blob_path
,
:request
,
:response
)
expect
(
subject
).
to
include
(
:blob_path
,
:request
,
:response
)
expect
(
subject
).
to
include
(
:scan
)
expect
(
subject
).
to
include
(
:scan
)
expect
(
subject
).
to
include
(
:false_positive
)
expect
(
subject
).
to
include
(
:assets
,
:evidence_source
,
:supporting_messages
)
expect
(
subject
).
to
include
(
:assets
,
:evidence_source
,
:supporting_messages
)
expect
(
subject
).
to
include
(
:uuid
)
expect
(
subject
).
to
include
(
:uuid
)
expect
(
subject
).
to
include
(
:details
)
expect
(
subject
).
to
include
(
:details
)
end
end
context
'false-positive'
do
it
'finds the vulnerability_finding as false_positive'
do
expect
(
subject
[
:false_positive
]).
to
be
(
true
)
end
it
'does not contain false_positive field if feature_flag is disabled'
do
stub_feature_flags
(
vulnerability_flags:
false
)
expect
(
subject
).
not_to
include
(
:false_positive
)
end
it
'does not contain false_positive field if license is not available'
do
stub_licensed_features
(
sast_fp_reduction:
false
)
expect
(
subject
).
not_to
include
(
:false_positive
)
end
end
context
'when not allowed to admin vulnerability feedback'
do
context
'when not allowed to admin vulnerability feedback'
do
before
do
before
do
project
.
add_guest
(
user
)
project
.
add_guest
(
user
)
...
...
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