mrjoy-bundler-audit 0.3.1 → 0.3.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 797e11ab94369f9ca56d1ebec7b486b739ef76a0
4
- data.tar.gz: f86b4d43b7bc27285b9da49494d7f9bcb6d3da2d
3
+ metadata.gz: 37d67a169ac19c5c1b329c949c4af7dd044876bd
4
+ data.tar.gz: efbdd7e8335a6f685f77f45bfa6e4d3f4f10804f
5
5
  SHA512:
6
- metadata.gz: ecbadf97664bc14844269e91b523feb2bf17dfd569af3621a8a015b40c4c7e5b69bad171497bb950616df115f0c8fd752dda12e8551c5c8caea3571b8e100d08
7
- data.tar.gz: 39df3b13657c0069d7739b600dc8c1feac26a51fe790438b3284d46d32a8f9a6dd2b31d9ad05e1edaed20d948d44835d0e0763b7ca0b05737eb0a7cf20ce1465
6
+ metadata.gz: c09b134df68524a62017773ca38bfb95cb10a9cd91a46fde8ba3686fd85910231cc85e9a463b9cd1fb925084311780121b1564e213b108aa2729e5d67f87ca2c
7
+ data.tar.gz: 966ebb4387b593babd08f303530c7f2f32d7771e622d0371dd687222ee4f12d8f49167c8dcff091ce3c6534fe1fcdb200cdbe0b1cfa5e865cb67ceb078ee6abc
data/.gitignore CHANGED
@@ -1,6 +1,9 @@
1
1
  Gemfile.lock
2
2
  doc/
3
+ coverage/
4
+ .yardoc/
3
5
  pkg/
4
6
  spec/bundle/*/Gemfile.lock
5
7
  spec/bundle/*/.bundle/
6
8
  vendor/bundle/
9
+ tmp/
data/ChangeLog.md CHANGED
@@ -1,3 +1,12 @@
1
+ ### mrjoy-0.3.2 / 2013-11-04
2
+
3
+ * Fix for [serious issue](https://github.com/rubysec/bundler-audit/issues/48)
4
+ that would cause bundle-audit to ignore a locally installed cache of the
5
+ vulnerability database in favor of its vendored version.
6
+ * Simplified code according to ABC metric, getting CodeClimate results to 4.0.
7
+ * Added SimpleCov to ensure reasonable test coverage.
8
+ * Updated docs to explain differentiation of this fork vs. upstream.
9
+
1
10
  ### mrjoy-0.3.1 / 2013-11-04
2
11
 
3
12
  * Integrated upstream 0.3.0 changes.
@@ -53,9 +62,9 @@
53
62
  * Require RubyGems >= 1.8.0. Prior versions of RubyGems could not correctly
54
63
  parse approximate version requirements (`~> 1.2.3`).
55
64
  * Updated the [ruby-advisory-db].
56
- * Added {Bundle::Audit::Advisory#unaffected_versions}.
57
- * Added {Bundle::Audit::Advisory#unaffected?}.
58
- * Added {Bundle::Audit::Advisory#patched?}.
65
+ * Added {Bundler::Audit::Advisory#unaffected_versions}.
66
+ * Added {Bundler::Audit::Advisory#unaffected?}.
67
+ * Added {Bundler::Audit::Advisory#patched?}.
59
68
 
60
69
  ### 0.1.2 / 2013-02-17
61
70
 
data/Gemfile CHANGED
@@ -5,10 +5,11 @@ source 'https://rubygems.org/'
5
5
  gemspec
6
6
 
7
7
  group :development do
8
- gem 'rake', '~> 10.0'
8
+ gem 'rake', '~> 10.0', :require => false
9
9
  gem 'kramdown', '~> 0.14'
10
10
 
11
11
  gem 'rubygems-tasks', '~> 0.2'
12
- gem 'rspec', '~> 2.4'
13
- gem 'yard', '~> 0.8'
12
+ gem 'rspec', '~> 2.4', :require => false
13
+ gem 'yard', '~> 0.8', :require => false
14
+ gem 'simplecov', '~> 0.7', :require => false
14
15
  end
data/README.md CHANGED
@@ -19,6 +19,18 @@ Patch-level verification for [Bundler][bundler].
19
19
  * Prints advisory information.
20
20
  * Does not require a network connection.
21
21
 
22
+ ## Benefits of This Fork
23
+
24
+ * **IMPORTANT**: At present, the upstream repository (v0.3.0) will tend to use
25
+ an *older* vendored copy of the vulnerability database despite the user
26
+ installing a local cache! As of v0.3.2, this fork is *not* susceptible to
27
+ this problem. [Read here for more info.](https://github.com/rubysec/bundler-audit/issues/48)
28
+ * Kept up to date with upstream frequently.
29
+ * Simpler, more robust testing infrastructure for greater assurance of code
30
+ quality, and easier contribution.
31
+ * Simplified code (see CodeClimate results) to enable more easily reasoning
32
+ about the code.
33
+
22
34
  ## Synopsis
23
35
 
24
36
  Audit a projects `Gemfile.lock`:
@@ -31,7 +43,7 @@ Audit a projects `Gemfile.lock`:
31
43
  URL: http://www.osvdb.org/show/osvdb/91452
32
44
  Title: XSS vulnerability in sanitize_css in Action Pack
33
45
  Solution: upgrade to ~> 2.3.18, ~> 3.1.12, >= 3.2.13
34
-
46
+
35
47
  Name: actionpack
36
48
  Version: 3.2.10
37
49
  Advisory: OSVDB-91454
@@ -39,7 +51,7 @@ Audit a projects `Gemfile.lock`:
39
51
  URL: http://osvdb.org/show/osvdb/91454
40
52
  Title: XSS Vulnerability in the `sanitize` helper of Ruby on Rails
41
53
  Solution: upgrade to ~> 2.3.18, ~> 3.1.12, >= 3.2.13
42
-
54
+
43
55
  Name: actionpack
44
56
  Version: 3.2.10
45
57
  Advisory: OSVDB-89026
@@ -47,7 +59,7 @@ Audit a projects `Gemfile.lock`:
47
59
  URL: http://osvdb.org/show/osvdb/89026
48
60
  Title: Ruby on Rails params_parser.rb Action Pack Type Casting Parameter Parsing Remote Code Execution
49
61
  Solution: upgrade to ~> 2.3.15, ~> 3.0.19, ~> 3.1.10, >= 3.2.11
50
-
62
+
51
63
  Name: activerecord
52
64
  Version: 3.2.10
53
65
  Advisory: OSVDB-91453
@@ -55,7 +67,7 @@ Audit a projects `Gemfile.lock`:
55
67
  URL: http://osvdb.org/show/osvdb/91453
56
68
  Title: Symbol DoS vulnerability in Active Record
57
69
  Solution: upgrade to ~> 2.3.18, ~> 3.1.12, >= 3.2.13
58
-
70
+
59
71
  Name: activerecord
60
72
  Version: 3.2.10
61
73
  Advisory: OSVDB-90072
@@ -63,7 +75,7 @@ Audit a projects `Gemfile.lock`:
63
75
  URL: http://direct.osvdb.org/show/osvdb/90072
64
76
  Title: Ruby on Rails Active Record attr_protected Method Bypass
65
77
  Solution: upgrade to ~> 2.3.17, ~> 3.1.11, >= 3.2.12
66
-
78
+
67
79
  Name: activerecord
68
80
  Version: 3.2.10
69
81
  Advisory: OSVDB-89025
@@ -71,7 +83,7 @@ Audit a projects `Gemfile.lock`:
71
83
  URL: http://osvdb.org/show/osvdb/89025
72
84
  Title: Ruby on Rails Active Record JSON Parameter Parsing Query Bypass
73
85
  Solution: upgrade to ~> 2.3.16, ~> 3.0.19, ~> 3.1.10, >= 3.2.11
74
-
86
+
75
87
  Name: activesupport
76
88
  Version: 3.2.10
77
89
  Advisory: OSVDB-91451
@@ -79,7 +91,7 @@ Audit a projects `Gemfile.lock`:
79
91
  URL: http://www.osvdb.org/show/osvdb/91451
80
92
  Title: XML Parsing Vulnerability affecting JRuby users
81
93
  Solution: upgrade to ~> 3.1.12, >= 3.2.13
82
-
94
+
83
95
  Unpatched versions found!
84
96
 
85
97
  Update the [ruby-advisory-db] that `bundle-audit` uses:
data/Rakefile CHANGED
@@ -26,8 +26,22 @@ Gem::Tasks.new
26
26
  namespace :db do
27
27
  desc 'Updates data/ruby-advisory-db'
28
28
  task :update do
29
+ vendored_ctime = nil
29
30
  chdir 'data/ruby-advisory-db' do
30
31
  sh 'git', 'pull', 'origin', 'master'
32
+ vendored_ctime = `git log --pretty="%cd" -1`.chomp
33
+ end
34
+ File.open("lib/bundler/audit/vendored_time.rb", "w") do |fh|
35
+ fh.write(%Q{
36
+ # WARNING: DO NOT EDIT THIS FILE BY HAND. IT IS AUTO-GENERATED!
37
+ module Bundler
38
+ module Audit
39
+ class Database
40
+ VENDORED_REPO_CTIME = Time.parse("#{vendored_ctime}")
41
+ end
42
+ end
43
+ end
44
+ })
31
45
  end
32
46
 
33
47
  sh 'git', 'commit', 'data/ruby-advisory-db',
@@ -84,26 +84,33 @@ module Bundler
84
84
  end
85
85
 
86
86
  def print_advisory(gem, advisory)
87
- say "Name: ", :red
88
- say gem.name
89
-
90
- say "Version: ", :red
91
- say gem.version
87
+ print_affected_gem(gem)
92
88
 
93
89
  say "Advisory: ", :red
94
90
  say advisory.id
95
91
 
96
92
  say "Criticality: ", :red
97
- case advisory.criticality
98
- when :low then say "Low"
99
- when :medium then say "Medium", :yellow
100
- when :high then say "High", [:red, :bold]
101
- else say "Unknown"
102
- end
93
+ say *CRITICALITY_MAP[advisory.criticality]
103
94
 
104
95
  say "URL: ", :red
105
96
  say advisory.url
106
97
 
98
+ print_advisory_details advisory
99
+ print_advisory_solution advisory
100
+
101
+ say
102
+ end
103
+
104
+ protected
105
+ def print_affected_gem(gem)
106
+ say "Name: ", :red
107
+ say gem.name
108
+
109
+ say "Version: ", :red
110
+ say gem.version
111
+ end
112
+
113
+ def print_advisory_details(advisory)
107
114
  if options.verbose?
108
115
  say "Description:", :red
109
116
  say
@@ -111,11 +118,12 @@ module Bundler
111
118
  print_wrapped advisory.description, :indent => 2
112
119
  say
113
120
  else
114
-
115
121
  say "Title: ", :red
116
122
  say advisory.title
117
123
  end
124
+ end
118
125
 
126
+ def print_advisory_solution(advisory)
119
127
  unless advisory.patched_versions.empty?
120
128
  say "Solution: upgrade to ", :red
121
129
  say advisory.patched_versions.join(', ')
@@ -123,10 +131,15 @@ module Bundler
123
131
  say "Solution: ", :red
124
132
  say "remove or disable this gem until a patch is available!", [:red, :bold]
125
133
  end
126
-
127
- say
128
134
  end
129
135
 
136
+ CRITICALITY_MAP = Hash({
137
+ :low => ["Low"],
138
+ :medium => ["Medium", :yellow],
139
+ :high => ["High", [:red, :bold]],
140
+ }) do |data, key|
141
+ "Unknown"
142
+ end
130
143
  end
131
144
  end
132
145
  end
@@ -17,11 +17,12 @@
17
17
  # along with mrjoy-bundler-audit. If not, see <http://www.gnu.org/licenses/>.
18
18
  #
19
19
 
20
- require 'bundler/audit/advisory'
21
-
22
20
  require 'time'
23
21
  require 'yaml'
24
22
 
23
+ require 'bundler/audit/advisory'
24
+ require 'bundler/audit/vendored_time'
25
+
25
26
  module Bundler
26
27
  module Audit
27
28
  #
@@ -68,7 +69,7 @@ module Bundler
68
69
  def self.path
69
70
  if File.directory?(USER_PATH)
70
71
  t1 = Dir.chdir(USER_PATH) { Time.parse(`git log --pretty="%cd" -1`) }
71
- t2 = File.ctime(VENDORED_PATH)
72
+ t2 = VENDORED_REPO_CTIME
72
73
 
73
74
  if t1 >= t2 then USER_PATH
74
75
  else VENDORED_PATH
@@ -62,36 +62,48 @@ module Bundler
62
62
  def scan(options={})
63
63
  return enum_for(__method__,options) unless block_given?
64
64
 
65
- ignore = Set[]
66
- ignore += options[:ignore] if options[:ignore]
65
+ get_insecure_sources.each { |source| yield source }
66
+ get_unpatched_gems(options[:ignore]).each { |gem| yield gem }
67
67
 
68
- @lockfile.sources.map do |source|
68
+ return self
69
+ end
70
+
71
+ protected
72
+
73
+ def get_insecure_sources
74
+ insecure = []
75
+ @lockfile.sources.each do |source|
69
76
  case source
70
77
  when Source::Git
71
- case source.uri
72
- when /^git:/, /^http:/
73
- yield InsecureSource.new(source.uri)
74
- end
78
+ next unless(source.uri =~ /^(git|http):/)
79
+
80
+ insecure << InsecureSource.new(source.uri)
75
81
  when Source::Rubygems
76
- source.remotes.each do |uri|
77
- if uri.scheme == 'http'
78
- yield InsecureSource.new(uri.to_s)
79
- end
82
+ source.remotes.map do |uri|
83
+ next unless uri.scheme == 'http'
84
+
85
+ insecure << InsecureSource.new(uri.to_s)
80
86
  end
81
87
  end
82
88
  end
83
89
 
90
+ return insecure
91
+ end
92
+
93
+ def get_unpatched_gems(ignore)
94
+ ignore = Set.new(ignore) # If ignore is empty the Set will contain nil,
95
+ # but since we should never have a nil version
96
+ # that's a non-issue.
97
+ unpatched = []
84
98
  @lockfile.specs.each do |gem|
85
99
  @database.check_gem(gem) do |advisory|
86
- unless ignore.include?(advisory.id)
87
- yield UnpatchedGem.new(gem,advisory)
88
- end
100
+ next if ignore.include?(advisory.id)
101
+
102
+ unpatched << UnpatchedGem.new(gem,advisory)
89
103
  end
90
104
  end
91
-
92
- return self
105
+ return unpatched
93
106
  end
94
-
95
107
  end
96
108
  end
97
109
  end
@@ -0,0 +1,9 @@
1
+
2
+ # WARNING: DO NOT EDIT THIS FILE BY HAND. IT IS AUTO-GENERATED!
3
+ module Bundler
4
+ module Audit
5
+ class Database
6
+ VENDORED_REPO_CTIME = Time.parse("Wed Oct 23 11:22:06 2013 -0400")
7
+ end
8
+ end
9
+ end
@@ -20,6 +20,6 @@
20
20
  module Bundler
21
21
  module Audit
22
22
  # bundler-audit version
23
- VERSION = '0.3.1'
23
+ VERSION = '0.3.2'
24
24
  end
25
25
  end
@@ -8,13 +8,13 @@ describe Bundler::Audit::Advisory do
8
8
  let(:id) { 'OSVDB-84243' }
9
9
  let(:path) { File.join(root,'gems',gem,"#{id}.yml") }
10
10
  let(:an_unaffected_version) do
11
- YAML.
12
- load(File.read(path))['unaffected_versions'].
13
- map { |item| item.split(/\s*,\s*/) }.
14
- flatten.
15
- select { |ver| ver =~ /^(~>|>=|=|<=)/ }.
16
- first.
17
- sub(/^.*?(~>|>=|=|<=)\s+/, '')
11
+ Advisory.load(path).
12
+ unaffected_versions. # Only care about unaffected versions...
13
+ first. # And even then, any will do.
14
+ requirements. # This is where we find versions...
15
+ first. # Again, any will do.
16
+ last. # We don't care about the bound, just the version number.
17
+ to_s # And we'd like it as a string.
18
18
  end
19
19
 
20
20
  describe "load" do
@@ -28,6 +28,15 @@ describe Bundler::Audit::Advisory do
28
28
  its(:cvss_v2) { should == data['cvss_v2'] }
29
29
  its(:description) { should == data['description'] }
30
30
 
31
+ context "YAML data not representing a hash" do
32
+ it "should raise an exception" do
33
+ path = File.expand_path('../fixtures/not_a_hash.yml', __FILE__)
34
+ expect {
35
+ Advisory.load(path)
36
+ }.to raise_exception("advisory data in #{path.dump} was not a Hash")
37
+ end
38
+ end
39
+
31
40
  describe "#patched_versions" do
32
41
  subject { described_class.load(path).patched_versions }
33
42
 
@@ -9,6 +9,37 @@ describe Bundler::Audit::Database do
9
9
  it "it should be a directory" do
10
10
  File.directory?(subject).should be_true
11
11
  end
12
+
13
+ it "should prefer the user repo, iff it's as up to date, or more up to date than the vendored one" do
14
+ Bundler::Audit::Database.update!
15
+
16
+ # As up to date...
17
+ expect(Bundler::Audit::Database.path).to eq mocked_user_path
18
+
19
+ # More up to date...
20
+ fake_a_commit_in_the_user_repo
21
+ expect(Bundler::Audit::Database.path).to eq mocked_user_path
22
+
23
+ roll_user_repo_back(2)
24
+ expect(Bundler::Audit::Database.path).to eq Bundler::Audit::Database::VENDORED_PATH
25
+ end
26
+ end
27
+
28
+ describe "update!" do
29
+ it "should create the USER_PATH path as needed" do
30
+ Bundler::Audit::Database.update!
31
+ expect(File.directory?(mocked_user_path)).to be true
32
+ end
33
+
34
+ it "should create the repo, then update it given multple successive calls." do
35
+ expect_update_to_clone_repo!
36
+ Bundler::Audit::Database.update!
37
+ expect(File.directory?(mocked_user_path)).to be true
38
+
39
+ expect_update_to_update_repo!
40
+ Bundler::Audit::Database.update!
41
+ expect(File.directory?(mocked_user_path)).to be true
42
+ end
12
43
  end
13
44
 
14
45
  describe "#initialize" do
@@ -0,0 +1,2 @@
1
+ ---
2
+ "Just a string."
@@ -1,8 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "CLI" do
4
- include Helpers
5
-
6
4
  let(:directory) { File.join('spec','bundle',bundle) }
7
5
 
8
6
  context "when auditing a vulnerable bundle" do
@@ -16,8 +14,9 @@ describe "CLI" do
16
14
  # zero-width prefix before
17
15
  # the first match.
18
16
 
19
- # Note the "{8,}" below indicates the minimum number of advisories that
20
- # we should see matches for -- as a particular version of code will never
17
+ # Note the "{vuln_count}" below indicates the minimum number of
18
+ # advisories that we should see matches for -- as a particular version of
19
+ # code will never
21
20
  advisory_pattern = /(Name: [^\n]+
22
21
  Version: \d+\.\d+\.\d+
23
22
  Advisory: OSVDB-\d+
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,7 @@
1
+ require 'simplecov'
2
+ require 'json'
3
+ SimpleCov.start
4
+
1
5
  require 'rspec'
2
6
  require 'bundler/audit/version'
3
7
 
@@ -21,6 +25,48 @@ module Helpers
21
25
  def audit_in_directory(additions, directory, options={})
22
26
  Dir.chdir(directory) { decolorize(sh([executable, additions].compact.join(' '), options)) }
23
27
  end
28
+
29
+ def mocked_user_path
30
+ File.expand_path('../../tmp/data', __FILE__)
31
+ end
32
+
33
+ def expect_update_to_clone_repo!
34
+ Bundler::Audit::Database.
35
+ should_receive(:system).
36
+ with('git', 'clone', Bundler::Audit::Database::VENDORED_PATH, mocked_user_path).
37
+ and_call_original
38
+ end
39
+
40
+ def expect_update_to_update_repo!
41
+ Bundler::Audit::Database.
42
+ should_receive(:system).
43
+ with('git', 'pull', 'origin', 'master').
44
+ and_call_original
45
+ end
46
+
47
+ def fake_a_commit_in_the_user_repo
48
+ Dir.chdir(mocked_user_path) do
49
+ system 'git', 'commit', '--allow-empty', '-m', 'Dummy commit.'
50
+ end
51
+ end
52
+
53
+ def roll_user_repo_back(num_commits)
54
+ Dir.chdir(mocked_user_path) do
55
+ system 'git', 'checkout', "HEAD~#{num_commits}"
56
+ system 'git', 'branch', '-f', 'master', 'HEAD'
57
+ system 'git', 'checkout', 'master'
58
+ end
59
+ end
24
60
  end
25
61
 
26
62
  include Bundler::Audit
63
+
64
+ RSpec.configure do |config|
65
+ include Helpers
66
+
67
+ config.before(:each) do
68
+ stub_const("Bundler::Audit::Database::URL", Bundler::Audit::Database::VENDORED_PATH)
69
+ stub_const("Bundler::Audit::Database::USER_PATH", mocked_user_path)
70
+ FileUtils.rm_rf mocked_user_path if(File.exist?(mocked_user_path))
71
+ end
72
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mrjoy-bundler-audit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Postmodern
@@ -55,6 +55,7 @@ files:
55
55
  - lib/bundler/audit/cli.rb
56
56
  - lib/bundler/audit/database.rb
57
57
  - lib/bundler/audit/scanner.rb
58
+ - lib/bundler/audit/vendored_time.rb
58
59
  - lib/bundler/audit/version.rb
59
60
  - mrjoy-bundler-audit.gemspec
60
61
  - spec/advisory_spec.rb
@@ -63,6 +64,7 @@ files:
63
64
  - spec/bundle/secure/Gemfile
64
65
  - spec/bundle/unpatched_gems/Gemfile
65
66
  - spec/database_spec.rb
67
+ - spec/fixtures/not_a_hash.yml
66
68
  - spec/integration_spec.rb
67
69
  - spec/scanner_spec.rb
68
70
  - spec/spec_helper.rb