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.
- checksums.yaml +4 -4
- data/lib/package/audit/cli.rb +32 -32
- data/lib/package/audit/const/fields.rb +4 -4
- data/lib/package/audit/const/file.rb +1 -0
- data/lib/package/audit/const/yaml.rb +13 -0
- data/lib/package/audit/enum/option.rb +13 -0
- data/lib/package/audit/enum/report.rb +12 -0
- data/lib/package/audit/enum/technology.rb +14 -0
- data/lib/package/audit/formatter/risk.rb +1 -1
- data/lib/package/audit/formatter/version.rb +1 -1
- data/lib/package/audit/formatter/version_date.rb +1 -1
- data/lib/package/audit/formatter/vulnerability.rb +1 -1
- data/lib/package/audit/{package.rb → models/package.rb} +7 -6
- data/lib/package/audit/npm/node_collection.rb +21 -10
- data/lib/package/audit/npm/vulnerability_finder.rb +1 -1
- data/lib/package/audit/npm/yarn_lock_parser.rb +1 -1
- data/lib/package/audit/ruby/bundler_specs.rb +1 -1
- data/lib/package/audit/ruby/gem_collection.rb +23 -6
- data/lib/package/audit/ruby/gem_meta_data.rb +1 -1
- data/lib/package/audit/ruby/vulnerability_finder.rb +1 -1
- data/lib/package/audit/services/command_parser.rb +103 -0
- data/lib/package/audit/services/package_filter.rb +39 -0
- data/lib/package/audit/services/package_finder.rb +58 -0
- data/lib/package/audit/{printer.rb → services/package_printer.rb} +12 -11
- data/lib/package/audit/{risk_calculator.rb → services/risk_calculator.rb} +8 -4
- data/lib/package/audit/technology/detector.rb +40 -0
- data/lib/package/audit/technology/validator.rb +56 -0
- data/lib/package/audit/util/summary_printer.rb +20 -9
- data/lib/package/audit/version.rb +1 -1
- data/sig/package/audit/cli.rbs +2 -0
- data/sig/package/audit/const/fields.rbs +2 -1
- data/sig/package/audit/const/file.rbs +1 -0
- data/sig/package/audit/const/yaml.rbs +13 -0
- data/sig/package/audit/enum/option.rbs +13 -0
- data/sig/package/audit/enum/report.rbs +12 -0
- data/sig/package/audit/enum/technology.rbs +12 -0
- data/sig/package/audit/{package.rbs → models/package.rbs} +3 -1
- data/sig/package/audit/{risk.rbs → models/risk.rbs} +1 -1
- data/sig/package/audit/npm/node_collection.rbs +4 -5
- data/sig/package/audit/npm/vulnerability_finder.rbs +1 -1
- data/sig/package/audit/ruby/gem_collection.rbs +4 -1
- data/sig/package/audit/services/command_parser.rbs +31 -0
- data/sig/package/audit/services/package_filter.rbs +19 -0
- data/sig/package/audit/services/package_finder.rbs +23 -0
- data/sig/package/audit/{printer.rbs → services/package_printer.rbs} +3 -3
- data/sig/package/audit/technology/detector.rbs +19 -0
- data/sig/package/audit/technology/validator.rbs +19 -0
- data/sig/package/audit/util/summary_printer.rbs +5 -5
- metadata +30 -14
- data/lib/package/audit/command_service.rb +0 -187
- data/sig/package/audit/command_service.rbs +0 -29
- /data/lib/package/audit/{risk.rb → models/risk.rb} +0 -0
- /data/lib/package/audit/{duplicate_package_merger.rb → services/duplicate_package_merger.rb} +0 -0
- /data/sig/package/audit/{duplicate_package_merger.rbs → services/duplicate_package_merger.rbs} +0 -0
- /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 '
|
3
|
-
require_relative 'formatter/
|
4
|
-
require_relative 'formatter/
|
5
|
-
require_relative 'formatter/
|
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
|
10
|
+
class PackagePrinter
|
10
11
|
BASH_FORMATTING_REGEX = /\e\[\d+(?:;\d+)*m/
|
11
12
|
|
12
13
|
COLUMN_GAP = 2
|
13
14
|
|
14
|
-
def initialize(
|
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[
|
24
|
-
csv(fields, exclude_headers: @options[
|
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::
|
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.
|
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(
|
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 #{
|
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(
|
26
|
-
|
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(
|
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
|
-
|
37
|
-
|
38
|
-
|
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
|
data/sig/package/audit/cli.rbs
CHANGED
@@ -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
|
|
@@ -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]
|
@@ -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
|
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[
|
9
|
+
@options: Hash[String, untyped]
|
10
10
|
|
11
|
-
def initialize: (
|
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.
|
5
|
+
def self.all: -> void
|
6
6
|
|
7
|
-
def self.
|
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
|