chelsea 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +9 -0
- data/Gemfile.lock +5 -2
- data/README.md +1 -1
- data/bin/chelsea +1 -1
- data/chelsea.gemspec +0 -1
- data/lib/chelsea/gems.rb +118 -14
- data/lib/chelsea/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1633315a7f5da46a2c43414058160959b0be5202a3c7a6aa333e99f91f48a755
|
4
|
+
data.tar.gz: ac7a5f1f3c77061ccf54edf458758b621038f74ca9e272261cb0dc417cb94298
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b7eea08843bed093b27054b29da075edfc63730836421e8151e0dfd661d06f030bf7be242c8a08e11d5c4aae49434d3976f4b8a628962f44fa8e8b787979eea
|
7
|
+
data.tar.gz: c946fd43b812750e8d3ebe7b4c13914ca54e257c6b86a63d3abb1224bec4d94af027a1e4dcc7cd65940af23091b5e82d10d99e5397c1406e6d4199f2fb2f49b8
|
data/.circleci/config.yml
CHANGED
@@ -30,6 +30,15 @@ jobs:
|
|
30
30
|
bundle exec rspec --format progress \
|
31
31
|
--format RspecJunitFormatter \
|
32
32
|
--out test_results/rspec.xml
|
33
|
+
- run:
|
34
|
+
name: Build gem
|
35
|
+
command: gem build chelsea.gemspec
|
36
|
+
- run:
|
37
|
+
name: Install gem
|
38
|
+
command: gem install ./chelsea-*.gem
|
39
|
+
- run:
|
40
|
+
name: Dogfood
|
41
|
+
command: chelsea --file Gemfile.lock
|
33
42
|
- store_test_results:
|
34
43
|
path: test_results
|
35
44
|
release:
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
chelsea (0.0.
|
5
|
-
bundler (
|
4
|
+
chelsea (0.0.2)
|
5
|
+
bundler (>= 1.2.0, < 3)
|
6
6
|
pastel (~> 0.7.2)
|
7
7
|
rest-client (~> 2.0.2)
|
8
8
|
slop (~> 4.8.0)
|
@@ -43,6 +43,8 @@ GEM
|
|
43
43
|
diff-lcs (>= 1.2.0, < 2.0)
|
44
44
|
rspec-support (~> 3.9.0)
|
45
45
|
rspec-support (3.9.2)
|
46
|
+
rspec_junit_formatter (0.4.1)
|
47
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
46
48
|
slop (4.8.0)
|
47
49
|
tty-color (0.5.1)
|
48
50
|
tty-cursor (0.7.1)
|
@@ -60,6 +62,7 @@ DEPENDENCIES
|
|
60
62
|
chelsea!
|
61
63
|
rake (~> 10.0)
|
62
64
|
rspec (~> 3.0)
|
65
|
+
rspec_junit_formatter (~> 0.4.1)
|
63
66
|
|
64
67
|
BUNDLED WITH
|
65
68
|
2.0.2
|
data/README.md
CHANGED
data/bin/chelsea
CHANGED
data/chelsea.gemspec
CHANGED
@@ -35,7 +35,6 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
36
36
|
spec.require_paths = ["lib"]
|
37
37
|
|
38
|
-
|
39
38
|
spec.add_dependency "tty-font", "~> 0.5.0"
|
40
39
|
spec.add_dependency "tty-spinner", "~> 0.9.3"
|
41
40
|
spec.add_dependency "slop", "~> 4.8.0"
|
data/lib/chelsea/gems.rb
CHANGED
@@ -5,6 +5,9 @@ require 'tty-spinner'
|
|
5
5
|
require 'bundler'
|
6
6
|
require 'bundler/lockfile_parser'
|
7
7
|
require_relative 'version'
|
8
|
+
require 'rubygems'
|
9
|
+
require 'rubygems/commands/dependency_command'
|
10
|
+
require 'pstore'
|
8
11
|
|
9
12
|
module Chelsea
|
10
13
|
class Gems
|
@@ -17,6 +20,8 @@ module Chelsea
|
|
17
20
|
@coordinates = Hash.new()
|
18
21
|
@coordinates["coordinates"] = Array.new()
|
19
22
|
@server_response = Array.new()
|
23
|
+
@reverse_deps = Hash.new()
|
24
|
+
@store = PStore.new(get_db_store_location())
|
20
25
|
|
21
26
|
if not gemfile_lock_file_exists()
|
22
27
|
return
|
@@ -28,6 +33,12 @@ module Chelsea
|
|
28
33
|
)
|
29
34
|
end
|
30
35
|
|
36
|
+
def get_db_store_location()
|
37
|
+
initial_path = File.join("#{Dir.home}", ".ossindex")
|
38
|
+
Dir.mkdir(initial_path) unless File.exists? initial_path
|
39
|
+
path = File.join(initial_path, "chelsea.pstore")
|
40
|
+
end
|
41
|
+
|
31
42
|
def execute(input: $stdin, output: $stdout)
|
32
43
|
n = get_dependencies()
|
33
44
|
if n == 0
|
@@ -58,6 +69,10 @@ module Chelsea
|
|
58
69
|
spinner = TTY::Spinner.new(format, success_mark: @pastel.green('+'), hide_cursor: true)
|
59
70
|
spinner.auto_spin()
|
60
71
|
|
72
|
+
reverse = Gem::Commands::DependencyCommand.new
|
73
|
+
reverse.options[:reverse_dependencies] = true
|
74
|
+
@reverse_deps = reverse.reverse_dependencies(@lockfile.specs)
|
75
|
+
|
61
76
|
@lockfile.specs.each do |gem|
|
62
77
|
@dependencies[gem.name] = [gem.name, gem.version]
|
63
78
|
rescue StandardError => e
|
@@ -95,28 +110,36 @@ module Chelsea
|
|
95
110
|
end
|
96
111
|
end
|
97
112
|
|
98
|
-
def get_user_agent()
|
99
|
-
user_agent = "chelsea/#{Chelsea::VERSION}"
|
100
|
-
|
101
|
-
user_agent
|
102
|
-
end
|
103
|
-
|
104
113
|
def get_vulns()
|
105
114
|
require 'json'
|
106
115
|
require 'rest-client'
|
107
116
|
format = "[#{@pastel.green(':spinner')}] " + @pastel.white("Making request to OSS Index server")
|
108
117
|
spinner = TTY::Spinner.new(format, success_mark: @pastel.green('+'), hide_cursor: true)
|
109
118
|
spinner.auto_spin()
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
119
|
+
|
120
|
+
check_db_for_cached_values()
|
121
|
+
|
122
|
+
if @coordinates["coordinates"].count() > 0
|
123
|
+
chunked = Hash.new()
|
124
|
+
@coordinates["coordinates"].each_slice(128).to_a.each do |coords|
|
125
|
+
chunked["coordinates"] = coords
|
126
|
+
r = RestClient.post "https://ossindex.sonatype.org/api/v3/component-report", chunked.to_json,
|
127
|
+
{content_type: :json, accept: :json, 'User-Agent': get_user_agent()}
|
128
|
+
|
129
|
+
if r.code == 200
|
130
|
+
@server_response = @server_response.concat(JSON.parse(r.body))
|
131
|
+
save_values_to_db(JSON.parse(r.body))
|
132
|
+
spinner.success("...done.")
|
133
|
+
@server_response.count()
|
134
|
+
else
|
135
|
+
spinner.stop("...request failed.")
|
136
|
+
print_err "Error getting data from OSS Index server. Server returned non-success code #{r.code}."
|
137
|
+
0
|
138
|
+
end
|
139
|
+
end
|
140
|
+
else
|
114
141
|
spinner.success("...done.")
|
115
142
|
@server_response.count()
|
116
|
-
else
|
117
|
-
spinner.stop("...request failed.")
|
118
|
-
print_err "Error getting data from OSS Index server. Server returned non-success code #{r.code}."
|
119
|
-
0
|
120
143
|
end
|
121
144
|
rescue SocketError => e
|
122
145
|
spinner.stop("...request failed.")
|
@@ -150,17 +173,42 @@ module Chelsea
|
|
150
173
|
i += 1
|
151
174
|
package = r["coordinates"]
|
152
175
|
vulnerable = r["vulnerabilities"].length() > 0
|
176
|
+
coord = r["coordinates"].sub("pkg:gem/", "")
|
177
|
+
name = coord.split('@')[0]
|
178
|
+
version = coord.split('@')[1]
|
179
|
+
reverse_dep_coord = "#{name}-#{version}"
|
153
180
|
if vulnerable
|
154
181
|
puts @pastel.red("[#{i}/#{count}] - #{package} ") + @pastel.red.bold("Vulnerable.")
|
182
|
+
print_reverse_deps(@reverse_deps[reverse_dep_coord], name, version)
|
155
183
|
r["vulnerabilities"].each do |k, v|
|
156
184
|
puts @pastel.red.bold(" #{k}:#{v}")
|
157
185
|
end
|
158
186
|
else
|
159
187
|
puts(@pastel.white("[#{i}/#{count}] - #{package} ") + @pastel.green.bold("No vulnerabilities found!"))
|
188
|
+
print_reverse_deps(@reverse_deps[reverse_dep_coord], name, version)
|
160
189
|
end
|
161
190
|
end
|
162
191
|
end
|
163
192
|
|
193
|
+
def print_reverse_deps(reverse_deps, name, version)
|
194
|
+
reverse_deps.each do |dep|
|
195
|
+
dep.each do |gran|
|
196
|
+
if gran.class == String && !gran.include?(name)
|
197
|
+
# There is likely a fun and clever way to check @server-results, etc... and see if a dep is in there
|
198
|
+
# Right now this looks at all Ruby deps, so it might find some in your Library, but that don't belong to your project
|
199
|
+
puts "\tRequired by: " + gran
|
200
|
+
else
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def to_purl(name, version)
|
207
|
+
purl = "pkg:gem/#{name}@#{version}"
|
208
|
+
|
209
|
+
purl
|
210
|
+
end
|
211
|
+
|
164
212
|
def print_err(s)
|
165
213
|
puts @pastel.red.bold(s)
|
166
214
|
end
|
@@ -168,5 +216,61 @@ module Chelsea
|
|
168
216
|
def print_success(s)
|
169
217
|
puts @pastel.green.bold(s)
|
170
218
|
end
|
219
|
+
|
220
|
+
private
|
221
|
+
|
222
|
+
def get_user_agent()
|
223
|
+
user_agent = "chelsea/#{Chelsea::VERSION}"
|
224
|
+
|
225
|
+
user_agent
|
226
|
+
end
|
227
|
+
|
228
|
+
# This method will take an array of values, and save them to a pstore database
|
229
|
+
# and as well set a TTL of Time.now to be checked later
|
230
|
+
def save_values_to_db(values)
|
231
|
+
values.each do |val|
|
232
|
+
if get_cached_value_from_db(val["coordinates"]).nil?
|
233
|
+
new_val = val.dup
|
234
|
+
new_val["ttl"] = Time.now
|
235
|
+
@store.transaction do
|
236
|
+
@store[new_val["coordinates"]] = new_val
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Checks pstore to see if a coordinate exists, and if it does also
|
243
|
+
# checks to see if it's ttl has expired. Returns nil unless a record
|
244
|
+
# is valid in the cache (ttl has not expired) and found
|
245
|
+
def get_cached_value_from_db(coordinate)
|
246
|
+
record = @store.transaction { @store[coordinate] }
|
247
|
+
if !record.nil?
|
248
|
+
diff = (Time.now - record['ttl']) / 3600
|
249
|
+
if diff > 12
|
250
|
+
return nil
|
251
|
+
else
|
252
|
+
return record
|
253
|
+
end
|
254
|
+
else
|
255
|
+
return nil
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# Goes through the list of @coordinates and checks pstore for them, if it finds a valid coord
|
260
|
+
# it will add it to the server response. If it does not, it will append the coord to a new hash
|
261
|
+
# and eventually set @coordinates to the new hash, so we query OSS Index on only coords not in cache
|
262
|
+
def check_db_for_cached_values()
|
263
|
+
new_coords = Hash.new
|
264
|
+
new_coords["coordinates"] = Array.new
|
265
|
+
@coordinates["coordinates"].each do |coord|
|
266
|
+
record = get_cached_value_from_db(coord)
|
267
|
+
if !record.nil?
|
268
|
+
@server_response << record
|
269
|
+
else
|
270
|
+
new_coords["coordinates"].push(coord)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
@coordinates = new_coords
|
274
|
+
end
|
171
275
|
end
|
172
276
|
end
|
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.3
|
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-03-
|
11
|
+
date: 2020-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-font
|