mrjoy-bundler-audit 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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