Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeff Cousens committed Feb 3, 2016
0 parents commit 7535b70
Show file tree
Hide file tree
Showing 26 changed files with 635 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/.bundle/
/.yardoc
/Gemfile.lock
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "vendor/ruby-advisory-db"]
path = vendor/ruby-advisory-db
url = https://github.com/rubysec/ruby-advisory-db
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--color
13 changes: 13 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Metrics/LineLength:
Exclude:
- 'ruby_audit.gemspec'

Metrics/MethodLength:
Max: 15

Style/Documentation:
Enabled: false

Style/FileName:
Exclude:
- 'exe/ruby-audit'
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.3.0
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
language: ruby
cache: bundler
branches:
only:
- master
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Change Log

## 1.0.0 (2016-02-03)

* Initial Release
27 changes: 27 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Contributing to RubyAudit

We welcome pull requests from everyone!

## Getting Started

1. Fork it ( https://github.com/civisanalytics/ruby_audit/fork )
2. Install the development dependencies (`bundle install`)
3. Make sure you are able to run the test suite locally (`rake`)
4. Create a feature branch (`git checkout -b my-new-feature`)
5. Make your change. Don't forget tests
6. Make sure the test suite, including your new tests, passes (`rake`)
7. Commit your changes (`git commit -am 'Add some feature'`)
8. Push to the branch (`git push origin my-new-feature`)
9. Create a new pull request
10. If the Travis build fails, address any issues

## Tips

- All pull requests must include test coverage. If you’re not sure how to test
your changes, feel free to ask for help.
- Contributions must conform to the
[Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide).
- Don’t forget to add your change to the [CHANGELOG](CHANGELOG.md). See
[Keep a CHANGELOG](http://keepachangelog.com/) for guidelines.

Thank you for taking the time to contribute to RubyAudit!
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source 'https://rubygems.org'

# Specify your gem's dependencies in ruby_audit.gemspec
gemspec
13 changes: 13 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright (C) 2016 Civis Analytics

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# RubyAudit

[![Build Status](https://travis-ci.org/civisanalytics/ruby_audit.svg?branch=master)](https://travis-ci.org/civisanalytics/ruby_audit)
[![Gem Version](https://badge.fury.io/rb/ruby_audit.svg)](http://badge.fury.io/rb/ruby_audit)
[![Dependency Status](https://gemnasium.com/civisanalytics/ruby_audit.svg)](https://gemnasium.com/civisanalytics/ruby_audit)

RubyAudit checks your current version of Ruby and RubyGems against known security vulnerabilities (CVEs), alerting you if you are using an insecure version.
It complements [bundler-audit](https://github.com/rubysec/bundler-audit), providing complete coverage for your Ruby stack.
If you use Bundler, you should use both RubyAudit and bundler-audit.

RubyAudit is based on and leverages bundler-audit, and would not exist without the hard work of the [rubysec](https://github.com/rubysec) team, specifically bundler-audit and [ruby-advisory-db](https://github.com/rubysec/ruby-advisory-db).

"If I have seen further it is by standing on the shoulders of Giants." -- Isaac Newton

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'ruby_audit'
```

And then execute:

$ bundle

Or install it yourself as:

$ gem install ruby_audit

## Usage

To check your current version of Ruby and RubyGems:

```bash
$ ruby-audit check
```

You can ignore specific advisories by specifying `-i <advisory>`:

```bash
$ ruby-audit check -i CVE-2015-7551
```

By default, RubyAudit will check for updates to the ruby-advisory-db when it runs.
If you are using RubyAudit offline, you can bypass this check by specifying `-n`:

```bash
$ ruby-audit check -n
```

## Development

After checking out the repo, run `bin/setup` to install dependencies.
Then, run `rake spec` to run the tests.
You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`.
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

See [CONTRIBUTING](CONTRIBUTING.md).

## License

RubyAudit is released under the [GNU General Public License version 3](LICENSE.md).
9 changes: 9 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require 'bundler/gem_tasks'

require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new

require 'rubocop/rake_task'
RuboCop::RakeTask.new

task default: [:rubocop, :spec]
7 changes: 7 additions & 0 deletions bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env ruby

require 'bundler/setup'
require 'ruby_audit'

require 'pry'
Pry.start
8 changes: 8 additions & 0 deletions bin/setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle install

# Do any other automated setup that you need to do here
6 changes: 6 additions & 0 deletions exe/ruby-audit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env ruby

require 'bundler/setup'
require 'ruby_audit'

RubyAudit::CLI.start
5 changes: 5 additions & 0 deletions lib/ruby_audit.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require 'bundler/audit/cli'
require 'ruby_audit/cli'
require 'ruby_audit/database'
require 'ruby_audit/scanner'
require 'ruby_audit/version'
68 changes: 68 additions & 0 deletions lib/ruby_audit/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
module RubyAudit
class CLI < Bundler::Audit::CLI
desc 'check', 'Checks Ruby and RubyGems for insecure versions'
method_option :ignore, type: :array, aliases: '-i'
method_option :no_update, type: :boolean, aliases: '-n'
method_option :verbose, type: :boolean, aliases: '-v'
def check
update unless options[:no_update]

check_for_stale_database

scanner = Scanner.new
vulnerable = false

scanner.scan(ignore: options[:ignore]) do |result|
vulnerable = true
print_advisory result.gem, result.advisory
end

if vulnerable
say 'Vulnerabilities found!', :red
exit 1
else
say 'No vulnerabilities found', :green
end
end

# Copied from bundler-audit master. Not present in 0.4.0.
desc 'update', 'Updates the ruby-advisory-db'
def update
say 'Updating ruby-advisory-db ...'

case Database.update!
when true
say 'Updated ruby-advisory-db', :green
when false
say 'Failed updating ruby-advisory-db!', :red
exit 1
when nil
say 'Skipping update', :yellow
end

puts "ruby-advisory-db: #{Database.new.size} advisories"
end

desc 'version', 'Prints the ruby-audit version'
def version
database = Database.new
puts "#{File.basename($PROGRAM_NAME)} #{VERSION} "\
"(advisories: #{database.size})"
end

private

def check_for_stale_database
database = Database.new
if database.size == 89
# bundler-audit 0.4.0 comes bundled with an old verison of
# ruby-advisory-db that has 89 advisories and NO advisories for Ruby
# or RubyGems. If #size == 89, the database has never been updated.
say 'The database must be updated before using RubyAudit', :red
exit 1
elsif database.stale
say 'The database has not been updated in over 7 days', :yellow
end
end
end
end
49 changes: 49 additions & 0 deletions lib/ruby_audit/database.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module RubyAudit
class Database < Bundler::Audit::Database
def advisories_for(name, type)
return enum_for(__method__, name, type) unless block_given?

each_advisory_path_for(name, type) do |path|
yield Bundler::Audit::Advisory.load(path)
end
end

def check_ruby(ruby, &block)
check(ruby, 'rubies', &block)
end

def check_library(library, &block)
check(library, 'libraries', &block)
end

def check(object, type = 'gems')
return enum_for(__method__, object, type) unless block_given?

advisories_for(object.name, type) do |advisory|
yield advisory if advisory.vulnerable?(object.version)
end
end

def stale
if File.directory?(USER_PATH) &&
File.exist?(File.join(USER_PATH, '.git'))
ts = Time.parse(
`cd #{USER_PATH} && git log --date=iso8601 --pretty="%cd" -1`).utc
ts < (Date.today - 7).to_time
else
true
end
end

protected

def each_advisory_path(&block)
Dir.glob(File.join(@path, '{gems,libraries,rubies}', '*', '*.yml'),
&block)
end

def each_advisory_path_for(name, type = 'gems', &block)
Dir.glob(File.join(@path, type, name, '*.yml'), &block)
end
end
end
80 changes: 80 additions & 0 deletions lib/ruby_audit/scanner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
module RubyAudit
class Scanner < Bundler::Audit::Scanner
class Version
def initialize(name, version)
@name = name
@version = Gem::Version.new(version)
end

attr_reader :name, :version
end

def initialize
@database = Database.new
end

def scan(options = {}, &block)
return enum_for(__method__, options) unless block

scan_ruby(options, &block)
scan_rubygems(options, &block)

self
end

def scan_ruby(options = {}, &block)
if RUBY_PATCHLEVEL < 0
version = ruby_version
else
version = "#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
end
specs = [Version.new(RUBY_ENGINE, version)]
scan_inner(specs, 'ruby', options, &block)
end

def scan_rubygems(options = {}, &block)
specs = [Version.new('rubygems', rubygems_version)]
scan_inner(specs, 'library', options, &block)
end

private

def ruby_version
# .gsub to separate strings (e.g., 2.1.0dev -> 2.1.0.dev,
# 2.2.0preview1 -> 2.2.0.preview.1).
`ruby --version`.split[1]
.gsub(/(\d)([a-z]+)/, '\1.\2')
.gsub(/([a-z]+)(\d)/, '\1.\2')
end

def rubygems_version
`gem --version`.strip
end

def scan_inner(specs, type, options = {})
return enum_for(__method__, options) unless block_given?

ignore = Set[]
ignore += options[:ignore] if options[:ignore]

specs.each do |spec|
@database.send("check_#{type}".to_sym, spec) do |advisory|
unless ignore.include?(cve_id(advisory)) ||
ignore.include?(osvdb_id(advisory))
yield UnpatchedGem.new(spec, advisory)
end
end
end
end

# Workaround for advisory.cve_id, present in master but not 0.4.0.
def cve_id(advisory)
"CVE-#{advisory.cve}" if advisory.cve
end

# Workaround for advisory.osvdb_id, present in master but not 0.4.0.
def osvdb_id(advisory)
"OSVDB-#{advisory.osvdb}" if advisory.osvdb
end
end
end
Loading

0 comments on commit 7535b70

Please sign in to comment.