package-audit 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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