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.

@@ -57,13 +57,13 @@ class Gem::DependencyInstaller
57
57
  # :build_args:: See Gem::Installer::new
58
58
 
59
59
  def initialize(options = {})
60
- if options[:install_dir] then
61
- @gem_home = options[:install_dir]
60
+ @install_dir = options[:install_dir] || Gem.dir
62
61
 
63
- # HACK shouldn't change the global settings
64
- Gem::Specification.dirs = @gem_home
65
- Gem.ensure_gem_subdirectories @gem_home
66
- options[:install_dir] = @gem_home # FIX: because we suck and reuse below
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
@@ -1,8 +1,9 @@
1
- ##
1
+ #--
2
2
  # This file contains all the various exceptions and other errors that are used
3
3
  # inside of RubyGems.
4
4
  #
5
5
  # DOC: Confirm _all_
6
+ #++
6
7
 
7
8
  module Gem
8
9
  ##
@@ -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
- if verbose
46
- puts(command)
47
- system(command)
48
- else
49
- results << command
50
- results << `#{command} #{redirector}`
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
- say "Enter your RubyGems.org credentials."
34
- say "Don't have an account yet? Create one at http://rubygems.org/sign_up"
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 :get, "api/v1/api_key" do |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
 
@@ -277,9 +277,13 @@ EOM
277
277
  # the security policy.
278
278
 
279
279
  def digest entry # :nodoc:
280
- return unless @checksums
280
+ algorithms = if @checksums then
281
+ @checksums.keys
282
+ else
283
+ [Gem::Security::DIGEST_NAME]
284
+ end
281
285
 
282
- @checksums.each_key do |algorithm|
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
@@ -23,15 +23,18 @@ class Gem::Package::Old < Gem::Package
23
23
  require 'zlib'
24
24
  Gem.load_yaml
25
25
 
26
- @gem = gem
27
- @contents = nil
28
- @spec = nil
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
- @spec = Gem::Specification.from_yaml yaml
140
- rescue YAML::SyntaxError => e
141
- raise Gem::Exception, "Failed to parse gem specification out of gem file"
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
- chain.each_cons 2 do |issuer, cert|
53
- check_cert cert, issuer, time
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
- true
57
- rescue Gem::Security::Exception => e
58
- raise Gem::Security::Exception, "invalid signing chain: #{e.message}"
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
- "signed-only: %p trusted-only: %p]" % [
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
- signer_digests = digests.values.first || {}
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.instance_eval { @specification_version ||= NONEXISTENT_SPECIFICATION_VERSION }
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
@@ -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
- # Need to do this in the project because $SAFE fucks up _everything_
122
- tmpdir = File.expand_path("tmp/test")
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 ruby = ENV['RUBY'] then
134
- Gem.class_eval { ruby, @ruby = @ruby, ruby.dup }
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.class_eval { @ruby = _ } if _
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
@@ -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"