rubygems-update 2.0.0.rc.1 → 2.0.0.rc.2
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.
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"
|