What Should Be Removed from Public Source Control in Ruby on Rails

What should be removed from public source control in Ruby on Rails?

I've been looking into this recently as well; I wanted to keep sensitive information hidden throughout the process of pushing open source code to Github, then automatically pushed to Travis CI for testing, then from Travis being automatically deployed to Heroku. Here are all the details of what I've found so far looking at various StackOverflow Q&As, blogs etc, which will hopefully serve as a reference for you, even if only for config inside the Rails app (omit any {{ ... }} you see)

Disclaimer: I'm by no means an expert here, so please keep in mind there are likely better ways to do this than what I'm trying. I'd love to be able to learn some new tricks in this Q&A thread.


Inside the Rails App

I currently use the Figaro gem to hide sensitive information in ENV environment variables. In my (.gitignored) config/application.yml, I keep the following information:

# App keys
SECRET_TOKEN: # your rake secret generated token

development:
DB_NAME: # your dev db name here
DB_USER: # your dev db username here
DB_PASSWORD: # your dev db password here

test:
DB_NAME: # your test db name here
DB_USER: # your test db username here
DB_PASSWORD: # your test db password here

production:
DB_NAME: # your prod db name here
DB_USER: # your prod db username here
DB_PASSWORD: # your prod db password here

# Third Party keys that you will reference in their relevant files
THIRD_PARTY_API_OR_LICENSE_KEY: # list of whatever api/license keys you use

(DB_NAME, DB_USER, and DB_PASSWORD will be used dynamically depending on what environment your app is running in).

An empty version of the above file (config/application.example.yml) gets pushed to Github with some instructions on how to fill it in.

The files that are pushed to Github and reference these variables look like this:

config/database.yml
(Postgresql is used here, but you should be able to change the settings for whatever database you use)

postgresql: &postgresql
adapter: postgresql
database: <%= ENV['DB_NAME'] %>
username: <%= ENV['DB_USER'] %>
password: <%= ENV['DB_PASSWORD'] %>
min_messages: ERROR

defaults: &defaults
pool: 5
timeout: 5000
host: localhost
<<: *<%= ENV['DB'] || "postgresql" %>

development:
<<: *defaults

test:
<<: *defaults

production:
<<: *defaults

config/initializers/secret_token.rb

if Rails.env.production? && ENV['SECRET_TOKEN'].blank?
raise 'SECRET_TOKEN environment variable must be set!'
end

YourApp::Application.config.secret_token =
ENV['SECRET_TOKEN'] || {{WHATEVER_SECRET_TOKEN_RAILS_GENERATED_BY_DEFAULT}}

(Plus, whatever files would be referencing THIRD_PARTY_API_OR_LICENSE_KEY-type keys.)

Testing on Travis CI

Create encrypted travis variables using the Travis gem. The Heroku API key and Heroku Git URL are needed if you deploy direct to Heroku from a Travis worker (see this StackOverflow Q&A for details), otherwise you can omit them if you just use it for testing:

$ gem install travis
$ travis encrypt your_username/your_repo HEROKU_API_KEY={{YOUR_HEROKU_API_KEY}}
$ travis encrypt HEROKU_GIT_URL={{YOUR_HEROKU_GIT_URL}} # eg git@heroku.com:your_app.git
$ travis encrypt DB_NAME={{YOUR_DB_NAME_UNDER_TEST}} # eg your_app_test
$ travis encrypt DB_USER={{YOUR_DB_USER_UNDER_TEST}}
$ travis encrypt DB_PASSWORD={{YOUR_DB_PASSWORD_UNDER_TEST}}

(Plus, encrypt any other keys you may need during testing, if any...)

Then add them to .travis.yml
(once again Postgresql-focused, but you should be able to change the settings for whatever database you use)

env:
global:
- secure: {{YOUR_ENCRYPTED_HEROKU_API_KEY}}
- secure: {{YOUR_ENCRYPTED_HEROKU_GIT_URL}}
- secure: {{YOUR_ENCRYPTED_DB_NAME}}
- secure: {{YOUR_ENCRYPTED_DB_USER}}
- secure: {{YOUR_ENCRYPTED_DB_PASSWORD}}
matrix:
- DB: postgresql
before_script:
- psql -c "create database $DB_NAME;" -U $DB_USER
- RAILS_ENV=test bundle exec rake db:migrate
script:
- bundle exec rspec spec/
after_success:
- gem install heroku
- git remote add heroku $HEROKU_GIT_URL
# ... see link above for the rest of the config content

Multiple variables marked with the same name of secure are fine; they'll show up in the config as HEROKU_API_KEY=[secure] HEROKU_GIT_URL=[secure] etc.

Deployment to Heroku

Use the Figaro's Heroku rake task to automatically set the environment variables that Heroku needs to see in production:

$ rake figaro:heroku

Or, set them manually:

$ heroku config:set SECRET_TOKEN={{YOUR_SECRET_TOKEN}}
$ heroku config:set DB_NAME={{YOUR_DB_NAME_UNDER_PRODUCTION}} # eg your_app_production
$ heroku config:set DB_USER={{YOUR_DB_USER_UNDER_PRODUCTION}}
$ heroku config:set DB_PASSWORD={{YOUR_DB_PASSWORD_UNDER_PRODUCTION}}
$ heroku config:set THIRD_PARTY_API_OR_LICENSE_KEY={{YOUR_THIRD_PARTY_API_OR_LICENSE_KEY}}

Then, attempt a deployment.


That's all I have for now. Not sure at the moment if I should be hiding more info or if I'm not hiding it well enough, but it's a work in progress.

Ruby on Rails 3.2.13 - Brakeman - Session secret should not be included in version control

That particular message in Brakeman was silenced for me when I put secret information into ENV variables, as you mentioned. Personally, I like to use the Figaro gem for this, but I think dotenv is popular as well.

Some other resources that may be of interest to you regarding this are:

  • Code Climate blog entry: Rails Insecure Defaults blog entry on Code Climate
  • StackOverflow thread: What should be removed from public source control in Ruby on Rails?

Rails: exclude anything from version control?

DHH just posted on Twitter that there will be a default .gitignore in Rails 3, which includes:

db/*.sqlite3
log/*.log
tmp/**/*

Which is usually what I exclude, some people also like to exclude the database.yml file if it's going on a public repo and you don't want to expose your database passwords.

Do you add public/assets in version control?

I was looking for an answer to this too. I found the official Rails Guide has some thoughts on this:

http://guides.rubyonrails.org/asset_pipeline.html#local-precompilation

Here's a quote of the relevant section (emphasis added):

There are several reasons why you might want to precompile your assets locally. Among them are:

  • You may not have write access to your production file system.
  • You may be deploying to more than one server, and want to avoid duplication of work.
  • You may be doing frequent deploys that do not include asset changes.

Local compilation allows you to commit the compiled files into source control, and deploy as normal.

There are three caveats:

  • You must not run the Capistrano deployment task that precompiles assets.
  • You must ensure any necessary compressors or minifiers are available on your development system.
  • You must change the following application configuration setting:

In config/environments/development.rb, place the following line:

config.assets.prefix = "/dev-assets"

The prefix change makes Sprockets use a different URL for serving assets in development mode, and pass all requests to Sprockets. The prefix is still set to /assets in the production environment. Without this change, the application would serve the precompiled assets from /assets in development, and you would not see any local changes until you compile assets again.

In practice, this will allow you to precompile locally, have those files in your working tree, and commit those files to source control when needed. Development mode will work as expected.

So, it looks like it might be a good idea to put precompiled assets into VCS on occasion.

Rails which files to ignore for GIT

Github has sample .gitignore files for almost any kind of project known to humanity.

Check out the repo: https://github.com/github/gitignore

Avoiding to hardcode server configuration

This solution is the best one I've found for this problem (and the one I personally use).

You should place your config files in

/path/to/deployed_app/shared

Then in a capistrano task, sym link to those files:

namespace :deploy do
task :symlink_shared do
run "ln -s #{shared_path}/database.yml #{release_path}/config/"
end
end

before "deploy:restart", "deploy:symlink_shared"

Should I include .ruby-version and .ruby-gemset when deploying a rails app?

Per the docs Heroku will look for your Ruby version in a few places:
1) Gemfile
2) An environment variable called CUSTOM_RUBY_VERSION

I prefer to specify the Ruby version in my Gemfile.

So, Heroku should ignore .ruby-version. The Ruby you specify in your Gemfile should probably match the version specified in .ruby-version

As a general rule I would check .ruby-version into source control.



Related Topics



Leave a reply



Submit