bundler-leak 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.gitignore +11 -0
- data/.gitmodules +3 -0
- data/.rspec +1 -0
- data/.travis.yml +13 -0
- data/.yardopts +1 -0
- data/COPYING.txt +674 -0
- data/ChangeLog.md +125 -0
- data/Gemfile +15 -0
- data/README.md +118 -0
- data/Rakefile +57 -0
- data/bin/bundle-leak +10 -0
- data/bin/bundler-leak +3 -0
- data/bundler-leak.gemspec +67 -0
- data/data/ruby-mem-advisory-db.ts +1 -0
- data/data/ruby-mem-advisory-db/.gitignore +1 -0
- data/data/ruby-mem-advisory-db/.rspec +1 -0
- data/data/ruby-mem-advisory-db/.travis.yml +12 -0
- data/data/ruby-mem-advisory-db/CONTRIBUTING.md +69 -0
- data/data/ruby-mem-advisory-db/CONTRIBUTORS.md +40 -0
- data/data/ruby-mem-advisory-db/Gemfile +9 -0
- data/data/ruby-mem-advisory-db/LICENSE.txt +5 -0
- data/data/ruby-mem-advisory-db/README.md +72 -0
- data/data/ruby-mem-advisory-db/Rakefile +26 -0
- data/data/ruby-mem-advisory-db/gems/celluloid/670.yml +10 -0
- data/data/ruby-mem-advisory-db/gems/grape/301.yml +9 -0
- data/data/ruby-mem-advisory-db/gems/oj/229.yml +9 -0
- data/data/ruby-mem-advisory-db/gems/redcarpet/516.yml +12 -0
- data/data/ruby-mem-advisory-db/gems/redis/612.yml +9 -0
- data/data/ruby-mem-advisory-db/gems/sidekiq-statistic/73.yml +9 -0
- data/data/ruby-mem-advisory-db/gems/sidekiq/2598.yml +9 -0
- data/data/ruby-mem-advisory-db/gems/therubyracer/336.yml +13 -0
- data/data/ruby-mem-advisory-db/gems/zipruby/PRE-SA-2012-02.yml +9 -0
- data/data/ruby-mem-advisory-db/scripts/post-advisories.sh +18 -0
- data/data/ruby-mem-advisory-db/spec/advisories_spec.rb +23 -0
- data/data/ruby-mem-advisory-db/spec/advisory_example.rb +209 -0
- data/data/ruby-mem-advisory-db/spec/gem_example.rb +37 -0
- data/data/ruby-mem-advisory-db/spec/library_example.rb +21 -0
- data/data/ruby-mem-advisory-db/spec/ruby_example.rb +22 -0
- data/data/ruby-mem-advisory-db/spec/spec_helper.rb +1 -0
- data/gemspec.yml +14 -0
- data/lib/bundler/plumber.rb +20 -0
- data/lib/bundler/plumber/advisory.rb +119 -0
- data/lib/bundler/plumber/cli.rb +135 -0
- data/lib/bundler/plumber/database.rb +249 -0
- data/lib/bundler/plumber/scanner.rb +133 -0
- data/lib/bundler/plumber/task.rb +49 -0
- data/lib/bundler/plumber/version.rb +24 -0
- data/spec/advisory_spec.rb +155 -0
- data/spec/audit_spec.rb +8 -0
- data/spec/bundle/insecure_sources/Gemfile +39 -0
- data/spec/bundle/secure/Gemfile +38 -0
- data/spec/bundle/unpatched_gems/Gemfile +39 -0
- data/spec/cli_spec.rb +99 -0
- data/spec/database_spec.rb +138 -0
- data/spec/fixtures/not_a_hash.yml +2 -0
- data/spec/integration_spec.rb +68 -0
- data/spec/scanner_spec.rb +61 -0
- data/spec/spec_helper.rb +62 -0
- metadata +141 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2019 Ombulabs (hello at ombulabs.com)
|
3
|
+
# Copyright (c) 2013-2016 Hal Brodigan (postmodern.mod3 at gmail.com)
|
4
|
+
#
|
5
|
+
# bundler-leak is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# bundler-leak is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with bundler-leak. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'bundler'
|
20
|
+
require 'bundler/plumber/database'
|
21
|
+
require 'bundler/lockfile_parser'
|
22
|
+
|
23
|
+
require 'ipaddr'
|
24
|
+
require 'resolv'
|
25
|
+
require 'set'
|
26
|
+
require 'uri'
|
27
|
+
|
28
|
+
module Bundler
|
29
|
+
module Plumber
|
30
|
+
class Scanner
|
31
|
+
|
32
|
+
# Represents a gem that is covered by an Advisory
|
33
|
+
UnpatchedGem = Struct.new(:gem, :advisory)
|
34
|
+
|
35
|
+
# The advisory database
|
36
|
+
#
|
37
|
+
# @return [Database]
|
38
|
+
attr_reader :database
|
39
|
+
|
40
|
+
# Project root directory
|
41
|
+
attr_reader :root
|
42
|
+
|
43
|
+
# The parsed `Gemfile.lock` from the project
|
44
|
+
#
|
45
|
+
# @return [Bundler::LockfileParser]
|
46
|
+
attr_reader :lockfile
|
47
|
+
|
48
|
+
#
|
49
|
+
# Initializes a scanner.
|
50
|
+
#
|
51
|
+
# @param [String] root
|
52
|
+
# The path to the project root.
|
53
|
+
#
|
54
|
+
# @param [String] gemfile_lock
|
55
|
+
# Alternative name for the `Gemfile.lock` file.
|
56
|
+
#
|
57
|
+
def initialize(root=Dir.pwd,gemfile_lock='Gemfile.lock')
|
58
|
+
@root = File.expand_path(root)
|
59
|
+
@database = Database.new
|
60
|
+
@lockfile = LockfileParser.new(
|
61
|
+
File.read(File.join(@root,gemfile_lock))
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Scans the project for issues.
|
67
|
+
#
|
68
|
+
# @param [Hash] options
|
69
|
+
# Additional options.
|
70
|
+
#
|
71
|
+
# @option options [Array<String>] :ignore
|
72
|
+
# The advisories to ignore.
|
73
|
+
#
|
74
|
+
# @yield [result]
|
75
|
+
# The given block will be passed the results of the scan.
|
76
|
+
#
|
77
|
+
# @return [Enumerator]
|
78
|
+
# If no block is given, an Enumerator will be returned.
|
79
|
+
#
|
80
|
+
def scan(options={},&block)
|
81
|
+
return enum_for(__method__, options) unless block
|
82
|
+
|
83
|
+
ignore = Set[]
|
84
|
+
ignore += options[:ignore] if options[:ignore]
|
85
|
+
|
86
|
+
scan_specs(options, &block)
|
87
|
+
|
88
|
+
return self
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Scans the gem sources in the lockfile.
|
93
|
+
#
|
94
|
+
# @param [Hash] options
|
95
|
+
# Additional options.
|
96
|
+
#
|
97
|
+
# @option options [Array<String>] :ignore
|
98
|
+
# The advisories to ignore.
|
99
|
+
#
|
100
|
+
# @yield [result]
|
101
|
+
# The given block will be passed the results of the scan.
|
102
|
+
#
|
103
|
+
# @yieldparam [UnpatchedGem] result
|
104
|
+
# A result from the scan.
|
105
|
+
#
|
106
|
+
# @return [Enumerator]
|
107
|
+
# If no block is given, an Enumerator will be returned.
|
108
|
+
#
|
109
|
+
# @api semipublic
|
110
|
+
#
|
111
|
+
# @since 0.4.0
|
112
|
+
#
|
113
|
+
def scan_specs(options={})
|
114
|
+
return enum_for(__method__, options) unless block_given?
|
115
|
+
|
116
|
+
ignore = Set[]
|
117
|
+
ignore += options[:ignore] if options[:ignore]
|
118
|
+
|
119
|
+
@lockfile.specs.each do |gem|
|
120
|
+
@database.check_gem(gem) do |advisory|
|
121
|
+
|
122
|
+
# TODO this logic should be modified for rubymem
|
123
|
+
#unless (ignore.include?(advisory.cve_id) || ignore.include?(advisory.osvdb_id))
|
124
|
+
# yield UnpatchedGem.new(gem,advisory)
|
125
|
+
#end
|
126
|
+
yield UnpatchedGem.new(gem, advisory)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2019 Ombulabs (hello at ombulabs.com)
|
3
|
+
# Copyright (c) 2013-2016 Hal Brodigan (postmodern.mod3 at gmail.com)
|
4
|
+
#
|
5
|
+
# bundler-leak is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# bundler-leak is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with bundler-leak. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'rake/tasklib'
|
20
|
+
|
21
|
+
module Bundler
|
22
|
+
module Plumber
|
23
|
+
class Task < Rake::TaskLib
|
24
|
+
#
|
25
|
+
# Initializes the task.
|
26
|
+
#
|
27
|
+
def initialize
|
28
|
+
define
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
#
|
34
|
+
# Defines the `bundle:leak` task.
|
35
|
+
#
|
36
|
+
def define
|
37
|
+
namespace :bundle do
|
38
|
+
desc 'Updates the ruby-mem-advisory-db then runs bundle-leak'
|
39
|
+
task :leak do
|
40
|
+
require 'bundler/plumber/cli'
|
41
|
+
%w(update check).each do |command|
|
42
|
+
Bundler::Plumber::CLI.start [command]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2019 Ombulabs (hello at ombulabs.com)
|
3
|
+
# Copyright (c) 2019 Ombulabs (hello at ombulabs.com)
|
4
|
+
#
|
5
|
+
# bundler-leak is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# bundler-leak is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with bundler-leak. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
module Bundler
|
20
|
+
module Plumber
|
21
|
+
# bundler-leak version
|
22
|
+
VERSION = '0.0.0'
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'bundler/plumber/database'
|
3
|
+
require 'bundler/plumber/advisory'
|
4
|
+
|
5
|
+
describe Bundler::Plumber::Advisory do
|
6
|
+
let(:root) { Bundler::Plumber::Database::VENDORED_PATH }
|
7
|
+
let(:gem) { 'therubyracer' }
|
8
|
+
let(:id) { '336' }
|
9
|
+
let(:path) { File.join(root,'gems',gem,"#{id}.yml") }
|
10
|
+
let(:an_unaffected_version) do
|
11
|
+
Bundler::Plumber::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
|
26
|
+
|
27
|
+
subject { described_class.load(path) }
|
28
|
+
|
29
|
+
describe "load" do
|
30
|
+
let(:data) { YAML.load_file(path) }
|
31
|
+
|
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 '#date' do
|
48
|
+
subject { super().date }
|
49
|
+
it { is_expected.to eq(data['date']) }
|
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
|
65
|
+
|
66
|
+
describe "#patched_versions" do
|
67
|
+
subject { described_class.load(path).patched_versions }
|
68
|
+
|
69
|
+
it "should all be Gem::Requirement objects" do
|
70
|
+
expect(subject.all? { |version|
|
71
|
+
expect(version).to be_kind_of(Gem::Requirement)
|
72
|
+
}).to be_truthy
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should parse the versions" do
|
76
|
+
expect(subject.map(&:to_s)).to eq(data['patched_versions'])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
describe "#unaffected?" do
|
83
|
+
context "when passed a version that matches one unaffected version" do
|
84
|
+
let(:version) { Gem::Version.new(an_unaffected_version) }
|
85
|
+
|
86
|
+
it "should return true" do
|
87
|
+
expect(subject.unaffected?(version)).to be_truthy
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when passed a version that matches no unaffected version" do
|
92
|
+
let(:version) { Gem::Version.new('3.0.9') }
|
93
|
+
|
94
|
+
it "should return false" do
|
95
|
+
expect(subject.unaffected?(version)).to be_falsey
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#patched?" do
|
101
|
+
context "when passed a version that matches one patched version" do
|
102
|
+
let(:version) { Gem::Version.new('0.12.4') }
|
103
|
+
|
104
|
+
it "should return true", doku: true do
|
105
|
+
expect(subject.patched?(version)).to be_truthy
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when passed a version that matches no patched version" do
|
110
|
+
let(:version) { Gem::Version.new('2.9.0') }
|
111
|
+
|
112
|
+
it "should return false" do
|
113
|
+
expect(subject.patched?(version)).to be_falsey
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#vulnerable?" do
|
119
|
+
context "when passed a version that matches one patched version" do
|
120
|
+
let(:version) { Gem::Version.new('0.12.4') }
|
121
|
+
|
122
|
+
it "should return false" do
|
123
|
+
expect(subject.vulnerable?(version)).to be_falsey
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "when passed a version that matches no patched version" do
|
128
|
+
let(:version) { Gem::Version.new('2.9.0') }
|
129
|
+
|
130
|
+
it "should return true" do
|
131
|
+
expect(subject.vulnerable?(version)).to be_truthy
|
132
|
+
end
|
133
|
+
|
134
|
+
context "when unaffected_versions is not empty" do
|
135
|
+
subject { described_class.load(path) }
|
136
|
+
|
137
|
+
context "when passed a version that matches one unaffected version" do
|
138
|
+
let(:version) { Gem::Version.new(an_unaffected_version) }
|
139
|
+
|
140
|
+
it "should return false" do
|
141
|
+
expect(subject.vulnerable?(version)).to be_falsey
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when passed a version that matches no unaffected version" do
|
146
|
+
let(:version) { Gem::Version.new('1.2.3') }
|
147
|
+
|
148
|
+
it "should return true" do
|
149
|
+
expect(subject.vulnerable?(version)).to be_truthy
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/spec/audit_spec.rb
ADDED
@@ -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', platform: [:mri, :rbx]
|
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', '~> 4.2.7.1'
|
4
|
+
|
5
|
+
# Bundle edge Rails instead:
|
6
|
+
# gem 'rails', :git => 'git://github.com/rails/rails.git'
|
7
|
+
|
8
|
+
gem 'sqlite3', platform: [:mri, :rbx]
|
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'
|