gems-status 0.63.0 → 0.64.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/bin/gems-status +24 -5
- data/lib/gems-status.rb +1 -36
- data/lib/gems-status/checkers/not_a_security_alert_checker.rb +50 -70
- data/lib/gems-status/checkers/scm_check_messages_factory.rb +25 -0
- data/lib/gems-status/gem_simple.rb +9 -2
- data/lib/gems-status/runner.rb +53 -0
- data/lib/gems-status/sources/lockfile_gems.rb +22 -32
- data/lib/gems-status/text_view.rb +35 -23
- data/lib/gems-status/utils.rb +30 -0
- data/test/test-gem_simple.rb +48 -0
- data/test/test-has_a_license.rb +17 -0
- data/test/test-is_not_gpl.rb +28 -0
- data/test/test-is_rubygems.rb +34 -0
- data/test/test-lockfile_gems.rb +20 -13
- data/test/test-not_a_security_alert_checker.rb +158 -0
- data/test/test-runner.rb +40 -0
- data/test/test-scm_check_messages.rb +40 -0
- data/test/test-scm_check_messages_factory.rb +15 -0
- data/test/test-scm_security_messages.rb +27 -0
- data/test/test-security_alert.rb +15 -0
- metadata +16 -9
- data/lib/gems-status/gems_command.rb +0 -39
- data/lib/gems-status/gems_composite_command.rb +0 -57
- data/lib/gems-status/sources/ruby_gems_gems_gem_simple.rb +0 -46
- data/test/test-gems_command.rb +0 -67
- data/test/test-gems_composite_command.rb +0 -14
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.64.0
|
data/bin/gems-status
CHANGED
@@ -20,6 +20,25 @@ if !File::exists?(ARGV[0]) then
|
|
20
20
|
exit
|
21
21
|
end
|
22
22
|
|
23
|
+
|
24
|
+
def setup_runner(conf)
|
25
|
+
GemsStatus::Utils::known_licenses = conf["licenses"]
|
26
|
+
runner = GemsStatus::Runner.new
|
27
|
+
c = conf["source"]
|
28
|
+
gems = eval("GemsStatus::#{c["classname"]}").new(c)
|
29
|
+
runner.source = gems
|
30
|
+
if conf["checkers"]
|
31
|
+
conf["checkers"].each do |c|
|
32
|
+
checker = eval("GemsStatus::#{c["classname"]}").new(c)
|
33
|
+
runner.add_checker(checker)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
if conf["comments"]
|
37
|
+
runner.add_comments(conf["comments"])
|
38
|
+
end
|
39
|
+
return runner
|
40
|
+
end
|
41
|
+
|
23
42
|
conf_file = ARGV[0]
|
24
43
|
begin
|
25
44
|
conf = YAML::load(ERB.new(File::read(conf_file)).result)
|
@@ -27,9 +46,9 @@ rescue
|
|
27
46
|
GemsStatus::Utils::log_error("?", "There was a problem opening #{conf_file}")
|
28
47
|
exit
|
29
48
|
end
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
exit 1 if
|
49
|
+
|
50
|
+
runner = setup_runner(conf)
|
51
|
+
runner.execute
|
52
|
+
runner.print
|
53
|
+
exit 1 if runner.checker_results && runner.checker_results.length > 0
|
35
54
|
|
data/lib/gems-status.rb
CHANGED
@@ -7,42 +7,7 @@ require "yaml"
|
|
7
7
|
|
8
8
|
require "gems-status/gem_simple"
|
9
9
|
require "gems-status/sources.rb"
|
10
|
-
require "gems-status/
|
10
|
+
require "gems-status/runner"
|
11
11
|
require "gems-status/checkers"
|
12
12
|
|
13
|
-
module GemsStatus
|
14
|
-
|
15
|
-
class GemStatus
|
16
|
-
def initialize(conf)
|
17
|
-
@conf = conf
|
18
|
-
Utils::known_licenses = @conf["licenses"]
|
19
|
-
@gems_composite_command = nil
|
20
|
-
@gems_composite_command = GemsCompositeCommand.new
|
21
|
-
c = @conf["source"]
|
22
|
-
gems = eval(c["classname"]).new(c)
|
23
|
-
@gems_composite_command.command = gems
|
24
|
-
if @conf["checkers"]
|
25
|
-
@conf["checkers"].each do |c|
|
26
|
-
checker = eval(c["classname"]).new(c)
|
27
|
-
@gems_composite_command.add_checker(checker)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
if @conf["comments"]
|
31
|
-
@gems_composite_command.add_comments(@conf["comments"])
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def execute
|
36
|
-
@gems_composite_command.execute
|
37
|
-
end
|
38
|
-
|
39
|
-
def results
|
40
|
-
{:results => @gems_composite_command.results, :checker_results => @gems_composite_command.checker_results}
|
41
|
-
end
|
42
|
-
|
43
|
-
def print
|
44
|
-
@gems_composite_command.print
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
13
|
|
@@ -1,13 +1,10 @@
|
|
1
|
-
require "gmail"
|
2
1
|
require "json"
|
3
2
|
require "open-uri"
|
4
3
|
|
5
4
|
require "gems-status/checkers/gem_checker"
|
6
5
|
require "gems-status/checkers/security_alert"
|
7
|
-
require "gems-status/checkers/git_check_messages"
|
8
|
-
require "gems-status/checkers/hg_check_messages"
|
9
|
-
require "gems-status/checkers/svn_check_messages"
|
10
6
|
require "gems-status/checkers/scm_security_messages"
|
7
|
+
require "gems-status/checkers/scm_check_messages_factory"
|
11
8
|
|
12
9
|
module GemsStatus
|
13
10
|
|
@@ -27,6 +24,32 @@ module GemsStatus
|
|
27
24
|
@emails = Utils.download_emails(@email_username, @email_password, @mailing_lists)
|
28
25
|
end
|
29
26
|
|
27
|
+
def check?(gem)
|
28
|
+
@gem = gem
|
29
|
+
#ignore upstream checks
|
30
|
+
return true if gem.origin == gem.gems_url
|
31
|
+
|
32
|
+
@security_messages = {}
|
33
|
+
look_in_scm(gem)
|
34
|
+
look_in_emails(gem)
|
35
|
+
filter_security_messages_already_fixed(gem.version, gem.date)
|
36
|
+
send_emails(gem)
|
37
|
+
return @security_messages.length == 0
|
38
|
+
end
|
39
|
+
|
40
|
+
def description
|
41
|
+
if !@gem
|
42
|
+
Utils::log_debug("No gem. That means that check method has not been called in NotASecurityAlertChecker")
|
43
|
+
return
|
44
|
+
end
|
45
|
+
message(@gem)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def match_name(str, name)
|
51
|
+
str =~ /[gem|ruby].*\b#{name}\b/ || str =~ /#{name}\b.*[gem|ruby].*\b/
|
52
|
+
end
|
30
53
|
|
31
54
|
def message(gem)
|
32
55
|
return unless gem
|
@@ -44,18 +67,12 @@ module GemsStatus
|
|
44
67
|
return if @security_messages.length == 0
|
45
68
|
#gems.origin == gems.gems_url if we are looking to an upstream gem,
|
46
69
|
#for example in rubygems.org. We only care about our application gems.
|
70
|
+
#where the origin will be a gemfile.lock file
|
47
71
|
return if gem.origin == gem.gems_url
|
48
72
|
mssg = message(gem)
|
49
73
|
@email_to.each do |email_receiver|
|
50
|
-
|
51
|
-
|
52
|
-
to email_receiver
|
53
|
-
subject "[gems-status] security alerts for #{gem.name}"
|
54
|
-
text_part do
|
55
|
-
body mssg
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
74
|
+
GemsStatus::Utils.send_email(email_receiver, @email_username,
|
75
|
+
@email_password, gem.name, mssg)
|
59
76
|
end
|
60
77
|
Utils::log_debug "Email sent to #{@email_to} "
|
61
78
|
Utils::log_debug "with body #{mssg} "
|
@@ -76,52 +93,21 @@ module GemsStatus
|
|
76
93
|
"email_#{listname}_#{gem.name}_#{gem.origin}_#{email.uid}"
|
77
94
|
end
|
78
95
|
|
79
|
-
def match_name(str, name)
|
80
|
-
str =~ /[gem|ruby].*\b#{name}\b/
|
81
|
-
end
|
82
|
-
|
83
96
|
def look_in_emails(gem)
|
84
97
|
@emails.each do |listname, emails|
|
85
98
|
emails.each do |email|
|
86
|
-
if
|
99
|
+
if listname.strip == "rubyonrails-security@googlegroups.com" && gem.name == "rails"
|
87
100
|
@security_messages[key_for_emails(listname, gem, email)] = SecurityAlert.new(email.subject)
|
88
101
|
Utils::log_debug "looking for security emails: listname matches gem #{gem.name}: #{listname}"
|
89
|
-
|
90
|
-
end
|
91
|
-
if match_name(email.subject, gem.name)
|
102
|
+
elsif match_name(email.subject, gem.name)
|
92
103
|
@security_messages[key_for_emails(listname, gem, email)] = SecurityAlert.new(email.subject)
|
93
104
|
Utils::log_debug "looking for security emails: subject matches gem #{gem.name}: #{email.subject}"
|
94
|
-
next
|
95
105
|
end
|
96
106
|
end
|
97
107
|
end
|
98
108
|
end
|
99
109
|
|
100
|
-
def check?(gem)
|
101
|
-
@gem = gem
|
102
|
-
#ignore upstream checks
|
103
|
-
return true if gem.origin == gem.gems_url
|
104
|
-
|
105
|
-
@security_messages = {}
|
106
|
-
look_in_scm(gem)
|
107
|
-
look_in_emails(gem)
|
108
|
-
filter_security_messages_already_fixed(gem.version, gem.date)
|
109
|
-
send_emails(gem)
|
110
|
-
return @security_messages.length == 0
|
111
|
-
end
|
112
|
-
|
113
|
-
def description
|
114
|
-
if !@gem
|
115
|
-
Utils::log_debug("No gem. That means that check method has not been called in NotASecurityAlertChecker")
|
116
|
-
return
|
117
|
-
end
|
118
|
-
message(@gem)
|
119
|
-
end
|
120
|
-
|
121
|
-
private
|
122
|
-
|
123
110
|
def filter_security_messages_already_fixed(version, date)
|
124
|
-
#TODO: let's use a database instead of having the info in yaml file
|
125
111
|
@security_messages.delete_if do |k,v|
|
126
112
|
@fixed[k] && Gem::Version.new(@fixed[k]) <= version
|
127
113
|
end
|
@@ -140,20 +126,7 @@ module GemsStatus
|
|
140
126
|
Utils::log_error gem.name, "There was a problem downloading info for #{gem.name} #{e.to_s}"
|
141
127
|
return nil
|
142
128
|
end
|
143
|
-
|
144
|
-
if gem_version_information["project_uri"] &&
|
145
|
-
gem_version_information["project_uri"].include?("github")
|
146
|
-
uri = gem_version_information["project_uri"]
|
147
|
-
end
|
148
|
-
if gem_version_information["homepage_uri"] &&
|
149
|
-
gem_version_information["homepage_uri"].include?("github")
|
150
|
-
uri = gem_version_information["homepage_uri"]
|
151
|
-
end
|
152
|
-
if gem_version_information["source_code_uri"] &&
|
153
|
-
gem_version_information["source_code_uri"].include?("github")
|
154
|
-
uri = gem_version_information["source_code_uri"]
|
155
|
-
end
|
156
|
-
return uri
|
129
|
+
gem_uri(gem_version_information)
|
157
130
|
end
|
158
131
|
|
159
132
|
def look_for_security_messages(name, source_repo, origin, counter = 0)
|
@@ -166,16 +139,8 @@ module GemsStatus
|
|
166
139
|
Dir.mkdir(name)
|
167
140
|
end
|
168
141
|
Dir.chdir(name) do
|
169
|
-
|
170
|
-
|
171
|
-
Utils::log_debug "git repo"
|
172
|
-
elsif source_repo.include?("svn")
|
173
|
-
scmCheckMessages = SvnCheckMessages.new
|
174
|
-
Utils::log_debug "svn repo"
|
175
|
-
elsif source_repo.include?("bitbucket")
|
176
|
-
scmCheckMessages = HgCheckMessages.new
|
177
|
-
Utils::log_debug "mercurial repo"
|
178
|
-
else
|
142
|
+
scmCheckMessages = ScmCheckMessagesFactory.get_instance(source_repo)
|
143
|
+
if scmCheckMessages == nil
|
179
144
|
Utils::log_error name, "Not a valid source repo #{source_repo}"
|
180
145
|
return {}
|
181
146
|
end
|
@@ -185,5 +150,20 @@ module GemsStatus
|
|
185
150
|
end
|
186
151
|
end
|
187
152
|
|
153
|
+
def gem_uri(gem_version_information)
|
154
|
+
if gem_version_information["project_uri"] &&
|
155
|
+
gem_version_information["project_uri"].include?("github")
|
156
|
+
return gem_version_information["project_uri"]
|
157
|
+
elsif gem_version_information["homepage_uri"] &&
|
158
|
+
gem_version_information["homepage_uri"].include?("github")
|
159
|
+
return gem_version_information["homepage_uri"]
|
160
|
+
elsif gem_version_information["source_code_uri"] &&
|
161
|
+
gem_version_information["source_code_uri"].include?("github")
|
162
|
+
return gem_version_information["source_code_uri"]
|
163
|
+
else
|
164
|
+
return nil
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
188
168
|
end
|
189
169
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "gems-status/checkers/git_check_messages"
|
2
|
+
require "gems-status/checkers/hg_check_messages"
|
3
|
+
require "gems-status/checkers/svn_check_messages"
|
4
|
+
require "gems-status/utils"
|
5
|
+
|
6
|
+
module GemsStatus
|
7
|
+
|
8
|
+
class ScmCheckMessagesFactory
|
9
|
+
def self.get_instance(source_repo)
|
10
|
+
if source_repo.include?("git")
|
11
|
+
Utils::log_debug "git repo"
|
12
|
+
GitCheckMessages.new
|
13
|
+
elsif source_repo.include?("svn")
|
14
|
+
Utils::log_debug "svn repo"
|
15
|
+
SvnCheckMessages.new
|
16
|
+
elsif source_repo.include?("bitbucket")
|
17
|
+
Utils::log_debug "mercurial repo"
|
18
|
+
HgCheckMessages.new
|
19
|
+
else
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -23,9 +23,16 @@ module GemsStatus
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def date
|
26
|
-
Utils::
|
27
|
-
nil
|
26
|
+
Utils::download_date(@name, @version)
|
28
27
|
end
|
29
28
|
|
29
|
+
def md5
|
30
|
+
if from_git?
|
31
|
+
return nil
|
32
|
+
end
|
33
|
+
Utils::download_md5(@name, @version, @gems_url)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
30
37
|
end
|
31
38
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "gems-status/gem_simple"
|
2
|
+
require "gems-status/text_view"
|
3
|
+
|
4
|
+
module GemsStatus
|
5
|
+
|
6
|
+
class Runner
|
7
|
+
attr_accessor :gem_list, :checker_results, :source
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@source = nil
|
11
|
+
@checkers = []
|
12
|
+
@checker_results = {}
|
13
|
+
@comments = {}
|
14
|
+
@gem_list = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_checker(check_object)
|
18
|
+
@checkers << check_object
|
19
|
+
end
|
20
|
+
|
21
|
+
def execute
|
22
|
+
return unless @source
|
23
|
+
@gem_list = @source.gem_list
|
24
|
+
@checkers.each do |check_object|
|
25
|
+
Utils::log_debug "checking #{check_object.class.name}"
|
26
|
+
@gem_list.each do |name, gem|
|
27
|
+
if !check_object.check?(gem)
|
28
|
+
@checker_results[name] = [] unless @checker_results[name]
|
29
|
+
@checker_results[name] << check_object.clone
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_comments(comments)
|
36
|
+
@comments = comments
|
37
|
+
end
|
38
|
+
|
39
|
+
def are_there_gems?
|
40
|
+
return @gem_list && !@gem_list.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
def print
|
44
|
+
return if !are_there_gems?
|
45
|
+
view = TextView.new
|
46
|
+
view.print_head
|
47
|
+
ids = @source.filename
|
48
|
+
view.print_description(ids)
|
49
|
+
view.print_results(@gem_list, @checker_results, @comments)
|
50
|
+
view.print_tail
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -4,20 +4,17 @@ require "open-uri"
|
|
4
4
|
require "zlib"
|
5
5
|
|
6
6
|
require "bundler"
|
7
|
-
require "gems-status/
|
8
|
-
require "gems-status/gems_command"
|
7
|
+
require "gems-status/gem_simple"
|
9
8
|
require "gems-status/utils"
|
10
9
|
|
11
10
|
module GemsStatus
|
12
11
|
|
13
|
-
class LockfileGems
|
12
|
+
class LockfileGems
|
14
13
|
attr_reader :filename
|
15
14
|
def initialize(conf)
|
16
|
-
Utils::check_parameters('LockfileGems', conf, ["
|
15
|
+
Utils::check_parameters('LockfileGems', conf, ["filename", "gems_url"])
|
17
16
|
@filename = conf['filename']
|
18
17
|
@gems_url = conf['gems_url']
|
19
|
-
@result = {}
|
20
|
-
@ident = conf['id']
|
21
18
|
end
|
22
19
|
|
23
20
|
def get_data(dirname, filename)
|
@@ -32,43 +29,36 @@ module GemsStatus
|
|
32
29
|
return data
|
33
30
|
end
|
34
31
|
|
35
|
-
def
|
36
|
-
|
37
|
-
changes = false
|
38
|
-
@result.each do |k, gems|
|
39
|
-
gems.each do |gem2|
|
40
|
-
if gem.depends?(gem2)
|
41
|
-
changes = gem.merge_deps(gem2) || changes
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
return changes
|
46
|
-
end
|
47
|
-
|
48
|
-
def execute
|
32
|
+
def gem_list
|
33
|
+
gems = {}
|
49
34
|
Utils::log_debug "reading #{@filename}"
|
50
35
|
Dir.chdir(File.dirname(@filename)) do
|
51
36
|
file_data = get_data(File::dirname(@filename), File::basename(@filename))
|
52
37
|
if file_data.empty?
|
53
38
|
Utils::log_error("?", "file empty #{@filename}")
|
54
|
-
|
39
|
+
return
|
55
40
|
end
|
56
41
|
lockfile = Bundler::LockfileParser.new(file_data)
|
57
42
|
lockfile.specs.each do |spec|
|
58
|
-
name = spec.name
|
59
43
|
version = Gem::Version.create(spec.version)
|
60
|
-
dependencies
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
gems_url = spec.source.uri
|
65
|
-
else
|
66
|
-
gems_url = @gems_url
|
67
|
-
end
|
68
|
-
@result[name] = RubyGemsGems_GemSimple.new(name, version , '', @filename,
|
69
|
-
gems_url, dependencies)
|
44
|
+
Utils::log_debug "dependencies for #{spec.name} #{spec.dependencies}"
|
45
|
+
gems[spec.name] = GemSimple.new(spec.name, version , nil,
|
46
|
+
@filename, gems_url(spec),
|
47
|
+
spec.dependencies)
|
70
48
|
end
|
71
49
|
end
|
50
|
+
gems
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def gems_url(spec)
|
56
|
+
if spec.source.class.name == "Bundler::Source::Git"
|
57
|
+
Utils::log_debug "this comes from git #{spec.name} #{spec.version}"
|
58
|
+
spec.source.uri
|
59
|
+
else
|
60
|
+
@gems_url
|
61
|
+
end
|
72
62
|
end
|
73
63
|
end
|
74
64
|
end
|