mrjoy-bundler-audit 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.gitignore +6 -0
  4. data/.gitmodules +3 -0
  5. data/.rspec +1 -0
  6. data/.travis.yml +5 -0
  7. data/.yardopts +1 -0
  8. data/COPYING.txt +674 -0
  9. data/ChangeLog.md +79 -0
  10. data/Gemfile +14 -0
  11. data/README.md +105 -0
  12. data/Rakefile +47 -0
  13. data/bin/bundle-audit +10 -0
  14. data/data/ruby-advisory-db/.rspec +1 -0
  15. data/data/ruby-advisory-db/CONTRIBUTING.md +6 -0
  16. data/data/ruby-advisory-db/CONTRIBUTORS.md +13 -0
  17. data/data/ruby-advisory-db/Gemfile +3 -0
  18. data/data/ruby-advisory-db/LICENSE.txt +5 -0
  19. data/data/ruby-advisory-db/README.md +86 -0
  20. data/data/ruby-advisory-db/Rakefile +27 -0
  21. data/data/ruby-advisory-db/gems/actionpack/OSVDB-79727.yml +26 -0
  22. data/data/ruby-advisory-db/gems/actionpack/OSVDB-84243.yml +28 -0
  23. data/data/ruby-advisory-db/gems/actionpack/OSVDB-84513.yml +23 -0
  24. data/data/ruby-advisory-db/gems/actionpack/OSVDB-84515.yml +26 -0
  25. data/data/ruby-advisory-db/gems/actionpack/OSVDB-89026.yml +24 -0
  26. data/data/ruby-advisory-db/gems/actionpack/OSVDB-91452.yml +20 -0
  27. data/data/ruby-advisory-db/gems/actionpack/OSVDB-91454.yml +23 -0
  28. data/data/ruby-advisory-db/gems/activerecord/OSVDB-82403.yml +25 -0
  29. data/data/ruby-advisory-db/gems/activerecord/OSVDB-82610.yml +24 -0
  30. data/data/ruby-advisory-db/gems/activerecord/OSVDB-89025.yml +24 -0
  31. data/data/ruby-advisory-db/gems/activerecord/OSVDB-90072.yml +21 -0
  32. data/data/ruby-advisory-db/gems/activerecord/OSVDB-90073.yml +23 -0
  33. data/data/ruby-advisory-db/gems/activerecord/OSVDB-91453.yml +26 -0
  34. data/data/ruby-advisory-db/gems/activesupport/OSVDB-79726.yml +26 -0
  35. data/data/ruby-advisory-db/gems/activesupport/OSVDB-84516.yml +23 -0
  36. data/data/ruby-advisory-db/gems/activesupport/OSVDB-89594.yml +25 -0
  37. data/data/ruby-advisory-db/gems/activesupport/OSVDB-91451.yml +28 -0
  38. data/data/ruby-advisory-db/gems/command_wrap/OSVDB-91450.yml +10 -0
  39. data/data/ruby-advisory-db/gems/crack/OSVDB-90742.yml +17 -0
  40. data/data/ruby-advisory-db/gems/cremefraiche/OSVDB-93395.yml +11 -0
  41. data/data/ruby-advisory-db/gems/curl/OSVDB-91230.yml +12 -0
  42. data/data/ruby-advisory-db/gems/devise/OSVDB-89642.yml +20 -0
  43. data/data/ruby-advisory-db/gems/dragonfly/OSVDB-90647.yml +19 -0
  44. data/data/ruby-advisory-db/gems/enum_column3/OSVDB-94679.yml +9 -0
  45. data/data/ruby-advisory-db/gems/extlib/OSVDB-90740.yml +18 -0
  46. data/data/ruby-advisory-db/gems/fastreader/OSVDB-91232.yml +12 -0
  47. data/data/ruby-advisory-db/gems/fileutils/OSVDB-90715.yml +10 -0
  48. data/data/ruby-advisory-db/gems/fileutils/OSVDB-90716.yml +10 -0
  49. data/data/ruby-advisory-db/gems/fileutils/OSVDB-90717.yml +10 -0
  50. data/data/ruby-advisory-db/gems/flash_tool/OSVDB-90829.yml +9 -0
  51. data/data/ruby-advisory-db/gems/ftpd/OSVDB-90784.yml +18 -0
  52. data/data/ruby-advisory-db/gems/gtk2/OSVDB-40774.yml +20 -0
  53. data/data/ruby-advisory-db/gems/httparty/OSVDB-90741.yml +19 -0
  54. data/data/ruby-advisory-db/gems/json/OSVDB-90074.yml +23 -0
  55. data/data/ruby-advisory-db/gems/karteek-docsplit/OSVDB-92117.yml +10 -0
  56. data/data/ruby-advisory-db/gems/kelredd-pruview/OSVDB-92228.yml +10 -0
  57. data/data/ruby-advisory-db/gems/ldoce/OSVDB-91870.yml +10 -0
  58. data/data/ruby-advisory-db/gems/loofah/OSVDB-90945.yml +21 -0
  59. data/data/ruby-advisory-db/gems/mail/OSVDB-70667.yml +21 -0
  60. data/data/ruby-advisory-db/gems/mail/OSVDB-81631.yml +14 -0
  61. data/data/ruby-advisory-db/gems/mail/OSVDB-81632.yml +16 -0
  62. data/data/ruby-advisory-db/gems/md2pdf/OSVDB-92290.yml +10 -0
  63. data/data/ruby-advisory-db/gems/mini_magick/OSVDB-91231.yml +15 -0
  64. data/data/ruby-advisory-db/gems/multi_xml/OSVDB-89148.yml +16 -0
  65. data/data/ruby-advisory-db/gems/newrelic_rpm/OSVDB-90189.yml +17 -0
  66. data/data/ruby-advisory-db/gems/nori/OSVDB-90196.yml +19 -0
  67. data/data/ruby-advisory-db/gems/omniauth-oauth2/OSVDB-90264.yml +16 -0
  68. data/data/ruby-advisory-db/gems/pdfkit/OSVDB-90867.yml +11 -0
  69. data/data/ruby-advisory-db/gems/rack-cache/OSVDB-83077.yml +18 -0
  70. data/data/ruby-advisory-db/gems/rack/OSVDB-89939.yml +23 -0
  71. data/data/ruby-advisory-db/gems/rdoc/OSVDB-90004.yml +27 -0
  72. data/data/ruby-advisory-db/gems/rgpg/OSVDB-95948.yml +13 -0
  73. data/data/ruby-advisory-db/gems/ruby_parser/OSVDB-90561.yml +11 -0
  74. data/data/ruby-advisory-db/gems/spree/OSVDB-91216.yml +10 -0
  75. data/data/ruby-advisory-db/gems/spree/OSVDB-91217.yml +10 -0
  76. data/data/ruby-advisory-db/gems/spree/OSVDB-91218.yml +10 -0
  77. data/data/ruby-advisory-db/gems/spree/OSVDB-91219.yml +10 -0
  78. data/data/ruby-advisory-db/gems/thumbshooter/OSVDB-91839.yml +10 -0
  79. data/data/ruby-advisory-db/lib/scrape.rb +87 -0
  80. data/data/ruby-advisory-db/spec/advisory_example.rb +165 -0
  81. data/data/ruby-advisory-db/spec/gems_spec.rb +8 -0
  82. data/data/ruby-advisory-db/spec/spec_helper.rb +1 -0
  83. data/gemspec.yml +16 -0
  84. data/lib/bundler/audit.rb +21 -0
  85. data/lib/bundler/audit/advisory.rb +142 -0
  86. data/lib/bundler/audit/cli.rb +124 -0
  87. data/lib/bundler/audit/database.rb +187 -0
  88. data/lib/bundler/audit/scanner.rb +97 -0
  89. data/lib/bundler/audit/version.rb +25 -0
  90. data/mrjoy-bundler-audit.gemspec +66 -0
  91. data/spec/advisory_spec.rb +145 -0
  92. data/spec/audit_spec.rb +8 -0
  93. data/spec/bundle/insecure_sources/Gemfile +39 -0
  94. data/spec/bundle/secure/Gemfile +38 -0
  95. data/spec/bundle/unpatched_gems/Gemfile +38 -0
  96. data/spec/database_spec.rb +81 -0
  97. data/spec/integration_spec.rb +81 -0
  98. data/spec/scanner_spec.rb +74 -0
  99. data/spec/spec_helper.rb +21 -0
  100. metadata +162 -0
@@ -0,0 +1,97 @@
1
+ require 'bundler'
2
+ require 'bundler/audit/database'
3
+ require 'bundler/lockfile_parser'
4
+
5
+ require 'set'
6
+
7
+ module Bundler
8
+ module Audit
9
+ class Scanner
10
+
11
+ # Represents a plain-text source
12
+ InsecureSource = Struct.new(:source)
13
+
14
+ # Represents a gem that is covered by an Advisory
15
+ UnpatchedGem = Struct.new(:gem, :advisory)
16
+
17
+ # The advisory database
18
+ #
19
+ # @return [Database]
20
+ attr_reader :database
21
+
22
+ # Project root directory
23
+ attr_reader :root
24
+
25
+ # The parsed `Gemfile.lock` from the project
26
+ #
27
+ # @return [Bundler::LockfileParser]
28
+ attr_reader :lockfile
29
+
30
+ #
31
+ # Initializes a scanner.
32
+ #
33
+ # @param [String] root
34
+ # The path to the project root.
35
+ #
36
+ def initialize(root=Dir.pwd)
37
+ @root = File.expand_path(root)
38
+ @database = Database.new
39
+ @lockfile = LockfileParser.new(
40
+ File.read(File.join(@root,'Gemfile.lock'))
41
+ )
42
+ end
43
+
44
+ #
45
+ # Scans the project for issues.
46
+ #
47
+ # @param [Hash] options
48
+ # Additional options.
49
+ #
50
+ # @option options [Array<String>] :ignore
51
+ # The advisories to ignore.
52
+ #
53
+ # @yield [result]
54
+ # The given block will be passed the results of the scan.
55
+ #
56
+ # @yieldparam [InsecureSource, UnpatchedGem] result
57
+ # A result from the scan.
58
+ #
59
+ # @return [Enumerator]
60
+ # If no block is given, an Enumerator will be returned.
61
+ #
62
+ def scan(options={})
63
+ return enum_for(__method__,options) unless block_given?
64
+
65
+ ignore = Set[]
66
+ ignore += options[:ignore] if options[:ignore]
67
+
68
+ @lockfile.sources.map do |source|
69
+ case source
70
+ when Source::Git
71
+ case source.uri
72
+ when /^git:/, /^http:/
73
+ yield InsecureSource.new(source.uri)
74
+ end
75
+ when Source::Rubygems
76
+ source.remotes.each do |uri|
77
+ if uri.scheme == 'http'
78
+ yield InsecureSource.new(uri.to_s)
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ @lockfile.specs.each do |gem|
85
+ @database.check_gem(gem) do |advisory|
86
+ unless ignore.include?("CVE-#{advisory.cve}")
87
+ yield UnpatchedGem.new(gem,advisory)
88
+ end
89
+ end
90
+ end
91
+
92
+ return self
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,25 @@
1
+ #
2
+ # Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ # Modifications Copyright (c) 2013 Jon Frisby (jfrisby@mrjoy.com), or their
4
+ # respective authors.
5
+ #
6
+ # mrjoy-bundler-audit is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # mrjoy-bundler-audit is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with mrjoy-bundler-audit. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ module Bundler
21
+ module Audit
22
+ # bundler-audit version
23
+ VERSION = '0.1.4'
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'bundler/audit/version'
14
+ Bundler::Audit::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+
24
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
25
+
26
+ gem.files = `git ls-files`.split($/)
27
+ gem.files = glob[gemspec['files']] if gemspec['files']
28
+
29
+ # add paths from data/ruby-advisory-db/
30
+ gem.files += Dir.chdir('data/ruby-advisory-db') do
31
+ `git ls-files`.split($/).map do |sub_path|
32
+ File.join('data','ruby-advisory-db',sub_path)
33
+ end
34
+ end
35
+
36
+ gem.executables = gemspec.fetch('executables') do
37
+ glob['bin/*'].map { |path| File.basename(path) }
38
+ end
39
+
40
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
41
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
42
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
43
+
44
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
45
+ %w[ext lib].select { |dir| File.directory?(dir) }
46
+ })
47
+
48
+ gem.requirements = gemspec['requirements']
49
+ gem.required_ruby_version = gemspec['required_ruby_version']
50
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
51
+ gem.post_install_message = gemspec['post_install_message']
52
+
53
+ split = lambda { |string| string.split(/,\s*/) }
54
+
55
+ if gemspec['dependencies']
56
+ gemspec['dependencies'].each do |name,versions|
57
+ gem.add_dependency(name,split[versions])
58
+ end
59
+ end
60
+
61
+ if gemspec['development_dependencies']
62
+ gemspec['development_dependencies'].each do |name,versions|
63
+ gem.add_development_dependency(name,split[versions])
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,145 @@
1
+ require 'spec_helper'
2
+ require 'bundler/audit/database'
3
+ require 'bundler/audit/advisory'
4
+
5
+ describe Bundler::Audit::Advisory do
6
+ let(:root) { Bundler::Audit::Database::PATH }
7
+ let(:gem) { 'actionpack' }
8
+ let(:path) { File.join(root,gem,"OSVDB-89026.yml") }
9
+ let(:cve) { YAML.load(File.read(path))['cve'] }
10
+ let(:an_unaffected_version) do
11
+ YAML.load(File.read(path))['unaffected_versions'].first.sub(/^.*?(~>|>=|>|=)\s+/, '')
12
+ end
13
+
14
+ describe "load" do
15
+ let(:data) { YAML.load_file(path) }
16
+
17
+ subject { described_class.load(path) }
18
+
19
+ its(:cve) { should == cve }
20
+ its(:url) { should == data['url'] }
21
+ its(:title) { should == data['title'] }
22
+ its(:cvss_v2) { should == data['cvss_v2'] }
23
+ its(:description) { should == data['description'] }
24
+
25
+ describe "#patched_versions" do
26
+ subject { described_class.load(path).patched_versions }
27
+
28
+ it "should all be Gem::Requirement objects" do
29
+ subject.all? { |version|
30
+ version.should be_kind_of(Gem::Requirement)
31
+ }.should be_true
32
+ end
33
+
34
+ it "should parse the versions" do
35
+ subject.map(&:to_s).should == data['patched_versions']
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "#criticality" do
41
+ context "when cvss_v2 is between 0.0 and 3.3" do
42
+ before { subject.stub(:cvss_v2).and_return(3.3) }
43
+
44
+ its(:criticality) { should == :low }
45
+ end
46
+
47
+ context "when cvss_v2 is between 3.3 and 6.6" do
48
+ before { subject.stub(:cvss_v2).and_return(6.6) }
49
+
50
+ its(:criticality) { should == :medium }
51
+ end
52
+
53
+ context "when cvss_v2 is between 6.6 and 10.0" do
54
+ before { subject.stub(:cvss_v2).and_return(10.0) }
55
+
56
+ its(:criticality) { should == :high }
57
+ end
58
+ end
59
+
60
+ describe "#unaffected?" do
61
+ let(:gem) { 'activerecord' }
62
+ let(:path) { File.join(root,gem,"OSVDB-82403.yml") }
63
+
64
+ subject { described_class.load(path) }
65
+
66
+ context "when passed a version that matches one unaffected version" do
67
+ let(:version) { Gem::Version.new(an_unaffected_version) }
68
+
69
+ it "should return true" do
70
+ subject.unaffected?(version).should be_true
71
+ end
72
+ end
73
+
74
+ context "when passed a version that matches no unaffected version" do
75
+ let(:version) { Gem::Version.new('3.0.9') }
76
+
77
+ it "should return false" do
78
+ subject.unaffected?(version).should be_false
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "#patched?" do
84
+ subject { described_class.load(path) }
85
+
86
+ context "when passed a version that matches one patched version" do
87
+ let(:version) { Gem::Version.new('3.1.11') }
88
+
89
+ it "should return true" do
90
+ subject.patched?(version).should be_true
91
+ end
92
+ end
93
+
94
+ context "when passed a version that matches no patched version" do
95
+ let(:version) { Gem::Version.new('3.1.9') }
96
+
97
+ it "should return false" do
98
+ subject.patched?(version).should be_false
99
+ end
100
+ end
101
+ end
102
+
103
+ describe "#vulnerable?" do
104
+ subject { described_class.load(path) }
105
+
106
+ context "when passed a version that matches one patched version" do
107
+ let(:version) { Gem::Version.new('3.1.11') }
108
+
109
+ it "should return false" do
110
+ subject.vulnerable?(version).should be_false
111
+ end
112
+ end
113
+
114
+ context "when passed a version that matches no patched version" do
115
+ let(:version) { Gem::Version.new('3.1.9') }
116
+
117
+ it "should return true" do
118
+ subject.vulnerable?(version).should be_true
119
+ end
120
+
121
+ context "when unaffected_versions is not empty" do
122
+ let(:gem) { 'activerecord' }
123
+ let(:path) { File.join(root,gem,"OSVDB-82403.yml") }
124
+
125
+ subject { described_class.load(path) }
126
+
127
+ context "when passed a version that matches one unaffected version" do
128
+ let(:version) { Gem::Version.new(an_unaffected_version) }
129
+
130
+ it "should return false" do
131
+ subject.vulnerable?(version).should be_false
132
+ end
133
+ end
134
+
135
+ context "when passed a version that matches no unaffected version" do
136
+ let(:version) { Gem::Version.new('1.2.3') }
137
+
138
+ it "should return true" do
139
+ subject.vulnerable?(version).should be_true
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'bundler/audit'
3
+
4
+ describe Bundler::Audit do
5
+ it "should have a VERSION constant" do
6
+ subject.const_get('VERSION').should_not be_empty
7
+ end
8
+ end
@@ -0,0 +1,39 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rails', '3.2.12'
4
+
5
+ # Bundle edge Rails instead:
6
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
+
8
+ gem 'sqlite3'
9
+
10
+
11
+ # Gems used only for assets and not required
12
+ # in production environments by default.
13
+ group :assets do
14
+ # gem 'sass-rails', '~> 3.2.3'
15
+ # gem 'coffee-rails', '~> 3.2.1'
16
+
17
+ # See https://github.com/sstephenson/execjs#readme for more supported runtimes
18
+ # gem 'therubyracer', :platforms => :ruby
19
+
20
+ # gem 'uglifier', '>= 1.0.3'
21
+ end
22
+
23
+ gem 'jquery-rails', :git => 'git://github.com/rails/jquery-rails.git',
24
+ :tag => 'v2.2.1'
25
+
26
+ # To use ActiveModel has_secure_password
27
+ # gem 'bcrypt-ruby', '~> 3.0.0'
28
+
29
+ # To use Jbuilder templates for JSON
30
+ # gem 'jbuilder'
31
+
32
+ # Use unicorn as the app server
33
+ # gem 'unicorn'
34
+
35
+ # Deploy with Capistrano
36
+ # gem 'capistrano'
37
+
38
+ # To use debugger
39
+ # gem 'debugger'
@@ -0,0 +1,38 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '3.2.13'
4
+
5
+ # Bundle edge Rails instead:
6
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
+
8
+ gem 'sqlite3'
9
+
10
+
11
+ # Gems used only for assets and not required
12
+ # in production environments by default.
13
+ group :assets do
14
+ # gem 'sass-rails', '~> 3.2.3'
15
+ # gem 'coffee-rails', '~> 3.2.1'
16
+
17
+ # See https://github.com/sstephenson/execjs#readme for more supported runtimes
18
+ # gem 'therubyracer', :platforms => :ruby
19
+
20
+ # gem 'uglifier', '>= 1.0.3'
21
+ end
22
+
23
+ gem 'jquery-rails'
24
+
25
+ # To use ActiveModel has_secure_password
26
+ # gem 'bcrypt-ruby', '~> 3.0.0'
27
+
28
+ # To use Jbuilder templates for JSON
29
+ # gem 'jbuilder'
30
+
31
+ # Use unicorn as the app server
32
+ # gem 'unicorn'
33
+
34
+ # Deploy with Capistrano
35
+ # gem 'capistrano'
36
+
37
+ # To use debugger
38
+ # gem 'debugger'
@@ -0,0 +1,38 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '3.2.10'
4
+
5
+ # Bundle edge Rails instead:
6
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
+
8
+ gem 'sqlite3'
9
+
10
+
11
+ # Gems used only for assets and not required
12
+ # in production environments by default.
13
+ group :assets do
14
+ # gem 'sass-rails', '~> 3.2.3'
15
+ # gem 'coffee-rails', '~> 3.2.1'
16
+
17
+ # See https://github.com/sstephenson/execjs#readme for more supported runtimes
18
+ # gem 'therubyracer', :platforms => :ruby
19
+
20
+ # gem 'uglifier', '>= 1.0.3'
21
+ end
22
+
23
+ gem 'jquery-rails'
24
+
25
+ # To use ActiveModel has_secure_password
26
+ # gem 'bcrypt-ruby', '~> 3.0.0'
27
+
28
+ # To use Jbuilder templates for JSON
29
+ # gem 'jbuilder'
30
+
31
+ # Use unicorn as the app server
32
+ # gem 'unicorn'
33
+
34
+ # Deploy with Capistrano
35
+ # gem 'capistrano'
36
+
37
+ # To use debugger
38
+ # gem 'debugger'