rubygems-update 2.0.0.rc.1 → 2.0.0.rc.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubygems-update might be problematic. Click here for more details.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +3 -0
- data.tar.gz.sig +0 -0
- data/History.txt +165 -3
- data/Manifest.txt +1 -0
- data/lib/rubygems.rb +19 -37
- data/lib/rubygems/commands/push_command.rb +18 -11
- data/lib/rubygems/compatibility.rb +5 -1
- data/lib/rubygems/config_file.rb +42 -1
- data/lib/rubygems/dependency_installer.rb +7 -8
- data/lib/rubygems/errors.rb +2 -1
- data/lib/rubygems/ext/builder.rb +13 -6
- data/lib/rubygems/gemcutter_utilities.rb +12 -4
- data/lib/rubygems/package.rb +10 -2
- data/lib/rubygems/package/old.rb +37 -6
- data/lib/rubygems/security/policy.rb +44 -10
- data/lib/rubygems/specification.rb +7 -1
- data/lib/rubygems/ssl_certs/.document +1 -0
- data/lib/rubygems/test_case.rb +19 -5
- data/test/rubygems/test_gem.rb +42 -2
- data/test/rubygems/test_gem_commands_push_command.rb +2 -1
- data/test/rubygems/test_gem_config_file.rb +98 -34
- data/test/rubygems/test_gem_dependency_installer.rb +34 -2
- data/test/rubygems/test_gem_gemcutter_utilities.rb +23 -4
- data/test/rubygems/test_gem_installer.rb +27 -0
- data/test/rubygems/test_gem_package.rb +54 -3
- data/test/rubygems/test_gem_package_old.rb +42 -0
- data/test/rubygems/test_gem_security_policy.rb +144 -32
- data/test/rubygems/test_gem_specification.rb +9 -0
- metadata +136 -165
- metadata.gz.sig +0 -0
@@ -57,13 +57,13 @@ class Gem::DependencyInstaller
|
|
57
57
|
# :build_args:: See Gem::Installer::new
|
58
58
|
|
59
59
|
def initialize(options = {})
|
60
|
-
|
61
|
-
@gem_home = options[:install_dir]
|
60
|
+
@install_dir = options[:install_dir] || Gem.dir
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
if options[:install_dir] then
|
63
|
+
# HACK shouldn't change the global settings, needed for -i behavior
|
64
|
+
# maybe move to the install command? See also github #442
|
65
|
+
Gem::Specification.dirs = @install_dir
|
66
|
+
Gem.ensure_gem_subdirectories @install_dir
|
67
67
|
end
|
68
68
|
|
69
69
|
options = DEFAULT_OPTIONS.merge options
|
@@ -91,7 +91,6 @@ class Gem::DependencyInstaller
|
|
91
91
|
@installed_gems = []
|
92
92
|
@toplevel_specs = nil
|
93
93
|
|
94
|
-
@install_dir = options[:install_dir] || Gem.dir
|
95
94
|
@cache_dir = options[:cache_dir] || @install_dir
|
96
95
|
|
97
96
|
# Set with any errors that SpecFetcher finds while search through
|
@@ -260,7 +259,7 @@ class Gem::DependencyInstaller
|
|
260
259
|
set = Gem::AvailableSet.new
|
261
260
|
|
262
261
|
if consider_local?
|
263
|
-
if File.file? gem_name then
|
262
|
+
if gem_name =~ /\.gem$/ and File.file? gem_name then
|
264
263
|
src = Gem::Source::SpecificFile.new(gem_name)
|
265
264
|
set.add src.spec, src
|
266
265
|
else
|
data/lib/rubygems/errors.rb
CHANGED
data/lib/rubygems/ext/builder.rb
CHANGED
@@ -19,6 +19,7 @@ class Gem::Ext::Builder
|
|
19
19
|
mf = Gem.read_binary 'Makefile'
|
20
20
|
mf = mf.gsub(/^RUBYARCHDIR\s*=\s*\$[^$]*/, "RUBYARCHDIR = #{dest_path}")
|
21
21
|
mf = mf.gsub(/^RUBYLIBDIR\s*=\s*\$[^$]*/, "RUBYLIBDIR = #{dest_path}")
|
22
|
+
mf = mf.gsub(/\s*\S+\.time$/, "")
|
22
23
|
|
23
24
|
File.open('Makefile', 'wb') {|f| f.print mf}
|
24
25
|
|
@@ -42,12 +43,18 @@ class Gem::Ext::Builder
|
|
42
43
|
def self.run(command, results, command_name = nil)
|
43
44
|
verbose = Gem.configuration.really_verbose
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
begin
|
47
|
+
# TODO use Process.spawn when ruby 1.8 support is dropped.
|
48
|
+
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], nil
|
49
|
+
if verbose
|
50
|
+
puts(command)
|
51
|
+
system(command)
|
52
|
+
else
|
53
|
+
results << command
|
54
|
+
results << `#{command} #{redirector}`
|
55
|
+
end
|
56
|
+
ensure
|
57
|
+
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
|
51
58
|
end
|
52
59
|
|
53
60
|
unless $?.success? then
|
@@ -27,17 +27,25 @@ module Gem::GemcutterUtilities
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
def sign_in
|
30
|
+
def sign_in sign_in_host = self.host
|
31
31
|
return if Gem.configuration.rubygems_api_key
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
pretty_host = if Gem::DEFAULT_HOST == sign_in_host then
|
34
|
+
'RubyGems.org'
|
35
|
+
else
|
36
|
+
sign_in_host
|
37
|
+
end
|
38
|
+
|
39
|
+
say "Enter your #{pretty_host} credentials."
|
40
|
+
say "Don't have an account yet? " +
|
41
|
+
"Create one at https://#{sign_in_host}/sign_up"
|
35
42
|
|
36
43
|
email = ask " Email: "
|
37
44
|
password = ask_for_password "Password: "
|
38
45
|
say "\n"
|
39
46
|
|
40
|
-
response = rubygems_api_request
|
47
|
+
response = rubygems_api_request(:get, "api/v1/api_key",
|
48
|
+
sign_in_host) do |request|
|
41
49
|
request.basic_auth email, password
|
42
50
|
end
|
43
51
|
|
data/lib/rubygems/package.rb
CHANGED
@@ -277,9 +277,13 @@ EOM
|
|
277
277
|
# the security policy.
|
278
278
|
|
279
279
|
def digest entry # :nodoc:
|
280
|
-
|
280
|
+
algorithms = if @checksums then
|
281
|
+
@checksums.keys
|
282
|
+
else
|
283
|
+
[Gem::Security::DIGEST_NAME]
|
284
|
+
end
|
281
285
|
|
282
|
-
|
286
|
+
algorithms.each do |algorithm|
|
283
287
|
digester = OpenSSL::Digest.new algorithm
|
284
288
|
|
285
289
|
digester << entry.read(16384) until entry.eof?
|
@@ -473,6 +477,10 @@ EOM
|
|
473
477
|
@security_policy
|
474
478
|
|
475
479
|
true
|
480
|
+
rescue Gem::Security::Exception
|
481
|
+
@spec = nil
|
482
|
+
@files = []
|
483
|
+
raise
|
476
484
|
rescue Errno::ENOENT => e
|
477
485
|
raise Gem::Package::FormatError.new e.message
|
478
486
|
rescue Gem::Package::TarInvalidError => e
|
data/lib/rubygems/package/old.rb
CHANGED
@@ -23,15 +23,18 @@ class Gem::Package::Old < Gem::Package
|
|
23
23
|
require 'zlib'
|
24
24
|
Gem.load_yaml
|
25
25
|
|
26
|
-
@
|
27
|
-
@
|
28
|
-
@
|
26
|
+
@contents = nil
|
27
|
+
@gem = gem
|
28
|
+
@security_policy = nil
|
29
|
+
@spec = nil
|
29
30
|
end
|
30
31
|
|
31
32
|
##
|
32
33
|
# A list of file names contained in this gem
|
33
34
|
|
34
35
|
def contents
|
36
|
+
verify
|
37
|
+
|
35
38
|
return @contents if @contents
|
36
39
|
|
37
40
|
open @gem, 'rb' do |io|
|
@@ -46,6 +49,8 @@ class Gem::Package::Old < Gem::Package
|
|
46
49
|
# Extracts the files in this package into +destination_dir+
|
47
50
|
|
48
51
|
def extract_files destination_dir
|
52
|
+
verify
|
53
|
+
|
49
54
|
errstr = "Error reading files from gem"
|
50
55
|
|
51
56
|
open @gem, 'rb' do |io|
|
@@ -125,6 +130,8 @@ class Gem::Package::Old < Gem::Package
|
|
125
130
|
# The specification for this gem
|
126
131
|
|
127
132
|
def spec
|
133
|
+
verify
|
134
|
+
|
128
135
|
return @spec if @spec
|
129
136
|
|
130
137
|
yaml = ''
|
@@ -136,12 +143,36 @@ class Gem::Package::Old < Gem::Package
|
|
136
143
|
end
|
137
144
|
end
|
138
145
|
|
139
|
-
|
140
|
-
|
141
|
-
|
146
|
+
yaml_error = if RUBY_VERSION < '1.9' then
|
147
|
+
YAML::ParseError
|
148
|
+
elsif YAML::ENGINE.yamler == 'syck' then
|
149
|
+
YAML::ParseError
|
150
|
+
else
|
151
|
+
YAML::SyntaxError
|
152
|
+
end
|
153
|
+
|
154
|
+
begin
|
155
|
+
@spec = Gem::Specification.from_yaml yaml
|
156
|
+
rescue yaml_error => e
|
157
|
+
raise Gem::Exception, "Failed to parse gem specification out of gem file"
|
158
|
+
end
|
142
159
|
rescue ArgumentError => e
|
143
160
|
raise Gem::Exception, "Failed to parse gem specification out of gem file"
|
144
161
|
end
|
145
162
|
|
163
|
+
##
|
164
|
+
# Raises an exception if a security policy that verifies data is active.
|
165
|
+
# Old format gems cannot be verified as signed.
|
166
|
+
|
167
|
+
def verify
|
168
|
+
return true unless @security_policy
|
169
|
+
|
170
|
+
raise Gem::Security::Exception,
|
171
|
+
'old format gems do not contain signatures and cannot be verified' if
|
172
|
+
@security_policy.verify_data
|
173
|
+
|
174
|
+
true
|
175
|
+
end
|
176
|
+
|
146
177
|
end
|
147
178
|
|
@@ -49,13 +49,18 @@ class Gem::Security::Policy
|
|
49
49
|
# and is valid for the given +time+.
|
50
50
|
|
51
51
|
def check_chain chain, time
|
52
|
-
|
53
|
-
|
54
|
-
end
|
52
|
+
raise Gem::Security::Exception, 'missing signing chain' unless chain
|
53
|
+
raise Gem::Security::Exception, 'empty signing chain' if chain.empty?
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
begin
|
56
|
+
chain.each_cons 2 do |issuer, cert|
|
57
|
+
check_cert cert, issuer, time
|
58
|
+
end
|
59
|
+
|
60
|
+
true
|
61
|
+
rescue Gem::Security::Exception => e
|
62
|
+
raise Gem::Security::Exception, "invalid signing chain: #{e.message}"
|
63
|
+
end
|
59
64
|
end
|
60
65
|
|
61
66
|
##
|
@@ -74,6 +79,9 @@ class Gem::Security::Policy
|
|
74
79
|
# If the +issuer+ is +nil+ no verification is performed.
|
75
80
|
|
76
81
|
def check_cert signer, issuer, time
|
82
|
+
raise Gem::Security::Exception, 'missing signing certificate' unless
|
83
|
+
signer
|
84
|
+
|
77
85
|
message = "certificate #{signer.subject}"
|
78
86
|
|
79
87
|
if not_before = signer.not_before and not_before > time then
|
@@ -97,6 +105,12 @@ class Gem::Security::Policy
|
|
97
105
|
# Ensures the public key of +key+ matches the public key in +signer+
|
98
106
|
|
99
107
|
def check_key signer, key
|
108
|
+
unless signer and key then
|
109
|
+
return true unless @only_signed
|
110
|
+
|
111
|
+
raise Gem::Security::Exception, 'missing key or signature'
|
112
|
+
end
|
113
|
+
|
100
114
|
raise Gem::Security::Exception,
|
101
115
|
"certificate #{signer.subject} does not match the signing key" unless
|
102
116
|
signer.public_key.to_pem == key.public_key.to_pem
|
@@ -109,8 +123,12 @@ class Gem::Security::Policy
|
|
109
123
|
# +time+.
|
110
124
|
|
111
125
|
def check_root chain, time
|
126
|
+
raise Gem::Security::Exception, 'missing signing chain' unless chain
|
127
|
+
|
112
128
|
root = chain.first
|
113
129
|
|
130
|
+
raise Gem::Security::Exception, 'missing root certificate' unless root
|
131
|
+
|
114
132
|
raise Gem::Security::Exception,
|
115
133
|
"root certificate #{root.subject} is not self-signed " +
|
116
134
|
"(issuer #{root.issuer})" if
|
@@ -124,8 +142,12 @@ class Gem::Security::Policy
|
|
124
142
|
# the digests of the two certificates match according to +digester+
|
125
143
|
|
126
144
|
def check_trust chain, digester, trust_dir
|
145
|
+
raise Gem::Security::Exception, 'missing signing chain' unless chain
|
146
|
+
|
127
147
|
root = chain.first
|
128
148
|
|
149
|
+
raise Gem::Security::Exception, 'missing root certificate' unless root
|
150
|
+
|
129
151
|
path = Gem::Security.trust_dir.cert_path root
|
130
152
|
|
131
153
|
unless File.exist? path then
|
@@ -152,8 +174,8 @@ class Gem::Security::Policy
|
|
152
174
|
end
|
153
175
|
|
154
176
|
def inspect # :nodoc:
|
155
|
-
"[Policy: %s - data: %p signer: %p chain: %p root: %p " +
|
156
|
-
|
177
|
+
("[Policy: %s - data: %p signer: %p chain: %p root: %p " +
|
178
|
+
"signed-only: %p trusted-only: %p]") % [
|
157
179
|
@name, @verify_chain, @verify_data, @verify_root, @verify_signer,
|
158
180
|
@only_signed, @only_trusted,
|
159
181
|
]
|
@@ -177,11 +199,16 @@ class Gem::Security::Policy
|
|
177
199
|
trust_dir = opt[:trust_dir]
|
178
200
|
time = Time.now
|
179
201
|
|
180
|
-
signer_digests = digests.find do |algorithm, file_digests|
|
202
|
+
_, signer_digests = digests.find do |algorithm, file_digests|
|
181
203
|
file_digests.values.first.name == Gem::Security::DIGEST_NAME
|
182
204
|
end
|
183
205
|
|
184
|
-
|
206
|
+
if @verify_data then
|
207
|
+
raise Gem::Security::Exception, 'no digests provided (probable bug)' if
|
208
|
+
signer_digests.nil? or signer_digests.empty?
|
209
|
+
else
|
210
|
+
signer_digests = {}
|
211
|
+
end
|
185
212
|
|
186
213
|
signer = chain.last
|
187
214
|
|
@@ -195,6 +222,13 @@ class Gem::Security::Policy
|
|
195
222
|
|
196
223
|
check_trust chain, digester, trust_dir if @only_trusted
|
197
224
|
|
225
|
+
signatures.each do |file, _|
|
226
|
+
digest = signer_digests[file]
|
227
|
+
|
228
|
+
raise Gem::Security::Exception, "missing digest for #{file}" unless
|
229
|
+
digest
|
230
|
+
end
|
231
|
+
|
198
232
|
signer_digests.each do |file, digest|
|
199
233
|
signature = signatures[file]
|
200
234
|
|
@@ -656,6 +656,12 @@ class Gem::Specification
|
|
656
656
|
|
657
657
|
@@all = specs.values
|
658
658
|
|
659
|
+
# After a reset, make sure already loaded specs
|
660
|
+
# are still marked as activated.
|
661
|
+
specs = {}
|
662
|
+
Gem.loaded_specs.each_value{|s| specs[s] = true}
|
663
|
+
@@all.each{|s| s.activated = true if specs[s]}
|
664
|
+
|
659
665
|
_resort!
|
660
666
|
end
|
661
667
|
@@all
|
@@ -898,7 +904,7 @@ class Gem::Specification
|
|
898
904
|
raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
|
899
905
|
end
|
900
906
|
|
901
|
-
spec.
|
907
|
+
spec.specification_version ||= NONEXISTENT_SPECIFICATION_VERSION
|
902
908
|
spec.reset_nil_attributes_to_default
|
903
909
|
|
904
910
|
spec
|
@@ -0,0 +1 @@
|
|
1
|
+
# Ignore all files in this directory
|
data/lib/rubygems/test_case.rb
CHANGED
@@ -118,8 +118,8 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|
118
118
|
@current_dir = Dir.pwd
|
119
119
|
@ui = Gem::MockGemUi.new
|
120
120
|
|
121
|
-
|
122
|
-
tmpdir
|
121
|
+
tmpdir = File.expand_path Dir.tmpdir
|
122
|
+
tmpdir.untaint
|
123
123
|
|
124
124
|
if ENV['KEEP_FILES'] then
|
125
125
|
@tempdir = File.join(tmpdir, "test_rubygems_#{$$}.#{Time.now.to_i}")
|
@@ -127,11 +127,25 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|
127
127
|
@tempdir = File.join(tmpdir, "test_rubygems_#{$$}")
|
128
128
|
end
|
129
129
|
@tempdir.untaint
|
130
|
+
|
131
|
+
FileUtils.mkdir_p @tempdir
|
132
|
+
|
133
|
+
# This makes the tempdir consistent on OS X.
|
134
|
+
# File.expand_path Dir.tmpdir #=> "/var/..."
|
135
|
+
# Dir.chdir Dir.tmpdir do File.expand_path '.' end #=> "/private/var/..."
|
136
|
+
# TODO use File#realpath above instead of #expand_path once 1.8 support is
|
137
|
+
# dropped.
|
138
|
+
Dir.chdir @tempdir do
|
139
|
+
@tempdir = File.expand_path '.'
|
140
|
+
@tempdir.untaint
|
141
|
+
end
|
142
|
+
|
130
143
|
@gemhome = File.join @tempdir, 'gemhome'
|
131
144
|
@userhome = File.join @tempdir, 'userhome'
|
132
145
|
|
133
|
-
@orig_ruby = if
|
134
|
-
|
146
|
+
@orig_ruby = if ENV['RUBY'] then
|
147
|
+
ruby = Gem.instance_variable_get :@ruby
|
148
|
+
Gem.instance_variable_set :@ruby, ENV['RUBY']
|
135
149
|
ruby
|
136
150
|
end
|
137
151
|
|
@@ -251,7 +265,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
|
|
251
265
|
ENV['GEM_PATH'] = @orig_gem_path
|
252
266
|
|
253
267
|
_ = @orig_ruby
|
254
|
-
Gem.
|
268
|
+
Gem.instance_variable_set :@ruby, @orig_ruby if @orig_ruby
|
255
269
|
|
256
270
|
if @orig_ENV_HOME then
|
257
271
|
ENV['HOME'] = @orig_ENV_HOME
|
data/test/rubygems/test_gem.rb
CHANGED
@@ -667,6 +667,25 @@ class TestGem < Gem::TestCase
|
|
667
667
|
assert_equal %w[http://rubygems.org/], Gem.default_sources
|
668
668
|
end
|
669
669
|
|
670
|
+
def test_self_detect_gemdeps
|
671
|
+
rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], '-'
|
672
|
+
|
673
|
+
FileUtils.mkdir_p 'detect/a/b'
|
674
|
+
FileUtils.mkdir_p 'detect/a/Isolate'
|
675
|
+
|
676
|
+
FileUtils.touch 'detect/Isolate'
|
677
|
+
|
678
|
+
begin
|
679
|
+
Dir.chdir 'detect/a/b'
|
680
|
+
|
681
|
+
assert_empty Gem.detect_gemdeps
|
682
|
+
ensure
|
683
|
+
Dir.chdir @tempdir
|
684
|
+
end
|
685
|
+
ensure
|
686
|
+
ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps
|
687
|
+
end
|
688
|
+
|
670
689
|
def test_self_dir
|
671
690
|
assert_equal @gemhome, Gem.dir
|
672
691
|
end
|
@@ -959,6 +978,27 @@ class TestGem < Gem::TestCase
|
|
959
978
|
assert_includes Gem::Specification.all_names, @a1.full_name
|
960
979
|
end
|
961
980
|
|
981
|
+
def test_self_refresh_keeps_loaded_specs_activated
|
982
|
+
util_make_gems
|
983
|
+
|
984
|
+
a1_spec = @a1.spec_file
|
985
|
+
moved_path = File.join @tempdir, File.basename(a1_spec)
|
986
|
+
|
987
|
+
FileUtils.mv a1_spec, moved_path
|
988
|
+
|
989
|
+
Gem.refresh
|
990
|
+
|
991
|
+
s = Gem::Specification.first
|
992
|
+
s.activate
|
993
|
+
|
994
|
+
Gem.refresh
|
995
|
+
|
996
|
+
Gem::Specification.each{|spec| assert spec.activated? if spec == s}
|
997
|
+
|
998
|
+
Gem.loaded_specs.delete(s)
|
999
|
+
Gem.refresh
|
1000
|
+
end
|
1001
|
+
|
962
1002
|
def test_self_ruby_escaping_spaces_in_path
|
963
1003
|
orig_ruby = Gem.ruby
|
964
1004
|
orig_bindir = Gem::ConfigMap[:bindir]
|
@@ -1436,7 +1476,7 @@ class TestGem < Gem::TestCase
|
|
1436
1476
|
ENV['GEM_PATH'] = path
|
1437
1477
|
ENV['RUBYGEMS_GEMDEPS'] = "-"
|
1438
1478
|
|
1439
|
-
out = `#{Gem.ruby.untaint} -I #{LIB_PATH.untaint} -rubygems -e "p Gem.loaded_specs.values.map(&:full_name).sort"`
|
1479
|
+
out = `#{Gem.ruby.dup.untaint} -I #{LIB_PATH.untaint} -rubygems -e "p Gem.loaded_specs.values.map(&:full_name).sort"`
|
1440
1480
|
|
1441
1481
|
assert_equal '["a-1", "b-1", "c-1"]', out.strip
|
1442
1482
|
end
|
@@ -1468,7 +1508,7 @@ class TestGem < Gem::TestCase
|
|
1468
1508
|
|
1469
1509
|
Dir.mkdir "sub1"
|
1470
1510
|
out = Dir.chdir "sub1" do
|
1471
|
-
`#{Gem.ruby.untaint} -I #{LIB_PATH.untaint} -rubygems -e "p Gem.loaded_specs.values.map(&:full_name).sort"`
|
1511
|
+
`#{Gem.ruby.dup.untaint} -I #{LIB_PATH.untaint} -rubygems -e "p Gem.loaded_specs.values.map(&:full_name).sort"`
|
1472
1512
|
end
|
1473
1513
|
|
1474
1514
|
Dir.rmdir "sub1"
|