chelsea 0.0.18 → 0.0.19
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 +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +19 -3
- data/Jenkinsfile +2 -0
- data/bin/chelsea +1 -1
- data/chelsea.gemspec +2 -0
- data/lib/chelsea/cli.rb +2 -2
- data/lib/chelsea/deps.rb +3 -3
- data/lib/chelsea/formatters/factory.rb +5 -5
- data/lib/chelsea/formatters/text.rb +52 -37
- data/lib/chelsea/formatters/xml.rb +6 -5
- data/lib/chelsea/gems.rb +7 -8
- data/lib/chelsea/oss_index.rb +3 -3
- data/lib/chelsea/version.rb +1 -1
- metadata +30 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a44baa47f70b877e0f6b8051962bf0c66eae508bb0fa148d47056b7d5dfdf6bb
|
|
4
|
+
data.tar.gz: 5565acd13beccaab790612682ae19d50a8b9c4427f83692476ffcbe6ddd5425c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 50c1634dae11bd146bbf734706abc60b3c06bb6cab1bb177cbf5e98c528c4d1dd25a0a9fd4d47719b3887dc4aaf9ce7a5f42126d7973b1008eac4c87c99cdd7b
|
|
7
|
+
data.tar.gz: f8db897e7a16e5f87b8a3f3f0f7a8ae98541d058922c54d4d580fbe36763e128f3b30f9f8cde5f138b410af172208d3948025ee9342858113ab31ea1fe1ac51c
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
chelsea (0.0.
|
|
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.
|
|
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.
|
|
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)
|
data/Jenkinsfile
CHANGED
data/bin/chelsea
CHANGED
|
@@ -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 '-
|
|
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
|
data/chelsea.gemspec
CHANGED
|
@@ -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
|
data/lib/chelsea/cli.rb
CHANGED
|
@@ -78,7 +78,7 @@ module Chelsea
|
|
|
78
78
|
def _process_file
|
|
79
79
|
gems = Chelsea::Gems.new(
|
|
80
80
|
file: @opts[:file],
|
|
81
|
-
|
|
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
|
-
|
|
90
|
+
verbose: @opts[:verbose],
|
|
91
91
|
options: @opts
|
|
92
92
|
)
|
|
93
93
|
gems.collect_iq
|
data/lib/chelsea/deps.rb
CHANGED
|
@@ -23,8 +23,8 @@ require 'rest-client'
|
|
|
23
23
|
|
|
24
24
|
module Chelsea
|
|
25
25
|
class Deps
|
|
26
|
-
def initialize(path:,
|
|
27
|
-
@
|
|
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',
|
|
23
|
+
def get_formatter(format: 'text', verbose:)
|
|
24
24
|
case format
|
|
25
25
|
when 'text'
|
|
26
|
-
Chelsea::TextFormatter.new
|
|
26
|
+
Chelsea::TextFormatter.new verbose: verbose
|
|
27
27
|
when 'json'
|
|
28
|
-
Chelsea::JsonFormatter.new
|
|
28
|
+
Chelsea::JsonFormatter.new verbose: verbose
|
|
29
29
|
when 'xml'
|
|
30
|
-
Chelsea::XMLFormatter.new
|
|
30
|
+
Chelsea::XMLFormatter.new verbose: verbose
|
|
31
31
|
else
|
|
32
|
-
Chelsea::TextFormatter.new
|
|
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(
|
|
23
|
-
@
|
|
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 =
|
|
29
|
-
if
|
|
29
|
+
response = ''
|
|
30
|
+
if @options[:verbose]
|
|
30
31
|
response += "\n"\
|
|
31
32
|
"Audit Results\n"\
|
|
32
33
|
"=============\n"
|
|
33
34
|
end
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
server_response.each do |r|
|
|
40
|
-
|
|
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
|
|
48
|
-
response += @pastel.red(
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
82
|
-
|
|
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
|
|
99
|
+
@pastel.cyan.bold
|
|
85
100
|
when 4..5
|
|
86
|
-
@pastel.yellow.bold
|
|
101
|
+
@pastel.yellow.bold
|
|
87
102
|
when 6..7
|
|
88
|
-
@pastel.orange.bold
|
|
103
|
+
@pastel.orange.bold
|
|
89
104
|
else
|
|
90
|
-
@pastel.red.bold
|
|
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(
|
|
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] =
|
|
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[
|
|
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
|
data/lib/chelsea/gems.rb
CHANGED
|
@@ -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:,
|
|
35
|
-
@
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
data/lib/chelsea/oss_index.rb
CHANGED
|
@@ -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 ?
|
|
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
|
|
86
|
+
RestClient::Resource.new(_api_url)
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
|
data/lib/chelsea/version.rb
CHANGED
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.
|
|
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-
|
|
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
|