gems-status 0.63.0 → 0.64.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.
- 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
|