chelsea 0.0.27 → 0.0.28

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: 0f179d743f4810498f2e0edbe787038e2caed8e43af7279c39bf309860a568ae
4
- data.tar.gz: b20643fbaa0bbc56073a53575b4d3d5ba2d1b4f5b8b1e996dcdc373e2a2bd997
3
+ metadata.gz: 1d6bcb375015c64ae7e452f93e38b10cfabb4ecbc9425fad0121e926a0148efa
4
+ data.tar.gz: f1a171d3a72a0bf910ac4e22258cee6a0d6c3e8181307856a34a5b22ca0435c7
5
5
  SHA512:
6
- metadata.gz: b44c830f8e38ba6693babade3cb1da853baf545a6839aa79bea41a5821712cf055737e8af349c1c9aa9653bb09c5faa1cad0660ec3806f0add68418dadd36f54
7
- data.tar.gz: ec6ebcd7e0ac9fb7ebb30349c824187cfc06390fabd40a76a39c4c622a6801c513c5446f89dc3422f703e15cab214a3b1fb72ff7acd4f7ef6e249a27c8331b6e
6
+ metadata.gz: decb1e4e8a54798161b2e888e1694d9558ba0bbacd6708c6cf32d4b71b32cb05520f017733a18e90dab99c0e2e2be500d3c8b8701b1ff464041ad63ab89ffa74
7
+ data.tar.gz: 94f91e9b3f248d7a3c494fdba567f832edf38b2e91e75f791ac1d9dace17b285e89d09c43bae25d6faacd0b2a76e5a4bb211acb3153dfc57ea4b581243f5d8d1
@@ -18,7 +18,7 @@ version: 2.1
18
18
  jobs:
19
19
  build:
20
20
  docker:
21
- - image: circleci/ruby:2.6.5-stretch
21
+ - image: circleci/ruby:2.6.6-stretch
22
22
  environment:
23
23
  BUNDLE_PATH: vendor/bundle
24
24
  steps:
@@ -48,6 +48,9 @@ jobs:
48
48
  bundle exec rspec --format progress \
49
49
  --format RspecJunitFormatter \
50
50
  --out test_results/rspec.xml
51
+ - run:
52
+ name: Run linter
53
+ command: bundle exec rubocop
51
54
  - run:
52
55
  name: Build gem
53
56
  command: gem build chelsea.gemspec
@@ -64,7 +67,7 @@ jobs:
64
67
  path: test_results
65
68
  release:
66
69
  docker:
67
- - image: circleci/ruby:2.6.5-stretch
70
+ - image: circleci/ruby:2.6.6-stretch
68
71
  steps:
69
72
  - add_ssh_keys:
70
73
  fingerprints:
@@ -23,7 +23,7 @@ If applicable, add screenshots to help explain your problem.
23
23
 
24
24
  **Desktop (please complete the following information):**
25
25
  - OS: [e.g. OS X 1.13.6]
26
- - Ruby Version: [e.g. 2.6.5]
26
+ - Ruby Version: [e.g. 2.6.6]
27
27
  - Bundler Version: [e.g. 2.1.4]
28
28
  - chelsea Version [e.g. 0.0.11]
29
29
 
@@ -0,0 +1,6 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ TargetRubyVersion: 2.6.6
4
+
5
+ Metrics/BlockLength:
6
+ IgnoredMethods: ['Slop.parse']
data/Gemfile CHANGED
@@ -1,6 +1,11 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
6
 
5
7
  # Specify your gem's dependencies in chelsea.gemspec
6
8
  gemspec
9
+
10
+ # linter
11
+ gem 'rubocop', require: false
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- chelsea (0.0.26)
4
+ chelsea (0.0.27)
5
5
  bundler (>= 1.2.0, < 3)
6
6
  ox (~> 2.13.2)
7
7
  pastel (~> 0.7.2)
@@ -16,6 +16,7 @@ GEM
16
16
  specs:
17
17
  addressable (2.7.0)
18
18
  public_suffix (>= 2.0.2, < 5.0)
19
+ ast (2.4.2)
19
20
  byebug (11.1.2)
20
21
  crack (0.4.3)
21
22
  safe_yaml (~> 1.0.0)
@@ -32,15 +33,21 @@ GEM
32
33
  necromancer (0.6.0)
33
34
  netrc (0.11.0)
34
35
  ox (2.13.4)
36
+ parallel (1.20.1)
37
+ parser (3.0.0.0)
38
+ ast (~> 2.4.1)
35
39
  pastel (0.7.4)
36
40
  equatable (~> 0.6)
37
41
  tty-color (~> 0.5)
38
42
  public_suffix (4.0.3)
43
+ rainbow (3.0.0)
39
44
  rake (12.3.3)
45
+ regexp_parser (2.0.3)
40
46
  rest-client (2.0.2)
41
47
  http-cookie (>= 1.0.2, < 2.0)
42
48
  mime-types (>= 1.16, < 4.0)
43
49
  netrc (~> 0.8)
50
+ rexml (3.2.4)
44
51
  rspec (3.9.0)
45
52
  rspec-core (~> 3.9.0)
46
53
  rspec-expectations (~> 3.9.0)
@@ -56,6 +63,18 @@ GEM
56
63
  rspec-support (3.9.2)
57
64
  rspec_junit_formatter (0.4.1)
58
65
  rspec-core (>= 2, < 4, != 2.12.0)
66
+ rubocop (1.9.0)
67
+ parallel (~> 1.10)
68
+ parser (>= 3.0.0.0)
69
+ rainbow (>= 2.2.2, < 4.0)
70
+ regexp_parser (>= 1.8, < 3.0)
71
+ rexml
72
+ rubocop-ast (>= 1.2.0, < 2.0)
73
+ ruby-progressbar (~> 1.7)
74
+ unicode-display_width (>= 1.4.0, < 3.0)
75
+ rubocop-ast (1.4.1)
76
+ parser (>= 2.7.1.5)
77
+ ruby-progressbar (1.11.0)
59
78
  safe_yaml (1.0.5)
60
79
  slop (4.8.2)
61
80
  strings (0.1.8)
@@ -94,6 +113,7 @@ DEPENDENCIES
94
113
  rake (~> 12.3)
95
114
  rspec (~> 3.0)
96
115
  rspec_junit_formatter (~> 0.4.1)
116
+ rubocop
97
117
  webmock (~> 3.8.3)
98
118
 
99
119
  BUNDLED WITH
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -14,9 +16,9 @@
14
16
  # limitations under the License.
15
17
  #
16
18
 
17
- require "bundler/gem_tasks"
18
- require "rspec/core/rake_task"
19
+ require 'bundler/gem_tasks'
20
+ require 'rspec/core/rake_task'
19
21
 
20
22
  RSpec::Core::RakeTask.new(:spec)
21
23
 
22
- task :default => :spec
24
+ task default: :spec
@@ -16,7 +16,8 @@
16
16
  #
17
17
 
18
18
  # frozen_string_literal: true
19
- require_relative "../lib/chelsea"
19
+
20
+ require_relative '../lib/chelsea'
20
21
  require 'slop'
21
22
  opts =
22
23
  begin
@@ -31,13 +32,19 @@ opts =
31
32
  o.string '-iu', '--iquser', 'Specify the IQ username', default: 'admin'
32
33
  o.string '-it', '--iqpass', 'Specify the IQ auth token', default: 'admin123'
33
34
  o.string '-w', '--whitelist', 'Set path to vulnerability whitelist file'
34
- o.bool '-v', '--verbose', 'For text format, list dependencies, their reverse dependencies (what brought them in to your project), and if they are vulnerable. (default: false)', default: false
35
- o.string '-t', '--format', 'Choose what type of format you want your report in (default: text) (options: text, json, xml)', default: 'text'
35
+ o.bool '-v', '--verbose',
36
+ 'For text format, list dependencies, their reverse dependencies (what brought them in to your project), and
37
+ if they are vulnerable. (default: false)', default: false
38
+ o.string '-t', '--format',
39
+ 'Choose what type of format you want your report in (default: text) (options: text, json, xml)',
40
+ default: 'text'
36
41
  o.bool '-b', '--iq', 'Use Nexus IQ Server to audit your project'
37
- o.string '-s', '--stage', 'Specify Nexus IQ Stage (default: build) (options: develop, build, stage-release, release, operate)', default: 'build'
42
+ o.string '-s', '--stage',
43
+ 'Specify Nexus IQ Stage (default: build) (options: develop, build, stage-release, release, operate)',
44
+ default: 'build'
38
45
  o.on '--version', 'Print the version' do
39
- puts Chelsea::VERSION
40
- exit
46
+ puts Chelsea::VERSION
47
+ exit
41
48
  end
42
49
  o.on '-h', '--help', 'Show usage' do
43
50
  puts(o)
@@ -45,7 +52,7 @@ opts =
45
52
  end
46
53
  end
47
54
  rescue Slop::Error => e
48
- puts(e.message + ' (try --help)')
55
+ puts("#{e.message} (try --help)")
49
56
  exit 1
50
57
  end
51
58
  if opts.arguments.count.positive?
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  #
3
5
  # Copyright 2019-Present Sonatype Inc.
4
6
  #
@@ -15,9 +17,8 @@
15
17
  # limitations under the License.
16
18
  #
17
19
 
20
+ require 'bundler/setup'
21
+ require 'chelsea'
18
22
 
19
- require "bundler/setup"
20
- require "chelsea"
21
-
22
- require "irb"
23
+ require 'irb'
23
24
  IRB.start(__FILE__)
@@ -1,41 +1,43 @@
1
+ # frozen_string_literal: true
1
2
 
2
- lib = File.expand_path("../lib", __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "chelsea/version"
5
+ require 'chelsea/version'
5
6
 
6
7
  Gem::Specification.new do |spec|
7
- spec.name = "chelsea"
8
- spec.license = "Apache-2.0"
8
+ spec.name = 'chelsea'
9
+ spec.license = 'Apache-2.0'
9
10
  spec.version = Chelsea::VERSION
10
- spec.authors = ["Allister Beharry"]
11
- spec.email = ["allister.beharry@gmail.com"]
11
+ spec.authors = ['Allister Beharry']
12
+ spec.email = ['allister.beharry@gmail.com']
13
+ spec.required_ruby_version = '>= 2.6.6'
12
14
 
13
- spec.summary = "Audit Ruby package dependencies for security vulnerabilities."
14
- spec.homepage = "https://github.com/sonatype-nexus-community/chelsea"
15
-
16
- spec.metadata["homepage_uri"] = spec.homepage
17
- spec.metadata["source_code_uri"] = "https://github.com/sonatype-nexus-community/chelsea"
18
- spec.metadata["changelog_uri"] = "https://github.com/sonatype-nexus-community/chelsea/CHANGELOG"
15
+ spec.summary = 'Audit Ruby package dependencies for security vulnerabilities.'
16
+ spec.homepage = 'https://github.com/sonatype-nexus-community/chelsea'
19
17
 
20
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = 'https://github.com/sonatype-nexus-community/chelsea'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/sonatype-nexus-community/chelsea/CHANGELOG'
21
+
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
23
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
24
  end
23
- spec.bindir = "bin"
25
+ spec.bindir = 'bin'
24
26
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
25
- spec.require_paths = ["lib"]
27
+ spec.require_paths = ['lib']
26
28
 
27
- spec.add_dependency "tty-font", "~> 0.5.0"
28
- spec.add_dependency "tty-spinner", "~> 0.9.3"
29
- spec.add_dependency "slop", "~> 4.8.1"
30
- spec.add_dependency "pastel", "~> 0.7.2"
31
- spec.add_dependency "rest-client", "~> 2.0.2"
32
- spec.add_dependency "bundler", ">= 1.2.0", "< 3"
33
- spec.add_dependency "ox", "~> 2.13.2"
34
- spec.add_dependency "tty-table", "~> 0.11.0"
29
+ spec.add_dependency 'bundler', '>= 1.2.0', '< 3'
30
+ spec.add_dependency 'ox', '~> 2.13.2'
31
+ spec.add_dependency 'pastel', '~> 0.7.2'
32
+ spec.add_dependency 'rest-client', '~> 2.0.2'
33
+ spec.add_dependency 'slop', '~> 4.8.1'
34
+ spec.add_dependency 'tty-font', '~> 0.5.0'
35
+ spec.add_dependency 'tty-spinner', '~> 0.9.3'
36
+ spec.add_dependency 'tty-table', '~> 0.11.0'
35
37
 
36
- spec.add_development_dependency "rake", "~> 12.3"
37
- spec.add_development_dependency "rspec", "~> 3.0"
38
- spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.1"
39
- spec.add_development_dependency "webmock", "~> 3.8.3"
40
- spec.add_development_dependency "byebug", "~> 11.1.2"
38
+ spec.add_development_dependency 'byebug', '~> 11.1.2'
39
+ spec.add_development_dependency 'rake', '~> 12.3'
40
+ spec.add_development_dependency 'rspec', '~> 3.0'
41
+ spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4.1'
42
+ spec.add_development_dependency 'webmock', '~> 3.8.3'
41
43
  end
@@ -40,7 +40,7 @@ module Chelsea
40
40
  end
41
41
 
42
42
  def random_urn_uuid
43
- 'urn:uuid:' + SecureRandom.uuid
43
+ "urn:uuid:#{SecureRandom.uuid}"
44
44
  end
45
45
 
46
46
  private
@@ -87,8 +87,8 @@ module Chelsea
87
87
  component
88
88
  end
89
89
 
90
- def _show_logo
91
- logo = %Q(
90
+ def _show_logo # rubocop:disable Metrics/MethodLength
91
+ logo = %(
92
92
  -o/
93
93
  -+hNmNN-
94
94
  .:+osyhddddyso/-``ody+- .NN.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -26,7 +28,7 @@ require_relative 'config'
26
28
  module Chelsea
27
29
  ##
28
30
  # This class provides an interface to the oss index, gems and deps
29
- class CLI
31
+ class CLI # rubocop:disable Metrics/ClassLength
30
32
  def initialize(opts)
31
33
  @opts = opts
32
34
  @pastel = Pastel.new
@@ -34,26 +36,28 @@ module Chelsea
34
36
  _show_logo # Move to formatter
35
37
  end
36
38
 
37
- def process!
39
+ # rubocop:disable Metrics/CyclomaticComplexity
40
+ def process! # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
38
41
  if @opts.config?
39
42
  _set_config # move to init
40
43
  elsif @opts.clear?
41
44
  require_relative 'db'
42
45
  Chelsea::DB.new.clear_cache
43
- puts "OSS Index cache cleared"
46
+ puts 'OSS Index cache cleared'
44
47
  elsif @opts.file? && @opts.iq?
45
48
  dependencies = _process_file_iq
46
49
  _submit_sbom(dependencies)
47
50
  elsif !@opts.file? && @opts.iq?
48
- abort "Missing the --file argument. It is required with the --iq argument."
51
+ abort 'Missing the --file argument. It is required with the --iq argument.'
49
52
  elsif @opts.file?
50
53
  _process_file
51
54
  elsif @opts.help? # quit on opts.help earlier
52
55
  puts _cli_flags # this doesn't exist
53
56
  else
54
- abort "Missing arguments! Chelsea did nothing. Try providing the --file <Gemfile.lock> argument."
57
+ abort 'Missing arguments! Chelsea did nothing. Try providing the --file <Gemfile.lock> argument.'
55
58
  end
56
59
  end
60
+ # rubocop:enable Metrics/CyclomaticComplexity
57
61
 
58
62
  def self.version
59
63
  Chelsea::VERSION
@@ -61,7 +65,7 @@ module Chelsea
61
65
 
62
66
  private
63
67
 
64
- def _submit_sbom(gems)
68
+ def _submit_sbom(gems) # rubocop:disable Metrics/MethodLength
65
69
  iq = Chelsea::IQClient.new(
66
70
  options: {
67
71
  public_application_id: @opts[:application],
@@ -74,7 +78,7 @@ module Chelsea
74
78
  bom = Chelsea::Bom.new(gems.deps.dependencies).collect
75
79
 
76
80
  status_url = iq.post_sbom(bom)
77
-
81
+
78
82
  return unless status_url
79
83
 
80
84
  msg, color, exit_code = iq.poll_status(status_url)
@@ -131,7 +135,7 @@ module Chelsea
131
135
 
132
136
  def _flags_set?
133
137
  # I'm still unsure what this is trying to express
134
- valid_flags = _flags.collect {|arg| @opts[arg] }.compact
138
+ valid_flags = _flags.collect { |arg| @opts[arg] }.compact
135
139
  valid_flags.count > 1
136
140
  end
137
141
 
@@ -143,7 +147,7 @@ module Chelsea
143
147
  def _show_logo
144
148
  font = TTY::Font.new(:doom)
145
149
  puts @pastel.green(font.write('Chelsea'))
146
- puts @pastel.green('Version: ' + CLI.version)
150
+ puts @pastel.green("Version: #{CLI.version}")
147
151
  end
148
152
 
149
153
  def _load_config
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -17,6 +19,7 @@
17
19
  require 'yaml'
18
20
  require_relative 'oss_index'
19
21
 
22
+ # Saved credentials
20
23
  module Chelsea
21
24
  @oss_index_config_location = File.join(Dir.home.to_s, '.ossindex')
22
25
  @oss_index_config_filename = '.oss-index-config'
@@ -43,10 +46,8 @@ module Chelsea
43
46
  @client
44
47
  end
45
48
 
46
- def self.oss_index_config
47
- if !File.exist? File.join(@oss_index_config_location, @oss_index_config_filename)
48
- { oss_index_user_name: '', oss_index_user_token: '' }
49
- else
49
+ def self.oss_index_config # rubocop:disable Metrics/MethodLength
50
+ if File.exist? File.join(@oss_index_config_location, @oss_index_config_filename)
50
51
  conf_hash = YAML.safe_load(
51
52
  File.read(
52
53
  File.join(@oss_index_config_location, @oss_index_config_filename)
@@ -56,6 +57,8 @@ module Chelsea
56
57
  oss_index_user_name: conf_hash['Username'],
57
58
  oss_index_user_token: conf_hash['Token']
58
59
  }
60
+ else
61
+ { oss_index_user_name: '', oss_index_user_token: '' }
59
62
  end
60
63
  end
61
64
 
@@ -71,20 +74,18 @@ module Chelsea
71
74
  config = {}
72
75
 
73
76
  puts 'What username do you want to authenticate as (ex: your email address)? '
74
- config['Username'] = STDIN.gets.chomp
77
+ config['Username'] = $stdin.gets.chomp
75
78
 
76
79
  puts 'What token do you want to use? '
77
- config['Token'] = STDIN.gets.chomp
80
+ config['Token'] = $stdin.gets.chomp
78
81
 
79
82
  _write_oss_index_config_file(config)
80
83
  end
81
84
 
82
85
  def self._write_oss_index_config_file(config)
83
- unless File.exist? @oss_index_config_location
84
- Dir.mkdir(@oss_index_config_location)
85
- end
86
- File.open(File.join(@oss_index_config_location, @oss_index_config_filename), "w") do |file|
86
+ Dir.mkdir(@oss_index_config_location) unless File.exist? @oss_index_config_location
87
+ File.open(File.join(@oss_index_config_location, @oss_index_config_filename), 'w') do |file|
87
88
  file.write config.to_yaml
88
89
  end
89
90
  end
90
- end
91
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -17,6 +19,7 @@
17
19
  require 'pstore'
18
20
 
19
21
  module Chelsea
22
+ # OSS Index data cache
20
23
  class DB
21
24
  def initialize
22
25
  @store = PStore.new(_get_db_store_location)
@@ -45,7 +48,7 @@ module Chelsea
45
48
  end
46
49
  end
47
50
 
48
- def _get_db_store_location()
51
+ def _get_db_store_location
49
52
  initial_path = File.join(Dir.home.to_s, '.ossindex')
50
53
  Dir.mkdir(initial_path) unless File.exist? initial_path
51
54
  File.join(initial_path, 'chelsea.pstore')
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -15,8 +17,9 @@
15
17
  #
16
18
 
17
19
  module Chelsea
20
+ # Project dependency exception
18
21
  class DependencyException < StandardError
19
- def initialize(msg="This is a custom exception", exception_type="custom")
22
+ def initialize(msg = 'This is a custom exception', exception_type = 'custom')
20
23
  @exception_type = exception_type
21
24
  super(msg)
22
25
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -22,6 +24,7 @@ require 'json'
22
24
  require 'rest-client'
23
25
 
24
26
  module Chelsea
27
+ # Project dependencies
25
28
  class Deps
26
29
  def initialize(path:, verbose: false)
27
30
  @verbose = verbose
@@ -47,7 +50,7 @@ module Chelsea
47
50
 
48
51
  # Collects all reverse dependencies in reverse_dependencies instance var
49
52
  # this rescue block honks
50
- def reverse_dependencies
53
+ def reverse_dependencies # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
51
54
  reverse = Gem::Commands::DependencyCommand.new
52
55
  reverse.options[:reverse_dependencies] = true
53
56
  # We want to filter the reverses dependencies by specs in lockfile
@@ -68,7 +71,7 @@ module Chelsea
68
71
  # in dependencies_versions and coordinates instance vars
69
72
  def coordinates
70
73
  dependencies.each_with_object({ 'coordinates' => [] }) do |(name, v), coords|
71
- coords['coordinates'] << self.class.to_purl(name, v[1]);
74
+ coords['coordinates'] << self.class.to_purl(name, v[1])
72
75
  end
73
76
  end
74
77
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -20,7 +22,7 @@ require_relative 'text'
20
22
 
21
23
  # Factory for formatting dependencies
22
24
  class FormatterFactory
23
- def get_formatter(format: 'text', verbose:)
25
+ def get_formatter(verbose:, format: 'text')
24
26
  case format
25
27
  when 'text'
26
28
  Chelsea::TextFormatter.new verbose: verbose
@@ -28,7 +30,7 @@ class FormatterFactory
28
30
  Chelsea::JsonFormatter.new verbose: verbose
29
31
  when 'xml'
30
32
  Chelsea::XMLFormatter.new verbose: verbose
31
- else
33
+ else # rubocop:disable Lint/DuplicateBranch
32
34
  Chelsea::TextFormatter.new verbose: verbose
33
35
  end
34
36
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -14,15 +16,17 @@
14
16
  # limitations under the License.
15
17
  #
16
18
 
19
+ # Base formatter class
17
20
  class Formatter
18
- def initialize
19
- @pastel = Pastel.new
20
- end
21
- def get_results
22
- raise 'must implement get_results method in subclass'
23
- end
24
-
25
- def do_print
26
- raise 'must implement do_print method in subclass'
27
- end
28
- end
21
+ def initialize
22
+ @pastel = Pastel.new
23
+ end
24
+
25
+ def fetch_results
26
+ raise 'must implement get_results method in subclass'
27
+ end
28
+
29
+ def do_print
30
+ raise 'must implement do_print method in subclass'
31
+ end
32
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -18,12 +20,14 @@ require 'json'
18
20
  require_relative 'formatter'
19
21
 
20
22
  module Chelsea
23
+ # Produce output in json format
21
24
  class JsonFormatter < Formatter
22
25
  def initialize(options)
26
+ super()
23
27
  @options = options
24
28
  end
25
29
 
26
- def get_results(server_response, reverse_deps)
30
+ def fetch_results(server_response, _reverse_deps)
27
31
  server_response.to_json
28
32
  end
29
33
 
@@ -1,3 +1,6 @@
1
+ # rubocop:disable Style/FrozenStringLiteralComment
2
+ # rubocop:enable Style/FrozenStringLiteralComment
3
+
1
4
  #
2
5
  # Copyright 2019-Present Sonatype Inc.
3
6
  #
@@ -19,13 +22,16 @@ require 'tty-table'
19
22
  require_relative 'formatter'
20
23
 
21
24
  module Chelsea
25
+ # Produce output in text format
22
26
  class TextFormatter < Formatter
23
27
  def initialize(options)
28
+ super()
24
29
  @options = options
25
30
  @pastel = Pastel.new
26
31
  end
27
32
 
28
- def get_results(server_response, reverse_dependencies)
33
+ # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
34
+ def fetch_results(server_response, reverse_dependencies) # rubocop:disable Metrics/MethodLength
29
35
  response = ''
30
36
  if @options[:verbose]
31
37
  response += "\n"\
@@ -65,6 +71,7 @@ module Chelsea
65
71
  response += table.render(:unicode)
66
72
  response
67
73
  end
74
+ # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
68
75
 
69
76
  def do_print(results)
70
77
  puts results
@@ -109,9 +116,7 @@ module Chelsea
109
116
  def _get_reverse_deps(coords, name)
110
117
  coords.each_with_object('') do |dep, s|
111
118
  dep.each do |gran|
112
- if gran.class == String && !gran.include?(name)
113
- s << "\tRequired by: #{gran}\n"
114
- end
119
+ s << "\tRequired by: #{gran}\n" if gran.instance_of?(String) && !gran.include?(name)
115
120
  end
116
121
  end
117
122
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -17,12 +19,14 @@
17
19
  require 'ox'
18
20
  require_relative 'formatter'
19
21
  module Chelsea
22
+ # Produce output in xml format
20
23
  class XMLFormatter < Formatter
21
24
  def initialize(options)
25
+ super()
22
26
  @options = options
23
27
  end
24
28
 
25
- def get_results(server_response, reverse_deps)
29
+ def fetch_results(server_response, _reverse_deps) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
26
30
  doc = Ox::Document.new
27
31
  instruct = Ox::Instruct.new(:xml)
28
32
  instruct[:version] = '1.0'
@@ -37,13 +41,13 @@ module Chelsea
37
41
 
38
42
  server_response.each do |coord|
39
43
  testcase = Ox::Element.new('testcase')
40
- testcase[:classname] = coord["coordinates"]
41
- testcase[:name] = coord["coordinates"]
44
+ testcase[:classname] = coord['coordinates']
45
+ testcase[:name] = coord['coordinates']
42
46
 
43
47
  if coord['vulnerabilities'].length.positive?
44
48
  failure = Ox::Element.new('failure')
45
- failure[:type] = "Vulnerable Dependency"
46
- failure << get_vulnerability_block(coord["vulnerabilities"])
49
+ failure[:type] = 'Vulnerable Dependency'
50
+ failure << get_vulnerability_block(coord['vulnerabilities'])
47
51
  testcase << failure
48
52
  testsuite << testcase
49
53
  elsif @options[:verbose]
@@ -58,20 +62,20 @@ module Chelsea
58
62
  puts Ox.dump(results)
59
63
  end
60
64
 
61
- def get_vulnerability_block(vulnerabilities)
62
- vulnBlock = String.new
65
+ def get_vulnerability_block(vulnerabilities) # rubocop:disable Metrics/MethodLength
66
+ vuln_block = ''
63
67
  vulnerabilities.each do |vuln|
64
- vulnBlock += "Vulnerability Title: #{vuln["title"]}\n"\
65
- "ID: #{vuln["id"]}\n"\
66
- "Description: #{vuln["description"]}\n"\
67
- "CVSS Score: #{vuln["cvssScore"]}\n"\
68
- "CVSS Vector: #{vuln["cvssVector"]}\n"\
69
- "CVE: #{vuln["cve"]}\n"\
70
- "Reference: #{vuln["reference"]}"\
68
+ vuln_block += "Vulnerability Title: #{vuln['title']}\n"\
69
+ "ID: #{vuln['id']}\n"\
70
+ "Description: #{vuln['description']}\n"\
71
+ "CVSS Score: #{vuln['cvssScore']}\n"\
72
+ "CVSS Vector: #{vuln['cvssVector']}\n"\
73
+ "CVE: #{vuln['cve']}\n"\
74
+ "Reference: #{vuln['reference']}"\
71
75
  "\n"
72
76
  end
73
-
74
- vulnBlock
77
+
78
+ vuln_block
75
79
  end
76
80
  end
77
81
  end
@@ -15,6 +15,7 @@
15
15
  #
16
16
 
17
17
  # frozen_string_literal: true
18
+
18
19
  require 'pastel'
19
20
  require 'bundler'
20
21
  require 'bundler/lockfile_parser'
@@ -31,11 +32,10 @@ module Chelsea
31
32
  # Class to collect and audit packages from a Gemfile.lock
32
33
  class Gems
33
34
  attr_accessor :deps
34
- def initialize(file:, verbose:, options: { 'format': 'text' })
35
+
36
+ def initialize(file:, verbose:, options: { format: 'text' }) # rubocop:disable Metrics/MethodLength
35
37
  @verbose = verbose
36
- unless File.file?(file) || file.nil?
37
- raise 'Gemfile.lock not found, check --file path'
38
- end
38
+ raise 'Gemfile.lock not found, check --file path' unless File.file?(file) || file.nil?
39
39
 
40
40
  _silence_stderr unless @verbose
41
41
 
@@ -52,7 +52,7 @@ module Chelsea
52
52
  # Audits depenencies using deps library and prints results
53
53
  # using formatter library
54
54
 
55
- def execute
55
+ def execute # rubocop:disable Metrics/MethodLength
56
56
  server_response, dependencies, reverse_dependencies = audit
57
57
  if dependencies.nil?
58
58
  _print_err 'No dependencies retrieved. Exiting.'
@@ -62,20 +62,19 @@ module Chelsea
62
62
  _print_success 'No vulnerability data retrieved from server. Exiting.'
63
63
  return
64
64
  end
65
- results = @formatter.get_results(server_response, reverse_dependencies)
65
+ results = @formatter.fetch_results(server_response, reverse_dependencies)
66
66
  @formatter.do_print(results)
67
67
 
68
68
  server_response.map { |r| r['vulnerabilities'].length.positive? }.any?
69
69
  end
70
70
 
71
71
  def collect_iq
72
- dependencies = @deps.dependencies
73
- dependencies
72
+ @deps.dependencies
74
73
  end
75
74
 
76
75
  # Runs through auditing algorithm, raising exceptions
77
76
  # on REST calls made by @deps.get_vulns
78
- def audit
77
+ def audit # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
79
78
  # This spinner management is out of control
80
79
  # we should wrap a block with start and stop messages,
81
80
  # or use a stack to ensure all spinners stop.
@@ -84,7 +83,7 @@ module Chelsea
84
83
  begin
85
84
  dependencies = @deps.dependencies
86
85
  spin.success('...done.')
87
- rescue StandardError => e
86
+ rescue StandardError
88
87
  spin.stop
89
88
  _print_err "Parsing dependency line #{gem} failed."
90
89
  end
@@ -100,16 +99,16 @@ module Chelsea
100
99
  begin
101
100
  server_response = @client.get_vulns(coordinates)
102
101
  spin.success('...done.')
103
- rescue SocketError => e
102
+ rescue SocketError
104
103
  spin.stop('...request failed.')
105
104
  _print_err 'Socket error getting data from OSS Index server.'
106
105
  rescue RestClient::RequestFailed => e
107
106
  spin.stop('...request failed.')
108
107
  _print_err "Error getting data from OSS Index server:#{e.response}."
109
- rescue RestClient::ResourceNotFound => e
108
+ rescue RestClient::ResourceNotFound
110
109
  spin.stop('...request failed.')
111
110
  _print_err 'Error getting data from OSS Index server. Resource not found.'
112
- rescue Errno::ECONNREFUSED => e
111
+ rescue Errno::ECONNREFUSED
113
112
  spin.stop('...request failed.')
114
113
  _print_err 'Error getting data from OSS Index server. Connection refused.'
115
114
  end
@@ -122,12 +121,12 @@ module Chelsea
122
121
  $stderr.reopen('/dev/null', 'w')
123
122
  end
124
123
 
125
- def _print_err(s)
126
- puts @pastel.red.bold(s)
124
+ def _print_err(msg)
125
+ puts @pastel.red.bold(msg)
127
126
  end
128
127
 
129
- def _print_success(s)
130
- puts @pastel.green.bold(s)
128
+ def _print_success(msg)
129
+ puts @pastel.green.bold(msg)
131
130
  end
132
131
  end
133
132
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -22,8 +24,8 @@ require 'uri'
22
24
  require_relative 'spinner'
23
25
 
24
26
  module Chelsea
25
- class IQClient
26
-
27
+ # IQ audit operations
28
+ class IQClient # rubocop:disable Metrics/ClassLength
27
29
  DEFAULT_OPTIONS = {
28
30
  public_application_id: 'testapp',
29
31
  server_url: 'http://localhost:8070',
@@ -31,7 +33,7 @@ module Chelsea
31
33
  auth_token: 'admin123',
32
34
  internal_application_id: '',
33
35
  stage: 'build'
34
- }
36
+ }.freeze
35
37
 
36
38
  def initialize(options: DEFAULT_OPTIONS)
37
39
  @options = options
@@ -39,8 +41,8 @@ module Chelsea
39
41
  @spinner = Chelsea::Spinner.new
40
42
  end
41
43
 
42
- def post_sbom(sbom)
43
- spin = @spinner.spin_msg "Submitting sbom to Nexus IQ Server"
44
+ def post_sbom(sbom) # rubocop:disable Metrics/MethodLength
45
+ spin = @spinner.spin_msg 'Submitting sbom to Nexus IQ Server'
44
46
  @internal_application_id = _get_internal_application_id
45
47
  resource = RestClient::Resource.new(
46
48
  _api_url,
@@ -48,12 +50,12 @@ module Chelsea
48
50
  password: @options[:auth_token]
49
51
  )
50
52
  res = resource.post sbom.to_s, _headers.merge(content_type: 'application/xml')
51
- if res.code != 202
53
+ if res.code == 202
54
+ spin.success('...done.')
55
+ status_url(res)
56
+ else
52
57
  spin.stop('...request failed.')
53
58
  nil
54
- else
55
- spin.success("...done.")
56
- status_url(res)
57
59
  end
58
60
  end
59
61
 
@@ -63,17 +65,15 @@ module Chelsea
63
65
  end
64
66
 
65
67
  def poll_status(url)
66
- spin = @spinner.spin_msg "Polling Nexus IQ Server for results"
68
+ spin = @spinner.spin_msg 'Polling Nexus IQ Server for results'
67
69
  loop do
68
- begin
69
- res = _poll_iq_server(url)
70
- if res.code == 200
71
- spin.success("...done.")
72
- return _handle_response(res)
73
- end
74
- rescue
75
- sleep(1)
70
+ res = _poll_iq_server(url)
71
+ if res.code == 200
72
+ spin.success('...done.')
73
+ return _handle_response(res)
76
74
  end
75
+ rescue StandardError
76
+ sleep(1)
77
77
  end
78
78
  end
79
79
 
@@ -88,28 +88,28 @@ module Chelsea
88
88
 
89
89
  private
90
90
 
91
- def _handle_response(res)
91
+ def _handle_response(res) # rubocop:disable Metrics/MethodLength
92
92
  res = JSON.parse(res.body)
93
93
  # get absolute report url
94
94
  absolute_report_html_url = URI.join(@options[:server_url], res['reportHtmlUrl'])
95
95
 
96
96
  case res['policyAction']
97
97
  when POLICY_ACTION_FAILURE
98
- return "Hi! Chelsea here, you have some policy violations to clean up!"\
98
+ ['Hi! Chelsea here, you have some policy violations to clean up!'\
99
99
  "\nReport URL: #{absolute_report_html_url}",
100
- COLOR_FAILURE, 1
100
+ COLOR_FAILURE, 1]
101
101
  when POLICY_ACTION_WARNING
102
- return "Hi! Chelsea here, you have some policy warnings to peck at!"\
102
+ ['Hi! Chelsea here, you have some policy warnings to peck at!'\
103
103
  "\nReport URL: #{absolute_report_html_url}",
104
- COLOR_WARNING, 0
104
+ COLOR_WARNING, 0]
105
105
  when POLICY_ACTION_NONE
106
- return "Hi! Chelsea here, no policy violations for this audit!"\
106
+ ['Hi! Chelsea here, no policy violations for this audit!'\
107
107
  "\nReport URL: #{absolute_report_html_url}",
108
- COLOR_NONE, 0
108
+ COLOR_NONE, 0]
109
109
  else
110
- return "Hi! Chelsea here, no policy violations for this audit, but unknown policy action!"\
110
+ ['Hi! Chelsea here, no policy violations for this audit, but unknown policy action!'\
111
111
  "\nReport URL: #{absolute_report_html_url}",
112
- COLOR_FAILURE, 1
112
+ COLOR_FAILURE, 1]
113
113
  end
114
114
  end
115
115
 
@@ -137,26 +137,22 @@ module Chelsea
137
137
  res['statusUrl']
138
138
  end
139
139
 
140
- private
141
-
142
- def _poll_status
140
+ def _poll_status # rubocop:disable Metrics/MethodLength
143
141
  return unless @status_url
144
142
 
145
143
  loop do
146
- begin
147
- res = check_status(@status_url)
148
- if res.code == 200
149
- puts JSON.parse(res.body)
150
- break
151
- end
152
- rescue RestClient::ResourceNotFound => _e
153
- print '.'
154
- sleep(1)
144
+ res = check_status(@status_url)
145
+ if res.code == 200
146
+ puts JSON.parse(res.body)
147
+ break
155
148
  end
149
+ rescue RestClient::ResourceNotFound => _e
150
+ print '.'
151
+ sleep(1)
156
152
  end
157
153
  end
158
154
 
159
- def _get_internal_application_id
155
+ def _get_internal_application_id # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
160
156
  resource = RestClient::Resource.new(
161
157
  _internal_application_id_api_url,
162
158
  user: @options[:username],
@@ -164,7 +160,7 @@ module Chelsea
164
160
  )
165
161
  res = resource.get _headers
166
162
  if res.code != 200
167
- puts "failed to get internal application id for IQ application id: #{@options[:public_application_id]}. response status: #{res.code}"
163
+ puts "failure reading application id: #{@options[:public_application_id]}. response status: #{res.code}"
168
164
  return
169
165
  end
170
166
  body = JSON.parse(res)
@@ -180,7 +176,9 @@ module Chelsea
180
176
  end
181
177
 
182
178
  def _api_url
179
+ # rubocop:disable Layout/LineLength
183
180
  "#{@options[:server_url]}/api/v2/scan/applications/#{@internal_application_id}/sources/chelsea?stageId=#{@options[:stage]}"
181
+ # rubocop:enable Layout/LineLength
184
182
  end
185
183
 
186
184
  def _internal_application_id_api_url
@@ -21,11 +21,12 @@ require 'rest-client'
21
21
  require_relative 'db'
22
22
 
23
23
  module Chelsea
24
+ # OSS Index audit operations
24
25
  class OSSIndex
25
26
  DEFAULT_OPTIONS = {
26
27
  oss_index_username: '',
27
28
  oss_index_user_token: ''
28
- }
29
+ }.freeze
29
30
  def initialize(options: DEFAULT_OPTIONS)
30
31
  @oss_index_user_name = options[:oss_index_user_name]
31
32
  @oss_index_user_token = options[:oss_index_user_token]
@@ -37,13 +38,11 @@ module Chelsea
37
38
 
38
39
  def get_vulns(coordinates)
39
40
  remaining_coordinates, cached_server_response = _cache(coordinates)
40
- unless remaining_coordinates['coordinates'].count.positive?
41
- return cached_server_response
42
- end
41
+ return cached_server_response unless remaining_coordinates['coordinates'].count.positive?
43
42
 
44
43
  remaining_coordinates['coordinates'].each_slice(128).to_a.each do |coords|
45
44
  res_json = JSON.parse(call_oss_index({ 'coordinates' => coords }))
46
- cached_server_response = cached_server_response.concat(res_json)
45
+ cached_server_response.concat(res_json)
47
46
  @db.save_values_to_db(res_json)
48
47
  end
49
48
 
@@ -57,15 +56,15 @@ module Chelsea
57
56
 
58
57
  private
59
58
 
60
- def _cache(coordinates)
59
+ def _cache(coordinates) # rubocop:disable Metrics/MethodLength
61
60
  new_coords = { 'coordinates' => [] }
62
61
  cached_server_response = []
63
62
  coordinates['coordinates'].each do |coord|
64
63
  record = @db.get_cached_value_from_db(coord)
65
- if !record.nil?
66
- cached_server_response << record
67
- else
64
+ if record.nil?
68
65
  new_coords['coordinates'].push(coord)
66
+ else
67
+ cached_server_response << record
69
68
  end
70
69
  end
71
70
  [new_coords, cached_server_response]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -18,6 +20,7 @@ require 'tty-spinner'
18
20
  require 'pastel'
19
21
 
20
22
  module Chelsea
23
+ # the spinner we use in Chelsea, needs work
21
24
  class Spinner
22
25
  def initialize
23
26
  @pastel = Pastel.new
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Copyright 2019-Present Sonatype Inc.
3
5
  #
@@ -15,5 +17,5 @@
15
17
  #
16
18
 
17
19
  module Chelsea
18
- VERSION = '0.0.27'.freeze
20
+ VERSION = '0.0.28'
19
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chelsea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.27
4
+ version: 0.0.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Allister Beharry
@@ -11,109 +11,109 @@ cert_chain: []
11
11
  date: 2021-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: tty-font
14
+ name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.5.0
19
+ version: 1.2.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '3'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: 0.5.0
29
+ version: 1.2.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '3'
27
33
  - !ruby/object:Gem::Dependency
28
- name: tty-spinner
34
+ name: ox
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - "~>"
32
38
  - !ruby/object:Gem::Version
33
- version: 0.9.3
39
+ version: 2.13.2
34
40
  type: :runtime
35
41
  prerelease: false
36
42
  version_requirements: !ruby/object:Gem::Requirement
37
43
  requirements:
38
44
  - - "~>"
39
45
  - !ruby/object:Gem::Version
40
- version: 0.9.3
46
+ version: 2.13.2
41
47
  - !ruby/object:Gem::Dependency
42
- name: slop
48
+ name: pastel
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
51
  - - "~>"
46
52
  - !ruby/object:Gem::Version
47
- version: 4.8.1
53
+ version: 0.7.2
48
54
  type: :runtime
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
51
57
  requirements:
52
58
  - - "~>"
53
59
  - !ruby/object:Gem::Version
54
- version: 4.8.1
60
+ version: 0.7.2
55
61
  - !ruby/object:Gem::Dependency
56
- name: pastel
62
+ name: rest-client
57
63
  requirement: !ruby/object:Gem::Requirement
58
64
  requirements:
59
65
  - - "~>"
60
66
  - !ruby/object:Gem::Version
61
- version: 0.7.2
67
+ version: 2.0.2
62
68
  type: :runtime
63
69
  prerelease: false
64
70
  version_requirements: !ruby/object:Gem::Requirement
65
71
  requirements:
66
72
  - - "~>"
67
73
  - !ruby/object:Gem::Version
68
- version: 0.7.2
74
+ version: 2.0.2
69
75
  - !ruby/object:Gem::Dependency
70
- name: rest-client
76
+ name: slop
71
77
  requirement: !ruby/object:Gem::Requirement
72
78
  requirements:
73
79
  - - "~>"
74
80
  - !ruby/object:Gem::Version
75
- version: 2.0.2
81
+ version: 4.8.1
76
82
  type: :runtime
77
83
  prerelease: false
78
84
  version_requirements: !ruby/object:Gem::Requirement
79
85
  requirements:
80
86
  - - "~>"
81
87
  - !ruby/object:Gem::Version
82
- version: 2.0.2
88
+ version: 4.8.1
83
89
  - !ruby/object:Gem::Dependency
84
- name: bundler
90
+ name: tty-font
85
91
  requirement: !ruby/object:Gem::Requirement
86
92
  requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: 1.2.0
90
- - - "<"
93
+ - - "~>"
91
94
  - !ruby/object:Gem::Version
92
- version: '3'
95
+ version: 0.5.0
93
96
  type: :runtime
94
97
  prerelease: false
95
98
  version_requirements: !ruby/object:Gem::Requirement
96
99
  requirements:
97
- - - ">="
98
- - !ruby/object:Gem::Version
99
- version: 1.2.0
100
- - - "<"
100
+ - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '3'
102
+ version: 0.5.0
103
103
  - !ruby/object:Gem::Dependency
104
- name: ox
104
+ name: tty-spinner
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: 2.13.2
109
+ version: 0.9.3
110
110
  type: :runtime
111
111
  prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: 2.13.2
116
+ version: 0.9.3
117
117
  - !ruby/object:Gem::Dependency
118
118
  name: tty-table
119
119
  requirement: !ruby/object:Gem::Requirement
@@ -128,6 +128,20 @@ dependencies:
128
128
  - - "~>"
129
129
  - !ruby/object:Gem::Version
130
130
  version: 0.11.0
131
+ - !ruby/object:Gem::Dependency
132
+ name: byebug
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: 11.1.2
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: 11.1.2
131
145
  - !ruby/object:Gem::Dependency
132
146
  name: rake
133
147
  requirement: !ruby/object:Gem::Requirement
@@ -184,20 +198,6 @@ dependencies:
184
198
  - - "~>"
185
199
  - !ruby/object:Gem::Version
186
200
  version: 3.8.3
187
- - !ruby/object:Gem::Dependency
188
- name: byebug
189
- requirement: !ruby/object:Gem::Requirement
190
- requirements:
191
- - - "~>"
192
- - !ruby/object:Gem::Version
193
- version: 11.1.2
194
- type: :development
195
- prerelease: false
196
- version_requirements: !ruby/object:Gem::Requirement
197
- requirements:
198
- - - "~>"
199
- - !ruby/object:Gem::Version
200
- version: 11.1.2
201
201
  description:
202
202
  email:
203
203
  - allister.beharry@gmail.com
@@ -217,6 +217,7 @@ files:
217
217
  - ".github/pull_request_template.md"
218
218
  - ".gitignore"
219
219
  - ".rspec"
220
+ - ".rubocop.yml"
220
221
  - ".vscode/launch.json"
221
222
  - CODE_OF_CONDUCT.md
222
223
  - CONTRIBUTORS.md
@@ -267,7 +268,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
267
268
  requirements:
268
269
  - - ">="
269
270
  - !ruby/object:Gem::Version
270
- version: '0'
271
+ version: 2.6.6
271
272
  required_rubygems_version: !ruby/object:Gem::Requirement
272
273
  requirements:
273
274
  - - ">="