package-audit 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/lib/package/audit/cli.rb +42 -42
  3. data/lib/package/audit/const/cmd.rb +3 -3
  4. data/lib/package/audit/const/fields.rb +4 -4
  5. data/lib/package/audit/const/file.rb +1 -0
  6. data/lib/package/audit/const/yaml.rb +13 -0
  7. data/lib/package/audit/enum/option.rb +13 -0
  8. data/lib/package/audit/enum/report.rb +12 -0
  9. data/lib/package/audit/enum/technology.rb +14 -0
  10. data/lib/package/audit/formatter/risk.rb +1 -1
  11. data/lib/package/audit/formatter/version.rb +1 -1
  12. data/lib/package/audit/formatter/version_date.rb +1 -1
  13. data/lib/package/audit/formatter/vulnerability.rb +1 -1
  14. data/lib/package/audit/{package.rb → models/package.rb} +8 -7
  15. data/lib/package/audit/npm/node_collection.rb +25 -14
  16. data/lib/package/audit/npm/vulnerability_finder.rb +4 -3
  17. data/lib/package/audit/npm/yarn_lock_parser.rb +10 -6
  18. data/lib/package/audit/ruby/bundler_specs.rb +16 -9
  19. data/lib/package/audit/ruby/gem_collection.rb +36 -15
  20. data/lib/package/audit/ruby/gem_meta_data.rb +1 -1
  21. data/lib/package/audit/ruby/vulnerability_finder.rb +4 -3
  22. data/lib/package/audit/services/command_parser.rb +103 -0
  23. data/lib/package/audit/services/package_filter.rb +39 -0
  24. data/lib/package/audit/services/package_finder.rb +58 -0
  25. data/lib/package/audit/{printer.rb → services/package_printer.rb} +12 -11
  26. data/lib/package/audit/{risk_calculator.rb → services/risk_calculator.rb} +8 -4
  27. data/lib/package/audit/technology/detector.rb +40 -0
  28. data/lib/package/audit/technology/validator.rb +56 -0
  29. data/lib/package/audit/util/summary_printer.rb +22 -11
  30. data/lib/package/audit/version.rb +1 -1
  31. data/sig/package/audit/cli.rbs +2 -0
  32. data/sig/package/audit/const/fields.rbs +2 -1
  33. data/sig/package/audit/const/file.rbs +1 -0
  34. data/sig/package/audit/const/yaml.rbs +13 -0
  35. data/sig/package/audit/enum/option.rbs +13 -0
  36. data/sig/package/audit/enum/report.rbs +12 -0
  37. data/sig/package/audit/enum/technology.rbs +12 -0
  38. data/sig/package/audit/{package.rbs → models/package.rbs} +3 -1
  39. data/sig/package/audit/{risk.rbs → models/risk.rbs} +1 -1
  40. data/sig/package/audit/npm/node_collection.rbs +4 -5
  41. data/sig/package/audit/npm/vulnerability_finder.rbs +3 -2
  42. data/sig/package/audit/npm/yarn_lock_parser.rbs +1 -0
  43. data/sig/package/audit/ruby/bundler_specs.rbs +2 -2
  44. data/sig/package/audit/ruby/gem_collection.rbs +11 -4
  45. data/sig/package/audit/ruby/vulnerability_finder.rbs +3 -0
  46. data/sig/package/audit/services/command_parser.rbs +31 -0
  47. data/sig/package/audit/services/package_filter.rbs +19 -0
  48. data/sig/package/audit/services/package_finder.rbs +23 -0
  49. data/sig/package/audit/{printer.rbs → services/package_printer.rbs} +3 -3
  50. data/sig/package/audit/technology/detector.rbs +19 -0
  51. data/sig/package/audit/technology/validator.rbs +19 -0
  52. data/sig/package/audit/util/summary_printer.rbs +5 -5
  53. metadata +30 -14
  54. data/lib/package/audit/command_service.rb +0 -187
  55. data/sig/package/audit/command_service.rbs +0 -29
  56. /data/lib/package/audit/{risk.rb → models/risk.rb} +0 -0
  57. /data/lib/package/audit/{duplicate_package_merger.rb → services/duplicate_package_merger.rb} +0 -0
  58. /data/sig/package/audit/{duplicate_package_merger.rbs → services/duplicate_package_merger.rbs} +0 -0
  59. /data/sig/package/audit/{risk_calculator.rbs → services/risk_calculator.rbs} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55535a9ef08ce99d8cdacbfe15e0ec11e770f4803e4ef212d9ff4565111c89a6
4
- data.tar.gz: 3f1efc9489c0ac9139f94bb7ed66d8ccee255e9c61f79440c899c0dcc4cd5885
3
+ metadata.gz: d30d08ba36373c75427371f922cb0a5819a021868bf82001428e0541571df9f8
4
+ data.tar.gz: ac4dce54e3905dd56de9b137a62101de7267262c1f6b0310e4697c8f016a36b8
5
5
  SHA512:
6
- metadata.gz: 9c7ee67ccfadae05b1ec3a7e53d77ed8d977ae43bd54bbc0b95dee86e33ddceb87592089abc7a1410dba71c00802cc6172c3849d23e789878a9e8e14a1de2d96
7
- data.tar.gz: 4ff43ca9c9e7bc410b545cde33b77798bfe71d40ebf92874235a695fb1862b2fa826849ce62f67cab831dfa22b987506248754e0a03b3827612e17b12df3f9be
6
+ metadata.gz: 00be4151f4f124614d117a739a558f9f2816f0f72095f222ddadf5101a6d089b40bdc5369c4a68c9b096b1547932561394f1fee5ca58712e13a4909c4a8c9558
7
+ data.tar.gz: f224c2c2fe2ff39586d20989ef6999d7b2a52acd2276dcdd9895441105ccaebc5991523676b88545a5afa96d4ffcac10291ab76dfab735b65d42aabc4598d7e4
@@ -1,11 +1,8 @@
1
- require_relative './const/time'
2
- require_relative './version'
3
- require_relative './util/summary_printer'
4
- require_relative './ruby/bundler_specs'
5
- require_relative './printer'
6
- require_relative './ruby/gem_collection'
7
- require_relative './npm/node_collection'
8
- require_relative './command_service'
1
+ require_relative 'const/file'
2
+ require_relative 'const/time'
3
+ require_relative 'enum/option'
4
+ require_relative 'services/command_parser'
5
+ require_relative 'version'
9
6
 
10
7
  require 'json'
11
8
  require 'thor'
@@ -15,57 +12,52 @@ module Package
15
12
  class CLI < Thor
16
13
  default_task :report
17
14
 
15
+ class_option Enum::Option::CONFIG,
16
+ aliases: '-c', banner: 'FILE',
17
+ desc: "Path to a custom configuration file, default: #{Const::File::CONFIG})"
18
+ class_option Enum::Option::TECHNOLOGY,
19
+ aliases: '-t', repeatable: true,
20
+ desc: 'Technology to be audited (repeat this flag for each technology)'
21
+ class_option Enum::Option::INCLUDE_IGNORED,
22
+ type: :boolean, default: false,
23
+ desc: 'Include packages ignored by a configuration file'
24
+ class_option Enum::Option::CSV,
25
+ type: :boolean, default: false,
26
+ desc: 'Output reports using comma separated values (CSV)'
27
+ class_option Enum::Option::CSV_EXCLUDE_HEADERS,
28
+ type: :boolean, default: false,
29
+ desc: "Hide headers when using the --#{Enum::Option::CSV} option"
30
+
31
+ map '-v' => :version
18
32
  map '--version' => :version
19
33
 
20
- desc 'report', 'Show a report of potentially deprecated, outdated or vulnerable packages'
21
- method_option :csv, type: :boolean, default: false, desc: 'Output using comma separated values (CSV)'
22
- method_option :'exclude-headers', type: :boolean, default: false, desc: 'Hide headers if when using CSV'
23
-
24
- def report
25
- within_rescue_block do
26
- exit CommandService.new(Dir.pwd, options).all
27
- end
34
+ desc 'report [DIR]', 'Show a report of potentially deprecated, outdated or vulnerable packages'
35
+ def report(dir = Dir.pwd)
36
+ within_rescue_block { exit CommandParser.new(dir, options, Enum::Report::ALL).run }
28
37
  end
29
38
 
30
- desc 'deprecated',
39
+ desc 'deprecated [DIR]',
31
40
  "Show packages with no updates by author for at least #{Const::Time::YEARS_ELAPSED_TO_BE_OUTDATED} years"
32
- method_option :csv, type: :boolean, default: false, desc: 'Output using comma separated values (CSV)'
33
- method_option :'exclude-headers', type: :boolean, default: false, desc: 'Hide headers if when using CSV'
34
-
35
- def deprecated
36
- within_rescue_block do
37
- exit CommandService.new(Dir.pwd, options).deprecated
38
- end
41
+ def deprecated(dir = Dir.pwd)
42
+ within_rescue_block { exit CommandParser.new(dir, options, Enum::Report::DEPRECATED).run }
39
43
  end
40
44
 
41
- desc 'outdated', 'Show packages that are out of date'
42
- method_option :csv, type: :boolean, default: false, desc: 'Output using comma separated values (CSV)'
43
- method_option :'exclude-headers', type: :boolean, default: false, desc: 'Hide headers if when using CSV'
44
-
45
- def outdated
46
- within_rescue_block do
47
- exit CommandService.new(Dir.pwd, options).outdated
48
- end
45
+ desc 'outdated [DIR]', 'Show packages that are out of date'
46
+ def outdated(dir = Dir.pwd)
47
+ within_rescue_block { exit CommandParser.new(dir, options, Enum::Report::OUTDATED).run }
49
48
  end
50
49
 
51
- desc 'vulnerable', 'Show packages and their dependencies that have security vulnerabilities'
52
- method_option :csv, type: :boolean, default: false, desc: 'Output using comma separated values (CSV)'
53
- method_option :'exclude-headers', type: :boolean, default: false, desc: 'Hide headers if when using CSV'
54
-
55
- def vulnerable
56
- within_rescue_block do
57
- exit CommandService.new(Dir.pwd, options).vulnerable
58
- end
50
+ desc 'vulnerable [DIR]', 'Show packages and their dependencies that have security vulnerabilities'
51
+ def vulnerable(dir = Dir.pwd)
52
+ within_rescue_block { exit CommandParser.new(dir, options, Enum::Report::VULNERABLE).run }
59
53
  end
60
54
 
61
55
  desc 'risk', 'Print information on how risk is calculated'
62
-
63
56
  def risk
64
57
  Util::SummaryPrinter.risk
65
58
  end
66
59
 
67
60
  desc 'version', 'Print the currently installed version of the package-audit gem'
68
-
69
61
  def version
70
62
  puts "package-audit #{VERSION}"
71
63
  end
@@ -74,6 +66,14 @@ module Package
74
66
  true
75
67
  end
76
68
 
69
+ def method_missing(command, *args)
70
+ invoke :report, [command], args
71
+ end
72
+
73
+ def respond_to_missing?
74
+ true
75
+ end
76
+
77
77
  private
78
78
 
79
79
  def within_rescue_block
@@ -2,14 +2,14 @@ module Package
2
2
  module Audit
3
3
  module Const
4
4
  module Cmd
5
- BUNDLE_AUDIT = 'bundle exec bundle-audit check --update'
6
- BUNDLE_AUDIT_JSON = 'bundle exec bundle-audit check --update --quiet --format json'
5
+ BUNDLE_AUDIT = 'bundle-audit check --update'
6
+ BUNDLE_AUDIT_JSON = 'bundle-audit check --update --quiet --format json %s'
7
7
 
8
8
  NPM_AUDIT = 'npm audit'
9
9
  NPM_AUDIT_JSON = 'npm audit --json'
10
10
 
11
11
  YARN_AUDIT = 'yarn audit'
12
- YARN_AUDIT_JSON = 'yarn audit --json'
12
+ YARN_AUDIT_JSON = 'yarn audit --json --cwd %s'
13
13
  end
14
14
  end
15
15
  end
@@ -2,7 +2,7 @@ module Package
2
2
  module Audit
3
3
  module Const
4
4
  module Fields
5
- ALL = %i[
5
+ AVAILABLE = %i[
6
6
  name
7
7
  version
8
8
  version_date
@@ -14,15 +14,15 @@ module Package
14
14
  risk_explanation
15
15
  ]
16
16
 
17
- REPORT = %i[name version latest_version latest_version_date groups vulnerabilities risk_type risk_explanation]
18
- VULNERABLE = %i[name version latest_version groups vulnerabilities]
17
+ ALL = %i[name version latest_version latest_version_date groups vulnerabilities risk_type risk_explanation]
18
+ DEPRECATED = %i[name version latest_version latest_version_date groups]
19
19
  OUTDATED = %i[name version latest_version latest_version_date groups]
20
+ VULNERABLE = %i[name version latest_version groups vulnerabilities]
20
21
 
21
22
  # the names of these fields must match the instance variables in the Dependency class
22
23
  HEADERS = {
23
24
  name: 'Package',
24
25
  version: 'Version',
25
- version_date: 'Date',
26
26
  latest_version: 'Latest',
27
27
  latest_version_date: 'Latest Date',
28
28
  groups: 'Groups',
@@ -2,6 +2,7 @@ module Package
2
2
  module Audit
3
3
  module Const
4
4
  module File
5
+ CONFIG = '.package-audit.yml'
5
6
  GEMFILE = 'Gemfile'
6
7
  GEMFILE_LOCK = 'Gemfile.lock'
7
8
  PACKAGE_JSON = 'package.json'
@@ -0,0 +1,13 @@
1
+ module Package
2
+ module Audit
3
+ module Const
4
+ module YAML
5
+ DEPRECATED = 'deprecated'
6
+ OUTDATED = 'outdated'
7
+ VULNERABLE = 'vulnerable'
8
+ TECHNOLOGY = 'technology'
9
+ VERSION = 'version'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Package
2
+ module Audit
3
+ module Enum
4
+ module Option
5
+ CONFIG = 'config'
6
+ CSV = 'csv'
7
+ CSV_EXCLUDE_HEADERS = 'exclude-headers'
8
+ INCLUDE_IGNORED = 'include-ignored'
9
+ TECHNOLOGY = 'technology'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Package
2
+ module Audit
3
+ module Enum
4
+ module Report
5
+ ALL = :all
6
+ DEPRECATED = :deprecated
7
+ OUTDATED = :outdated
8
+ VULNERABLE = :vulnerable
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module Package
2
+ module Audit
3
+ module Enum
4
+ module Technology
5
+ NODE = 'node'
6
+ RUBY = 'ruby'
7
+
8
+ def self.all
9
+ constants.map { |key| Enum::Technology.const_get(key) }.sort
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
- require_relative './base'
2
1
  require_relative '../util/bash_color'
2
+ require_relative 'base'
3
3
 
4
4
  module Package
5
5
  module Audit
@@ -1,5 +1,5 @@
1
- require_relative './base'
2
1
  require_relative '../util/bash_color'
2
+ require_relative 'base'
3
3
 
4
4
  module Package
5
5
  module Audit
@@ -1,6 +1,6 @@
1
- require_relative './base'
2
1
  require_relative '../const/time'
3
2
  require_relative '../util/bash_color'
3
+ require_relative 'base'
4
4
 
5
5
  require 'time'
6
6
 
@@ -1,6 +1,6 @@
1
- require_relative './base'
2
1
  require_relative '../enum/vulnerability_type'
3
2
  require_relative '../util/bash_color'
3
+ require_relative 'base'
4
4
 
5
5
  module Package
6
6
  module Audit
@@ -1,18 +1,19 @@
1
- require_relative './risk'
2
- require_relative './risk_calculator'
3
- require_relative './enum/environment'
4
- require_relative './enum/risk_type'
5
- require_relative './enum/risk_explanation'
1
+ require_relative '../enum/environment'
2
+ require_relative '../enum/risk_explanation'
3
+ require_relative '../enum/risk_type'
4
+ require_relative '../services/risk_calculator'
5
+ require_relative 'risk'
6
6
 
7
7
  module Package
8
8
  module Audit
9
9
  class Package
10
- attr_reader :name, :version
10
+ attr_reader :name, :version, :technology
11
11
  attr_accessor :groups, :version_date, :latest_version, :latest_version_date, :vulnerabilities
12
12
 
13
- def initialize(name, version, **attr)
13
+ def initialize(name, version, technology, **attr)
14
14
  @name = name.to_s
15
15
  @version = version.to_s
16
+ @technology = technology.to_s
16
17
  @groups = []
17
18
  @vulnerabilities = []
18
19
  @risks = []
@@ -1,23 +1,34 @@
1
- require_relative './yarn_lock_parser'
2
- require_relative './npm_meta_data'
3
- require_relative './vulnerability_finder'
4
- require_relative '../duplicate_package_merger'
1
+ require_relative '../const/file'
2
+ require_relative '../services/duplicate_package_merger'
3
+ require_relative 'npm_meta_data'
4
+ require_relative 'vulnerability_finder'
5
+ require_relative 'yarn_lock_parser'
5
6
 
6
7
  module Package
7
8
  module Audit
8
9
  module Npm
9
10
  class NodeCollection
10
- PACKAGE_JSON = 'package.json'
11
- PACKAGE_LOCK = 'package-lock.json'
12
- YARN_LOCK = 'yarn.lock'
13
-
14
- def initialize(dir)
11
+ def initialize(dir, report)
15
12
  @dir = dir
13
+ @report = report
14
+ end
15
+
16
+ def fetch
17
+ case @report
18
+ when Enum::Report::DEPRECATED
19
+ deprecated
20
+ when Enum::Report::OUTDATED
21
+ outdated
22
+ when Enum::Report::VULNERABLE
23
+ vulnerable
24
+ else
25
+ all
26
+ end
16
27
  end
17
28
 
18
29
  def all
19
30
  implicit_pkgs = fetch_from_lock_file
20
- vulnerable_pkgs = VulnerabilityFinder.new(implicit_pkgs).run
31
+ vulnerable_pkgs = VulnerabilityFinder.new(@dir, implicit_pkgs).run
21
32
  pkgs = NpmMetaData.new(vulnerable_pkgs + implicit_pkgs).fetch.filter(&:risk?)
22
33
  DuplicatePackageMerger.new(pkgs).run
23
34
  end
@@ -36,7 +47,7 @@ module Package
36
47
 
37
48
  def vulnerable
38
49
  implicit_pkgs = fetch_from_lock_file
39
- vulnerable_pkgs = VulnerabilityFinder.new(implicit_pkgs).run
50
+ vulnerable_pkgs = VulnerabilityFinder.new(@dir, implicit_pkgs).run
40
51
  pkgs = NpmMetaData.new(vulnerable_pkgs).fetch
41
52
  DuplicatePackageMerger.new(pkgs).run
42
53
  end
@@ -44,7 +55,7 @@ module Package
44
55
  private
45
56
 
46
57
  def fetch_from_package_json
47
- package_json = JSON.parse(File.read("#{@dir}/#{PACKAGE_JSON}"), symbolize_names: true)
58
+ package_json = JSON.parse(File.read("#{@dir}/#{Const::File::PACKAGE_JSON}"), symbolize_names: true)
48
59
  default_deps = package_json[:dependencies] || {}
49
60
  dev_deps = package_json[:devDependencies] || {}
50
61
  [default_deps, dev_deps]
@@ -52,8 +63,8 @@ module Package
52
63
 
53
64
  def fetch_from_lock_file
54
65
  default_deps, dev_deps = fetch_from_package_json
55
- if File.exist?("#{@dir}/#{YARN_LOCK}")
56
- YarnLockParser.new("#{@dir}/#{YARN_LOCK}").fetch(default_deps || {}, dev_deps || {})
66
+ if File.exist?("#{@dir}/#{Const::File::YARN_LOCK}")
67
+ YarnLockParser.new("#{@dir}/#{Const::File::YARN_LOCK}").fetch(default_deps || {}, dev_deps || {})
57
68
  else
58
69
  []
59
70
  end
@@ -7,13 +7,14 @@ module Package
7
7
  class VulnerabilityFinder
8
8
  AUDIT_ADVISORY_REGEX = /^{"type":"auditAdvisory".*$/
9
9
 
10
- def initialize(pkgs)
10
+ def initialize(dir, pkgs)
11
+ @dir = dir
11
12
  @pkg_hash = pkgs.to_h { |pkg| [pkg.name, pkg] }
12
13
  @vuln_hash = {}
13
14
  end
14
15
 
15
16
  def run
16
- json_string_lines = `#{Const::Cmd::YARN_AUDIT_JSON}`
17
+ json_string_lines = `#{format(Const::Cmd::YARN_AUDIT_JSON, @dir)}`
17
18
  array = json_string_lines.scan(AUDIT_ADVISORY_REGEX)
18
19
 
19
20
  vulnerability_json_array = JSON.parse("[#{array.join(',')}]", symbolize_names: true)
@@ -33,7 +34,7 @@ module Package
33
34
  full_name = "#{name}@#{version}"
34
35
  vulnerability = advisory[:severity] || Enum::VulnerabilityType::UNKNOWN
35
36
 
36
- @vuln_hash[full_name] = Package.new(name, version) unless @vuln_hash.key? full_name
37
+ @vuln_hash[full_name] = Package.new(name, version, 'node') unless @vuln_hash.key? full_name
37
38
  @vuln_hash[full_name].update vulnerabilities: @vuln_hash[full_name].vulnerabilities + [vulnerability]
38
39
  @vuln_hash[full_name].update groups: @pkg_hash[parent_name].groups
39
40
  end
@@ -3,7 +3,8 @@ module Package
3
3
  module Npm
4
4
  class YarnLockParser
5
5
  def initialize(yarn_lock_path)
6
- @yarn_lock_path = File.read(yarn_lock_path)
6
+ @yarn_lock_file = File.read(yarn_lock_path)
7
+ @yarn_lock_path = yarn_lock_path
7
8
  end
8
9
 
9
10
  def fetch(default_deps, dev_deps)
@@ -11,7 +12,7 @@ module Package
11
12
  default_deps.merge(dev_deps).each do |dep_name, expected_version|
12
13
  pkg_block = fetch_package_block(dep_name, expected_version)
13
14
  version = fetch_package_version(dep_name, pkg_block)
14
- pks = Package.new(dep_name.to_s, version)
15
+ pks = Package.new(dep_name.to_s, version, 'node')
15
16
  pks.update groups: dev_deps.key?(dep_name) ? %i[development] : %i[default development]
16
17
  pkgs << pks
17
18
  end
@@ -22,17 +23,20 @@ module Package
22
23
 
23
24
  def fetch_package_block(dep_name, expected_version)
24
25
  regex = /#{Regexp.escape(dep_name)}@#{Regexp.escape(expected_version)}.*?:.*?(\n\n|\z)/m
25
- blocks = @yarn_lock_path.match(regex)
26
+ blocks = @yarn_lock_file.match(regex)
26
27
  if blocks.nil? || blocks[0].nil?
27
- raise NoMatchingPatternError, "Unable to find #{dep_name} in #{@yarn_lock_path}"
28
+ raise NoMatchingPatternError, "Unable to find \"#{dep_name}\" in #{@yarn_lock_path}"
28
29
  end
29
30
 
30
31
  blocks[0] || ''
31
32
  end
32
33
 
33
34
  def fetch_package_version(dep_name, pkg_block)
34
- version = pkg_block.match(/version "(.*?)"/)&.[](1)
35
- raise NoMatchingPatternError, "Unable to find #{dep_name} version in #{@yarn_lock_path}" if version.nil?
35
+ version = pkg_block.match(/version"?\s*"(.*?)"/)&.captures&.[](0)
36
+ if version.nil?
37
+ raise NoMatchingPatternError,
38
+ "Unable to find the version of \"#{dep_name}\" in #{@yarn_lock_path}"
39
+ end
36
40
 
37
41
  version || '0.0.0.0'
38
42
  end
@@ -1,6 +1,6 @@
1
- require_relative '../package'
2
- require_relative './gem_meta_data'
3
- require_relative './vulnerability_finder'
1
+ require_relative '../models/package'
2
+ require_relative 'gem_meta_data'
3
+ require_relative 'vulnerability_finder'
4
4
 
5
5
  require 'bundler'
6
6
 
@@ -8,16 +8,23 @@ module Package
8
8
  module Audit
9
9
  module Ruby
10
10
  class BundlerSpecs
11
- def self.all
12
- Bundler.ui.silence { Bundler.definition.resolve }
11
+ def self.all(dir)
12
+ Bundler.with_unbundled_env do
13
+ ENV['BUNDLE_GEMFILE'] = "#{dir}/Gemfile"
14
+ Bundler.ui.silence { Bundler.definition.resolve }
15
+ end
13
16
  end
14
17
 
15
- def self.gemfile
16
- current_dependencies = Bundler.ui.silence do
17
- Bundler.load.dependencies.to_h { |dep| [dep.name, dep] }
18
+ def self.gemfile(dir)
19
+ current_dependencies = Bundler.with_unbundled_env do
20
+ ENV['BUNDLE_GEMFILE'] = "#{dir}/Gemfile"
21
+ Bundler.reset!
22
+ Bundler.ui.silence do
23
+ Bundler.load.dependencies.to_h { |dep| [dep.name, dep] }
24
+ end
18
25
  end
19
26
 
20
- gemfile_specs, = all.partition do |spec|
27
+ gemfile_specs, = all(dir).partition do |spec|
21
28
  current_dependencies.key? spec.name
22
29
  end
23
30
  gemfile_specs
@@ -1,35 +1,56 @@
1
- require_relative './bundler_specs'
2
- require_relative './../enum/risk_type'
3
- require_relative '../duplicate_package_merger'
1
+ require_relative '../enum/report'
2
+ require_relative '../enum/risk_type'
3
+ require_relative '../services/duplicate_package_merger'
4
+ require_relative 'bundler_specs'
4
5
 
5
6
  module Package
6
7
  module Audit
7
8
  module Ruby
8
9
  class GemCollection
9
- def self.all
10
- specs = BundlerSpecs.gemfile
11
- pkgs = specs.map { |spec| Package.new(spec.name, spec.version) }
12
- vulnerable_pkgs = VulnerabilityFinder.new.run
10
+ def initialize(dir, report)
11
+ @dir = dir
12
+ @report = report
13
+ end
14
+
15
+ def fetch
16
+ case @report
17
+ when Enum::Report::DEPRECATED
18
+ deprecated
19
+ when Enum::Report::OUTDATED
20
+ outdated
21
+ when Enum::Report::VULNERABLE
22
+ vulnerable
23
+ else
24
+ all
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def all
31
+ specs = BundlerSpecs.gemfile(@dir)
32
+ pkgs = specs.map { |spec| Package.new(spec.name, spec.version, Enum::Technology::RUBY) }
33
+ vulnerable_pkgs = VulnerabilityFinder.new(@dir).run
13
34
  pkgs = GemMetaData.new(pkgs + vulnerable_pkgs).fetch.filter(&:risk?)
14
35
  DuplicatePackageMerger.new(pkgs).run
15
36
  end
16
37
 
17
- def self.deprecated
18
- specs = BundlerSpecs.gemfile
19
- pkgs = specs.map { |spec| Package.new(spec.name, spec.version) }
38
+ def deprecated
39
+ specs = BundlerSpecs.gemfile(@dir)
40
+ pkgs = specs.map { |spec| Package.new(spec.name, spec.version, Enum::Technology::RUBY) }
20
41
  pkgs = GemMetaData.new(pkgs).fetch.filter(&:deprecated?)
21
42
  DuplicatePackageMerger.new(pkgs).run
22
43
  end
23
44
 
24
- def self.outdated(include_implicit: false)
25
- specs = include_implicit ? BundlerSpecs.all : BundlerSpecs.gemfile
26
- pkgs = specs.map { |spec| Package.new(spec.name, spec.version) }
45
+ def outdated(include_implicit: false)
46
+ specs = include_implicit ? BundlerSpecs.all(@dir) : BundlerSpecs.gemfile(@dir)
47
+ pkgs = specs.map { |spec| Package.new(spec.name, spec.version, Enum::Technology::RUBY) }
27
48
  pkgs = GemMetaData.new(pkgs).fetch.filter(&:outdated?)
28
49
  DuplicatePackageMerger.new(pkgs).run
29
50
  end
30
51
 
31
- def self.vulnerable
32
- pkgs = VulnerabilityFinder.new.run
52
+ def vulnerable
53
+ pkgs = VulnerabilityFinder.new(@dir).run
33
54
  pkgs = GemMetaData.new(pkgs).fetch.filter(&:vulnerable?)
34
55
  DuplicatePackageMerger.new(pkgs).run
35
56
  end
@@ -1,4 +1,4 @@
1
- require_relative '../package'
1
+ require_relative '../models/package'
2
2
 
3
3
  module Package
4
4
  module Audit
@@ -5,12 +5,13 @@ module Package
5
5
  module Audit
6
6
  module Ruby
7
7
  class VulnerabilityFinder
8
- def initialize
8
+ def initialize(dir)
9
+ @dir = dir
9
10
  @vuln_hash = {}
10
11
  end
11
12
 
12
13
  def run
13
- json_result = `#{Const::Cmd::BUNDLE_AUDIT_JSON}`
14
+ json_result = `#{format(Const::Cmd::BUNDLE_AUDIT_JSON, @dir)}`
14
15
  vulnerability_json_array = JSON.parse(json_result, symbolize_names: true)[:results]
15
16
  vulnerability_json_array.each do |vulnerability_json|
16
17
  update_meta_data(vulnerability_json)
@@ -25,7 +26,7 @@ module Package
25
26
  version = json[:gem][:version]
26
27
  full_name = "#{name}@#{version}"
27
28
  vulnerability = json[:advisory][:criticality] || Enum::VulnerabilityType::UNKNOWN
28
- @vuln_hash[full_name] = Package.new(name, version) unless @vuln_hash.key? full_name
29
+ @vuln_hash[full_name] = Package.new(name, version, 'ruby') unless @vuln_hash.key? full_name
29
30
  @vuln_hash[full_name].update vulnerabilities: @vuln_hash[full_name].vulnerabilities + [vulnerability]
30
31
  end
31
32
  end