Commit 27b1996d authored by Sean McGivern's avatar Sean McGivern

Merge branch '229472-export-dep-path' into 'master'

Expose dependency path

See merge request gitlab-org/gitlab!40644
parents ba39d96a ed61909b
......@@ -3,8 +3,13 @@
class DependencyEntity < Grape::Entity
include RequestAwareEntity
class AncestorEntity < Grape::Entity
expose :name, :version
end
class LocationEntity < Grape::Entity
expose :blob_path, :path
expose :blob_path, :path, :top_level
expose :ancestors, using: AncestorEntity
end
class VulnerabilityEntity < Grape::Entity
......
......@@ -8,6 +8,7 @@ module Gitlab
class DependencyList
def initialize(project, sha)
@commit_path = ::Gitlab::Routing.url_helpers.project_blob_path(project, sha)
@project = project
end
def format(dependency, package_manager, file_path, vulnerabilities = [])
......@@ -15,10 +16,7 @@ module Gitlab
name: dependency['package']['name'],
packager: packager(package_manager),
package_manager: package_manager,
location: {
blob_path: blob_path(file_path),
path: file_path
},
location: formatted_location(dependency, file_path),
version: dependency['version'],
vulnerabilities: formatted_vulnerabilities(vulnerabilities),
licenses: []
......@@ -27,27 +25,12 @@ module Gitlab
private
attr_reader :commit_path
attr_reader :commit_path, :project
def blob_path(file_path)
"#{commit_path}/#{file_path}"
end
# Dependency List report is generated by dependency_scanning job.
# This is how the location is generated there
# https://gitlab.com/gitlab-org/security-products/analyzers/common/blob/a0a5074c49f34332aa3948cd9d6dc2c054cdf3a7/issue/issue.go#L169
def location(dependency, file_path)
{
'file' => file_path,
'dependency' => {
'package' => {
'name' => dependency['package']['name']
},
'version' => dependency['version']
}
}
end
def packager(package_manager)
case package_manager
when 'bundler'
......@@ -69,6 +52,30 @@ module Gitlab
end
end
def formatted_location(dependency, file_path)
base_location = {
blob_path: blob_path(file_path),
path: file_path
}
return base_location if Feature.disabled?(:path_to_vulnerable_dependency, project)
# TODO: update this code before https://gitlab.com/gitlab-org/gitlab/-/issues/229472 is closed
# We temporary return test dependency path to get a PoC with integration to frontend
base_location.merge({
ancestors:
[{
name: 'dep1',
version: '1.2'
},
{
name: 'dep2',
version: '10.11'
}],
top_level: false
})
end
# we know that Parsers::Security::DependencyList parses one vulnerability at a time
# however, to keep interface compability with rest of the code and have MVC we return array
# even tough we know that array's size will be 1
......@@ -77,6 +84,21 @@ module Gitlab
[{ name: vulnerabilities['message'], severity: vulnerabilities['severity'].downcase }]
end
# Dependency List report is generated by dependency_scanning job.
# This is how the location is generated there
# https://gitlab.com/gitlab-org/security-products/analyzers/common/blob/a0a5074c49f34332aa3948cd9d6dc2c054cdf3a7/issue/issue.go#L169
def location(dependency, file_path)
{
'file' => file_path,
'dependency' => {
'package' => {
'name' => dependency['package']['name']
},
'version' => dependency['version']
}
}
end
end
end
end
......
......@@ -8,10 +8,10 @@ FactoryBot.define do
version { '1.8.0' }
licenses { [] }
vulnerabilities { [] }
sequence(:location) do |n|
location do
{
blob_path: "/some_project/path/File_#{n}.lock",
path: "File_#{n}.lock"
blob_path: '/some_project/path/package_file.lock',
path: 'package_file.lock'
}
end
......@@ -41,6 +41,37 @@ FactoryBot.define do
end
end
trait :indirect do
location do
{
blob_path: '/some_project/path/package_file.lock',
path: 'package_file.lock',
ancestors:
[{
name: 'dep1',
version: '1.2'
},
{
name: 'dep2',
version: '10.11'
}],
top_level: false
}
end
end
trait :direct do
location do
{
blob_path: '/some_project/path/package_file.lock',
path: 'package_file.lock',
ancestors:
[],
top_level: true
}
end
end
initialize_with { attributes }
end
end
......@@ -31,12 +31,27 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Formatters::DependencyList do
expect(data[:package_manager]).to eq('bundler')
expect(data[:location][:blob_path]).to eq(blob_path)
expect(data[:location][:path]).to eq('rails/Gemfile.lock')
expect(data[:location][:top_level]).to be_falsey
expect(data[:location][:ancestors].first[:name]).to eq('dep1')
expect(data[:version]).to eq('2.2.0')
expect(data[:vulnerabilities]).to be_empty
expect(data[:licenses]).to be_empty
end
end
context 'when feature flag for dependency path is off' do
let(:dependency) { parsed_report['dependency_files'][0]['dependencies'][0] }
let(:location) { data[:location] }
before do
stub_feature_flags(path_to_vulnerable_dependency: false)
end
it { expect(location[:top_level]).to be_nil }
it { expect(location[:ancestors]).to be_nil }
it { expect(location[:path]).to eq('rails/Gemfile.lock') }
end
context 'with vulnerable dependency' do
let(:data) { formatter.format(dependency, package_manager, file_path, parsed_report['vulnerabilities'].first) }
let(:dependency) { parsed_report['dependency_files'][0]['dependencies'][1] }
......
......@@ -9,7 +9,7 @@ RSpec.describe DependencyEntity do
let_it_be(:user) { create(:user) }
let(:project) { create(:project, :repository, :private) }
let(:request) { double('request') }
let(:dependency) { build(:dependency, :with_vulnerabilities, :with_licenses) }
let(:dependency) { build(:dependency, :with_vulnerabilities, :with_licenses, :indirect) }
before do
allow(request).to receive(:project).and_return(project)
......@@ -51,5 +51,17 @@ RSpec.describe DependencyEntity do
is_expected.to eq(dependency.except(:vulnerabilities, :licenses, :package_manager))
end
end
context 'when there is no dependency path attributes' do
let(:dependency) { build(:dependency, :with_vulnerabilities, :with_licenses) }
it 'correctly represent location' do
location = subject[:location]
expect(location[:ancestors]).to be_nil
expect(location[:top_level]).to be_nil
expect(location[:path]).to eq('package_file.lock')
end
end
end
end
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