chelsea 0.0.18 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9caf22546a018a86b5c4c9e697de52e87088b0a2564517a8580957b9127210fa
4
- data.tar.gz: ef1f7c1fa82b6fd6e3e39f464f29b90d5f313b479ace42ded33c9206ca7a2479
3
+ metadata.gz: a44baa47f70b877e0f6b8051962bf0c66eae508bb0fa148d47056b7d5dfdf6bb
4
+ data.tar.gz: 5565acd13beccaab790612682ae19d50a8b9c4427f83692476ffcbe6ddd5425c
5
5
  SHA512:
6
- metadata.gz: 4a5fd5e2a8fbd040fb9018412db887d7320edbb60fbc482d9c28e55696124c64caab47ff3b46902ad1bf49c6464b5fafc1482e1243d35ee0616d171d16cc76f1
7
- data.tar.gz: ad61c6e0a252fd80edb3db6ca261013119237296497f4a7a42389ffdbfb3503bfac66da4bc6c1deab5fd5e5754f2016d188d98b8831cd9661575f6012aac89ba
6
+ metadata.gz: 50c1634dae11bd146bbf734706abc60b3c06bb6cab1bb177cbf5e98c528c4d1dd25a0a9fd4d47719b3887dc4aaf9ce7a5f42126d7973b1008eac4c87c99cdd7b
7
+ data.tar.gz: f8db897e7a16e5f87b8a3f3f0f7a8ae98541d058922c54d4d580fbe36763e128f3b30f9f8cde5f138b410af172208d3948025ee9342858113ab31ea1fe1ac51c
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
13
  .byebug_history
14
+ .ruby-version
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- chelsea (0.0.11)
4
+ chelsea (0.0.17)
5
5
  bundler (>= 1.2.0, < 3)
6
6
  ox (~> 2.13.2)
7
7
  pastel (~> 0.7.2)
@@ -9,6 +9,7 @@ PATH
9
9
  slop (~> 4.8.1)
10
10
  tty-font (~> 0.5.0)
11
11
  tty-spinner (~> 0.9.3)
12
+ tty-table (~> 0.11.0)
12
13
 
13
14
  GEM
14
15
  remote: https://rubygems.org/
@@ -27,10 +28,11 @@ GEM
27
28
  domain_name (~> 0.5)
28
29
  mime-types (3.3.1)
29
30
  mime-types-data (~> 3.2015)
30
- mime-types-data (3.2019.1009)
31
+ mime-types-data (3.2020.0512)
32
+ necromancer (0.6.0)
31
33
  netrc (0.11.0)
32
34
  ox (2.13.2)
33
- pastel (0.7.3)
35
+ pastel (0.7.4)
34
36
  equatable (~> 0.6)
35
37
  tty-color (~> 0.5)
36
38
  public_suffix (4.0.3)
@@ -56,14 +58,28 @@ GEM
56
58
  rspec-core (>= 2, < 4, != 2.12.0)
57
59
  safe_yaml (1.0.5)
58
60
  slop (4.8.1)
61
+ strings (0.1.8)
62
+ strings-ansi (~> 0.1)
63
+ unicode-display_width (~> 1.5)
64
+ unicode_utils (~> 1.4)
65
+ strings-ansi (0.2.0)
59
66
  tty-color (0.5.1)
60
67
  tty-cursor (0.7.1)
61
68
  tty-font (0.5.0)
69
+ tty-screen (0.8.0)
62
70
  tty-spinner (0.9.3)
63
71
  tty-cursor (~> 0.7)
72
+ tty-table (0.11.0)
73
+ equatable (~> 0.6)
74
+ necromancer (~> 0.5)
75
+ pastel (~> 0.7.2)
76
+ strings (~> 0.1.5)
77
+ tty-screen (~> 0.7)
64
78
  unf (0.1.4)
65
79
  unf_ext
66
80
  unf_ext (0.0.7.7)
81
+ unicode-display_width (1.7.0)
82
+ unicode_utils (1.4.0)
67
83
  webmock (3.8.3)
68
84
  addressable (>= 2.3.6)
69
85
  crack (>= 0.3.2)
@@ -43,5 +43,7 @@ dockerizedBuildPipeline(
43
43
  },
44
44
  onFailure: {
45
45
  githubStatusUpdate('failure')
46
+ notifyChat(currentBuild: currentBuild, env: env, room: 'community-oss-fun')
47
+ sendEmailNotification(currentBuild, env, [], 'community-group@sonatype.com')
46
48
  }
47
49
  )
@@ -31,7 +31,7 @@ opts =
31
31
  o.string '-iu', '--iquser', 'Specify the IQ username', default: 'admin'
32
32
  o.string '-it', '--iqpass', 'Specify the IQ auth token', default: 'admin123'
33
33
  o.string '-w', '--whitelist', 'Set path to vulnerability whitelist file'
34
- o.bool '-q', '--quiet', 'Make chelsea only output vulnerable third party dependencies for text output (default: false)', default: false
34
+ o.bool '-v', '--verbose', 'Make chelsea only output vulnerable third party dependencies for text output (default: true)', default: false
35
35
  o.string '-t', '--format', 'Choose what type of format you want your report in (default: text) (options: text, json, xml)', default: 'text'
36
36
  o.bool '-b', '--iq', 'Use Nexus IQ Server to audit your project'
37
37
  o.on '--version', 'Print the version' do
@@ -31,10 +31,12 @@ Gem::Specification.new do |spec|
31
31
  spec.add_dependency "rest-client", "~> 2.0.2"
32
32
  spec.add_dependency "bundler", ">= 1.2.0", "< 3"
33
33
  spec.add_dependency "ox", "~> 2.13.2"
34
+ spec.add_dependency "tty-table", "~> 0.11.0"
34
35
 
35
36
  spec.add_development_dependency "rake", "~> 12.3"
36
37
  spec.add_development_dependency "rspec", "~> 3.0"
37
38
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.1"
38
39
  spec.add_development_dependency "webmock", "~> 3.8.3"
39
40
  spec.add_development_dependency "byebug", "~> 11.1.2"
41
+ spec.add_development_dependency 'pry'
40
42
  end
@@ -78,7 +78,7 @@ module Chelsea
78
78
  def _process_file
79
79
  gems = Chelsea::Gems.new(
80
80
  file: @opts[:file],
81
- quiet: @opts[:quiet],
81
+ verbose: @opts[:verbose],
82
82
  options: @opts
83
83
  )
84
84
  gems.execute ? (exit 1) : (exit 0)
@@ -87,7 +87,7 @@ module Chelsea
87
87
  def _process_file_iq
88
88
  gems = Chelsea::Gems.new(
89
89
  file: @opts[:file],
90
- quiet: @opts[:quiet],
90
+ verbose: @opts[:verbose],
91
91
  options: @opts
92
92
  )
93
93
  gems.collect_iq
@@ -23,8 +23,8 @@ require 'rest-client'
23
23
 
24
24
  module Chelsea
25
25
  class Deps
26
- def initialize(path:, quiet: false)
27
- @quiet = quiet
26
+ def initialize(path:, verbose: false)
27
+ @verbose = verbose
28
28
  ENV['BUNDLE_GEMFILE'] = File.expand_path(path).chomp('.lock')
29
29
  @lockfile = Bundler::LockfileParser.new(File.read(path))
30
30
  end
@@ -57,7 +57,7 @@ module Chelsea
57
57
  reverse
58
58
  .reverse_dependencies(@lockfile.specs)
59
59
  .to_h
60
- .transform_values do |reverse_dep|
60
+ .transform_values! do |reverse_dep|
61
61
  reverse_dep.select do |name, _dep, _req, _|
62
62
  spec_names.include?(name.split('-')[0])
63
63
  end
@@ -20,16 +20,16 @@ require_relative 'text'
20
20
 
21
21
  # Factory for formatting dependencies
22
22
  class FormatterFactory
23
- def get_formatter(format: 'text', quiet: false)
23
+ def get_formatter(format: 'text', verbose:)
24
24
  case format
25
25
  when 'text'
26
- Chelsea::TextFormatter.new quiet: quiet
26
+ Chelsea::TextFormatter.new verbose: verbose
27
27
  when 'json'
28
- Chelsea::JsonFormatter.new quiet: quiet
28
+ Chelsea::JsonFormatter.new verbose: verbose
29
29
  when 'xml'
30
- Chelsea::XMLFormatter.new quiet: quiet
30
+ Chelsea::XMLFormatter.new verbose: verbose
31
31
  else
32
- Chelsea::TextFormatter.new quiet: quiet
32
+ Chelsea::TextFormatter.new verbose: verbose
33
33
  end
34
34
  end
35
35
  end
@@ -15,49 +15,54 @@
15
15
  #
16
16
 
17
17
  require 'pastel'
18
+ require 'tty-table'
18
19
  require_relative 'formatter'
19
20
 
20
21
  module Chelsea
21
22
  class TextFormatter < Formatter
22
- def initialize(quiet: false)
23
- @quiet = quiet
23
+ def initialize(options)
24
+ @options = options
24
25
  @pastel = Pastel.new
25
26
  end
26
27
 
27
28
  def get_results(server_response, reverse_dependencies)
28
- response = String.new
29
- if !@quiet
29
+ response = ''
30
+ if @options[:verbose]
30
31
  response += "\n"\
31
32
  "Audit Results\n"\
32
33
  "=============\n"
33
34
  end
34
35
 
35
- i = 0
36
- count = server_response.count()
37
- server_response.sort! {|x| x['vulnerabilities'].count}
38
-
39
- server_response.each do |r|
40
- i += 1
41
- package = r['coordinates']
42
- vulnerable = r['vulnerabilities'].length.positive?
43
- coord = r['coordinates'].sub('pkg:gem/', '')
44
- name = coord.split('@')[0]
45
- version = coord.split('@')[1]
36
+ vuln_count = server_response.count do |vuln|
37
+ vuln['vulnerabilities'].length.positive?
38
+ end
39
+ server_response.sort! { |x| x['vulnerabilities'].count }
40
+ server_response.each.with_index do |r, idx|
41
+ name, version = r['coordinates'].sub('pkg:gem/', '').split('@')
46
42
  reverse_deps = reverse_dependencies["#{name}-#{version}"]
47
- if vulnerable
48
- response += @pastel.red("[#{i}/#{count}] - #{package} ") + @pastel.red.bold("Vulnerable.\n")
43
+ if r['vulnerabilities'].length.positive?
44
+ response += @pastel.red(
45
+ "[#{idx}/#{server_response.count}] - #{r['coordinates']} "
46
+ )
47
+ response += @pastel.red.bold("Vulnerable.\n")
49
48
  response += _get_reverse_deps(reverse_deps, name) if reverse_deps
50
49
  r['vulnerabilities'].each do |k, _|
51
50
  response += _format_vuln(k)
52
51
  end
53
- else
54
- if !@quiet
55
- response += @pastel.white("[#{i}/#{count}] - #{package} ") + @pastel.green.bold("No vulnerabilities found!\n")
56
- response += _get_reverse_deps(reverse_deps, name) if reverse_deps
57
- end
52
+ elsif @options[:verbose]
53
+ response += @pastel.white(
54
+ "[#{idx}/#{server_response.count}] - #{r['coordinates']} "
55
+ )
56
+ response += @pastel.green.bold("No vulnerabilities found!\n")
57
+ response += _get_reverse_deps(reverse_deps, name) if reverse_deps
58
58
  end
59
59
  end
60
60
 
61
+ table = TTY::Table.new(
62
+ ['Dependencies Audited', 'Vulnerable Dependencies'],
63
+ [[server_response.count, vuln_count]]
64
+ )
65
+ response += table.render(:unicode)
61
66
  response
62
67
  end
63
68
 
@@ -65,34 +70,44 @@ module Chelsea
65
70
  puts results
66
71
  end
67
72
 
73
+ private
74
+
68
75
  def _format_vuln(vuln)
69
- cvssScore = vuln['cvssScore']
70
76
  vuln_response = "\n\tVulnerability Details:\n"
71
- vuln_response += _color_based_on_cvss_score(cvssScore, "\n\tID: #{vuln['id']}\n")
72
- vuln_response += _color_based_on_cvss_score(cvssScore, "\n\tTitle: #{vuln['title']}\n")
73
- vuln_response += _color_based_on_cvss_score(cvssScore, "\n\tDescription: #{vuln['description']}\n")
74
- vuln_response += _color_based_on_cvss_score(cvssScore, "\n\tCVSS Score: #{vuln['cvssScore']}\n")
75
- vuln_response += _color_based_on_cvss_score(cvssScore, "\n\tCVSS Vector: #{vuln['cvssVector']}\n")
76
- vuln_response += _color_based_on_cvss_score(cvssScore, "\n\tCVE: #{vuln['cve']}\n")
77
- vuln_response += _color_based_on_cvss_score(cvssScore, "\n\tReference: #{vuln['reference']}\n\n")
77
+ _color_method = _color_based_on_cvss_score(vuln['cvssScore'])
78
+ _report_lines(vuln).each do |line|
79
+ vuln_response += _color_method(line)
80
+ end
78
81
  vuln_response
79
82
  end
80
83
 
81
- def _color_based_on_cvss_score(cvssScore, text)
82
- case cvssScore
84
+ def _report_lines(vuln)
85
+ [
86
+ "\n\tID: #{vuln['id']}\n",
87
+ "\n\tTitle: #{vuln['title']}\n",
88
+ "\n\tDescription: #{vuln['description']}\n",
89
+ "\n\tCVSS Score: #{vuln['cvssScore']}\n",
90
+ "\n\tCVSS Vector: #{vuln['cvssVector']}\n",
91
+ "\n\tCVE: #{vuln['cve']}\n",
92
+ "\n\tReference: #{vuln['reference']}\n\n"
93
+ ]
94
+ end
95
+
96
+ def _color_based_on_cvss_score(cvss_score)
97
+ case cvss_score
83
98
  when 0..3
84
- @pastel.cyan.bold(text)
99
+ @pastel.cyan.bold
85
100
  when 4..5
86
- @pastel.yellow.bold(text)
101
+ @pastel.yellow.bold
87
102
  when 6..7
88
- @pastel.orange.bold(text)
103
+ @pastel.orange.bold
89
104
  else
90
- @pastel.red.bold(text)
105
+ @pastel.red.bold
91
106
  end
92
107
  end
93
108
 
94
109
  def _get_reverse_deps(coords, name)
95
- coords.each_with_object(String.new) do |dep, s|
110
+ coords.each_with_object('') do |dep, s|
96
111
  dep.each do |gran|
97
112
  if gran.class == String && !gran.include?(name)
98
113
  s << "\tRequired by: #{gran}\n"
@@ -31,8 +31,8 @@ module Chelsea
31
31
  doc << instruct
32
32
 
33
33
  testsuite = Ox::Element.new('testsuite')
34
- testsuite[:name] = "purl"
35
- testsuite[:tests] = server_response.count()
34
+ testsuite[:name] = 'purl'
35
+ testsuite[:tests] = server_response.count
36
36
  doc << testsuite
37
37
 
38
38
  server_response.each do |coord|
@@ -40,14 +40,15 @@ module Chelsea
40
40
  testcase[:classname] = coord["coordinates"]
41
41
  testcase[:name] = coord["coordinates"]
42
42
 
43
- if coord["vulnerabilities"].length() > 0
43
+ if coord['vulnerabilities'].length.positive?
44
44
  failure = Ox::Element.new('failure')
45
45
  failure[:type] = "Vulnerable Dependency"
46
46
  failure << get_vulnerability_block(coord["vulnerabilities"])
47
47
  testcase << failure
48
+ testsuite << testcase
49
+ elsif @options[:verbose]
50
+ testsuite << testcase
48
51
  end
49
-
50
- testsuite << testcase
51
52
  end
52
53
 
53
54
  doc
@@ -31,18 +31,19 @@ module Chelsea
31
31
  # Class to collect and audit packages from a Gemfile.lock
32
32
  class Gems
33
33
  attr_accessor :deps
34
- def initialize(file:, quiet: false, options: { 'format': 'text' })
35
- @quiet = quiet
34
+ def initialize(file:, verbose:, options: { 'format': 'text' })
35
+ @verbose = verbose
36
36
  unless File.file?(file) || file.nil?
37
37
  raise 'Gemfile.lock not found, check --file path'
38
38
  end
39
39
 
40
- _silence_stderr if @quiet
40
+ _silence_stderr unless @verbose
41
41
 
42
42
  @pastel = Pastel.new
43
43
  @formatter = FormatterFactory.new.get_formatter(
44
44
  format: options[:format],
45
- quiet: @quiet)
45
+ verbose: verbose
46
+ )
46
47
  @client = Chelsea.client(options)
47
48
  @deps = Chelsea::Deps.new(path: Pathname.new(file))
48
49
  @spinner = Chelsea::Spinner.new
@@ -58,7 +59,7 @@ module Chelsea
58
59
  return
59
60
  end
60
61
  if server_response.nil?
61
- _print_err 'No vulnerability data retrieved from server. Exiting.'
62
+ _print_success 'No vulnerability data retrieved from server. Exiting.'
62
63
  return
63
64
  end
64
65
  results = @formatter.get_results(server_response, reverse_dependencies)
@@ -94,6 +95,7 @@ module Chelsea
94
95
  coordinates = @deps.coordinates
95
96
  spin.success('...done.')
96
97
  spin = @spinner.spin_msg 'Making request to OSS Index server'
98
+ spin.stop
97
99
 
98
100
  begin
99
101
  server_response = @client.get_vulns(coordinates)
@@ -110,9 +112,6 @@ module Chelsea
110
112
  rescue Errno::ECONNREFUSED => e
111
113
  spin.stop('...request failed.')
112
114
  _print_err 'Error getting data from OSS Index server. Connection refused.'
113
- rescue StandardError => e
114
- spin.stop('...request failed.')
115
- _print_err 'UNKNOWN Error getting data from OSS Index server.'
116
115
  end
117
116
  [server_response, dependencies, reverse_dependencies]
118
117
  end
@@ -42,7 +42,7 @@ module Chelsea
42
42
  end
43
43
 
44
44
  remaining_coordinates['coordinates'].each_slice(128).to_a.each do |coords|
45
- res_json = call_oss_index({ 'coordinates' => coords })
45
+ res_json = JSON.parse(call_oss_index({ 'coordinates' => coords }))
46
46
  cached_server_response = cached_server_response.concat(res_json)
47
47
  @db.save_values_to_db(res_json)
48
48
  end
@@ -52,7 +52,7 @@ module Chelsea
52
52
 
53
53
  def call_oss_index(coords)
54
54
  r = _resource.post coords.to_json, _headers
55
- r.code == 200 ? JSON.parse(r.body) : {}
55
+ r.code == 200 ? r.body : {}
56
56
  end
57
57
 
58
58
  private
@@ -83,7 +83,7 @@ module Chelsea
83
83
  password: @oss_index_user_token
84
84
  )
85
85
  else
86
- RestClient::Resource.new _api_url
86
+ RestClient::Resource.new(_api_url)
87
87
  end
88
88
  end
89
89
 
@@ -15,5 +15,5 @@
15
15
  #
16
16
 
17
17
  module Chelsea
18
- VERSION = '0.0.18'.freeze
18
+ VERSION = '0.0.19'.freeze
19
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chelsea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.18
4
+ version: 0.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Allister Beharry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-01 00:00:00.000000000 Z
11
+ date: 2020-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-font
@@ -114,6 +114,20 @@ dependencies:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
116
  version: 2.13.2
117
+ - !ruby/object:Gem::Dependency
118
+ name: tty-table
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: 0.11.0
124
+ type: :runtime
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: 0.11.0
117
131
  - !ruby/object:Gem::Dependency
118
132
  name: rake
119
133
  requirement: !ruby/object:Gem::Requirement
@@ -184,6 +198,20 @@ dependencies:
184
198
  - - "~>"
185
199
  - !ruby/object:Gem::Version
186
200
  version: 11.1.2
201
+ - !ruby/object:Gem::Dependency
202
+ name: pry
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
187
215
  description:
188
216
  email:
189
217
  - allister.beharry@gmail.com