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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12e5cefdcebf95177fb2a4dc4d3dd21803549b66a16570ecd7244191f70665c2
4
- data.tar.gz: 6d42d99b6d1fbf033bcf1746857e92c819e0ad887dc7c680387a653b8d0d76ba
3
+ metadata.gz: 1633315a7f5da46a2c43414058160959b0be5202a3c7a6aa333e99f91f48a755
4
+ data.tar.gz: ac7a5f1f3c77061ccf54edf458758b621038f74ca9e272261cb0dc417cb94298
5
5
  SHA512:
6
- metadata.gz: '09e122e3b9957a32ef4b270404a7388a13009564282cde771444852a5092e5b669d627c89260e7efda00d61af747184b159b48d9ad69603918d096bcff702ff3'
7
- data.tar.gz: 0a4cd07a064cd5c40346ef6bd17fce588e97bfd242063c3e4e22b3db5c864378349d6ba6ab6ac9d9f13afffba1a1d37939d207696ce398840ae20c53799ff7c7
6
+ metadata.gz: 1b7eea08843bed093b27054b29da075edfc63730836421e8151e0dfd661d06f030bf7be242c8a08e11d5c4aae49434d3976f4b8a628962f44fa8e8b787979eea
7
+ data.tar.gz: c946fd43b812750e8d3ebe7b4c13914ca54e257c6b86a63d3abb1224bec4d94af027a1e4dcc7cd65940af23091b5e82d10d99e5397c1406e6d4199f2fb2f49b8
@@ -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:
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- chelsea (0.0.1)
5
- bundler (~> 2.0.0)
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
@@ -41,7 +41,7 @@ Options:
41
41
 
42
42
  Most basic usage is:
43
43
 
44
- `chelsea --file name.gemspec`
44
+ `chelsea --file Gemfile.lock`
45
45
 
46
46
  ## Development
47
47
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
- require "chelsea"
3
+ require_relative "../lib/chelsea"
4
4
 
5
5
  Chelsea::CLI.new.main
@@ -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"
@@ -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
- r = RestClient.post "https://ossindex.sonatype.org/api/v3/component-report", @coordinates.to_json,
111
- {content_type: :json, accept: :json, 'User-Agent': get_user_agent()}
112
- if r.code == 200
113
- @server_response = JSON.parse(r.body)
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
@@ -1,3 +1,3 @@
1
1
  module Chelsea
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  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.2
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-22 00:00:00.000000000 Z
11
+ date: 2020-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-font