package-audit 0.7.1 → 0.8.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a14d75d3c6f64af8c327c492e0d0c1bcf98fc3119964e63d944fc33fc6ce6b8e
4
- data.tar.gz: 01f5eaac43d53a65ac42a46a736793b8dbe56f4ad3531a8e649d9516b85a5027
3
+ metadata.gz: d613e9a49c48ae22ef6e156b7f6a6ba1f2ebe8172e30589cc2eabbb5530bfdc1
4
+ data.tar.gz: aad9e813b4e6d2b73f15b19626fbc70631312d8965823a27d44cceef4c5115aa
5
5
  SHA512:
6
- metadata.gz: 9f2599769354017f84a5eb4f5da8cb6b67b69be12ed6f67126ed0701b1746461960c24ecd1ba7d2cf81d5719ca18234f1f9bdcb645a5bb9d8916faaca040ee96
7
- data.tar.gz: 9eeeb933dd6e5535c0fdcdfca6fea339ca34fc1a611460b68ea0274da083ec08be63424eb82c7229ed939cf05fe49621bbf9f4d04af9abffc6001f7a43e507cb
6
+ metadata.gz: e6b3406928eb792637f7fbf5de5745a83ae1ce7181febc24d95882c6e38281002bcb953b3f727e18cf983606285f4df428aa36c203ed874a9d919c47c53dad9f
7
+ data.tar.gz: c6abc41931c2c26b91443474262353b35a0c64b0d2372258fec255f4f9569c127c3e48a172a219ec1fbd5a71fb7d4e3f15a6bbd6e2f717bb8b65ae0da74ec31f
@@ -14,15 +14,24 @@ module Package
14
14
  class CLI < Thor
15
15
  default_task :default
16
16
 
17
- class_option Enum::Option::CONFIG,
18
- aliases: '-c', banner: 'FILE',
19
- desc: "Path to a custom configuration file, default: #{Const::File::CONFIG})"
20
- class_option Enum::Option::GROUP,
21
- aliases: '-g', repeatable: true,
22
- desc: 'Group to be audited (repeat this flag for each group)'
17
+ class_option Enum::Option::DEPRECATED,
18
+ type: :boolean,
19
+ desc: 'Filter to show only deprecated packages (or use --skip-deprecated to exclude them)'
20
+ class_option Enum::Option::OUTDATED,
21
+ type: :boolean,
22
+ desc: 'Filter to show only outdated packages (or use --skip-outdated to exclude them)'
23
+ class_option Enum::Option::VULNERABLE,
24
+ type: :boolean,
25
+ desc: 'Filter to show only vulnerable packages (or use --skip-vulnerable to exclude them)'
23
26
  class_option Enum::Option::TECHNOLOGY,
24
27
  aliases: '-t', repeatable: true,
25
28
  desc: 'Technology to be audited (repeat this flag for each technology)'
29
+ class_option Enum::Option::GROUP,
30
+ aliases: '-g', repeatable: true,
31
+ desc: 'Group to be audited (repeat this flag for each group)'
32
+ class_option Enum::Option::CONFIG,
33
+ aliases: '-c', banner: 'FILE',
34
+ desc: "Path to a custom configuration file, default: #{Const::File::CONFIG})"
26
35
  class_option Enum::Option::INCLUDE_IGNORED,
27
36
  type: :boolean, default: false,
28
37
  desc: 'Include packages ignored by a configuration file'
@@ -38,23 +47,8 @@ module Package
38
47
 
39
48
  desc '[DIR]', 'Show a report of potentially deprecated, outdated or vulnerable packages'
40
49
  def default(dir = Dir.pwd)
41
- within_rescue_block { exit CommandParser.new(dir, options, Enum::Report::ALL).run }
42
- end
43
-
44
- desc 'deprecated [DIR]',
45
- "Show packages with no updates by author for at least #{Const::Time::YEARS_ELAPSED_TO_BE_OUTDATED} years"
46
- def deprecated(dir = Dir.pwd)
47
- within_rescue_block { exit CommandParser.new(dir, options, Enum::Report::DEPRECATED).run }
48
- end
49
-
50
- desc 'outdated [DIR]', 'Show packages that are out of date'
51
- def outdated(dir = Dir.pwd)
52
- within_rescue_block { exit CommandParser.new(dir, options, Enum::Report::OUTDATED).run }
53
- end
54
-
55
- desc 'vulnerable [DIR]', 'Show packages and their dependencies that have security vulnerabilities'
56
- def vulnerable(dir = Dir.pwd)
57
- within_rescue_block { exit CommandParser.new(dir, options, Enum::Report::VULNERABLE).run }
50
+ report = determine_report_type
51
+ within_rescue_block { exit CommandParser.new(dir, options, report).run }
58
52
  end
59
53
 
60
54
  desc 'risk', 'Print information on how risk is calculated'
@@ -81,6 +75,37 @@ module Package
81
75
 
82
76
  private
83
77
 
78
+ def determine_report_type # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
79
+ deprecated = options[Enum::Option::DEPRECATED]
80
+ outdated = options[Enum::Option::OUTDATED]
81
+ vulnerable = options[Enum::Option::VULNERABLE]
82
+
83
+ # Count positive filters (true) and negative filters (false)
84
+ positive_filters = [deprecated, outdated, vulnerable].count(true)
85
+ negative_filters = [deprecated, outdated, vulnerable].count(false)
86
+
87
+ # If any explicit filters are set (positive or negative), we need to filter
88
+ # Otherwise all are nil (not specified) and we show everything
89
+ has_explicit_filters = [deprecated, outdated, vulnerable].any? { |v| !v.nil? }
90
+
91
+ # If no filters specified at all, return ALL
92
+ return Enum::Report::ALL unless has_explicit_filters
93
+
94
+ # If only positive filters, handle them
95
+ if positive_filters.positive? && negative_filters.zero?
96
+ # Single positive filter - use specific report type
97
+ return Enum::Report::DEPRECATED if positive_filters == 1 && deprecated
98
+ return Enum::Report::OUTDATED if positive_filters == 1 && outdated
99
+ return Enum::Report::VULNERABLE if positive_filters == 1 && vulnerable
100
+
101
+ # Multiple positive filters - fetch ALL and filter in CommandParser
102
+ return Enum::Report::ALL
103
+ end
104
+
105
+ # If we have any filters (positive or negative), fetch ALL and filter in CommandParser
106
+ Enum::Report::ALL
107
+ end
108
+
84
109
  def within_rescue_block
85
110
  yield
86
111
  rescue StandardError => e
@@ -8,13 +8,12 @@ module Package
8
8
  version_date
9
9
  latest_version
10
10
  latest_version_date
11
- groups
11
+ flags
12
12
  vulnerabilities
13
13
  risk_type
14
- risk_explanation
15
14
  ]
16
15
 
17
- DEFAULT = %i[name version latest_version latest_version_date groups vulnerabilities risk_type risk_explanation]
16
+ DEFAULT = %i[name version latest_version latest_version_date flags vulnerabilities risk_type]
18
17
 
19
18
  # the names of these fields must match the instance variables in the Dependency class
20
19
  HEADERS = {
@@ -23,10 +22,9 @@ module Package
23
22
  version_date: 'Version Date',
24
23
  latest_version: 'Latest',
25
24
  latest_version_date: 'Latest Date',
26
- groups: 'Groups',
25
+ flags: 'Flags',
27
26
  vulnerabilities: 'Vulnerabilities',
28
- risk_type: 'Risk',
29
- risk_explanation: 'Risk Explanation'
27
+ risk_type: 'Risk'
30
28
  }
31
29
  end
32
30
  end
@@ -8,6 +8,9 @@ module Package
8
8
  GROUP = 'group'
9
9
  INCLUDE_IGNORED = 'include-ignored'
10
10
  TECHNOLOGY = 'technology'
11
+ DEPRECATED = 'deprecated'
12
+ OUTDATED = 'outdated'
13
+ VULNERABLE = 'vulnerable'
11
14
  end
12
15
  end
13
16
  end
@@ -80,6 +80,13 @@ module Package
80
80
  false
81
81
  end
82
82
 
83
+ def flags
84
+ v = vulnerable? ? 'V' : '·'
85
+ o = outdated? ? 'O' : '·'
86
+ d = deprecated? ? 'D' : '·'
87
+ "⦗#{v}#{o}#{d}⦘"
88
+ end
89
+
83
90
  def to_csv(fields)
84
91
  fields.map { |field| send(field) }.join(',')
85
92
  end
@@ -35,13 +35,15 @@ module Package
35
35
 
36
36
  def deprecated
37
37
  implicit_pkgs = fetch_from_lock_file
38
- pkgs = NpmMetaData.new(implicit_pkgs).fetch.filter(&:deprecated?)
38
+ vulnerable_pkgs = VulnerabilityFinder.new(@dir, implicit_pkgs).run
39
+ pkgs = NpmMetaData.new(vulnerable_pkgs + implicit_pkgs).fetch.filter(&:deprecated?)
39
40
  DuplicatePackageMerger.new(pkgs).run
40
41
  end
41
42
 
42
43
  def outdated
43
44
  implicit_pkgs = fetch_from_lock_file
44
- pkgs = NpmMetaData.new(implicit_pkgs).fetch.filter(&:outdated?)
45
+ vulnerable_pkgs = VulnerabilityFinder.new(@dir, implicit_pkgs).run
46
+ pkgs = NpmMetaData.new(vulnerable_pkgs + implicit_pkgs).fetch.filter(&:outdated?)
45
47
  DuplicatePackageMerger.new(pkgs).run
46
48
  end
47
49
 
@@ -38,14 +38,16 @@ module Package
38
38
  def deprecated
39
39
  specs = BundlerSpecs.gemfile(@dir)
40
40
  pkgs = specs.map { |spec| Package.new(spec.name, spec.version, Enum::Technology::RUBY) }
41
- pkgs = GemMetaData.new(@dir, pkgs).fetch.filter(&:deprecated?)
41
+ vulnerable_pkgs = VulnerabilityFinder.new(@dir).run
42
+ pkgs = GemMetaData.new(@dir, pkgs + vulnerable_pkgs).fetch.filter(&:deprecated?)
42
43
  DuplicatePackageMerger.new(pkgs).run
43
44
  end
44
45
 
45
46
  def outdated(include_implicit: false)
46
47
  specs = include_implicit ? BundlerSpecs.all(@dir) : BundlerSpecs.gemfile(@dir)
47
48
  pkgs = specs.map { |spec| Package.new(spec.name, spec.version, Enum::Technology::RUBY) }
48
- pkgs = GemMetaData.new(@dir, pkgs).fetch.filter(&:outdated?)
49
+ vulnerable_pkgs = VulnerabilityFinder.new(@dir).run
50
+ pkgs = GemMetaData.new(@dir, pkgs + vulnerable_pkgs).fetch.filter(&:outdated?)
49
51
  DuplicatePackageMerger.new(pkgs).run
50
52
  end
51
53
 
@@ -47,15 +47,24 @@ module Package
47
47
  thread_index = 0
48
48
 
49
49
  @spinner.start
50
+ @any_section_printed = false
50
51
  threads = @technologies.map.with_index do |technology, technology_index|
51
52
  Thread.new do
52
53
  all_pkgs, ignored_pkgs = PackageFinder.new(@config, @dir, @report, @groups).run(technology)
53
54
  ignored_pkgs = [] if @options[Enum::Option::INCLUDE_IGNORED]
54
55
  active_pkgs = (all_pkgs || []) - (ignored_pkgs || [])
56
+ active_pkgs = filter_by_flags(active_pkgs) if any_filters_set?
55
57
  cumulative_pkgs += active_pkgs
56
58
  mutex.synchronize { all_packages_for_config += all_pkgs || [] }
57
59
 
58
- sleep 0.1 while technology_index != thread_index # print each technology in order
60
+ # Wait for our turn to print (synchronized read of thread_index)
61
+ loop do
62
+ ready = mutex.synchronize { technology_index == thread_index }
63
+ break if ready
64
+
65
+ sleep 0.05
66
+ end
67
+
59
68
  mutex.synchronize do
60
69
  @spinner.stop
61
70
  print_results(technology, active_pkgs, ignored_pkgs || [])
@@ -74,22 +83,46 @@ module Package
74
83
  @spinner.stop # Stop spinner before cleaning config to ensure clean output
75
84
  clean_config(all_packages_for_config)
76
85
 
86
+ puts unless @options[Enum::Option::FORMAT] # Add final blank line for default format
87
+
77
88
  cumulative_pkgs.any? ? 1 : 0
78
89
  ensure
79
90
  @spinner.stop
80
91
  end
81
92
 
82
- def print_results(technology, pkgs, ignored_pkgs)
93
+ def print_results(technology, pkgs, ignored_pkgs) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
94
+ format = @options[Enum::Option::FORMAT]
95
+ is_pretty = format.nil?
96
+ is_csv = format == Enum::Format::CSV
97
+ has_packages = pkgs.any?
98
+
99
+ # Pretty format: blank line before each section
100
+ # CSV/Markdown: blank line between sections (only if previous section had output)
101
+ puts if is_pretty || (@any_section_printed && has_packages)
102
+
83
103
  PackagePrinter.new(@options, pkgs).print(Const::Fields::DEFAULT)
84
- print_summary(technology, pkgs, ignored_pkgs) unless @options[Enum::Option::FORMAT] == Enum::Format::CSV
85
- print_disclaimer(technology) unless @options[Enum::Option::FORMAT] || pkgs.empty?
104
+
105
+ # Markdown: blank line between table and summary (when there's a table)
106
+ puts if !is_pretty && !is_csv && has_packages
107
+
108
+ print_summary(technology, pkgs, ignored_pkgs) unless is_csv
109
+
110
+ # Pretty format: blank line before disclaimer
111
+ puts if is_pretty && has_packages
112
+
113
+ print_disclaimer(technology) unless format || pkgs.empty?
114
+
115
+ # Track that this section produced output (for CSV/Markdown separator logic)
116
+ # Pretty and Markdown always print summary, CSV only prints if there are packages
117
+ @any_section_printed = true if has_packages || !is_csv
86
118
  end
87
119
 
88
120
  def print_summary(technology, pkgs, ignored_pkgs)
121
+ format = @options[Enum::Option::FORMAT]
89
122
  if @report == Enum::Report::ALL
90
- Util::SummaryPrinter.statistics(@options[Enum::Option::FORMAT], technology, @report, pkgs, ignored_pkgs)
123
+ Util::SummaryPrinter.statistics(format, technology, @report, pkgs, ignored_pkgs)
91
124
  else
92
- Util::SummaryPrinter.total(technology, @report, pkgs, ignored_pkgs)
125
+ Util::SummaryPrinter.total(format, technology, @report, pkgs, ignored_pkgs)
93
126
  end
94
127
  end
95
128
 
@@ -147,6 +180,66 @@ module Package
147
180
 
148
181
  "#{array[0..-2].join(', ')}, and #{array.last}"
149
182
  end
183
+
184
+ def any_filters_set?
185
+ deprecated = @options[Enum::Option::DEPRECATED]
186
+ outdated = @options[Enum::Option::OUTDATED]
187
+ vulnerable = @options[Enum::Option::VULNERABLE]
188
+
189
+ # Check if any filter was explicitly set (not nil)
190
+ [deprecated, outdated, vulnerable].any? { |v| !v.nil? }
191
+ end
192
+
193
+ def filter_by_flags(pkgs) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
194
+ deprecated = @options[Enum::Option::DEPRECATED]
195
+ outdated = @options[Enum::Option::OUTDATED]
196
+ vulnerable = @options[Enum::Option::VULNERABLE]
197
+
198
+ # Determine which filters are positive (include) vs negative (exclude)
199
+ positive_filters = []
200
+ negative_filters = []
201
+
202
+ positive_filters << :deprecated if deprecated == true
203
+ positive_filters << :outdated if outdated == true
204
+ positive_filters << :vulnerable if vulnerable == true
205
+
206
+ negative_filters << :deprecated if deprecated == false
207
+ negative_filters << :outdated if outdated == false
208
+ negative_filters << :vulnerable if vulnerable == false
209
+
210
+ pkgs.select do |pkg|
211
+ # If we have positive filters, package must match at least one
212
+ if positive_filters.any?
213
+ matches_positive = positive_filters.any? do |filter|
214
+ case filter
215
+ when :deprecated then pkg.deprecated?
216
+ when :outdated then pkg.outdated?
217
+ when :vulnerable then pkg.vulnerable?
218
+ end
219
+ end
220
+ next false unless matches_positive
221
+ end
222
+
223
+ # If we have negative filters (skip flags), use different logic:
224
+ # A package should be excluded ONLY if ALL of its risk types are being skipped
225
+ if negative_filters.any?
226
+ # Determine which risk types we're showing (not skipping)
227
+ showing_deprecated = deprecated != false
228
+ showing_outdated = outdated != false
229
+ showing_vulnerable = vulnerable != false
230
+
231
+ # Check if package has at least one risk type that we're showing
232
+ has_shown_risk = false
233
+ has_shown_risk = true if pkg.deprecated? && showing_deprecated
234
+ has_shown_risk = true if pkg.outdated? && showing_outdated
235
+ has_shown_risk = true if pkg.vulnerable? && showing_vulnerable
236
+
237
+ next false unless has_shown_risk
238
+ end
239
+
240
+ true
241
+ end
242
+ end
150
243
  end
151
244
  end
152
245
  end
@@ -29,7 +29,6 @@ module Package
29
29
  else
30
30
  pretty(fields)
31
31
  end
32
- puts
33
32
  end
34
33
 
35
34
  private
@@ -47,19 +46,23 @@ module Package
47
46
  header = fields.map.with_index do |field, index|
48
47
  Const::Fields::HEADERS[field].gsub(BASH_FORMATTING_REGEX, '').ljust(max_widths[index])
49
48
  end.join(' ' * COLUMN_GAP)
50
- separator = max_widths.map { |width| '=' * width }.join('=' * COLUMN_GAP)
49
+ separator_plain = max_widths.map { |width| '' * width }.join('' * COLUMN_GAP)
50
+ separator = Util::BashColor.light_green(separator_plain)
51
51
 
52
- puts separator
53
- puts header
54
- puts separator
52
+ puts " #{separator}"
53
+ puts " #{header}"
54
+ puts " #{separator}"
55
55
 
56
56
  @pkgs.each do |pkg|
57
- puts fields.map.with_index { |key, index|
57
+ row = fields.map.with_index do |key, index|
58
58
  val = get_field_value(pkg, key)
59
59
  formatting_length = val.length - val.gsub(BASH_FORMATTING_REGEX, '').length
60
60
  val.ljust(max_widths[index] + formatting_length)
61
- }.join(' ' * COLUMN_GAP)
61
+ end.join(' ' * COLUMN_GAP)
62
+ puts " #{row}"
62
63
  end
64
+
65
+ puts " #{separator}"
63
66
  end
64
67
 
65
68
  def csv(fields = Const::Fields::DEFAULT, exclude_headers: false)
@@ -99,10 +102,8 @@ module Package
99
102
  end
100
103
  end
101
104
 
102
- def get_field_value(pkg, field) # rubocop:disable Metrics/MethodLength
105
+ def get_field_value(pkg, field)
103
106
  case field
104
- when :groups
105
- pkg.group_list
106
107
  when :risk_type
107
108
  Formatter::Risk.new(pkg.risk_type).format
108
109
  when :version
@@ -29,6 +29,10 @@ module Package
29
29
  def self.blue(str)
30
30
  "\e[34m#{str}\e[0m"
31
31
  end
32
+
33
+ def self.light_green(str)
34
+ "\e[38;5;154m#{str}\e[0m"
35
+ end
32
36
  end
33
37
  end
34
38
  end
@@ -6,42 +6,42 @@ module Package
6
6
  module Util
7
7
  module RiskLegend
8
8
  def self.print # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
9
- puts Util::BashColor.blue('1. Check if the package has a security vulnerability.')
10
- puts ' If yes, the following vulnerability -> risk mapping is used:'
11
- puts " - #{Util::BashColor.red('unknown')} vulnerability\t-> #{Util::BashColor.red('high')} risk"
12
- puts " - #{Util::BashColor.red('critical')} vulnerability\t-> #{Util::BashColor.red('high')} risk"
13
- puts " - #{Util::BashColor.red('high')} vulnerability\t-> #{Util::BashColor.red('high')} risk"
14
- puts " - #{Util::BashColor.orange('medium')} vulnerability\t-> #{Util::BashColor.orange('medium')} risk"
15
- puts " - #{Util::BashColor.orange('moderate')} vulnerability\t-> #{Util::BashColor.orange('medium')} risk" # rubocop:disable Layout/LineLength
16
- puts " - #{Util::BashColor.yellow('low')} vulnerability\t-> #{Util::BashColor.yellow('low')} risk"
9
+ puts " #{Util::BashColor.blue('1. Check if the package has a security vulnerability.')}"
10
+ puts ' If yes, the following vulnerability -> risk mapping is used:'
11
+ puts " - #{Util::BashColor.red('unknown')} vulnerability\t-> #{Util::BashColor.red('high')} risk"
12
+ puts " - #{Util::BashColor.red('critical')} vulnerability\t-> #{Util::BashColor.red('high')} risk"
13
+ puts " - #{Util::BashColor.red('high')} vulnerability\t-> #{Util::BashColor.red('high')} risk"
14
+ puts " - #{Util::BashColor.orange('medium')} vulnerability\t-> #{Util::BashColor.orange('medium')} risk"
15
+ puts " - #{Util::BashColor.orange('moderate')} vulnerability\t-> #{Util::BashColor.orange('medium')} risk" # rubocop:disable Layout/LineLength
16
+ puts " - #{Util::BashColor.yellow('low')} vulnerability\t-> #{Util::BashColor.yellow('low')} risk"
17
17
 
18
18
  puts
19
19
 
20
- puts Util::BashColor.blue('2. Check the package for potential deprecation.')
21
- puts " If no new releases by author for at least #{Const::Time::YEARS_ELAPSED_TO_BE_OUTDATED} years:"
22
- puts " - assign the risk to\t-> #{Util::BashColor.orange('medium')} risk"
20
+ puts " #{Util::BashColor.blue('2. Check the package for potential deprecation.')}"
21
+ puts " If no new releases by author for at least #{Const::Time::YEARS_ELAPSED_TO_BE_OUTDATED} years:"
22
+ puts " - assign the risk to\t-> #{Util::BashColor.orange('medium')} risk"
23
23
 
24
24
  puts
25
25
 
26
- puts Util::BashColor.blue('3. Check if a newer version of the package is available.')
26
+ puts " #{Util::BashColor.blue('3. Check if a newer version of the package is available.')}"
27
27
 
28
- puts ' If yes, assign risk as follows:'
29
- puts " - #{Util::BashColor.orange('major version')} mismatch\t-> #{Util::BashColor.orange('medium')} risk" # rubocop:disable Layout/LineLength
30
- puts " - #{Util::BashColor.yellow('minor version')} mismatch\t-> #{Util::BashColor.yellow('low')} risk"
31
- puts " - #{Util::BashColor.green('patch version')} mismatch\t-> #{Util::BashColor.yellow('low')} risk"
32
- puts " - #{Util::BashColor.green('build version')} mismatch\t-> #{Util::BashColor.yellow('low')} risk"
28
+ puts ' If yes, assign risk as follows:'
29
+ puts " - #{Util::BashColor.orange('major version')} mismatch\t-> #{Util::BashColor.orange('medium')} risk" # rubocop:disable Layout/LineLength
30
+ puts " - #{Util::BashColor.yellow('minor version')} mismatch\t-> #{Util::BashColor.yellow('low')} risk"
31
+ puts " - #{Util::BashColor.green('patch version')} mismatch\t-> #{Util::BashColor.yellow('low')} risk"
32
+ puts " - #{Util::BashColor.green('build version')} mismatch\t-> #{Util::BashColor.yellow('low')} risk"
33
33
 
34
34
  puts
35
35
 
36
- puts Util::BashColor.blue('4. Take the highest risk from the first 3 steps.')
37
- puts ' If two risks match in severity, use the following precedence:'
38
- puts " - #{Util::BashColor.red('vulnerability')} > #{Util::BashColor.orange('deprecation')} > #{Util::BashColor.yellow('outdatedness')}" # rubocop:disable Layout/LineLength
36
+ puts " #{Util::BashColor.blue('4. Take the highest risk from the first 3 steps.')}"
37
+ puts ' If two risks match in severity, use the following precedence:'
38
+ puts " - #{Util::BashColor.red('vulnerability')} > #{Util::BashColor.orange('deprecation')} > #{Util::BashColor.yellow('outdatedness')}" # rubocop:disable Layout/LineLength
39
39
 
40
40
  puts
41
41
 
42
- puts Util::BashColor.blue('5. Check whether the package is used in production or not.')
43
- puts ' If a package is limited to a non-production group:'
44
- puts " - cap risk severity to\t -> #{Util::BashColor.yellow('low')} risk"
42
+ puts " #{Util::BashColor.blue('5. Check whether the package is used in production or not.')}"
43
+ puts ' If a package is limited to a non-production group:'
44
+ puts " - cap risk severity to\t -> #{Util::BashColor.yellow('low')} risk"
45
45
  end
46
46
  end
47
47
  end
@@ -6,30 +6,38 @@ module Package
6
6
  module Util
7
7
  module SummaryPrinter
8
8
  def self.all
9
- printf("\n%<info>s\n%<cmd>s\n\n",
9
+ printf(" %<info>s\n %<cmd>s\n",
10
10
  info: Util::BashColor.blue('To show how risk is calculated run:'),
11
11
  cmd: Util::BashColor.magenta(' > package-audit risk'))
12
12
  end
13
13
 
14
14
  def self.deprecated
15
- puts Util::BashColor.blue('Although the packages above have no recent updates, they may not be deprecated.')
16
- puts Util::BashColor.blue("Please contact the package author for more information about its status.\n")
15
+ puts " #{Util::BashColor.blue('Although the packages above have no recent updates, ' \
16
+ 'they may not be deprecated.')}"
17
+ puts " #{Util::BashColor.blue('Please contact the package author for more information about its status.')}"
17
18
  end
18
19
 
19
20
  def self.vulnerable(technology, cmd)
20
- printf("%<info>s\n%<cmd>s\n\n",
21
+ printf(" %<info>s\n %<cmd>s\n",
21
22
  info: Util::BashColor.blue("For more information about #{technology.capitalize} vulnerabilities run:"),
22
23
  cmd: Util::BashColor.magenta(" > #{cmd}"))
23
24
  end
24
25
 
25
- def self.total(technology, report, pkgs, ignored_pkgs)
26
+ def self.total(format, technology, report, pkgs, ignored_pkgs) # rubocop:disable Metrics/MethodLength
27
+ prefix = format.nil? ? ' ' : ''
26
28
  if ignored_pkgs.any?
27
- puts Util::BashColor.cyan("Found a total of #{pkgs.length} #{technology.capitalize} packages " \
28
- "(#{ignored_pkgs.length} ignored).\n")
29
+ puts "#{prefix}#{Util::BashColor.cyan(
30
+ "Found a total of #{pkgs.length} #{technology.capitalize} packages " \
31
+ "(#{ignored_pkgs.length} ignored)."
32
+ )}"
29
33
  elsif pkgs.any?
30
- puts Util::BashColor.cyan("Found a total of #{pkgs.length} #{technology.capitalize} packages.\n")
34
+ puts "#{prefix}#{Util::BashColor.cyan(
35
+ "Found a total of #{pkgs.length} #{technology.capitalize} packages."
36
+ )}"
31
37
  else
32
- puts Util::BashColor.green("There are no #{report} #{technology.capitalize} packages!\n")
38
+ puts "#{prefix}#{Util::BashColor.green(
39
+ "There are no #{report} #{technology.capitalize} packages!"
40
+ )}"
33
41
  end
34
42
  end
35
43
 
@@ -57,27 +65,30 @@ module Package
57
65
  end
58
66
 
59
67
  private_class_method def self.display_results(format, technology, report, pkgs, ignored_pkgs, stats) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/ParameterLists
68
+ prefix = format.nil? ? ' ' : ''
60
69
  if pkgs.any?
61
- print status_message(stats)
70
+ print "#{prefix}#{status_message(stats)}"
62
71
  print Util::BashColor.cyan(' \\') if format == Enum::Format::MARKDOWN
63
72
  puts
64
- total(technology, report, pkgs, ignored_pkgs)
73
+ total(format, technology, report, pkgs, ignored_pkgs)
65
74
  elsif ignored_pkgs.any?
66
- print status_message(stats)
75
+ print "#{prefix}#{status_message(stats)}"
67
76
  print Util::BashColor.cyan(' \\') if format == Enum::Format::MARKDOWN
68
77
  puts
69
- puts Util::BashColor.green("There are no deprecated, outdated or vulnerable #{technology.capitalize} " \
70
- "packages (#{ignored_pkgs.length} ignored)!\n")
78
+ puts "#{prefix}#{Util::BashColor.green(
79
+ 'There are no deprecated, outdated or vulnerable ' \
80
+ "#{technology.capitalize} packages (#{ignored_pkgs.length} ignored)!"
81
+ )}"
71
82
  else
72
- puts Util::BashColor.green("There are no deprecated, outdated or vulnerable #{technology.capitalize} " \
73
- "packages!\n")
83
+ puts "#{prefix}#{Util::BashColor.green('There are no deprecated, outdated or vulnerable ' \
84
+ "#{technology.capitalize} packages!")}"
74
85
  end
75
86
  end
76
87
 
77
88
  private_class_method def self.status_message(stats)
78
- outdated_str = "#{stats[:outdated]} outdated" + outdated_details(stats)
79
- deprecated_str = "#{stats[:deprecated]} deprecated" + deprecated_details(stats)
80
- vulnerable_str = "#{stats[:vulnerable]} vulnerable" + vulnerability_details(stats)
89
+ outdated_str = "#{stats[:outdated]} ⦗O⦘utdated" + outdated_details(stats)
90
+ deprecated_str = "#{stats[:deprecated]} ⦗D⦘eprecated" + deprecated_details(stats)
91
+ vulnerable_str = "#{stats[:vulnerable]} ⦗V⦘ulnerable" + vulnerability_details(stats)
81
92
 
82
93
  Util::BashColor.cyan("#{vulnerable_str}, #{outdated_str}, #{deprecated_str}.")
83
94
  end
@@ -1,5 +1,5 @@
1
1
  module Package
2
2
  module Audit
3
- VERSION = '0.7.1'
3
+ VERSION = '0.8.1'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: package-audit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vadim Kononov
@@ -111,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
111
  - !ruby/object:Gem::Version
112
112
  version: '0'
113
113
  requirements: []
114
- rubygems_version: 3.6.9
114
+ rubygems_version: 3.7.2
115
115
  specification_version: 4
116
116
  summary: A helper tool to find outdated, deprecated and vulnerable dependencies.
117
117
  test_files: []