gems-status 0.8.0 → 0.9.0

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.
@@ -39,9 +39,9 @@ class GemsCompositeCommand < GemsCommand
39
39
  @checkers.each do |check_object|
40
40
  Utils::log_debug "checking #{check_object.class.name}"
41
41
  @results[@target].sort.each do |k, gems|
42
- @checker_results[k] = "" unless @checker_results[k]
43
42
  gems.each do |gem|
44
43
  if !check_object.check?(gem)
44
+ @checker_results[k] = "" unless @checker_results[k]
45
45
  @checker_results[gem.name] << "
46
46
  <br/>#{gem.name} #{gem.version} #{gem.origin}: <br/>
47
47
  #{check_object.description} "
@@ -103,7 +103,6 @@ class GemsCompositeCommand < GemsCommand
103
103
  comments = nil
104
104
  end
105
105
  ViewResults::print_results(k, @results, @target, checker_results, comments)
106
- @checker_results.delete(k)
107
106
  @comments.delete(k)
108
107
  end
109
108
  ViewResults::print_tail(@checker_results, @comments)
@@ -1,3 +1,3 @@
1
1
  module GemsStatusMetadata
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -1,3 +1,4 @@
1
+ require "gmail"
1
2
  require "json"
2
3
  require "open-uri"
3
4
 
@@ -9,24 +10,93 @@ require "gems-status/scm_security_messages"
9
10
 
10
11
  class NotASecurityAlertChecker < GemChecker
11
12
  def initialize(conf)
12
- Utils::check_parameters('NotASecurityAlertChecker', conf, ["fixed", "source_repos"])
13
+ Utils::check_parameters('NotASecurityAlertChecker', conf, ["fixed", "source_repos", "email_username", "email_password", "mailing_lists", "email_to"])
13
14
  @fixed = conf["fixed"]
14
15
  @source_repos = conf["source_repos"]
15
16
  @security_messages = {}
17
+ @email_username = conf["email_username"]
18
+ @email_password = conf["email_password"]
19
+ @mailing_lists = conf["mailing_lists"]
20
+ @email_to = conf["email_to"]
21
+ @emails = {}
22
+ download_emails
16
23
  end
17
24
 
18
- def check?(gem)
19
- @security_messages = {}
25
+ def download_emails
26
+ #TODO: only download new emails and keep the old ones in a database
27
+ #puts "Security email alerts from #{mailing_list} #{gmail.inbox.count(:unread, :to => mailing_list}"
28
+ Gmail.new(@email_username, @email_password) do |gmail|
29
+ @mailing_lists.each do |mailing_list|
30
+ @emails[mailing_list] = []
31
+ Utils::log_debug "Security email alerts from #{mailing_list} #{gmail.inbox.count( :to => mailing_list)}"
32
+ #TODO: only read new emails
33
+ #gmail.inbox.emails(:unread, :to => "rubyonrails-security@googlegroups.com").each do |email|
34
+ gmail.inbox.emails(:to => mailing_list).each do |email|
35
+ Utils::log_debug "Read #{email.subject}"
36
+ @emails[mailing_list] << email
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def send_emails(gem)
43
+ return if @security_messages.length == 0
44
+ #gems.origin == gems.gems_url if we are looking to an upstream gem,
45
+ #for example in rubygems.org. We only care about our application gems.
46
+ return if gem.origin == gem.gems_url
47
+ mssg = ""
48
+ mssg = "#{gem.name} #{gem.version} : #{gem.origin} \n"
49
+ @security_messages.each do |k,v|
50
+ mssg = mssg + "\n #{v}"
51
+ end
52
+ email_receiver = @email_to
53
+ Gmail.new(@email_username, @email_password) do |gmail|
54
+ gmail.deliver do
55
+ to email_receiver
56
+ subject "[gems-status] security alerts for #{gem.name}"
57
+ text_part do
58
+ body mssg
59
+ end
60
+ end
61
+ end
62
+ Utils::log_debug "Email sent to #{@email_to} "
63
+ Utils::log_debug "with body #{mssg} "
64
+ end
65
+
66
+ def look_in_scm(gem)
20
67
  version = gem.version
21
68
  source_repo = source_repo(gem)
22
69
  if ! source_repo
23
70
  Utils::log_error gem.name, "Not source URL for #{gem.name}"
24
- @security_messages = {gem.name => "Not source URL for #{gem.name}"}
25
- return false
71
+ return
26
72
  end
27
73
  Utils::log_debug "Source URL for #{gem.name} #{source_repo}"
28
74
  look_for_security_messages(gem.name, source_repo)
29
75
  filter_security_messages_already_fixed(gem.version)
76
+ end
77
+
78
+ def look_in_emails(gem)
79
+ @emails.each do |listname, emails|
80
+ emails.each do |email|
81
+ if listname.include?(gem.name)
82
+ @security_messages[Utils::next_key(gem.name)] = email.subject
83
+ Utils::log_debug "looking for security emails: listname matches gem #{gem.name}: #{listname}"
84
+ next
85
+ end
86
+ if email.subject.include?(gem.name)
87
+ @security_messages[Utils::next_key(gem.name)] = email.subject
88
+ Utils::log_debug "looking for security emails: subject matches gem #{gem.name}: #{email.subject}"
89
+ next
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ def check?(gem)
96
+ @security_messages = {}
97
+ look_in_scm(gem)
98
+ look_in_emails(gem)
99
+ send_emails(gem)
30
100
  return @security_messages.length == 0
31
101
  end
32
102
 
@@ -42,6 +112,7 @@ class NotASecurityAlertChecker < GemChecker
42
112
  private
43
113
 
44
114
  def filter_security_messages_already_fixed(version)
115
+ #TODO: let's use a database instead of having the info in yaml file
45
116
  @security_messages.delete_if do |k,v|
46
117
  @fixed[k] && Gem::Version.new(@fixed[k]) <= version
47
118
  end
@@ -1,6 +1,5 @@
1
1
  class ScmCheckMessages
2
2
  MAX_RETRIES = 3
3
- @@keys = {}
4
3
 
5
4
  def check_messages(name, source_repo, message_checker, counter = 0)
6
5
  begin
@@ -33,10 +32,7 @@ private
33
32
  end
34
33
 
35
34
  def next_key(name)
36
- @@keys[name] = 0 unless @@keys[name]
37
- key = name + @@keys[name].to_s
38
- @@keys[name] = @@keys[name] + 1
39
- return key
35
+ return Utils::next_key(name)
40
36
  end
41
37
 
42
38
  def message(commit)
@@ -5,11 +5,19 @@ class Utils
5
5
  attr_accessor :errors
6
6
  @@errors = {}
7
7
  @@md5_sums = {}
8
+ @@keys = {}
8
9
 
9
10
  def Utils.errors
10
11
  return @@errors
11
12
  end
12
-
13
+
14
+ def Utils.next_key(name)
15
+ @@keys[name] = 0 unless @@keys[name]
16
+ key = name + @@keys[name].to_s
17
+ @@keys[name] = @@keys[name] + 1
18
+ return key
19
+ end
20
+
13
21
  def Utils.check_parameters(classname, conf, parameters)
14
22
  if !conf['classname'] then
15
23
  raise "trying to initialize #{classname} when parameter classname does not exists"
@@ -3,9 +3,9 @@ require 'gems-status/gems_status_metadata'
3
3
  require 'gems-status/utils'
4
4
 
5
5
  class ViewResults
6
- @@patched = 0
7
- @@outdated = 0
8
- @@up_to_date = 0
6
+ @@patched = []
7
+ @@outdated = []
8
+ @@up_to_date = []
9
9
 
10
10
  def ViewResults.print_description(ids)
11
11
  puts "
@@ -47,18 +47,20 @@ class ViewResults
47
47
  <p> At the end there are the errors, checks and comments that do not apply to any of the gems. Look them carefully.
48
48
  </p>
49
49
  <p>
50
+ There is a summary at the end.
51
+ </p>
50
52
  You should run gems-status periodically until the lists of errors, patched, outdated and checks are gone.
51
53
  </p>
52
54
  "
53
55
  end
54
56
 
55
- def ViewResults.update_summary(name_color)
56
- if name_color == "alert"
57
- @@patched += 1
58
- elsif name_color == "warning"
59
- @@outdated += 1
57
+ def ViewResults.update_summary(gem_name, status)
58
+ if status == "alert"
59
+ @@patched << gem_name
60
+ elsif status == "warning"
61
+ @@outdated << gem_name
60
62
  else
61
- @@up_to_date += 1
63
+ @@up_to_date << gem_name
62
64
  end
63
65
  end
64
66
 
@@ -116,9 +118,9 @@ class ViewResults
116
118
  md5 = gem.md5
117
119
  end
118
120
  end
119
- puts "<tr><td width='50%'><span class='#{name_color}'>#{k.upcase}</span></td><td width='10%'>version</td><td width='40%'>md5</td></tr>"
121
+ puts "<tr><td width='50%'><span class='#{name_color}'><a name=\"#{k}\" />#{k}</span></td><td width='10%'>version</td><td width='40%'>md5</td></tr>"
120
122
  puts html_string
121
- update_summary(name_color)
123
+ update_summary(k, name_color)
122
124
  puts "</table>"
123
125
  puts "</p>"
124
126
  if checker_results
@@ -145,7 +147,7 @@ class ViewResults
145
147
  <style>
146
148
  body
147
149
  {
148
- font-size: 100%;
150
+ font-size: 90%;
149
151
  }
150
152
  h1
151
153
  {
@@ -155,7 +157,8 @@ class ViewResults
155
157
  h2
156
158
  {
157
159
  font-size: 100%;
158
- font-weight: bold;
160
+ font-style: italic;
161
+ font-weight: normal;
159
162
  }
160
163
  .gem_name
161
164
  {
@@ -186,19 +189,19 @@ class ViewResults
186
189
  .errors
187
190
  {
188
191
  color: #ff0000;
189
- font-size: 80%;
192
+ font-size: 100%;
190
193
  font-style: italic;
191
194
  }
192
195
  .check
193
196
  {
194
197
  color: #a0a0a0;
195
- font-size: 80%;
198
+ font-size: 100%;
196
199
  font-style: italic;
197
200
  }
198
201
  .comment
199
202
  {
200
203
  color: #a0a0a0;
201
- font-size: 80%;
204
+ font-size: 100%;
202
205
  font-style: italic;
203
206
  }
204
207
  .table_results
@@ -210,24 +213,48 @@ class ViewResults
210
213
  <body>"
211
214
  end
212
215
 
213
- def ViewResults.print_hash(desc, data, style)
216
+ def ViewResults.print_hash(desc, data, style, anchor = false)
214
217
  return if !data or data.length == 0
215
218
  puts "<p>"
216
219
  puts "<h2>#{desc}: #{data.length}</h2>"
217
- data.each {|k,v| puts "<span class='#{style}'>#{k.upcase} : #{v}</span><br/>"}
220
+ data.each do |k,v|
221
+ if anchor
222
+ puts "<a href=\"\##{k}\"><span class='#{style}'>#{k}</span></a>"
223
+ else
224
+ puts "<span class='#{style}'>#{k}</span>"
225
+ end
226
+ puts "<span class='#{style}'> #{v}</span><br/>"
227
+
228
+ end
218
229
  puts "</p>"
219
230
  end
220
231
 
221
232
  def ViewResults.print_summary
222
- puts "<h2>summary</h2>"
223
- puts "patched/errored: #{@@patched} outdated: #{@@outdated} up-to-date: #{@@up_to_date}"
233
+ puts "<a name='summary'/><h1>Summary</h1>"
234
+ puts "<p><h2>patched/errored</h2>"
235
+ puts "<ul>"
236
+ @@patched.each do |p|
237
+ puts "<li><a href=\"\##{p}\">#{p}</a>"
238
+ end
239
+ puts "</ul></p>"
240
+ puts "<p><h2>outdated #{@@outdated.length}</h2>"
241
+ @@outdated.each do |p|
242
+ puts "<li><a href=\"\##{p}\">#{p}</a>"
243
+ end
244
+ puts "</ul></p>"
245
+ puts "<p> <h2>up-to-date #{@@up_to_date.length}</h2>"
246
+ @@up_to_date.each do |p|
247
+ puts "<li><a href=\"\##{p}\">#{p}</a>"
248
+ end
249
+ puts "</ul></p>"
224
250
  end
225
251
 
226
252
  def ViewResults.print_tail(checker_results, comments)
227
- self.print_hash("checks", checker_results, "check")
253
+ puts "<h1>Others</h1>"
228
254
  self.print_hash("comments", comments, "comment")
229
255
  self.print_hash("errors", Utils::errors, "errors")
230
256
  self.print_summary
257
+ self.print_hash("checks", checker_results, "summary", true)
231
258
  date = Time.now.strftime('%a %b %d %H:%M:%S %Z %Y')
232
259
  puts "<p class='footer'>run by <a href=\"https://github.com/jordimassaguerpla/gems-status\">gems-status</a> - #{date} - version: #{GemsStatusMetadata::VERSION}</p>
233
260
  </body>
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gems-status
3
3
  version: !ruby/object:Gem::Version
4
- hash: 63
4
+ hash: 59
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 8
8
+ - 9
9
9
  - 0
10
- version: 0.8.0
10
+ version: 0.9.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jordi Massaguer Pla
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-06-18 00:00:00 Z
18
+ date: 2012-06-27 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: xml-simple