gems-status 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/gems-status/gems_composite_command.rb +1 -2
- data/lib/gems-status/gems_status_metadata.rb +1 -1
- data/lib/gems-status/not_a_security_alert_checker.rb +76 -5
- data/lib/gems-status/scm_check_messages.rb +1 -5
- data/lib/gems-status/utils.rb +9 -1
- data/lib/gems-status/view_results.rb +48 -21
- metadata +4 -4
@@ -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,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
|
19
|
-
|
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
|
-
|
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
|
-
|
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)
|
data/lib/gems-status/utils.rb
CHANGED
@@ -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 =
|
7
|
-
@@outdated =
|
8
|
-
@@up_to_date =
|
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(
|
56
|
-
if
|
57
|
-
@@patched
|
58
|
-
elsif
|
59
|
-
@@outdated
|
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
|
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}'
|
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:
|
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-
|
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:
|
192
|
+
font-size: 100%;
|
190
193
|
font-style: italic;
|
191
194
|
}
|
192
195
|
.check
|
193
196
|
{
|
194
197
|
color: #a0a0a0;
|
195
|
-
font-size:
|
198
|
+
font-size: 100%;
|
196
199
|
font-style: italic;
|
197
200
|
}
|
198
201
|
.comment
|
199
202
|
{
|
200
203
|
color: #a0a0a0;
|
201
|
-
font-size:
|
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
|
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 "<
|
223
|
-
puts "patched/errored
|
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
|
-
|
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:
|
4
|
+
hash: 59
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 9
|
9
9
|
- 0
|
10
|
-
version: 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
|
+
date: 2012-06-27 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: xml-simple
|