package-audit 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/lib/package/audit/cli.rb +32 -32
  3. data/lib/package/audit/const/fields.rb +4 -4
  4. data/lib/package/audit/const/file.rb +1 -0
  5. data/lib/package/audit/const/yaml.rb +13 -0
  6. data/lib/package/audit/enum/option.rb +13 -0
  7. data/lib/package/audit/enum/report.rb +12 -0
  8. data/lib/package/audit/enum/technology.rb +14 -0
  9. data/lib/package/audit/formatter/risk.rb +1 -1
  10. data/lib/package/audit/formatter/version.rb +1 -1
  11. data/lib/package/audit/formatter/version_date.rb +1 -1
  12. data/lib/package/audit/formatter/vulnerability.rb +1 -1
  13. data/lib/package/audit/{package.rb → models/package.rb} +7 -6
  14. data/lib/package/audit/npm/node_collection.rb +21 -10
  15. data/lib/package/audit/npm/vulnerability_finder.rb +1 -1
  16. data/lib/package/audit/npm/yarn_lock_parser.rb +1 -1
  17. data/lib/package/audit/ruby/bundler_specs.rb +1 -1
  18. data/lib/package/audit/ruby/gem_collection.rb +23 -6
  19. data/lib/package/audit/ruby/gem_meta_data.rb +1 -1
  20. data/lib/package/audit/ruby/vulnerability_finder.rb +1 -1
  21. data/lib/package/audit/services/command_parser.rb +103 -0
  22. data/lib/package/audit/services/package_filter.rb +39 -0
  23. data/lib/package/audit/services/package_finder.rb +58 -0
  24. data/lib/package/audit/{printer.rb → services/package_printer.rb} +12 -11
  25. data/lib/package/audit/{risk_calculator.rb → services/risk_calculator.rb} +8 -4
  26. data/lib/package/audit/technology/detector.rb +40 -0
  27. data/lib/package/audit/technology/validator.rb +56 -0
  28. data/lib/package/audit/util/summary_printer.rb +20 -9
  29. data/lib/package/audit/version.rb +1 -1
  30. data/sig/package/audit/cli.rbs +2 -0
  31. data/sig/package/audit/const/fields.rbs +2 -1
  32. data/sig/package/audit/const/file.rbs +1 -0
  33. data/sig/package/audit/const/yaml.rbs +13 -0
  34. data/sig/package/audit/enum/option.rbs +13 -0
  35. data/sig/package/audit/enum/report.rbs +12 -0
  36. data/sig/package/audit/enum/technology.rbs +12 -0
  37. data/sig/package/audit/{package.rbs → models/package.rbs} +3 -1
  38. data/sig/package/audit/{risk.rbs → models/risk.rbs} +1 -1
  39. data/sig/package/audit/npm/node_collection.rbs +4 -5
  40. data/sig/package/audit/npm/vulnerability_finder.rbs +1 -1
  41. data/sig/package/audit/ruby/gem_collection.rbs +4 -1
  42. data/sig/package/audit/services/command_parser.rbs +31 -0
  43. data/sig/package/audit/services/package_filter.rbs +19 -0
  44. data/sig/package/audit/services/package_finder.rbs +23 -0
  45. data/sig/package/audit/{printer.rbs → services/package_printer.rbs} +3 -3
  46. data/sig/package/audit/technology/detector.rbs +19 -0
  47. data/sig/package/audit/technology/validator.rbs +19 -0
  48. data/sig/package/audit/util/summary_printer.rbs +5 -5
  49. metadata +30 -14
  50. data/lib/package/audit/command_service.rb +0 -187
  51. data/sig/package/audit/command_service.rbs +0 -29
  52. /data/lib/package/audit/{risk.rb → models/risk.rb} +0 -0
  53. /data/lib/package/audit/{duplicate_package_merger.rb → services/duplicate_package_merger.rb} +0 -0
  54. /data/sig/package/audit/{duplicate_package_merger.rbs → services/duplicate_package_merger.rbs} +0 -0
  55. /data/sig/package/audit/{risk_calculator.rbs → services/risk_calculator.rbs} +0 -0
@@ -1,27 +1,28 @@
1
- require_relative 'const/fields'
2
- require_relative 'formatter/risk'
3
- require_relative 'formatter/version'
4
- require_relative 'formatter/version_date'
5
- require_relative 'formatter/vulnerability'
1
+ require_relative '../const/fields'
2
+ require_relative '../enum/option'
3
+ require_relative '../formatter/risk'
4
+ require_relative '../formatter/version'
5
+ require_relative '../formatter/version_date'
6
+ require_relative '../formatter/vulnerability'
6
7
 
7
8
  module Package
8
9
  module Audit
9
- class Printer
10
+ class PackagePrinter
10
11
  BASH_FORMATTING_REGEX = /\e\[\d+(?:;\d+)*m/
11
12
 
12
13
  COLUMN_GAP = 2
13
14
 
14
- def initialize(pkgs, options)
15
- @pkgs = pkgs
15
+ def initialize(options, pkgs)
16
16
  @options = options
17
+ @pkgs = pkgs
17
18
  end
18
19
 
19
20
  def print(fields)
20
21
  check_fields(fields)
21
22
  return if @pkgs.empty?
22
23
 
23
- if @options[:csv]
24
- csv(fields, exclude_headers: @options[:'exclude-headers'])
24
+ if @options[Enum::Option::CSV]
25
+ csv(fields, exclude_headers: @options[Enum::Option::CSV_EXCLUDE_HEADERS])
25
26
  else
26
27
  pretty(fields)
27
28
  end
@@ -38,7 +39,7 @@ module Package
38
39
  "Available fields names are: #{Const::Fields::ALL}."
39
40
  end
40
41
 
41
- def pretty(fields = Const::Fields::REPORT) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
42
+ def pretty(fields = Const::Fields::ALL) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
42
43
  # find the maximum length of each field across all the packages so we know how many
43
44
  # characters of horizontal space to allocate for each field when printing
44
45
  fields.each do |key|
@@ -1,4 +1,7 @@
1
- require_relative 'const/time'
1
+ require_relative '../const/time'
2
+ require_relative '../enum/vulnerability_type'
3
+
4
+ require 'time'
2
5
 
3
6
  module Package
4
7
  module Audit
@@ -62,12 +65,13 @@ module Package
62
65
  end
63
66
 
64
67
  def assess_deprecation_risks
68
+ risk = Risk.new(Enum::RiskType::MEDIUM, Enum::RiskExplanation::POTENTIAL_DEPRECATION)
69
+ return [risk] if @pkg.latest_version_date.nil?
70
+
65
71
  risks = []
66
72
  seconds_since_date = (Time.now - Time.parse(@pkg.latest_version_date)).to_i
67
73
 
68
- if seconds_since_date >= Const::Time::SECONDS_ELAPSED_TO_BE_OUTDATED
69
- risks << Risk.new(Enum::RiskType::MEDIUM, Enum::RiskExplanation::POTENTIAL_DEPRECATION)
70
- end
74
+ risks << risk if seconds_since_date >= Const::Time::SECONDS_ELAPSED_TO_BE_OUTDATED
71
75
  risks
72
76
  end
73
77
 
@@ -0,0 +1,40 @@
1
+ require_relative '../const/cmd'
2
+ require_relative '../const/file'
3
+ require_relative '../enum/report'
4
+ require_relative '../enum/technology'
5
+
6
+ require 'yaml'
7
+
8
+ module Package
9
+ module Audit
10
+ module Technology
11
+ class Detector
12
+ def initialize(dir)
13
+ @dir = dir
14
+ end
15
+
16
+ def detect
17
+ technologies = []
18
+ technologies << Enum::Technology::RUBY if ruby?
19
+ technologies << Enum::Technology::NODE if node?
20
+ technologies.sort
21
+ end
22
+
23
+ private
24
+
25
+ def node?
26
+ package_json_present = File.exist?("#{@dir}/#{Const::File::PACKAGE_JSON}")
27
+ package_lock_json_present = File.exist?("#{@dir}/#{Const::File::PACKAGE_LOCK_JSON}")
28
+ yarn_lock_present = File.exist?("#{@dir}/#{Const::File::YARN_LOCK}")
29
+ package_json_present && (package_lock_json_present || yarn_lock_present)
30
+ end
31
+
32
+ def ruby?
33
+ gemfile_present = File.exist?("#{@dir}/#{Const::File::GEMFILE}")
34
+ gemfile_lock_present = File.exist?("#{@dir}/#{Const::File::GEMFILE_LOCK}")
35
+ gemfile_present && gemfile_lock_present
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,56 @@
1
+ require_relative '../const/file'
2
+ require_relative '../enum/technology'
3
+
4
+ module Package
5
+ module Audit
6
+ module Technology
7
+ class Validator
8
+ def initialize(dir)
9
+ @dir = dir
10
+ end
11
+
12
+ def validate!(technology)
13
+ case technology
14
+ when Enum::Technology::NODE
15
+ validate_node!
16
+ when Enum::Technology::RUBY
17
+ validate_ruby!
18
+ else
19
+ raise ArgumentError, "\"#{technology}\" is not a supported technology, " \
20
+ "use one of #{Enum::Technology.all}"
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def validate_node!
27
+ package_json_present = File.exist?("#{@dir}/#{Const::File::PACKAGE_JSON}")
28
+ package_lock_json_present = File.exist?("#{@dir}/#{Const::File::PACKAGE_LOCK_JSON}")
29
+ yarn_lock_present = File.exist?("#{@dir}/#{Const::File::YARN_LOCK}")
30
+
31
+ unless package_json_present
32
+ puts Util::BashColor.red("\"#{Const::File::PACKAGE_JSON}\" was not found in #{@dir}")
33
+ end
34
+ unless package_lock_json_present || yarn_lock_present
35
+ puts Util::BashColor.red("\"#{Const::File::PACKAGE_LOCK_JSON}\" or \"#{Const::File::YARN_LOCK}\" " \
36
+ "was not found in #{@dir}")
37
+ end
38
+
39
+ exit 1 unless package_json_present && (package_lock_json_present || yarn_lock_present)
40
+ end
41
+
42
+ def validate_ruby!
43
+ gemfile_present = File.exist?("#{@dir}/#{Const::File::GEMFILE}")
44
+ gemfile_lock_present = File.exist?("#{@dir}/#{Const::File::GEMFILE_LOCK}")
45
+
46
+ puts Util::BashColor.red("\"#{Const::File::GEMFILE}\" was not found in #{@dir}") unless gemfile_present
47
+ unless gemfile_lock_present
48
+ puts Util::BashColor.red("\"#{Const::File::GEMFILE_LOCK}\" was not found in #{@dir}")
49
+ end
50
+
51
+ exit 1 unless gemfile_present && gemfile_lock_present
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -5,7 +5,7 @@ module Package
5
5
  module Audit
6
6
  module Util
7
7
  module SummaryPrinter
8
- def self.report
8
+ def self.all
9
9
  printf("\n%<info>s\n%<cmd>s\n\n",
10
10
  info: Util::BashColor.blue('To show how risk is calculated run:'),
11
11
  cmd: Util::BashColor.magenta(' > package-audit risk'))
@@ -16,26 +16,37 @@ module Package
16
16
  puts Util::BashColor.blue("Please contact the package author for more information about its status.\n")
17
17
  end
18
18
 
19
- def self.vulnerable(package_type, cmd)
19
+ def self.vulnerable(technology, cmd)
20
20
  printf("%<info>s\n%<cmd>s\n\n",
21
- info: Util::BashColor.blue("To get more information about the #{package_type} vulnerabilities run:"),
21
+ info: Util::BashColor.blue("To get more information about the #{technology} vulnerabilities run:"),
22
22
  cmd: Util::BashColor.magenta(" > #{cmd}"))
23
23
  end
24
24
 
25
- def self.total(package_type, pkgs)
26
- puts Util::BashColor.cyan("Found a total of #{pkgs.length} #{package_type}s.\n")
25
+ def self.total(technology, report, pkgs, ignored_pkgs)
26
+ if ignored_pkgs.any?
27
+ puts Util::BashColor.cyan("Found a total of #{pkgs.length} #{technology} packages " \
28
+ "(#{ignored_pkgs.length} ignored).\n")
29
+ elsif pkgs.any?
30
+ puts Util::BashColor.cyan("Found a total of #{pkgs.length} #{technology} packages.\n")
31
+ else
32
+ puts Util::BashColor.green("There are no #{report} #{technology} packages!\n")
33
+ end
27
34
  end
28
35
 
29
- def self.statistics(package_type, pkgs)
36
+ def self.statistics(technology, report, pkgs, ignored_pkgs)
30
37
  outdated = pkgs.count(&:outdated?)
31
38
  deprecated = pkgs.count(&:deprecated?)
32
39
  vulnerable = pkgs.count(&:vulnerable?)
33
40
 
34
41
  vulnerabilities = pkgs.sum { |pkg| pkg.vulnerabilities.length }
35
42
 
36
- puts Util::BashColor.cyan("Found a total of #{pkgs.length} #{package_type}s.\n" \
37
- "#{vulnerable} vulnerable (#{vulnerabilities} vulnerabilities), " \
38
- "#{outdated} outdated, #{deprecated} deprecated.\n")
43
+ if pkgs.any?
44
+ puts Util::BashColor.cyan("#{vulnerable} vulnerable (#{vulnerabilities} vulnerabilities), " \
45
+ "#{outdated} outdated, #{deprecated} deprecated.")
46
+ total(technology, report, pkgs, ignored_pkgs)
47
+ else
48
+ puts Util::BashColor.green("There are no deprecated, outdated or vulnerable #{technology} packages!\n")
49
+ end
39
50
  end
40
51
 
41
52
  def self.risk # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@@ -1,5 +1,5 @@
1
1
  module Package
2
2
  module Audit
3
- VERSION = '0.3.0'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
@@ -9,6 +9,8 @@ module Package
9
9
 
10
10
  def report: (String) -> void
11
11
 
12
+ def respond_to_missing?: -> bool
13
+
12
14
  def risk: -> void
13
15
 
14
16
  def version: -> void
@@ -3,9 +3,10 @@ module Package
3
3
  module Const
4
4
  module Fields
5
5
  ALL: Array[Symbol]
6
+ AVAILABLE: Array[Symbol]
7
+ DEPRECATED: Array[Symbol]
6
8
  HEADERS: Hash[Symbol, String]
7
9
  OUTDATED: Array[Symbol]
8
- REPORT: Array[Symbol]
9
10
  VULNERABLE: Array[Symbol]
10
11
  end
11
12
  end
@@ -2,6 +2,7 @@ module Package
2
2
  module Audit
3
3
  module Const
4
4
  module File
5
+ CONFIG: String
5
6
  GEMFILE: String
6
7
  GEMFILE_LOCK: String
7
8
  PACKAGE_JSON: String
@@ -0,0 +1,13 @@
1
+ module Package
2
+ module Audit
3
+ module Const
4
+ module YAML
5
+ DEPRECATED: String
6
+ OUTDATED: String
7
+ TECHNOLOGY: String
8
+ VERSION: String
9
+ VULNERABLE: String
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: String
6
+ CSV: String
7
+ CSV_EXCLUDE_HEADERS: String
8
+ INCLUDE_IGNORED: String
9
+ TECHNOLOGY: String
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: Symbol
6
+ DEPRECATED: Symbol
7
+ OUTDATED: Symbol
8
+ VULNERABLE: Symbol
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Package
2
+ module Audit
3
+ module Enum
4
+ module Technology
5
+ NODE: String
6
+ RUBY: String
7
+
8
+ def self.all: -> Array[String]
9
+ end
10
+ end
11
+ end
12
+ end
@@ -3,17 +3,19 @@ module Package
3
3
  class Package
4
4
  @groups: Array[Symbol]
5
5
  @risks: Array[Risk]
6
+ @technology: String
6
7
  @vulnerabilities: Array[String]
7
8
 
8
9
  attr_accessor groups: Array[Symbol]
9
10
  attr_accessor latest_version: String
10
11
  attr_accessor latest_version_date: String
11
12
  attr_reader name: String
13
+ attr_reader technology: String
12
14
  attr_reader version: String
13
15
  attr_accessor version_date: String
14
16
  attr_accessor vulnerabilities: Array[String]
15
17
 
16
- def initialize: (String, String, **untyped) -> void
18
+ def initialize: (String, String, String, **untyped) -> void
17
19
 
18
20
  def deprecated?: -> bool
19
21
 
@@ -4,7 +4,7 @@ module Package
4
4
  attr_reader explanation: String?
5
5
  attr_reader type: String
6
6
 
7
- def initialize: (String, ?String?)-> void
7
+ def initialize: (String, ?String?) -> void
8
8
 
9
9
  def <=>: (Risk) -> Integer?
10
10
  end
@@ -2,18 +2,17 @@ module Package
2
2
  module Audit
3
3
  module Npm
4
4
  class NodeCollection
5
- PACKAGE_JSON: String
6
- PACKAGE_LOCK: String
7
- YARN_LOCK: String
8
-
9
5
  @dir: String
6
+ @report: Symbol
10
7
 
11
- def initialize: (String) -> void
8
+ def initialize: (String, Symbol) -> void
12
9
 
13
10
  def all: -> Array[Package]
14
11
 
15
12
  def deprecated: -> Array[Package]
16
13
 
14
+ def fetch: -> Array[Package]
15
+
17
16
  def outdated: -> Array[Package]
18
17
 
19
18
  def vulnerable: -> Array[Package]
@@ -14,7 +14,7 @@ module Package
14
14
 
15
15
  private
16
16
 
17
- def update_meta_data: (Hash[Symbol, untyped])-> void
17
+ def update_meta_data: (Hash[Symbol, untyped]) -> void
18
18
  end
19
19
  end
20
20
  end
@@ -3,13 +3,16 @@ module Package
3
3
  module Ruby
4
4
  class GemCollection
5
5
  @dir: String
6
+ @report: Symbol
6
7
 
7
- def initialize: (String) -> void
8
+ def initialize: (String, Symbol) -> void
8
9
 
9
10
  def all: -> Array[Package]
10
11
 
11
12
  def deprecated: -> Array[Package]
12
13
 
14
+ def fetch: -> Array[Package]
15
+
13
16
  def outdated: (?include_implicit: bool) -> Array[Package]
14
17
 
15
18
  def vulnerable: -> Array[Package]
@@ -0,0 +1,31 @@
1
+ module Package
2
+ module Audit
3
+ class CommandParser
4
+ @config: Hash[String, untyped]?
5
+ @dir: String
6
+ @options: Hash[String, untyped]
7
+ @report: Symbol
8
+ @technologies: Array[String]
9
+
10
+ def initialize: (String, Hash[String, untyped], Symbol) -> void
11
+
12
+ def run: -> bool
13
+
14
+ private
15
+
16
+ def learn_more_command: (String) -> String?
17
+
18
+ def parse_config_file: -> Hash[String, untyped]?
19
+
20
+ def parse_technologies: -> Array[String]
21
+
22
+ def print_disclaimer: (String) -> void
23
+
24
+ def print_results: (String, Array[Package], Array[Package]) -> void
25
+
26
+ def print_summary: (String, Array[Package], Array[Package]) -> void
27
+
28
+ def report_fields: -> Array[Symbol]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ module Package
2
+ module Audit
3
+ class PackageFilter
4
+ @config: Hash[String, untyped]?
5
+
6
+ def initialize: (Hash[String, untyped]?) -> void
7
+
8
+ def ignored?: (Package) -> bool
9
+
10
+ private
11
+
12
+ def ignore_package?: (Package, Hash[String, untyped]?) -> bool
13
+
14
+ def pkg_version_in_config?: (Package, Hash[String, untyped]?) -> bool
15
+
16
+ def pkg_yaml_from_config: (Package) -> Hash[String, untyped]?
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ module Package
2
+ module Audit
3
+ class PackageFinder
4
+ @config: Hash[String, untyped]?
5
+ @dir: String
6
+ @report: Symbol
7
+
8
+ def initialize: (Hash[String, untyped]?, String, Symbol) -> void
9
+
10
+ def run: (String) -> Array[Array[Package]]
11
+
12
+ private
13
+
14
+ def filter_pkgs_based_on_config: (Array[Package]) -> Array[Package]
15
+
16
+ def find_by_technology: (String) -> Array[Package]
17
+
18
+ def find_node: -> Array[Package]
19
+
20
+ def find_ruby: -> Array[Package]
21
+ end
22
+ end
23
+ end
@@ -1,14 +1,14 @@
1
1
  module Package
2
2
  module Audit
3
- class Printer
3
+ class PackagePrinter
4
4
  BASH_FORMATTING_REGEX: Regexp
5
5
  COLUMN_GAP: Integer
6
6
  CSV_HEADERS: Hash[Symbol, String]
7
7
 
8
8
  @pkgs: Array[Package]
9
- @options: Hash[Symbol, untyped]
9
+ @options: Hash[String, untyped]
10
10
 
11
- def initialize: (Array[Package], Hash[Symbol, untyped]) -> void
11
+ def initialize: (Hash[String, untyped], Array[Package]) -> void
12
12
 
13
13
  def print: (Array[Symbol]) -> void
14
14
 
@@ -0,0 +1,19 @@
1
+ module Package
2
+ module Audit
3
+ module Technology
4
+ class Detector
5
+ @dir: String
6
+
7
+ def initialize: (String) -> void
8
+
9
+ def detect: -> Array[String]
10
+
11
+ private
12
+
13
+ def node?: -> bool
14
+
15
+ def ruby?: -> bool
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Package
2
+ module Audit
3
+ module Technology
4
+ class Validator
5
+ @dir: String
6
+
7
+ def initialize: (String) -> void
8
+
9
+ def validate!: (String) -> void
10
+
11
+ private
12
+
13
+ def validate_node!: -> void
14
+
15
+ def validate_ruby!: -> void
16
+ end
17
+ end
18
+ end
19
+ end
@@ -2,17 +2,17 @@ module Package
2
2
  module Audit
3
3
  module Util
4
4
  module SummaryPrinter
5
- def self.deprecated: -> void
5
+ def self.all: -> void
6
6
 
7
- def self.report: -> void
7
+ def self.deprecated: -> void
8
8
 
9
9
  def self.risk: -> void
10
10
 
11
- def self.statistics: (String, Array[Package]) -> void
11
+ def self.statistics: (String, Symbol, Array[Package], Array[Package]) -> void
12
12
 
13
- def self.total: (String, Array[Package]) -> void
13
+ def self.total: (String, Symbol, Array[Package], Array[Package]) -> void
14
14
 
15
- def self.vulnerable: (String, String) -> void
15
+ def self.vulnerable: (String, String?) -> void
16
16
  end
17
17
  end
18
18
  end