Update your gems for your Ruby on Rails applications to prevent vulnerabilities.

Use the Bundle Outdated command to keep your Rails applications secure

Last Updated on August 26, 2020 by Christopher G Mendla

Using outdated gems in your Ruby on Rails application introduces vulnerabilities to your Rails Applications. There is an easy way to find outdated gems using the Bundle Outdated command.

Do not go blindly along the updating path. Use version control and test the results of your updates. Be sure you have a solid backup and recovery plan in place.

The first thing to do is to check to see if you are on a current version of Ruby and Rails. The commands are ‘rails -v’ and ‘ruby -v’. Compare that with the latest releases of Ruby and Rails. Note that upgrades can be tricky so proceed with caution.

If you are significantly behind in your Ruby or Rails releases, you need to determine if you should update them first or update the outdated gems first. When updating Rails, you should update ALL of the code that changed between releases by checking railsdiff.org. Too many developers and teams just make the changes they think are critical which results in the underlying application code diverging from the true release code.

The next step is to determine how many outdated gems you have. The basic command is ‘bundle outdated’. However, you can modify that with grep and a pipe to get a count:

$ bundle outdated | grep -c "*"

This will return the number of outdated gems. This pipes the bundle outdated command to grep. The -c says count and the “*” is a handy way to get a unique count due to the way the list is returned.

Not all gems can be updated due to dependencies.

If you are using a test suite and rubocop, now would be a good time to run the test suite. The next step is to run ‘bundle outdated’ to see the gems. You will get results similar to the following

 $ bundle outdated

Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies............

Outdated gems included in the bundle:
  * actioncable (newest 5.2.3, installed 5.0.2)
  * actionmailer (newest 5.2.3, installed 5.0.2)
  * actionpack (newest 5.2.3, installed 5.0.2)
  * actionview (newest 5.2.3, installed 5.0.2)
  * active_model_serializers (newest 0.10.9, installed 0.10.4) in groups "default"
  * activejob (newest 5.2.3, installed 5.0.2)
  * activemodel (newest 5.2.3, installed 5.0.2)
  * activerecord (newest 5.2.3, installed 5.0.2)
  * activesupport (newest 5.2.3, installed 5.0.2)
  * arel (newest 9.0.0, installed 7.1.4)
  * autoprefixer-rails (newest 9.5.1, installed in groups "default"
  * bcrypt (newest 3.1.12, installed 3.1.11, requested ~> 3.1.7) in groups "default"
. . . 

Note that some of the gems show as being in a group and others do not. The gems that are shown as being in a group are gems that are listed in your gemfile explicitly. It is a good practice to call out the version in your gemfile

For example, here are three basic ways of calling a gem

gem samplegem              # no version is specified
gem samplegem, '1.1.1'     # locks that gem to version 1.1.1
gem samplegem, '~> 1.1.1'  # calls for version 1.1.1 but bundle update 
                           # will update to the highest minor version 

You can try ‘bundle update’. This will attempt to update all the gems that are not explicitly called in the gemfile or can be updated to a version compatible with the ‘~>’ version specified.

Now, run your tests. Are they still passing? Test the app in development. Is it still running OK? If you are lucky, it will test and run OK. If not, you will need to do some research as to why it failed. You are working with version control and can reset the branch, right?

Another alternative is to manually update each gem and then run your test suite. That can be time consuming and doesn’t always give predictable results. For example.

$ gem update samplegem
$ bundle install
$ rspec  # or whatever command launches your test suite. 

You will probably not be able to get all of the gems updated. If you want to see what other gems use a particular gem, you can do this

$ gem dependency -R thor
Gem thor-0.20.3
  bundler (~> 1.0, development)
  Used by
    rack-test-1.1.0 (thor (~> 0.19, development))
    railties- (thor (>= 0.19.0, < 2.0))

This shows which gems use the thor gem.

Once you get the gems that are not in the gemfile, you will need to look at the gems that are called out in your gemfile.

For example, if we see a line in the ‘bundle outdated’ results such as

  * puma (newest 3.12.1, installed 3.8.1, requested ~> 3.0) in groups "development, test"

We should be able to find that line in the ‘development, test’ group in our gemfile.

group :development, :test do
  gem 'byebug', platform: :mri
  gem 'pry-rails'
  # Use Puma as the dev app server
  gem 'puma', '~> 3.0'

To update to the latest current version of Puma (assuming there are no compatibility issues, you can change it as follows

group :development, :test do
  gem 'byebug', platform: :mri
  gem 'pry-rails'
  # Use Puma as the dev app server
  gem 'puma', '~> 3.12.1'

Then run ‘bundle install’ . Then run your test suite.

The process is tedious. In a production environment, you will probably be running bundle outdated several times a week. Constant integration apps such as Jenkins can be configured to fail builds that have over a set number of outdated gems.

You will occasionally run into situations where updating a gem causes conflicts that will break your app, build or tests.

Update your gems for your Ruby on Rails applications to prevent vulnerabilities.
geralt / Pixabay

Leave a Reply

Your email address will not be published. Required fields are marked *