Skip to content
This repository has been archived by the owner on Jul 24, 2021. It is now read-only.

Allow to configure severity threshold. #12

Merged
merged 15 commits into from
Oct 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
PATH
remote: .
specs:
dependency_spy (0.2.1)
dependency_spy (0.2.2)
bibliothecary (~> 6.3)
colorize (~> 0.8.1)
semantic_range (~> 2.1)
thor (~> 0.20)
yavdb (~> 0.4)
Expand All @@ -23,15 +24,16 @@ GEM
citrus (3.0.2)
codacy-coverage (2.1.0)
simplecov
commander (4.4.6)
highline (~> 1.7.2)
colorize (0.8.1)
commander (4.4.7)
highline (~> 2.0.0)
deb_control (0.0.1)
diff-lcs (1.3)
docile (1.3.1)
ethon (0.11.0)
ffi (>= 1.3.0)
ffi (1.9.25)
highline (1.7.10)
highline (2.0.0)
jaro_winkler (1.5.1)
json (2.1.0)
kramdown (1.17.0)
Expand Down Expand Up @@ -61,14 +63,14 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.0)
rubocop (0.59.2)
rubocop (0.60.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.5, != 2.5.1.1)
powerpack (~> 0.1)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
unicode-display_width (~> 1.4.0)
rubocop-rspec (1.30.0)
rubocop (>= 0.58.0)
ruby-ll (2.1.2)
Expand All @@ -89,7 +91,7 @@ GEM
typhoeus (1.3.0)
ethon (>= 0.9.0)
unicode-display_width (1.4.0)
yavdb (0.4.0)
yavdb (0.4.1)
json (~> 2.1)
kramdown (~> 1.17)
oga (~> 2.15)
Expand Down
1 change: 1 addition & 0 deletions dependency_spy.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Gem::Specification.new do |spec|

# Runtime
spec.add_runtime_dependency 'bibliothecary', ['~> 6.3']
spec.add_runtime_dependency 'colorize', ['~> 0.8.1']
spec.add_runtime_dependency 'semantic_range', ['~> 2.1']
spec.add_runtime_dependency 'thor', ['~> 0.20']
spec.add_runtime_dependency 'yavdb', ['~> 0.4']
Expand Down
23 changes: 17 additions & 6 deletions lib/dependency_spy/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
require_relative 'formatters/yaml'
require_relative 'outputs/stdout'
require_relative 'outputs/file'
require_relative 'helper/helper'

module DependencySpy
class CLI < Thor
Expand All @@ -46,14 +47,18 @@ class CLI < Thor
method_option('output-path', :aliases => :o, :type => :string)
method_option('database-path', :type => :string, :aliases => :p, :default => YAVDB::Constants::DEFAULT_YAVDB_DATABASE_PATH)
method_option('offline', :type => :boolean, :default => false)

method_option('severity-threshold', :aliases => :s, :type => :string, :enum => YAVDB::Constants::SEVERITIES, :default => 'low')
method_option('with-color', :type => :boolean, :default => true)
def check
manifests = API.check(options['path'], options['files'], options['platform'], options['database-path'], options['offline'])

formatted_output =
FORMATTERS
.find { |f| f.name.split('::').last.downcase == options['formatter'] }
.format(manifests)
formatted_output = if (options['formatter'] == 'text') && !options['output-path'] && options['with-color']
DependencySpy::Formatters::Text.format(manifests, options['severity-threshold'])
else
FORMATTERS
.find { |f| f.name.split('::').last.downcase == options['formatter'] }
.format(manifests)
end

if options['output-path']
DependencySpy::Outputs::FileSystem.write(options['output-path'], formatted_output)
Expand All @@ -62,7 +67,13 @@ def check
end

has_vulnerabilities =
manifests.any? { |manifest| manifest.dependencies.any? { |dependency| dependency.vulnerabilities.any? } }
manifests.any? do |manifest|
manifest[:dependencies]&.any? do |dependency|
dependency[:vulnerabilities]&.any? do |vuln|
DependencySpy::Helper.severity_above_threshold?(vuln.severity, options['severity-threshold'])
end
end
end

exit(1) if has_vulnerabilities
end
Expand Down
36 changes: 22 additions & 14 deletions lib/dependency_spy/dtos/dependency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,25 @@ class Manifest < Struct.new(
def to_map
map = {}
members.each do |m|
next unless self[m] && (
(self[m].is_a?(String) && !self[m].empty?) ||
(self[m].is_a?(Array) && self[m].any?))

map[m.to_s] = self[m] if self[m]
if !self[m] ||
(self[m].is_a?(String) && self[m].empty?) ||
(self[m].is_a?(Array) && self[m].none?)
next
elsif self[m].is_a?(Struct)
map[m.to_s] = self[m].to_map
else
map[m.to_s] = self[m]
end
end
map
end

def to_json(*attrs)
to_map.to_json(*attrs)
def to_json(*args)
to_map.to_json(*args)
end

def to_yaml(*attrs)
to_map.to_yaml(*attrs)
def to_yaml(*args)
to_map.to_yaml(*args)
end

end
Expand All @@ -55,11 +59,15 @@ class Dependency < Struct.new(
def to_map
map = {}
members.each do |m|
next unless self[m] && (
(self[m].is_a?(String) && !self[m].empty?) ||
(self[m].is_a?(Array) && self[m].any?))

map[m.to_s] = self[m] if self[m]
if !self[m] ||
(self[m].is_a?(String) && self[m].empty?) ||
(self[m].is_a?(Array) && self[m].none?)
next
elsif self[m].is_a?(Struct)
map[m.to_s] = self[m].to_map
else
map[m.to_s] = self[m]
end
end
map
end
Expand Down
13 changes: 5 additions & 8 deletions lib/dependency_spy/formatters/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,15 @@ class Json

def self.format(manifests)
filtered_manifests = manifests.map do |manifest|
manifest[:dependencies] = manifest[:dependencies].map do |dependency|
next unless dependency[:vulnerabilities].any?

dependency[:vulnerabilities] = dependency[:vulnerabilities].map(&:to_map)
dependency
end.reject(&:nil?).map(&:to_map)
manifest
vulnerable_dependencies = manifest[:dependencies]
.select { |dependency| dependency[:vulnerabilities].any? }
manifest_copy = Marshal.load(Marshal.dump(manifest))
manifest_copy[:dependencies] = vulnerable_dependencies
manifest_copy
end

filtered_manifests
.reject { |m| m[:dependencies].nil? }
.map(&:to_map)
.map(&:to_json)
end

Expand Down
11 changes: 8 additions & 3 deletions lib/dependency_spy/formatters/text.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require 'colorize'
require_relative '../helper/helper'

module DependencySpy
class Formatters
class Text

def self.format(manifests)
def self.format(manifests, severity_threshold = nil)
manifests_text = manifests.map do |manifest|
manifest_header = "#{manifest.platform}: #{manifest.kind} ~> #{manifest.path} "
manifest_body = manifest.dependencies.map do |package|
Expand All @@ -29,8 +31,11 @@ def self.format(manifests)
first = " Title: #{vuln.title}\n"
second = " Severity: #{(vuln.severity || 'unknown').capitalize}\n"
third = " Source: #{vuln.source_url}\n\n"

"#{first}#{second}#{third}"
if severity_threshold && DependencySpy::Helper.severity_above_threshold?(vuln.severity, severity_threshold)
"#{first}#{second}#{third}".red
else
"#{first}#{second}#{third}"
end
end

"#{package_header}\n#{package_body.join("\n")}"
Expand Down
15 changes: 6 additions & 9 deletions lib/dependency_spy/formatters/yaml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,16 @@ class Yaml

def self.format(manifests)
filtered_manifests = manifests.map do |manifest|
manifest[:dependencies] = manifest[:dependencies].map do |dependency|
next unless dependency[:vulnerabilities].any?

dependency[:vulnerabilities] = dependency[:vulnerabilities].map(&:to_map)
dependency
end.reject(&:nil?).map(&:to_map)
manifest
vulnerable_dependencies = manifest[:dependencies]
.select { |dependency| dependency[:vulnerabilities].any? }
manifest_copy = Marshal.load(Marshal.dump(manifest))
manifest_copy[:dependencies] = vulnerable_dependencies
manifest_copy
end

filtered_manifests
.reject { |m| m[:dependencies].nil? }
.map(&:to_map)
.map(&:to_yaml)
.map(&:to_json)
end

end
Expand Down
13 changes: 13 additions & 0 deletions lib/dependency_spy/helper/helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module DependencySpy
class Helper

def self.severity_above_threshold?(severity = 'unknown', severity_threshold)
return true if severity_threshold == 'low' || severity == 'unknown'
return ['medium', 'high'].include? severity if severity_threshold == 'medium'
return severity == 'high' if severity_threshold == 'high'

false
end

end
end
2 changes: 1 addition & 1 deletion lib/dependency_spy/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@

module DependencySpy

VERSION = '0.2.1'
VERSION = '0.2.2'

end
2 changes: 1 addition & 1 deletion spec/dependency_spy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
manifests = detected_manifests.select { |m| m.platform == 'npm' }
dependencies = manifests.map(&:dependencies).flatten
vulnerabilities = dependencies.map(&:vulnerabilities).flatten
expect(vulnerabilities).to have(87).items
expect(vulnerabilities).to have(62).items
end

it 'can read all dependencies for rubygems manifest' do
Expand Down