Commit 1672ec35 authored by Olivier Gonzalez's avatar Olivier Gonzalez

Add package name to dependency scanning reports

Generate specific location fingerprint per report type
Make metadata version dynamic and guess it based on content
parent ac44c83a
...@@ -7,8 +7,8 @@ module Gitlab ...@@ -7,8 +7,8 @@ module Gitlab
ParserNotFoundError = Class.new(StandardError) ParserNotFoundError = Class.new(StandardError)
PARSERS = { PARSERS = {
sast: ::Gitlab::Ci::Parsers::Security::Common, sast: ::Gitlab::Ci::Parsers::Security::Sast,
dependency_scanning: ::Gitlab::Ci::Parsers::Security::Common dependency_scanning: ::Gitlab::Ci::Parsers::Security::DependencyScanning
}.freeze }.freeze
def self.fabricate!(file_type) def self.fabricate!(file_type)
......
...@@ -7,8 +7,6 @@ module Gitlab ...@@ -7,8 +7,6 @@ module Gitlab
class Common class Common
SecurityReportParserError = Class.new(StandardError) SecurityReportParserError = Class.new(StandardError)
METADATA_VERSION = '1.2'
def parse!(json_data, report) def parse!(json_data, report)
vulnerabilities = JSON.parse!(json_data) vulnerabilities = JSON.parse!(json_data)
...@@ -41,7 +39,7 @@ module Gitlab ...@@ -41,7 +39,7 @@ module Gitlab
raw_metadata: data.to_json, raw_metadata: data.to_json,
# Version is hardcoded here untill provided in the report. # Version is hardcoded here untill provided in the report.
# See https://gitlab.com/gitlab-org/gitlab-ee/issues/8025 # See https://gitlab.com/gitlab-org/gitlab-ee/issues/8025
metadata_version: METADATA_VERSION metadata_version: metadata_version(data)
) )
end end
...@@ -80,10 +78,6 @@ module Gitlab ...@@ -80,10 +78,6 @@ module Gitlab
input.blank? ? 'undefined' : input.downcase input.blank? ? 'undefined' : input.downcase
end end
def generate_location_fingerprint(location)
Digest::SHA1.hexdigest("#{location['file']}:#{location['start_line']}:#{location['end_line']}")
end
def generate_project_fingerprint(compare_key) def generate_project_fingerprint(compare_key)
Digest::SHA1.hexdigest(compare_key) Digest::SHA1.hexdigest(compare_key)
end end
......
# frozen_string_literal: true
module Gitlab
module Ci
module Parsers
module Security
class DependencyScanning < Common
private
def metadata_version(vulnerability)
'1.3'
end
def generate_location_fingerprint(location)
Digest::SHA1.hexdigest("#{location['file']}:#{location['dependency']['package']['name']}")
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
module Parsers
module Security
class Sast < Common
private
def metadata_version(vulnerability)
'1.2'
end
def generate_location_fingerprint(location)
Digest::SHA1.hexdigest("#{location['file']}:#{location['start_line']}:#{location['end_line']}")
end
end
end
end
end
end
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Parsers::Security::Common do describe Gitlab::Ci::Parsers::Security::DependencyScanning do
describe '#parse!' do describe '#parse!' do
let(:project) { artifact.project } let(:project) { artifact.project }
let(:pipeline) { artifact.job.pipeline } 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) } let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type) }
let(:parser) { described_class.new } let(:parser) { described_class.new }
...@@ -15,24 +16,18 @@ describe Gitlab::Ci::Parsers::Security::Common do ...@@ -15,24 +16,18 @@ describe Gitlab::Ci::Parsers::Security::Common do
end end
end end
context 'sast report' do
let(:artifact) { create(:ee_ci_job_artifact, :sast) }
it "parses all identifiers and occurrences" do
expect(report.occurrences.length).to eq(3)
expect(report.identifiers.length).to eq(4)
expect(report.scanners.length).to eq(3)
end
end
context 'dependency_scanning report' do
let(:artifact) { create(:ee_ci_job_artifact, :dependency_scanning) }
it "parses all identifiers and occurrences" do it "parses all identifiers and occurrences" do
expect(report.occurrences.length).to eq(4) expect(report.occurrences.length).to eq(4)
expect(report.identifiers.length).to eq(7) expect(report.identifiers.length).to eq(7)
expect(report.scanners.length).to eq(2) expect(report.scanners.length).to eq(2)
end end
it "generates expected location fingerprint" do
expect(report.occurrences.first[:location_fingerprint]).to eq('2773f8cc955346ab1f756b94aa310db8e17c0944')
end
it "generates expected metadata_version" do
expect(report.occurrences.first[:metadata_version]).to eq('1.3')
end end
end end
end end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Ci::Parsers::Security::Sast do
describe '#parse!' do
let(:project) { artifact.project }
let(:pipeline) { artifact.job.pipeline }
let(:artifact) { create(:ee_ci_job_artifact, :sast) }
let(:report) { Gitlab::Ci::Reports::Security::Report.new(artifact.file_type) }
let(:parser) { described_class.new }
before do
artifact.each_blob do |blob|
parser.parse!(blob, report)
end
end
it "parses all identifiers and occurrences" do
expect(report.occurrences.length).to eq(3)
expect(report.identifiers.length).to eq(4)
expect(report.scanners.length).to eq(3)
end
it "generates expected location fingerprint" do
expect(report.occurrences.first[:location_fingerprint]).to eq('6b6bb283d43cc510d7d1e73e2882b3652cb34bd5')
end
it "generates expected metadata_version" do
expect(report.occurrences.first[:metadata_version]).to eq('1.2')
end
end
end
...@@ -11,7 +11,13 @@ ...@@ -11,7 +11,13 @@
"name": "Gemnasium" "name": "Gemnasium"
}, },
"location": { "location": {
"file": "app/pom.xml" "file": "app/pom.xml",
"dependency": {
"package": {
"name": "io.netty/netty"
},
"version": "3.9.1.Final"
}
}, },
"identifiers": [ "identifiers": [
{ {
...@@ -55,7 +61,13 @@ ...@@ -55,7 +61,13 @@
"name": "Gemnasium" "name": "Gemnasium"
}, },
"location": { "location": {
"file": "app/requirements.txt" "file": "app/requirements.txt",
"dependency": {
"package": {
"name": "Django"
},
"version": "1.11.3"
}
}, },
"identifiers": [ "identifiers": [
{ {
...@@ -93,7 +105,13 @@ ...@@ -93,7 +105,13 @@
"name": "Gemnasium" "name": "Gemnasium"
}, },
"location": { "location": {
"file": "rails/Gemfile.lock" "file": "rails/Gemfile.lock",
"dependency": {
"package": {
"name": "nokogiri"
},
"version": "1.8.0"
}
}, },
"identifiers": [ "identifiers": [
{ {
...@@ -131,7 +149,13 @@ ...@@ -131,7 +149,13 @@
"name": "bundler-audit" "name": "bundler-audit"
}, },
"location": { "location": {
"file": "sast-sample-rails/Gemfile.lock" "file": "sast-sample-rails/Gemfile.lock",
"dependency": {
"package": {
"name": "ffi"
},
"version": "1.9.18"
}
}, },
"identifiers": [ "identifiers": [
{ {
......
...@@ -11,7 +11,13 @@ ...@@ -11,7 +11,13 @@
"name": "Gemnasium" "name": "Gemnasium"
}, },
"location": { "location": {
"file": "app/pom.xml" "file": "app/pom.xml",
"dependency": {
"package": {
"name": "io.netty/netty"
},
"version": "3.9.1.Final"
}
}, },
"identifiers": [ "identifiers": [
{ {
...@@ -55,7 +61,13 @@ ...@@ -55,7 +61,13 @@
"name": "Gemnasium" "name": "Gemnasium"
}, },
"location": { "location": {
"file": "app/requirements.txt" "file": "app/requirements.txt",
"dependency": {
"package": {
"name": "Django"
},
"version": "1.11.3"
}
}, },
"identifiers": [ "identifiers": [
{ {
...@@ -93,7 +105,13 @@ ...@@ -93,7 +105,13 @@
"name": "Gemnasium" "name": "Gemnasium"
}, },
"location": { "location": {
"file": "rails/Gemfile.lock" "file": "rails/Gemfile.lock",
"dependency": {
"package": {
"name": "nokogiri"
},
"version": "1.8.0"
}
}, },
"identifiers": [ "identifiers": [
{ {
...@@ -131,7 +149,13 @@ ...@@ -131,7 +149,13 @@
"name": "bundler-audit" "name": "bundler-audit"
}, },
"location": { "location": {
"file": "sast-sample-rails/Gemfile.lock" "file": "sast-sample-rails/Gemfile.lock",
"dependency": {
"package": {
"name": "ffi"
},
"version": "1.9.18"
}
}, },
"identifiers": [ "identifiers": [
{ {
......
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