bundler-audit 0.3.0 → 0.4.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.travis.yml +5 -2
  4. data/ChangeLog.md +25 -0
  5. data/Gemfile +2 -1
  6. data/README.md +12 -1
  7. data/Rakefile +11 -13
  8. data/data/ruby-advisory-db/CONTRIBUTORS.md +9 -0
  9. data/data/ruby-advisory-db/gems/actionpack/OSVDB-100524.yml +20 -0
  10. data/data/ruby-advisory-db/gems/actionpack/OSVDB-100525.yml +21 -0
  11. data/data/ruby-advisory-db/gems/actionpack/OSVDB-100526.yml +27 -0
  12. data/data/ruby-advisory-db/gems/actionpack/OSVDB-100527.yml +24 -0
  13. data/data/ruby-advisory-db/gems/actionpack/OSVDB-100528.yml +22 -0
  14. data/data/ruby-advisory-db/gems/actionpack/OSVDB-103439.yml +24 -0
  15. data/data/ruby-advisory-db/gems/actionpack/OSVDB-103440.yml +22 -0
  16. data/data/ruby-advisory-db/gems/activerecord/OSVDB-103438.yml +23 -0
  17. data/data/ruby-advisory-db/gems/arabic-prawn/OSVDB-104365.yml +15 -0
  18. data/data/ruby-advisory-db/gems/cocaine/OSVDB-98835.yml +2 -2
  19. data/data/ruby-advisory-db/gems/crack/OSVDB-90742.yml +1 -1
  20. data/data/ruby-advisory-db/gems/curl/OSVDB-91230.yml +1 -1
  21. data/data/ruby-advisory-db/gems/echor/OSVDB-102129.yml +11 -0
  22. data/data/ruby-advisory-db/gems/echor/OSVDB-102130.yml +10 -0
  23. data/data/ruby-advisory-db/gems/gitlab-grit/OSVDB-99370.yml +14 -0
  24. data/data/ruby-advisory-db/gems/httparty/OSVDB-90741.yml +3 -8
  25. data/data/ruby-advisory-db/gems/i18n/OSVDB-100528.yml +17 -0
  26. data/data/ruby-advisory-db/gems/nokogiri/OSVDB-101179.yml +12 -0
  27. data/data/ruby-advisory-db/gems/nokogiri/OSVDB-101458.yml +15 -0
  28. data/data/ruby-advisory-db/gems/nori/OSVDB-90196.yml +1 -1
  29. data/data/ruby-advisory-db/gems/omniauth-facebook/OSVDB-99693.yml +22 -0
  30. data/data/ruby-advisory-db/gems/omniauth-facebook/OSVDB-99888.yml +17 -0
  31. data/data/ruby-advisory-db/gems/paperclip/OSVDB-103151.yml +13 -0
  32. data/data/ruby-advisory-db/gems/paratrooper-newrelic/OSVDB-101839.yml +12 -0
  33. data/data/ruby-advisory-db/gems/paratrooper-pingdom/OSVDB-101847.yml +13 -0
  34. data/data/ruby-advisory-db/gems/rack/OSVDB-89939.yml +1 -1
  35. data/data/ruby-advisory-db/gems/rbovirt/OSVDB-104080.yml +20 -0
  36. data/data/ruby-advisory-db/gems/rgpg/OSVDB-95948.yml +2 -1
  37. data/data/ruby-advisory-db/gems/sfpagent/OSVDB-105971.yml +13 -0
  38. data/data/ruby-advisory-db/gems/spree/OSVDB-91216.yml +3 -2
  39. data/data/ruby-advisory-db/gems/spree/OSVDB-91217.yml +3 -2
  40. data/data/ruby-advisory-db/gems/spree/OSVDB-91218.yml +3 -2
  41. data/data/ruby-advisory-db/gems/spree/OSVDB-91219.yml +3 -2
  42. data/data/ruby-advisory-db/gems/sprout/OSVDB-100598.yml +14 -0
  43. data/data/ruby-advisory-db/gems/webbynode/OSVDB-100920.yml +11 -0
  44. data/data/ruby-advisory-db/gems/will_paginate/OSVDB-101138.yml +15 -0
  45. data/data/ruby-advisory-db/spec/advisory_example.rb +3 -3
  46. data/data/ruby-advisory-db/spec/gems_spec.rb +3 -4
  47. data/data/ruby-advisory-db.ts +1 -0
  48. data/gemspec.yml +2 -0
  49. data/lib/bundler/audit/advisory.rb +5 -1
  50. data/lib/bundler/audit/cli.rb +13 -7
  51. data/lib/bundler/audit/database.rb +7 -4
  52. data/lib/bundler/audit/scanner.rb +101 -3
  53. data/lib/bundler/audit/version.rb +2 -2
  54. data/lib/bundler/audit.rb +1 -1
  55. data/spec/advisory_spec.rb +78 -27
  56. data/spec/audit_spec.rb +1 -1
  57. data/spec/bundle/insecure_sources/Gemfile +1 -1
  58. data/spec/bundle/secure/Gemfile +2 -2
  59. data/spec/bundle/unpatched_gems/Gemfile +1 -1
  60. data/spec/database_spec.rb +68 -11
  61. data/spec/fixtures/not_a_hash.yml +2 -0
  62. data/spec/integration_spec.rb +14 -73
  63. data/spec/scanner_spec.rb +8 -8
  64. data/spec/spec_helper.rb +43 -0
  65. metadata +71 -30
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  gem: rgpg
3
3
  osvdb: 95948
4
+ cve: 2013-4203
4
5
  url: http://www.osvdb.org/show/osvdb/95948
5
6
  title: Ruby rgpg Gem Shell Command Injection Vulnerabilities
6
7
  date: 2013-08-02
@@ -8,6 +9,6 @@ description: |
8
9
  rgpg Gem for Ruby contains a flaw in the GpgHelper module (lib/rgpg/gpg_helper.rb).
9
10
  The issue is due to the program failing to properly sanitize user-supplied input before being used in the system() function for execution.
10
11
  This may allow a remote attacker to execute arbitrary commands.
11
- cvss_v2:
12
+ cvss_v2: 7.5
12
13
  patched_versions:
13
14
  - ">= 0.2.3"
@@ -0,0 +1,13 @@
1
+ ---
2
+ gem: sfpagent
3
+ cve:
4
+ osvdb: 105971
5
+ url: http://www.osvdb.org/show/osvdb/105971
6
+ title: sfpagent Gem for Ruby Remote Command Injection
7
+ date: 2014-04-16
8
+ description: sfpagent Gem for Ruby contains a flaw that is triggered as JSON[body]
9
+ input is not properly sanitized when handling module names with shell metacharacters.
10
+ This may allow a context-dependent attacker to execute arbitrary commands.
11
+ cvss_v2:
12
+ patched_versions:
13
+ - ">= 0.4.15"
@@ -1,4 +1,4 @@
1
- ---
1
+ ---
2
2
  gem: spree
3
3
  cve: 2013-1656
4
4
  osvdb: 91216
@@ -7,4 +7,5 @@ title: Spree promotion_actions_controller.rb promotion_action Parameter Arbitrar
7
7
  date: 2013-02-21
8
8
  description: Spree contains a flaw that is triggered when handling input passed via the 'promotion_action' parameter to promotion_actions_controller.rb. This may allow a remote authenticated attacker to instantiate arbitrary Ruby objects and potentially execute arbitrary commands.
9
9
  cvss_v2: 4.3
10
- patched_versions:
10
+ patched_versions:
11
+ - ">= 2.0.0"
@@ -1,4 +1,4 @@
1
- ---
1
+ ---
2
2
  gem: spree
3
3
  cve: 2013-1656
4
4
  osvdb: 91217
@@ -7,4 +7,5 @@ title: Spree payment_methods_controller.rb payment_method Parameter Arbitrary Ru
7
7
  date: 2013-02-21
8
8
  description: Spree contains a flaw that is triggered when handling input passed via the 'payment_method' parameter to payment_methods_controller.rb. This may allow a remote authenticated attacker to instantiate arbitrary Ruby objects and potentially execute arbitrary commands.
9
9
  cvss_v2: 4.3
10
- patched_versions:
10
+ patched_versions:
11
+ - ">= 2.0.0"
@@ -1,4 +1,4 @@
1
- ---
1
+ ---
2
2
  gem: spree
3
3
  cve: 2013-1656
4
4
  osvdb: 91218
@@ -7,4 +7,5 @@ title: Spree promotions_controller.rb calculator_type Parameter Arbitrary Ruby O
7
7
  date: 2013-02-21
8
8
  description: Spree contains a flaw that is triggered when handling input passed via the 'calculator_type' parameter to promotions_controller.rb. This may allow a remote authenticated attacker to instantiate arbitrary Ruby objects and potentially execute arbitrary commands.
9
9
  cvss_v2: 4.3
10
- patched_versions:
10
+ patched_versions:
11
+ - ">= 2.0.0"
@@ -1,4 +1,4 @@
1
- ---
1
+ ---
2
2
  gem: spree
3
3
  cve: 2013-1656
4
4
  osvdb: 91219
@@ -7,4 +7,5 @@ title: Spree promotion_rules_controller.rb promotion_rule Parameter Arbitrary Ru
7
7
  date: 2013-02-21
8
8
  description: Spree contains a flaw that is triggered when handling input passed via the 'promotion_rule' parameter to promotion_rules_controller.rb. This may allow a remote authenticated attacker to instantiate arbitrary Ruby objects and potentially execute arbitrary commands.
9
9
  cvss_v2: 4.3
10
- patched_versions:
10
+ patched_versions:
11
+ - ">= 2.0.0"
@@ -0,0 +1,14 @@
1
+ ---
2
+ gem: sprout
3
+ cve: 2013-6421
4
+ osvdb: 100598
5
+ url: http://www.osvdb.org/show/osvdb/100598
6
+ title: Sprout Gem for Ruby contains a flaw
7
+ date: 2013-12-02
8
+ description: sprout Gem for Ruby contains a flaw in the unpack_zip() function in archive_unpacker.rb.
9
+ The issue is due to the program failing to properly sanitize input passed via the 'zip_file', 'dir',
10
+ 'zip_name', and 'output' parameters. This may allow a context-dependent attacker to execute arbitrary code.
11
+ cvss_v2: 7.5
12
+ patched_versions:
13
+ unaffected_versions:
14
+ - '< 0.7.246'
@@ -0,0 +1,11 @@
1
+ ---
2
+ gem: webbynode
3
+ osvdb: 100920
4
+ url: http://osvdb.org/show/osvdb/100920
5
+ title: Webbynode Gem for Ruby contains a flaw
6
+ date: 2013-12-12
7
+ description: Webbynode Gem for Ruby contains a flaw in notify.rb that is triggered
8
+ when handling a specially crafted growlnotify message. This may allow a
9
+ context-dependent attacker to execute arbitrary commands.
10
+ cvss_v2: 7.5
11
+ patched_versions:
@@ -0,0 +1,15 @@
1
+ ---
2
+ gem: will_paginate
3
+ osvdb: 101138
4
+ cve: 2013-6459
5
+ url: http://osvdb.org/show/osvdb/101138
6
+ title: will_paginate Gem for Ruby Generated Pagination Link Unspecified XSS
7
+ date: 2013-09-19
8
+ description: will_paginate Gem for Ruby contains a flaw that allows a cross-site scripting (XSS) attack.
9
+ This flaw exists because the application does not validate certain unspecified input related to
10
+ generated pagination links before returning it to the user. This may allow an attacker to create
11
+ a specially crafted request that would execute arbitrary script code in a users browser within the
12
+ trust relationship between their browser and the server.
13
+ cvss_v2: 4.3
14
+ patched_versions:
15
+ - ">= 3.0.5"
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ load File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
2
  require 'yaml'
3
3
 
4
4
  shared_examples_for 'Advisory' do |path|
@@ -131,7 +131,7 @@ shared_examples_for 'Advisory' do |path|
131
131
  it "should contain valid RubyGem version requirements" do
132
132
  lambda {
133
133
  Gem::Requirement.new(*subject)
134
- }.should_not raise_error(ArgumentError)
134
+ }.should_not raise_error
135
135
  end
136
136
  end
137
137
  end
@@ -155,7 +155,7 @@ shared_examples_for 'Advisory' do |path|
155
155
  it "should contain valid RubyGem version requirements" do
156
156
  lambda {
157
157
  Gem::Requirement.new(*subject)
158
- }.should_not raise_error(ArgumentError)
158
+ }.should_not raise_error
159
159
  end
160
160
  end
161
161
  end
@@ -1,8 +1,7 @@
1
- require 'spec_helper'
2
- require 'advisory_example'
3
-
1
+ load File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+ load File.join(File.dirname(__FILE__), 'advisory_example.rb')
4
3
  describe "gems" do
5
- Dir.glob('gems/*/*.yml') do |path|
4
+ Dir.glob(File.join(File.dirname(__FILE__), '../gems/*/*.yml')) do |path|
6
5
  include_examples 'Advisory', path
7
6
  end
8
7
  end
@@ -0,0 +1 @@
1
+ 2014-02-11 00:45:58 UTC
data/gemspec.yml CHANGED
@@ -6,7 +6,9 @@ authors: Postmodern
6
6
  email: postmodern.mod3@gmail.com
7
7
  homepage: https://github.com/rubysec/bundler-audit#readme
8
8
 
9
+ required_ruby_version: ">= 1.9.3"
9
10
  required_rubygems_version: ">= 1.8.0"
10
11
 
11
12
  dependencies:
13
+ thor: ~> 0.18
12
14
  bundler: ~> 1.2
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
2
+ # Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
3
3
  #
4
4
  # bundler-audit is free software: you can redistribute it and/or modify
5
5
  # it under the terms of the GNU General Public License as published by
@@ -25,6 +25,8 @@ module Bundler
25
25
  :title,
26
26
  :description,
27
27
  :cvss_v2,
28
+ :cve,
29
+ :osvdb,
28
30
  :unaffected_versions,
29
31
  :patched_versions)
30
32
 
@@ -59,6 +61,8 @@ module Bundler
59
61
  data['title'],
60
62
  data['description'],
61
63
  data['cvss_v2'],
64
+ data['cve'],
65
+ data['osvdb'],
62
66
  parse_versions[data['unaffected_versions']],
63
67
  parse_versions[data['patched_versions']]
64
68
  )
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
2
+ # Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
3
3
  #
4
4
  # bundler-audit is free software: you can redistribute it and/or modify
5
5
  # it under the terms of the GNU General Public License as published by
@@ -18,12 +18,13 @@
18
18
  require 'bundler/audit/scanner'
19
19
  require 'bundler/audit/version'
20
20
 
21
+ require 'thor'
21
22
  require 'bundler'
22
23
  require 'bundler/vendored_thor'
23
24
 
24
25
  module Bundler
25
26
  module Audit
26
- class CLI < Thor
27
+ class CLI < ::Thor
27
28
 
28
29
  default_task :check
29
30
  map '--version' => :version
@@ -48,10 +49,10 @@ module Bundler
48
49
  end
49
50
 
50
51
  if vulnerable
51
- say "Unpatched versions found!", :red
52
+ say "Vulnerabilities found!", :red
52
53
  exit 1
53
54
  else
54
- say "No unpatched versions found", :green
55
+ say "No vulnerabilities found", :green
55
56
  end
56
57
  end
57
58
 
@@ -72,9 +73,9 @@ module Bundler
72
73
 
73
74
  protected
74
75
 
75
- def say(string="", color=nil)
76
+ def say(message="", color=nil)
76
77
  color = nil unless $stdout.tty?
77
- super(string, color)
78
+ super(message.to_s, color)
78
79
  end
79
80
 
80
81
  def print_warning(message)
@@ -89,7 +90,12 @@ module Bundler
89
90
  say gem.version
90
91
 
91
92
  say "Advisory: ", :red
92
- say advisory.id
93
+
94
+ if advisory.cve
95
+ say "CVE-#{advisory.cve}"
96
+ elsif advisory.osvdb
97
+ say advisory.osvdb
98
+ end
93
99
 
94
100
  say "Criticality: ", :red
95
101
  case advisory.criticality
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
2
+ # Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
3
3
  #
4
4
  # bundler-audit is free software: you can redistribute it and/or modify
5
5
  # it under the terms of the GNU General Public License as published by
@@ -34,8 +34,11 @@ module Bundler
34
34
  # Default path to the ruby-advisory-db
35
35
  VENDORED_PATH = File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','data','ruby-advisory-db'))
36
36
 
37
+ # Timestamp for when the database was last updated
38
+ VENDORED_TIMESTAMP = Time.parse(File.read("#{VENDORED_PATH}.ts")).utc
39
+
37
40
  # Path to the user's copy of the ruby-advisory-db
38
- USER_PATH = File.join(Gem.user_home,'.local','share','ruby-advisory-db')
41
+ USER_PATH = File.expand_path(File.join(ENV['HOME'],'.local','share','ruby-advisory-db'))
39
42
 
40
43
  # The path to the advisory database
41
44
  attr_reader :path
@@ -65,8 +68,8 @@ module Bundler
65
68
  #
66
69
  def self.path
67
70
  if File.directory?(USER_PATH)
68
- t1 = Dir.chdir(USER_PATH) { Time.parse(`git log --pretty="%cd" -1`) }
69
- t2 = File.ctime(VENDORED_PATH)
71
+ t1 = Dir.chdir(USER_PATH) { Time.parse(`git log --date=iso8601 --pretty="%cd" -1`) }
72
+ t2 = VENDORED_TIMESTAMP
70
73
 
71
74
  if t1 >= t2 then USER_PATH
72
75
  else VENDORED_PATH
@@ -2,7 +2,10 @@ require 'bundler'
2
2
  require 'bundler/audit/database'
3
3
  require 'bundler/lockfile_parser'
4
4
 
5
+ require 'ipaddr'
6
+ require 'resolv'
5
7
  require 'set'
8
+ require 'uri'
6
9
 
7
10
  module Bundler
8
11
  module Audit
@@ -59,17 +62,46 @@ module Bundler
59
62
  # @return [Enumerator]
60
63
  # If no block is given, an Enumerator will be returned.
61
64
  #
62
- def scan(options={})
63
- return enum_for(__method__,options) unless block_given?
65
+ def scan(options={},&block)
66
+ return enum_for(__method__,options) unless block
64
67
 
65
68
  ignore = Set[]
66
69
  ignore += options[:ignore] if options[:ignore]
67
70
 
71
+ scan_sources(options,&block)
72
+ scan_specs(options,&block)
73
+
74
+ return self
75
+ end
76
+
77
+ #
78
+ # Scans the gem sources in the lockfile.
79
+ #
80
+ # @param [Hash] options
81
+ # Additional options.
82
+ #
83
+ # @yield [result]
84
+ # The given block will be passed the results of the scan.
85
+ #
86
+ # @yieldparam [InsecureSource] result
87
+ # A result from the scan.
88
+ #
89
+ # @return [Enumerator]
90
+ # If no block is given, an Enumerator will be returned.
91
+ #
92
+ # @api semipublic
93
+ #
94
+ # @since 0.4.0
95
+ #
96
+ def scan_sources(options={})
97
+ return enum_for(__method__,options) unless block_given?
98
+
68
99
  @lockfile.sources.map do |source|
69
100
  case source
70
101
  when Source::Git
71
102
  case source.uri
72
103
  when /^git:/, /^http:/
104
+ next if internal_host?(source.uri)
73
105
  yield InsecureSource.new(source.uri)
74
106
  end
75
107
  when Source::Rubygems
@@ -80,6 +112,35 @@ module Bundler
80
112
  end
81
113
  end
82
114
  end
115
+ end
116
+
117
+ #
118
+ # Scans the gem sources in the lockfile.
119
+ #
120
+ # @param [Hash] options
121
+ # Additional options.
122
+ #
123
+ # @option options [Array<String>] :ignore
124
+ # The advisories to ignore.
125
+ #
126
+ # @yield [result]
127
+ # The given block will be passed the results of the scan.
128
+ #
129
+ # @yieldparam [UnpatchedGem] result
130
+ # A result from the scan.
131
+ #
132
+ # @return [Enumerator]
133
+ # If no block is given, an Enumerator will be returned.
134
+ #
135
+ # @api semipublic
136
+ #
137
+ # @since 0.4.0
138
+ #
139
+ def scan_specs(options={})
140
+ return enum_for(__method__,options) unless block_given?
141
+
142
+ ignore = Set[]
143
+ ignore += options[:ignore] if options[:ignore]
83
144
 
84
145
  @lockfile.specs.each do |gem|
85
146
  @database.check_gem(gem) do |advisory|
@@ -88,10 +149,47 @@ module Bundler
88
149
  end
89
150
  end
90
151
  end
152
+ end
91
153
 
92
- return self
154
+ private
155
+
156
+ #
157
+ # Determines whether a URI is internal.
158
+ #
159
+ # @param [String] uri
160
+ # The source URI.
161
+ #
162
+ # @return [Boolean]
163
+ #
164
+ def internal_host?(uri)
165
+ return unless host = URI.parse(uri).host
166
+ Resolv.getaddresses(host).all? { |ip| internal_ip?(ip) }
167
+ rescue URI::Error
168
+ false
93
169
  end
94
170
 
171
+ # List of internal IP address ranges.
172
+ #
173
+ # @see https://tools.ietf.org/html/rfc1918#section-3
174
+ # @see https://tools.ietf.org/html/rfc4193#section-8
175
+ INTERNAL_SUBNETS = %w[
176
+ 10.0.0.0/8
177
+ 172.16.0.0/12
178
+ 192.168.0.0/16
179
+ fc00::/7
180
+ ].map(&IPAddr.method(:new))
181
+
182
+ #
183
+ # Determines whether an IP is internal.
184
+ #
185
+ # @param [String] ip
186
+ # The IPv4/IPv6 address.
187
+ #
188
+ # @return [Boolean]
189
+ #
190
+ def internal_ip?(ip)
191
+ INTERNAL_SUBNETS.any? { |subnet| subnet.include?(ip) }
192
+ end
95
193
  end
96
194
  end
97
195
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
2
+ # Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
3
3
  #
4
4
  # bundler-audit is free software: you can redistribute it and/or modify
5
5
  # it under the terms of the GNU General Public License as published by
@@ -18,6 +18,6 @@
18
18
  module Bundler
19
19
  module Audit
20
20
  # bundler-audit version
21
- VERSION = '0.3.0'
21
+ VERSION = '0.4.0'
22
22
  end
23
23
  end
data/lib/bundler/audit.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
2
+ # Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
3
3
  #
4
4
  # bundler-audit is free software: you can redistribute it and/or modify
5
5
  # it under the terms of the GNU General Public License as published by
@@ -7,50 +7,101 @@ describe Bundler::Audit::Advisory do
7
7
  let(:gem) { 'actionpack' }
8
8
  let(:id) { 'OSVDB-84243' }
9
9
  let(:path) { File.join(root,'gems',gem,"#{id}.yml") }
10
+ let(:an_unaffected_version) do
11
+ Bundler::Audit::Advisory.load(path).unaffected_versions.map { |version_rule|
12
+ # For all the rules, get the individual constraints out and see if we
13
+ # can find a suitable one...
14
+ version_rule.requirements.select { |(constraint, gem_version)|
15
+ # We only want constraints where the version number specified is
16
+ # one of the unaffected version. I.E. we don't want ">", "<", or if
17
+ # such a thing exists, "!=" constraints.
18
+ ['~>', '>=', '=', '<='].include?(constraint)
19
+ }.map { |(constraint, gem_version)|
20
+ # Fetch just the version component, which is a Gem::Version,
21
+ # and extract the string representation of the version.
22
+ gem_version.version
23
+ }
24
+ }.flatten.first
25
+ end
10
26
 
11
27
  describe "load" do
12
28
  let(:data) { YAML.load_file(path) }
13
29
 
14
30
  subject { described_class.load(path) }
15
31
 
16
- its(:id) { should == id }
17
- its(:url) { should == data['url'] }
18
- its(:title) { should == data['title'] }
19
- its(:cvss_v2) { should == data['cvss_v2'] }
20
- its(:description) { should == data['description'] }
32
+ describe '#id' do
33
+ subject { super().id }
34
+ it { is_expected.to eq(id) }
35
+ end
36
+
37
+ describe '#url' do
38
+ subject { super().url }
39
+ it { is_expected.to eq(data['url']) }
40
+ end
41
+
42
+ describe '#title' do
43
+ subject { super().title }
44
+ it { is_expected.to eq(data['title']) }
45
+ end
46
+
47
+ describe '#cvss_v2' do
48
+ subject { super().cvss_v2 }
49
+ it { is_expected.to eq(data['cvss_v2']) }
50
+ end
51
+
52
+ describe '#description' do
53
+ subject { super().description }
54
+ it { is_expected.to eq(data['description']) }
55
+ end
56
+
57
+ context "YAML data not representing a hash" do
58
+ it "should raise an exception" do
59
+ path = File.expand_path('../fixtures/not_a_hash.yml', __FILE__)
60
+ expect {
61
+ Advisory.load(path)
62
+ }.to raise_exception("advisory data in #{path.dump} was not a Hash")
63
+ end
64
+ end
21
65
 
22
66
  describe "#patched_versions" do
23
67
  subject { described_class.load(path).patched_versions }
24
68
 
25
69
  it "should all be Gem::Requirement objects" do
26
- subject.all? { |version|
27
- version.should be_kind_of(Gem::Requirement)
28
- }.should be_true
70
+ expect(subject.all? { |version|
71
+ expect(version).to be_kind_of(Gem::Requirement)
72
+ }).to be_truthy
29
73
  end
30
74
 
31
75
  it "should parse the versions" do
32
- subject.map(&:to_s).should == data['patched_versions']
76
+ expect(subject.map(&:to_s)).to eq(data['patched_versions'])
33
77
  end
34
78
  end
35
79
  end
36
80
 
37
81
  describe "#criticality" do
38
82
  context "when cvss_v2 is between 0.0 and 3.3" do
39
- before { subject.stub(:cvss_v2).and_return(3.3) }
40
-
41
- its(:criticality) { should == :low }
83
+ before {
84
+ @advisory = Advisory.new
85
+ @advisory.cvss_v2 = 3.3
86
+ }
87
+ it { expect(@advisory.criticality).to eq(:low) }
42
88
  end
43
89
 
44
90
  context "when cvss_v2 is between 3.3 and 6.6" do
45
- before { subject.stub(:cvss_v2).and_return(6.6) }
91
+ before {
92
+ @advisory = Advisory.new
93
+ @advisory.cvss_v2 = 6.6
94
+ }
95
+ it { expect(@advisory.criticality).to eq(:medium) }
46
96
 
47
- its(:criticality) { should == :medium }
48
97
  end
49
98
 
50
99
  context "when cvss_v2 is between 6.6 and 10.0" do
51
- before { subject.stub(:cvss_v2).and_return(10.0) }
52
-
53
- its(:criticality) { should == :high }
100
+ before {
101
+ @advisory = Advisory.new
102
+ @advisory.cvss_v2 = 10.0
103
+ }
104
+ it { expect(@advisory.criticality).to eq(:high) }
54
105
  end
55
106
  end
56
107
 
@@ -58,10 +109,10 @@ describe Bundler::Audit::Advisory do
58
109
  subject { described_class.load(path) }
59
110
 
60
111
  context "when passed a version that matches one unaffected version" do
61
- let(:version) { Gem::Version.new('2.3.10') }
112
+ let(:version) { Gem::Version.new(an_unaffected_version) }
62
113
 
63
114
  it "should return true" do
64
- subject.unaffected?(version).should be_true
115
+ expect(subject.unaffected?(version)).to be_truthy
65
116
  end
66
117
  end
67
118
 
@@ -69,7 +120,7 @@ describe Bundler::Audit::Advisory do
69
120
  let(:version) { Gem::Version.new('3.0.9') }
70
121
 
71
122
  it "should return false" do
72
- subject.unaffected?(version).should be_false
123
+ expect(subject.unaffected?(version)).to be_falsey
73
124
  end
74
125
  end
75
126
  end
@@ -81,7 +132,7 @@ describe Bundler::Audit::Advisory do
81
132
  let(:version) { Gem::Version.new('3.1.11') }
82
133
 
83
134
  it "should return true" do
84
- subject.patched?(version).should be_true
135
+ expect(subject.patched?(version)).to be_truthy
85
136
  end
86
137
  end
87
138
 
@@ -89,7 +140,7 @@ describe Bundler::Audit::Advisory do
89
140
  let(:version) { Gem::Version.new('2.9.0') }
90
141
 
91
142
  it "should return false" do
92
- subject.patched?(version).should be_false
143
+ expect(subject.patched?(version)).to be_falsey
93
144
  end
94
145
  end
95
146
  end
@@ -101,7 +152,7 @@ describe Bundler::Audit::Advisory do
101
152
  let(:version) { Gem::Version.new('3.1.11') }
102
153
 
103
154
  it "should return false" do
104
- subject.vulnerable?(version).should be_false
155
+ expect(subject.vulnerable?(version)).to be_falsey
105
156
  end
106
157
  end
107
158
 
@@ -109,17 +160,17 @@ describe Bundler::Audit::Advisory do
109
160
  let(:version) { Gem::Version.new('2.9.0') }
110
161
 
111
162
  it "should return true" do
112
- subject.vulnerable?(version).should be_true
163
+ expect(subject.vulnerable?(version)).to be_truthy
113
164
  end
114
165
 
115
166
  context "when unaffected_versions is not empty" do
116
167
  subject { described_class.load(path) }
117
168
 
118
169
  context "when passed a version that matches one unaffected version" do
119
- let(:version) { Gem::Version.new('2.3.12') }
170
+ let(:version) { Gem::Version.new(an_unaffected_version) }
120
171
 
121
172
  it "should return false" do
122
- subject.vulnerable?(version).should be_false
173
+ expect(subject.vulnerable?(version)).to be_falsey
123
174
  end
124
175
  end
125
176
 
@@ -127,7 +178,7 @@ describe Bundler::Audit::Advisory do
127
178
  let(:version) { Gem::Version.new('1.2.3') }
128
179
 
129
180
  it "should return true" do
130
- subject.vulnerable?(version).should be_true
181
+ expect(subject.vulnerable?(version)).to be_truthy
131
182
  end
132
183
  end
133
184
  end
data/spec/audit_spec.rb CHANGED
@@ -3,6 +3,6 @@ require 'bundler/audit'
3
3
 
4
4
  describe Bundler::Audit do
5
5
  it "should have a VERSION constant" do
6
- subject.const_get('VERSION').should_not be_empty
6
+ expect(subject.const_get('VERSION')).not_to be_empty
7
7
  end
8
8
  end