bundler-audit 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +4 -0
  5. data/ChangeLog.md +23 -0
  6. data/Gemfile +12 -0
  7. data/README.md +51 -69
  8. data/Rakefile +31 -47
  9. data/bundler-audit.gemspec +7 -0
  10. data/data/ruby-advisory-db/.rspec +1 -0
  11. data/data/ruby-advisory-db/CONTRIBUTING.md +6 -0
  12. data/data/ruby-advisory-db/CONTRIBUTORS.md +13 -0
  13. data/data/ruby-advisory-db/Gemfile +3 -0
  14. data/data/ruby-advisory-db/LICENSE.txt +5 -0
  15. data/data/ruby-advisory-db/README.md +86 -0
  16. data/data/ruby-advisory-db/Rakefile +27 -0
  17. data/data/ruby-advisory-db/gems/actionpack/OSVDB-79727.yml +26 -0
  18. data/data/{bundler/audit/rails/2012-3424.yml → ruby-advisory-db/gems/actionpack/OSVDB-84243.yml} +17 -6
  19. data/data/ruby-advisory-db/gems/actionpack/OSVDB-84513.yml +23 -0
  20. data/data/ruby-advisory-db/gems/actionpack/OSVDB-84515.yml +26 -0
  21. data/data/{bundler/audit/rails/2013-0156.yml → ruby-advisory-db/gems/actionpack/OSVDB-89026.yml} +8 -3
  22. data/data/ruby-advisory-db/gems/actionpack/OSVDB-91452.yml +20 -0
  23. data/data/ruby-advisory-db/gems/actionpack/OSVDB-91454.yml +23 -0
  24. data/data/ruby-advisory-db/gems/activerecord/OSVDB-82403.yml +25 -0
  25. data/data/ruby-advisory-db/gems/activerecord/OSVDB-82610.yml +24 -0
  26. data/data/{bundler/audit/rails/2013-0155.yml → ruby-advisory-db/gems/activerecord/OSVDB-89025.yml} +9 -4
  27. data/data/{bundler/audit/rails/2013-0276.yml → ruby-advisory-db/gems/activerecord/OSVDB-90072.yml} +8 -3
  28. data/data/{bundler/audit/rails/2013-0277.yml → ruby-advisory-db/gems/activerecord/OSVDB-90073.yml} +8 -3
  29. data/data/ruby-advisory-db/gems/activerecord/OSVDB-91453.yml +26 -0
  30. data/data/ruby-advisory-db/gems/activesupport/OSVDB-79726.yml +26 -0
  31. data/data/ruby-advisory-db/gems/activesupport/OSVDB-84516.yml +23 -0
  32. data/data/{bundler/audit/rails/2013-0333.yml → ruby-advisory-db/gems/activesupport/OSVDB-89594.yml} +8 -3
  33. data/data/ruby-advisory-db/gems/activesupport/OSVDB-91451.yml +28 -0
  34. data/data/ruby-advisory-db/gems/command_wrap/OSVDB-91450.yml +10 -0
  35. data/data/ruby-advisory-db/gems/crack/OSVDB-90742.yml +17 -0
  36. data/data/ruby-advisory-db/gems/cremefraiche/OSVDB-93395.yml +11 -0
  37. data/data/ruby-advisory-db/gems/curl/OSVDB-91230.yml +12 -0
  38. data/data/ruby-advisory-db/gems/devise/OSVDB-89642.yml +20 -0
  39. data/data/ruby-advisory-db/gems/dragonfly/OSVDB-90647.yml +19 -0
  40. data/data/ruby-advisory-db/gems/enum_column3/OSVDB-94679.yml +9 -0
  41. data/data/ruby-advisory-db/gems/extlib/OSVDB-90740.yml +18 -0
  42. data/data/ruby-advisory-db/gems/fastreader/OSVDB-91232.yml +12 -0
  43. data/data/ruby-advisory-db/gems/fileutils/OSVDB-90715.yml +10 -0
  44. data/data/ruby-advisory-db/gems/fileutils/OSVDB-90716.yml +10 -0
  45. data/data/ruby-advisory-db/gems/fileutils/OSVDB-90717.yml +10 -0
  46. data/data/ruby-advisory-db/gems/flash_tool/OSVDB-90829.yml +9 -0
  47. data/data/ruby-advisory-db/gems/ftpd/OSVDB-90784.yml +18 -0
  48. data/data/ruby-advisory-db/gems/gtk2/OSVDB-40774.yml +20 -0
  49. data/data/ruby-advisory-db/gems/httparty/OSVDB-90741.yml +19 -0
  50. data/data/{bundler/audit/json/2013-0269.yml → ruby-advisory-db/gems/json/OSVDB-90074.yml} +8 -4
  51. data/data/ruby-advisory-db/gems/karteek-docsplit/OSVDB-92117.yml +10 -0
  52. data/data/ruby-advisory-db/gems/kelredd-pruview/OSVDB-92228.yml +10 -0
  53. data/data/ruby-advisory-db/gems/ldoce/OSVDB-91870.yml +10 -0
  54. data/data/ruby-advisory-db/gems/loofah/OSVDB-90945.yml +21 -0
  55. data/data/ruby-advisory-db/gems/mail/OSVDB-70667.yml +21 -0
  56. data/data/ruby-advisory-db/gems/mail/OSVDB-81631.yml +14 -0
  57. data/data/ruby-advisory-db/gems/mail/OSVDB-81632.yml +16 -0
  58. data/data/ruby-advisory-db/gems/md2pdf/OSVDB-92290.yml +10 -0
  59. data/data/ruby-advisory-db/gems/mini_magick/OSVDB-91231.yml +15 -0
  60. data/data/ruby-advisory-db/gems/multi_xml/OSVDB-89148.yml +16 -0
  61. data/data/ruby-advisory-db/gems/newrelic_rpm/OSVDB-90189.yml +17 -0
  62. data/data/ruby-advisory-db/gems/nori/OSVDB-90196.yml +19 -0
  63. data/data/ruby-advisory-db/gems/omniauth-oauth2/OSVDB-90264.yml +16 -0
  64. data/data/ruby-advisory-db/gems/pdfkit/OSVDB-90867.yml +11 -0
  65. data/data/{bundler/audit/rack/2013-0263.yml → ruby-advisory-db/gems/rack/OSVDB-89939.yml} +11 -8
  66. data/data/ruby-advisory-db/gems/rack-cache/OSVDB-83077.yml +18 -0
  67. data/data/ruby-advisory-db/gems/rdoc/OSVDB-90004.yml +27 -0
  68. data/data/ruby-advisory-db/gems/rgpg/OSVDB-95948.yml +13 -0
  69. data/data/ruby-advisory-db/gems/ruby_parser/OSVDB-90561.yml +11 -0
  70. data/data/ruby-advisory-db/gems/spree/OSVDB-91216.yml +10 -0
  71. data/data/ruby-advisory-db/gems/spree/OSVDB-91217.yml +10 -0
  72. data/data/ruby-advisory-db/gems/spree/OSVDB-91218.yml +10 -0
  73. data/data/ruby-advisory-db/gems/spree/OSVDB-91219.yml +10 -0
  74. data/data/ruby-advisory-db/gems/thumbshooter/OSVDB-91839.yml +10 -0
  75. data/data/ruby-advisory-db/lib/scrape.rb +87 -0
  76. data/data/ruby-advisory-db/spec/advisory_example.rb +165 -0
  77. data/data/ruby-advisory-db/spec/gems_spec.rb +8 -0
  78. data/data/ruby-advisory-db/spec/spec_helper.rb +1 -0
  79. data/gemspec.yml +4 -7
  80. data/lib/bundler/audit/advisory.rb +51 -9
  81. data/lib/bundler/audit/cli.rb +25 -10
  82. data/lib/bundler/audit/database.rb +1 -30
  83. data/lib/bundler/audit/scanner.rb +97 -0
  84. data/lib/bundler/audit/version.rb +1 -1
  85. data/spec/advisory_spec.rb +67 -7
  86. data/spec/bundle/insecure_sources/Gemfile +39 -0
  87. data/spec/bundle/secure/Gemfile +38 -0
  88. data/spec/database_spec.rb +1 -32
  89. data/spec/integration_spec.rb +132 -0
  90. data/spec/scanner_spec.rb +74 -0
  91. data/spec/spec_helper.rb +14 -1
  92. metadata +112 -119
  93. data/data/bundler/audit/mail/2011-0739.yml +0 -17
  94. data/data/bundler/audit/mail/2012-2139.yml +0 -16
  95. data/data/bundler/audit/mail/2012-2140.yml +0 -13
  96. data/data/bundler/audit/rack-cache/2012-267.yml +0 -14
  97. data/data/bundler/audit/rails/2012-1098.yml +0 -19
  98. data/data/bundler/audit/rails/2012-1099.yml +0 -19
  99. data/data/bundler/audit/rails/2012-2660.yml +0 -17
  100. data/data/bundler/audit/rails/2012-2661.yml +0 -18
  101. data/data/bundler/audit/rails/2012-3463.yml +0 -19
  102. data/data/bundler/audit/rails/2012-3464.yml +0 -18
  103. data/data/bundler/audit/rails/2012-3465.yml +0 -19
  104. data/spec/bundle/Gemfile.lock +0 -92
  105. /data/spec/bundle/{Gemfile → unpatched_gems/Gemfile} +0 -0
@@ -15,11 +15,11 @@
15
15
  # along with bundler-audit. If not, see <http://www.gnu.org/licenses/>.
16
16
  #
17
17
 
18
- require 'bundler/audit/database'
18
+ require 'bundler/audit/scanner'
19
19
  require 'bundler/audit/version'
20
20
 
21
- require 'bundler/vendored_thor'
22
21
  require 'bundler'
22
+ require 'bundler/vendored_thor'
23
23
 
24
24
  module Bundler
25
25
  module Audit
@@ -30,21 +30,26 @@ module Bundler
30
30
 
31
31
  desc 'check', 'Checks the Gemfile.lock for insecure dependencies'
32
32
  method_option :verbose, :type => :boolean, :aliases => '-v'
33
+ method_option :ignore, :type => :array, :aliases => '-i'
33
34
 
34
35
  def check
35
- environment = Bundler.load
36
- database = Database.new
37
- vulnerable = false
36
+ scanner = Scanner.new
37
+ vulnerable = false
38
38
 
39
- database.check_bundle(environment) do |gem,advisory|
39
+ scanner.scan(:ignore => options.ignore) do |result|
40
40
  vulnerable = true
41
41
 
42
- print_advisory gem, advisory
42
+ case result
43
+ when Scanner::InsecureSource
44
+ print_warning "Insecure Source URI found: #{result.source}"
45
+ when Scanner::UnpatchedGem
46
+ print_advisory result.gem, result.advisory
47
+ end
43
48
  end
44
49
 
45
50
  if vulnerable
46
51
  say "Unpatched versions found!", :red
47
- return -1
52
+ exit 1
48
53
  else
49
54
  say "No unpatched versions found", :green
50
55
  end
@@ -59,6 +64,15 @@ module Bundler
59
64
 
60
65
  protected
61
66
 
67
+ def say(string="", color=nil)
68
+ color = nil unless $stdout.tty?
69
+ super(string, color)
70
+ end
71
+
72
+ def print_warning(message)
73
+ say message, :yellow
74
+ end
75
+
62
76
  def print_advisory(gem, advisory)
63
77
  say "Name: ", :red
64
78
  say gem.name
@@ -66,14 +80,15 @@ module Bundler
66
80
  say "Version: ", :red
67
81
  say gem.version
68
82
 
69
- say "CVE: ", :red
70
- say advisory.cve
83
+ say "Advisory: ", :red
84
+ say advisory.id
71
85
 
72
86
  say "Criticality: ", :red
73
87
  case advisory.criticality
74
88
  when :low then say "Low"
75
89
  when :medium then say "Medium", :yellow
76
90
  when :high then say "High", [:red, :bold]
91
+ else say "Unknown"
77
92
  end
78
93
 
79
94
  say "URL: ", :red
@@ -28,7 +28,7 @@ module Bundler
28
28
  class Database
29
29
 
30
30
  # directory containing advisories
31
- PATH = File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','data','bundler','audit'))
31
+ PATH = File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','data','ruby-advisory-db','gems'))
32
32
 
33
33
  # The path to the advisory database
34
34
  attr_reader :path
@@ -119,35 +119,6 @@ module Bundler
119
119
  end
120
120
  end
121
121
 
122
- #
123
- # Verifies whether the bundled gems are effected by any advisories.
124
- #
125
- # @param [Bundle::Environment] environment
126
- # The bundled gems.
127
- #
128
- # @yield [gem, advisory]
129
- # If a block is given, each advisory that effects a gem within the
130
- # bundle will be passed.
131
- #
132
- # @yieldparam [Gem::Specification] gem
133
- # The gem effected by the advisory.
134
- #
135
- # @yieldparam [Advisory] advisory
136
- # An advisory that effects a gem within the bundle.
137
- #
138
- # @return [Enumerator]
139
- # If no block is given, an Enumerator will be returned.
140
- #
141
- def check_bundle(environment)
142
- return enum_for(__method__,environment) unless block_given?
143
-
144
- environment.gems.each do |gem|
145
- check_gem(gem) do |advisory|
146
- yield gem, advisory
147
- end
148
- end
149
- end
150
-
151
122
  #
152
123
  # The number of advisories within the database.
153
124
  #
@@ -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?(advisory.id)
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
@@ -18,6 +18,6 @@
18
18
  module Bundler
19
19
  module Audit
20
20
  # bundler-audit version
21
- VERSION = "0.1.1"
21
+ VERSION = '0.2.0'
22
22
  end
23
23
  end
@@ -4,16 +4,16 @@ require 'bundler/audit/advisory'
4
4
 
5
5
  describe Bundler::Audit::Advisory do
6
6
  let(:root) { Bundler::Audit::Database::PATH }
7
- let(:gem) { 'rails' }
8
- let(:cve) { '2013-0156' }
9
- let(:path) { File.join(root,gem,"#{cve}.yml") }
7
+ let(:gem) { 'actionpack' }
8
+ let(:id) { 'OSVDB-84243' }
9
+ let(:path) { File.join(root,gem,"#{id}.yml") }
10
10
 
11
11
  describe "load" do
12
12
  let(:data) { YAML.load_file(path) }
13
13
 
14
14
  subject { described_class.load(path) }
15
15
 
16
- its(:cve) { should == cve }
16
+ its(:id) { should == id }
17
17
  its(:url) { should == data['url'] }
18
18
  its(:title) { should == data['title'] }
19
19
  its(:cvss_v2) { should == data['cvss_v2'] }
@@ -54,10 +54,50 @@ describe Bundler::Audit::Advisory do
54
54
  end
55
55
  end
56
56
 
57
+ describe "#unaffected?" do
58
+ subject { described_class.load(path) }
59
+
60
+ context "when passed a version that matches one unaffected version" do
61
+ let(:version) { Gem::Version.new('2.3.10') }
62
+
63
+ it "should return true" do
64
+ subject.unaffected?(version).should be_true
65
+ end
66
+ end
67
+
68
+ context "when passed a version that matches no unaffected version" do
69
+ let(:version) { Gem::Version.new('3.0.9') }
70
+
71
+ it "should return false" do
72
+ subject.unaffected?(version).should be_false
73
+ end
74
+ end
75
+ end
76
+
77
+ describe "#patched?" do
78
+ subject { described_class.load(path) }
79
+
80
+ context "when passed a version that matches one patched version" do
81
+ let(:version) { Gem::Version.new('3.1.11') }
82
+
83
+ it "should return true" do
84
+ subject.patched?(version).should be_true
85
+ end
86
+ end
87
+
88
+ context "when passed a version that matches no patched version" do
89
+ let(:version) { Gem::Version.new('2.9.0') }
90
+
91
+ it "should return false" do
92
+ subject.patched?(version).should be_false
93
+ end
94
+ end
95
+ end
96
+
57
97
  describe "#vulnerable?" do
58
98
  subject { described_class.load(path) }
59
99
 
60
- context "when passed a version that matches one patched_version" do
100
+ context "when passed a version that matches one patched version" do
61
101
  let(:version) { Gem::Version.new('3.1.11') }
62
102
 
63
103
  it "should return false" do
@@ -65,12 +105,32 @@ describe Bundler::Audit::Advisory do
65
105
  end
66
106
  end
67
107
 
68
- context "when passed a version that matches no patched_version" do
69
- let(:version) { Gem::Version.new('3.1.9') }
108
+ context "when passed a version that matches no patched version" do
109
+ let(:version) { Gem::Version.new('2.9.0') }
70
110
 
71
111
  it "should return true" do
72
112
  subject.vulnerable?(version).should be_true
73
113
  end
114
+
115
+ context "when unaffected_versions is not empty" do
116
+ subject { described_class.load(path) }
117
+
118
+ context "when passed a version that matches one unaffected version" do
119
+ let(:version) { Gem::Version.new('2.3.12') }
120
+
121
+ it "should return false" do
122
+ subject.vulnerable?(version).should be_false
123
+ end
124
+ end
125
+
126
+ context "when passed a version that matches no unaffected version" do
127
+ let(:version) { Gem::Version.new('1.2.3') }
128
+
129
+ it "should return true" do
130
+ subject.vulnerable?(version).should be_true
131
+ end
132
+ end
133
+ end
74
134
  end
75
135
  end
76
136
  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.14'
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'
@@ -1,7 +1,5 @@
1
1
  require 'spec_helper'
2
2
  require 'bundler/audit/database'
3
-
4
- require 'bundler'
5
3
  require 'tmpdir'
6
4
 
7
5
  describe Bundler::Audit::Database do
@@ -44,7 +42,7 @@ describe Bundler::Audit::Database do
44
42
  describe "#check_gem" do
45
43
  let(:gem) do
46
44
  Gem::Specification.new do |s|
47
- s.name = 'rails'
45
+ s.name = 'actionpack'
48
46
  s.version = '3.1.9'
49
47
  end
50
48
  end
@@ -71,35 +69,6 @@ describe Bundler::Audit::Database do
71
69
  end
72
70
  end
73
71
 
74
- describe "#check_bundle" do
75
- let(:path) { File.join(File.dirname(__FILE__),'bundle') }
76
- let(:bundle) do
77
- Dir.chdir(path) { Bundler.load }
78
- end
79
-
80
- context "when given a block" do
81
- it "should yield every advisory effecting the bundle" do
82
- advisories = []
83
-
84
- subject.check_bundle(bundle) do |gem,advisory|
85
- advisories << [gem, advisory]
86
- end
87
-
88
- advisories.should_not be_empty
89
- advisories.all? { |gem,advisory|
90
- gem.kind_of?(Gem::Specification) &&
91
- advisory.kind_of?(Bundler::Audit::Advisory)
92
- }.should be_true
93
- end
94
- end
95
-
96
- context "when given no block" do
97
- it "should return an Enumerator" do
98
- subject.check_bundle(bundle).should be_kind_of(Enumerable)
99
- end
100
- end
101
- end
102
-
103
72
  describe "#size" do
104
73
  it { subject.size.should > 0 }
105
74
  end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+
3
+ describe "CLI" do
4
+ include Helpers
5
+
6
+ let(:command) do
7
+ File.expand_path(File.join(File.dirname(__FILE__),'..','bin','bundle-audit'))
8
+ end
9
+
10
+ context "when auditing a bundle with unpatched gems" do
11
+ let(:bundle) { 'unpatched_gems' }
12
+ let(:directory) { File.join('spec','bundle',bundle) }
13
+
14
+ subject do
15
+ Dir.chdir(directory) { sh(command, :fail => true) }
16
+ end
17
+
18
+ it "should print a warning" do
19
+ subject.should include("Unpatched versions found!")
20
+ end
21
+
22
+ it "should print advisory information for the vulnerable gems" do
23
+ expect = %{
24
+ Name: actionpack
25
+ Version: 3.2.10
26
+ Advisory: OSVDB-91452
27
+ Criticality: Medium
28
+ URL: http://www.osvdb.org/show/osvdb/91452
29
+ Title: XSS vulnerability in sanitize_css in Action Pack
30
+ Solution: upgrade to ~> 2.3.18, ~> 3.1.12, >= 3.2.13
31
+
32
+ Name: actionpack
33
+ Version: 3.2.10
34
+ Advisory: OSVDB-91454
35
+ Criticality: Medium
36
+ URL: http://osvdb.org/show/osvdb/91454
37
+ Title: XSS Vulnerability in the `sanitize` helper of Ruby on Rails
38
+ Solution: upgrade to ~> 2.3.18, ~> 3.1.12, >= 3.2.13
39
+
40
+ Name: actionpack
41
+ Version: 3.2.10
42
+ Advisory: OSVDB-89026
43
+ Criticality: High
44
+ URL: http://osvdb.org/show/osvdb/89026
45
+ Title: Ruby on Rails params_parser.rb Action Pack Type Casting Parameter Parsing Remote Code Execution
46
+ Solution: upgrade to ~> 2.3.15, ~> 3.0.19, ~> 3.1.10, >= 3.2.11
47
+
48
+ Name: activerecord
49
+ Version: 3.2.10
50
+ Advisory: OSVDB-91453
51
+ Criticality: High
52
+ URL: http://osvdb.org/show/osvdb/91453
53
+ Title: Symbol DoS vulnerability in Active Record
54
+ Solution: upgrade to ~> 2.3.18, ~> 3.1.12, >= 3.2.13
55
+
56
+ Name: activerecord
57
+ Version: 3.2.10
58
+ Advisory: OSVDB-90072
59
+ Criticality: Medium
60
+ URL: http://direct.osvdb.org/show/osvdb/90072
61
+ Title: Ruby on Rails Active Record attr_protected Method Bypass
62
+ Solution: upgrade to ~> 2.3.17, ~> 3.1.11, >= 3.2.12
63
+
64
+ Name: activerecord
65
+ Version: 3.2.10
66
+ Advisory: OSVDB-89025
67
+ Criticality: High
68
+ URL: http://osvdb.org/show/osvdb/89025
69
+ Title: Ruby on Rails Active Record JSON Parameter Parsing Query Bypass
70
+ Solution: upgrade to ~> 2.3.16, ~> 3.0.19, ~> 3.1.10, >= 3.2.11
71
+
72
+ Name: activesupport
73
+ Version: 3.2.10
74
+ Advisory: OSVDB-91451
75
+ Criticality: High
76
+ URL: http://www.osvdb.org/show/osvdb/91451
77
+ Title: XML Parsing Vulnerability affecting JRuby users
78
+ Solution: upgrade to ~> 3.1.12, >= 3.2.13
79
+
80
+ Unpatched versions found!
81
+ }.strip.split "\n\n"
82
+
83
+ subject.strip.split("\n\n").should =~ expect
84
+ end
85
+ end
86
+
87
+ context "when auditing a bundle with ignored gems" do
88
+ let(:bundle) { 'unpatched_gems' }
89
+ let(:directory) { File.join('spec','bundle',bundle) }
90
+
91
+ let(:command) do
92
+ File.expand_path(File.join(File.dirname(__FILE__),'..','bin','bundle-audit -i OSVDB-89026'))
93
+ end
94
+
95
+ subject do
96
+ Dir.chdir(directory) { sh(command, :fail => true) }
97
+ end
98
+
99
+ it "should not print advisory information for ignored gem" do
100
+ subject.should_not include("OSVDB-89026")
101
+ end
102
+ end
103
+
104
+ context "when auditing a bundle with insecure sources" do
105
+ let(:bundle) { 'insecure_sources' }
106
+ let(:directory) { File.join('spec','bundle',bundle) }
107
+
108
+ subject do
109
+ Dir.chdir(directory) { sh(command, :fail => true) }
110
+ end
111
+
112
+ it "should print warnings about insecure sources" do
113
+ subject.should include(%{
114
+ Insecure Source URI found: git://github.com/rails/jquery-rails.git
115
+ Insecure Source URI found: http://rubygems.org/
116
+ }.strip)
117
+ end
118
+ end
119
+
120
+ context "when auditing a secure bundle" do
121
+ let(:bundle) { 'secure' }
122
+ let(:directory) { File.join('spec','bundle',bundle) }
123
+
124
+ subject do
125
+ Dir.chdir(directory) { sh(command) }
126
+ end
127
+
128
+ it "should print nothing when everything is fine" do
129
+ subject.strip.should == "No unpatched versions found"
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require 'bundler/audit/scanner'
3
+
4
+ describe Scanner do
5
+ describe "#scan" do
6
+ let(:bundle) { 'unpatched_gems' }
7
+ let(:directory) { File.join('spec','bundle',bundle) }
8
+
9
+ subject { described_class.new(directory) }
10
+
11
+ it "should yield results" do
12
+ results = []
13
+
14
+ subject.scan { |result| results << result }
15
+
16
+ results.should_not be_empty
17
+ end
18
+
19
+ context "when not called with a block" do
20
+ it "should return an Enumerator" do
21
+ subject.scan.should be_kind_of(Enumerable)
22
+ end
23
+ end
24
+ end
25
+
26
+ context "when auditing a bundle with unpatched gems" do
27
+ let(:bundle) { 'unpatched_gems' }
28
+ let(:directory) { File.join('spec','bundle',bundle) }
29
+ let(:scanner) { described_class.new(directory) }
30
+
31
+ subject { scanner.scan.to_a }
32
+
33
+ it "should match unpatched gems to their advisories" do
34
+ subject.all? { |result|
35
+ result.advisory.vulnerable?(result.gem.version)
36
+ }.should be_true
37
+ end
38
+
39
+ context "when the :ignore option is given" do
40
+ subject { scanner.scan(:ignore => ['OSVDB-89026']) }
41
+
42
+ it "should ignore the specified advisories" do
43
+ ids = subject.map { |result| result.advisory.id }
44
+
45
+ ids.should_not include('OSVDB-89026')
46
+ end
47
+ end
48
+ end
49
+
50
+ context "when auditing a bundle with insecure sources" do
51
+ let(:bundle) { 'insecure_sources' }
52
+ let(:directory) { File.join('spec','bundle',bundle) }
53
+ let(:scanner) { described_class.new(directory) }
54
+
55
+ subject { scanner.scan.to_a }
56
+
57
+ it "should match unpatched gems to their advisories" do
58
+ subject[0].source.should == 'git://github.com/rails/jquery-rails.git'
59
+ subject[1].source.should == 'http://rubygems.org/'
60
+ end
61
+ end
62
+
63
+ context "when auditing a secure bundle" do
64
+ let(:bundle) { 'secure' }
65
+ let(:directory) { File.join('spec','bundle',bundle) }
66
+ let(:scanner) { described_class.new(directory) }
67
+
68
+ subject { scanner.scan.to_a }
69
+
70
+ it "should print nothing when everything is fine" do
71
+ subject.should be_empty
72
+ end
73
+ end
74
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,18 @@
1
- gem 'rspec', '~> 2.4'
2
1
  require 'rspec'
3
2
  require 'bundler/audit/version'
4
3
 
4
+ module Helpers
5
+ def sh(command, options={})
6
+ Bundler.with_clean_env do
7
+ result = `#{command} 2>&1`
8
+ raise "FAILED #{command}\n#{result}" if $?.success? == !!options[:fail]
9
+ result
10
+ end
11
+ end
12
+
13
+ def decolorize(string)
14
+ string.gsub(/\e\[\d+m/, "")
15
+ end
16
+ end
17
+
5
18
  include Bundler::Audit