When rubygems updates ~/.gemrc, it erroneously converts some config keys from symbols to strings #837

Closed
rampion opened this Issue Feb 27, 2014 · 2 comments

Projects

None yet

3 participants

rampion commented Feb 27, 2014

tl;dr - when gem updates the user's ~/.gemrc, it converts some config keys to strings. As a consequence, those config values will be ignored.


In config_file.rb, we have

def initialize(args)
  #...
  @ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode
  @ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert
  @ssl_client_cert = @hash[:ssl_client_cert] if @hash.key? :ssl_client_cert
  #...
end

So detecting the SSL settings depends on the keys in @hash being symbols.

@hash is just generated from Hash#merge-ing several Hash objects created by YAML.load, so there's no conversion of keys there.

But when it overwrites ~/.gemrc, it calls #to_yaml

# Writes out this config file, replacing its source.
def write
  open config_file_name, 'w' do |io|
    io.write to_yaml
  end
end

And #to_yaml currently converts all but a few @hash keys to strings:

@hash.each do |key, value|
  key = key.to_s
  next if key =~ re
  yaml_hash[key.to_s] = value
end

So now keys that need to be symbols (like :ssl_client_cert) are stored as strings, which means that they'll be ignored on next run.


As a use case, consider a user with the following ~/.gemrc:


---
:ssl_client_cert: /path/to/cert.pem
:ssl_verify_mode: 1

Now if they add a new source:

% gem source -a http://foo.bar.bz/
http://foo.bar.bz/ added to sources

Their ~/.gemrc will now read


---
:sources:
- http://foo.bar.bz/
ssl_client_cert: /path/to/cert.pem
ssl_verify_mode: 1

And any attempt to use a gem source that uses client certificate authentication will fail:

% gem source -a https://secure.bar.bz/
Error fetching https://secure.bar.bz/
        SSL_connect returned=1 errno=0 state=SSLv3 read server session ticket A: sslv3 alert handhake failure (https://secure.bar.bz/)

If the ~/.gemrc file is manually edited to restore the keys to symbols:


---
:sources:
- http://foo.bar.bz/
:ssl_client_cert: /path/to/cert.pem
:ssl_verify_mode: 1

Then an attempt to use a gem source that uses client certificate authentication can now use those:

% gem source -a https://secure.bar.bz/
https://secure.bar.bz/ added to sources

(though the keys will have to edited again to actually use the secure gemserver).


I'm not sure what the best fix is. It'd be easy enough to save the :ssl_* keys explicitly in #to_yaml but that wouldn't be very DRY, and it'd leave the code open to another accidental key type conversion error in the future.

rampion commented Feb 27, 2014

I'm tempted to just maintain the key types as they are in @hash:

def to_yaml
  # ...
  @hash.each do |key, value|
     next if key.to_s =~ re
     yaml_hash[key] = value
  end
  #...
end

I don't think this would break anything, but I'm not familiar enough with the local ecosystem to be sure.

also running into this issue

@drbrain drbrain added this to the 2.3 milestone Apr 3, 2014
@drbrain drbrain closed this in 29f9fd0 Apr 3, 2014
@zzak zzak added a commit to zzak/rubygems that referenced this issue May 9, 2014
@drbrain @zzak drbrain + zzak Round-trip ~/.gemrc SSL entries
Previously SSL entries were not handled specially so their keys would be
converted from symbols to strings when the configuration file was
rewritten.

Now they are special-cased so they remain as symbols.

Fixes #837
badc2d4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment