Commit b11ed0e3 authored by Mehmet Emin INAC's avatar Mehmet Emin INAC Committed by Stan Hu

Fix the private interface of Security parsers

We don't need to pass the `report_data` and `report` objects around the
method as they are now attributes of the parser instance.
parent a0ffffd0
...@@ -19,12 +19,9 @@ module Gitlab ...@@ -19,12 +19,9 @@ module Gitlab
def parse! def parse!
raise SecurityReportParserError, "Invalid report format" unless report_data.is_a?(Hash) raise SecurityReportParserError, "Invalid report format" unless report_data.is_a?(Hash)
create_scanner(report, report_data.dig('scan', 'scanner')) create_scanner
create_scan(report, report_data.dig('scan')) create_scan
collate_remediations.each { |vulnerability| create_vulnerability(vulnerability) }
collate_remediations(report_data).each do |vulnerability|
create_vulnerability(report, vulnerability, report_data["version"])
end
report_data report_data
rescue JSON::ParserError rescue JSON::ParserError
...@@ -42,19 +39,30 @@ module Gitlab ...@@ -42,19 +39,30 @@ module Gitlab
@report_data ||= Gitlab::Json.parse!(json_data) @report_data ||= Gitlab::Json.parse!(json_data)
end end
def report_version
@report_version ||= report_data['version']
end
def top_level_scanner
@top_level_scanner ||= report_data.dig('scan', 'scanner')
end
def scan_data
@scan_data ||= report_data.dig('scan')
end
# map remediations to relevant vulnerabilities # map remediations to relevant vulnerabilities
def collate_remediations(report_data) def collate_remediations
return report_data["vulnerabilities"] || [] unless report_data["remediations"] return report_data["vulnerabilities"] || [] unless report_data["remediations"]
fixes = fixes_from(report_data)
report_data["vulnerabilities"].map do |vulnerability| report_data["vulnerabilities"].map do |vulnerability|
remediation = fixes[vulnerability['id']] || fixes[vulnerability['cve']] remediation = fixes[vulnerability['id']] || fixes[vulnerability['cve']]
vulnerability.merge("remediations" => [remediation]) vulnerability.merge("remediations" => [remediation])
end end
end end
def fixes_from(report_data) def fixes
report_data['remediations'].each_with_object({}) do |item, memo| @fixes ||= report_data['remediations'].each_with_object({}) do |item, memo|
item['fixes'].each do |fix| item['fixes'].each do |fix|
id = fix['id'] || fix['cve'] id = fix['id'] || fix['cve']
memo[id] = item if id memo[id] = item if id
...@@ -63,56 +71,54 @@ module Gitlab ...@@ -63,56 +71,54 @@ module Gitlab
end end
end end
def create_vulnerability(report, data, version) def create_vulnerability(data)
identifiers = create_identifiers(report, data['identifiers']) identifiers = create_identifiers(data['identifiers'])
links = create_links(report, data['links']) links = create_links(data['links'])
location = create_location(data['location'] || {}) location = create_location(data['location'] || {})
remediations = create_remediations(data['remediations']) remediations = create_remediations(data['remediations'])
report.add_finding( report.add_finding(
::Gitlab::Ci::Reports::Security::Finding.new( ::Gitlab::Ci::Reports::Security::Finding.new(
uuid: calculate_uuid_v5(report, location, identifiers.first), uuid: calculate_uuid_v5(identifiers.first, location),
report_type: report.type, report_type: report.type,
name: finding_name(data, identifiers, location), name: finding_name(data, identifiers, location),
compare_key: data['cve'] || '', compare_key: data['cve'] || '',
location: location, location: location,
severity: parse_severity_level(data['severity']&.downcase), severity: parse_severity_level(data['severity']),
confidence: parse_confidence_level(data['confidence']&.downcase), confidence: parse_confidence_level(data['confidence']),
scanner: create_scanner(report, data['scanner']), scanner: create_scanner(data['scanner']),
scan: report&.scan, scan: report&.scan,
identifiers: identifiers, identifiers: identifiers,
links: links, links: links,
remediations: remediations, remediations: remediations,
raw_metadata: data.to_json, raw_metadata: data.to_json,
metadata_version: version, metadata_version: report_version,
details: data['details'] || {})) details: data['details'] || {}))
end end
def create_scan(report, scan_data) def create_scan
return unless scan_data.is_a?(Hash) return unless scan_data.is_a?(Hash)
report.scan = ::Gitlab::Ci::Reports::Security::Scan.new(scan_data) report.scan = ::Gitlab::Ci::Reports::Security::Scan.new(scan_data)
end end
def create_scanner(report, scanner) def create_scanner(scanner_data = top_level_scanner)
return unless scanner.is_a?(Hash) return unless scanner_data.is_a?(Hash)
report.add_scanner( report.add_scanner(
::Gitlab::Ci::Reports::Security::Scanner.new( ::Gitlab::Ci::Reports::Security::Scanner.new(
external_id: scanner['id'], external_id: scanner_data['id'],
name: scanner['name'], name: scanner_data['name'],
vendor: scanner.dig('vendor', 'name'))) vendor: scanner_data.dig('vendor', 'name')))
end end
def create_identifiers(report, identifiers) def create_identifiers(identifiers)
return [] unless identifiers.is_a?(Array) return [] unless identifiers.is_a?(Array)
identifiers.map do |identifier| identifiers.map { |identifier| create_identifier(identifier) }.compact
create_identifier(report, identifier)
end.compact
end end
def create_identifier(report, identifier) def create_identifier(identifier)
return unless identifier.is_a?(Hash) return unless identifier.is_a?(Hash)
report.add_identifier( report.add_identifier(
...@@ -123,20 +129,16 @@ module Gitlab ...@@ -123,20 +129,16 @@ module Gitlab
url: identifier['url'])) url: identifier['url']))
end end
def create_links(report, links) def create_links(links)
return [] unless links.is_a?(Array) return [] unless links.is_a?(Array)
links links.map { |link| create_link(link) }.compact
.map { |link| create_link(report, link) }
.compact
end end
def create_link(report, link) def create_link(link)
return unless link.is_a?(Hash) return unless link.is_a?(Hash)
::Gitlab::Ci::Reports::Security::Link.new( ::Gitlab::Ci::Reports::Security::Link.new(name: link['name'], url: link['url'])
name: link['name'],
url: link['url'])
end end
def create_remediations(remediations_data) def create_remediations(remediations_data)
...@@ -146,15 +148,11 @@ module Gitlab ...@@ -146,15 +148,11 @@ module Gitlab
end end
def parse_severity_level(input) def parse_severity_level(input)
return input if ::Enums::Vulnerability.severity_levels.key?(input) input&.downcase.then { |value| ::Enums::Vulnerability.severity_levels.key?(value) ? value : 'unknown' }
'unknown'
end end
def parse_confidence_level(input) def parse_confidence_level(input)
return input if ::Enums::Vulnerability.confidence_levels.key?(input) input&.downcase.then { |value| ::Enums::Vulnerability.confidence_levels.key?(value) ? value : 'unknown' }
'unknown'
end end
def create_location(location_data) def create_location(location_data)
...@@ -169,7 +167,7 @@ module Gitlab ...@@ -169,7 +167,7 @@ module Gitlab
"#{identifier.name} in #{location&.fingerprint_path}" "#{identifier.name} in #{location&.fingerprint_path}"
end end
def calculate_uuid_v5(report, location, primary_identifier) def calculate_uuid_v5(primary_identifier, location)
uuid_v5_name_components = { uuid_v5_name_components = {
report_type: report.type, report_type: report.type,
primary_identifier_fingerprint: primary_identifier&.fingerprint, primary_identifier_fingerprint: primary_identifier&.fingerprint,
......
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