bundler-audit-ng 0.6.1
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 +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 +129 -0
- data/Gemfile +13 -0
- data/README.md +168 -0
- data/Rakefile +57 -0
- data/bin/bundle-audit +10 -0
- data/bin/bundler-audit +3 -0
- data/bundler-audit.gemspec +67 -0
- data/data/ruby-advisory-db.ts +1 -0
- data/gemspec.yml +14 -0
- data/lib/bundler/audit.rb +19 -0
- data/lib/bundler/audit/advisory.rb +177 -0
- data/lib/bundler/audit/cli.rb +155 -0
- data/lib/bundler/audit/database.rb +248 -0
- data/lib/bundler/audit/scanner.rb +213 -0
- data/lib/bundler/audit/task.rb +31 -0
- data/lib/bundler/audit/version.rb +23 -0
- data/spec/advisory_spec.rb +282 -0
- data/spec/audit_spec.rb +8 -0
- data/spec/bundle/insecure_sources/Gemfile +4 -0
- data/spec/bundle/secure/Gemfile +3 -0
- data/spec/bundle/unpatched_gems/Gemfile +3 -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 +103 -0
- data/spec/scanner_spec.rb +75 -0
- data/spec/spec_helper.rb +62 -0
- metadata +115 -0
@@ -0,0 +1 @@
|
|
1
|
+
2017-06-13 16:51:56 UTC
|
data/gemspec.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
name: bundler-audit-ng
|
2
|
+
summary: Patch-level verification for Bundler
|
3
|
+
description: bundler-audit provides patch-level verification for Bundled apps.
|
4
|
+
license: GPL-3.0+
|
5
|
+
authors: Postmodern, pxlpnk
|
6
|
+
email: rubygems@an-ti.eu
|
7
|
+
homepage: https://github.com/pxlpnk/bundler-audit-ng
|
8
|
+
|
9
|
+
required_ruby_version: ">= 1.9.3"
|
10
|
+
required_rubygems_version: ">= 1.8.0"
|
11
|
+
|
12
|
+
dependencies:
|
13
|
+
thor: ~> 0.18
|
14
|
+
bundler: ">= 1.2.0, < 3"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013-2019 Hal Brodigan (postmodern.mod3 at gmail.com)
|
3
|
+
#
|
4
|
+
# bundler-audit is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# bundler-audit is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with bundler-audit. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'bundler/audit/database'
|
19
|
+
require 'bundler/audit/version'
|
@@ -0,0 +1,177 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013-2019 Hal Brodigan (postmodern.mod3 at gmail.com)
|
3
|
+
#
|
4
|
+
# bundler-audit is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# bundler-audit is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with bundler-audit. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'yaml'
|
19
|
+
|
20
|
+
module Bundler
|
21
|
+
module Audit
|
22
|
+
class Advisory < Struct.new(:path,
|
23
|
+
:id,
|
24
|
+
:url,
|
25
|
+
:title,
|
26
|
+
:date,
|
27
|
+
:description,
|
28
|
+
:cvss_v2,
|
29
|
+
:cve,
|
30
|
+
:osvdb,
|
31
|
+
:ghsa,
|
32
|
+
:unaffected_versions,
|
33
|
+
:patched_versions)
|
34
|
+
|
35
|
+
#
|
36
|
+
# Loads the advisory from a YAML file.
|
37
|
+
#
|
38
|
+
# @param [String] path
|
39
|
+
# The path to the advisory YAML file.
|
40
|
+
#
|
41
|
+
# @return [Advisory]
|
42
|
+
#
|
43
|
+
# @api semipublic
|
44
|
+
#
|
45
|
+
def self.load(path)
|
46
|
+
id = File.basename(path).chomp('.yml')
|
47
|
+
data = YAML.load_file(path)
|
48
|
+
|
49
|
+
unless data.kind_of?(Hash)
|
50
|
+
raise("advisory data in #{path.dump} was not a Hash")
|
51
|
+
end
|
52
|
+
|
53
|
+
parse_versions = lambda { |versions|
|
54
|
+
Array(versions).map do |version|
|
55
|
+
Gem::Requirement.new(*version.split(', '))
|
56
|
+
end
|
57
|
+
}
|
58
|
+
|
59
|
+
return new(
|
60
|
+
path,
|
61
|
+
id,
|
62
|
+
data['url'],
|
63
|
+
data['title'],
|
64
|
+
data['date'],
|
65
|
+
data['description'],
|
66
|
+
data['cvss_v2'],
|
67
|
+
data['cve'],
|
68
|
+
data['osvdb'],
|
69
|
+
data['ghsa'],
|
70
|
+
parse_versions[data['unaffected_versions']],
|
71
|
+
parse_versions[data['patched_versions']]
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# The CVE identifier.
|
77
|
+
#
|
78
|
+
# @return [String, nil]
|
79
|
+
#
|
80
|
+
def cve_id
|
81
|
+
"CVE-#{cve}" if cve
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# The OSVDB identifier.
|
86
|
+
#
|
87
|
+
# @return [String, nil]
|
88
|
+
#
|
89
|
+
def osvdb_id
|
90
|
+
"OSVDB-#{osvdb}" if osvdb
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# The GHSA (GitHub Security Advisory) identifier
|
95
|
+
#
|
96
|
+
# @return [String, nil]
|
97
|
+
#
|
98
|
+
def ghsa_id
|
99
|
+
"GHSA-#{ghsa}" if ghsa
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Return a compacted list of all ids
|
104
|
+
def identifiers
|
105
|
+
[
|
106
|
+
cve_id,
|
107
|
+
osvdb_id,
|
108
|
+
ghsa_id
|
109
|
+
].compact
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Determines how critical the vulnerability is.
|
114
|
+
#
|
115
|
+
# @return [:low, :medium, :high]
|
116
|
+
# The criticality of the vulnerability based on the CVSSv2 score.
|
117
|
+
#
|
118
|
+
def criticality
|
119
|
+
case cvss_v2
|
120
|
+
when 0.0..3.3 then :low
|
121
|
+
when 3.3..6.6 then :medium
|
122
|
+
when 6.6..10.0 then :high
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
#
|
127
|
+
# Checks whether the version is not affected by the advisory.
|
128
|
+
#
|
129
|
+
# @param [Gem::Version] version
|
130
|
+
# The version to compare against {#unaffected_versions}.
|
131
|
+
#
|
132
|
+
# @return [Boolean]
|
133
|
+
# Specifies whether the version is not affected by the advisory.
|
134
|
+
#
|
135
|
+
# @since 0.2.0
|
136
|
+
#
|
137
|
+
def unaffected?(version)
|
138
|
+
unaffected_versions.any? do |unaffected_version|
|
139
|
+
unaffected_version === version
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Checks whether the version is patched against the advisory.
|
145
|
+
#
|
146
|
+
# @param [Gem::Version] version
|
147
|
+
# The version to compare against {#patched_versions}.
|
148
|
+
#
|
149
|
+
# @return [Boolean]
|
150
|
+
# Specifies whether the version is patched against the advisory.
|
151
|
+
#
|
152
|
+
# @since 0.2.0
|
153
|
+
#
|
154
|
+
def patched?(version)
|
155
|
+
patched_versions.any? do |patched_version|
|
156
|
+
patched_version === version
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
#
|
161
|
+
# Checks whether the version is vulnerable to the advisory.
|
162
|
+
#
|
163
|
+
# @param [Gem::Version] version
|
164
|
+
# The version to compare against {#patched_versions}.
|
165
|
+
#
|
166
|
+
# @return [Boolean]
|
167
|
+
# Specifies whether the version is vulnerable to the advisory or not.
|
168
|
+
#
|
169
|
+
def vulnerable?(version)
|
170
|
+
!patched?(version) && !unaffected?(version)
|
171
|
+
end
|
172
|
+
|
173
|
+
alias to_s id
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013-2019 Hal Brodigan (postmodern.mod3 at gmail.com)
|
3
|
+
#
|
4
|
+
# bundler-audit is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# bundler-audit is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with bundler-audit. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'bundler/audit/scanner'
|
19
|
+
require 'bundler/audit/version'
|
20
|
+
|
21
|
+
require 'thor'
|
22
|
+
require 'bundler'
|
23
|
+
require 'bundler/vendored_thor'
|
24
|
+
|
25
|
+
module Bundler
|
26
|
+
module Audit
|
27
|
+
class CLI < ::Thor
|
28
|
+
|
29
|
+
default_task :check
|
30
|
+
map '--version' => :version
|
31
|
+
|
32
|
+
desc 'check', 'Checks the Gemfile.lock for insecure dependencies'
|
33
|
+
method_option :quiet, :type => :boolean, :aliases => '-q'
|
34
|
+
method_option :verbose, :type => :boolean, :aliases => '-v'
|
35
|
+
method_option :ignore, :type => :array, :aliases => '-i'
|
36
|
+
method_option :update, :type => :boolean, :aliases => '-u'
|
37
|
+
|
38
|
+
def check
|
39
|
+
update if options[:update]
|
40
|
+
|
41
|
+
scanner = Scanner.new
|
42
|
+
vulnerable = false
|
43
|
+
|
44
|
+
scanner.scan(:ignore => options.ignore) do |result|
|
45
|
+
vulnerable = true
|
46
|
+
|
47
|
+
case result
|
48
|
+
when Scanner::InsecureSource
|
49
|
+
print_warning "Insecure Source URI found: #{result.source}"
|
50
|
+
when Scanner::UnpatchedGem
|
51
|
+
print_advisory result.gem, result.advisory
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if vulnerable
|
56
|
+
say "Vulnerabilities found!", :red
|
57
|
+
exit 1
|
58
|
+
else
|
59
|
+
say("No vulnerabilities found", :green) unless options.quiet?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
desc 'update', 'Updates the ruby-advisory-db'
|
64
|
+
method_option :quiet, :type => :boolean, :aliases => '-q'
|
65
|
+
|
66
|
+
def update
|
67
|
+
say("Updating ruby-advisory-db ...") unless options.quiet?
|
68
|
+
|
69
|
+
case Database.update!(quiet: options.quiet?)
|
70
|
+
when true
|
71
|
+
say("Updated ruby-advisory-db", :green) unless options.quiet?
|
72
|
+
when false
|
73
|
+
say "Failed updating ruby-advisory-db!", :red
|
74
|
+
exit 1
|
75
|
+
when nil
|
76
|
+
say "Skipping update", :yellow
|
77
|
+
end
|
78
|
+
|
79
|
+
unless options.quiet?
|
80
|
+
puts("ruby-advisory-db: #{Database.new.size} advisories")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
desc 'version', 'Prints the bundler-audit version'
|
85
|
+
def version
|
86
|
+
database = Database.new
|
87
|
+
|
88
|
+
puts "#{File.basename($0)} #{VERSION} (advisories: #{database.size})"
|
89
|
+
end
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
def say(message="", color=nil)
|
94
|
+
color = nil unless $stdout.tty?
|
95
|
+
super(message.to_s, color)
|
96
|
+
end
|
97
|
+
|
98
|
+
def print_warning(message)
|
99
|
+
say message, :yellow
|
100
|
+
end
|
101
|
+
|
102
|
+
def print_advisory(gem, advisory)
|
103
|
+
say "Name: ", :red
|
104
|
+
say gem.name
|
105
|
+
|
106
|
+
say "Version: ", :red
|
107
|
+
say gem.version
|
108
|
+
|
109
|
+
say "Advisory: ", :red
|
110
|
+
|
111
|
+
if advisory.cve
|
112
|
+
say advisory.cve_id
|
113
|
+
elsif advisory.osvdb
|
114
|
+
say advisory.osvdb_id
|
115
|
+
elsif advisory.ghsa
|
116
|
+
say advisory.ghsa_id
|
117
|
+
end
|
118
|
+
|
119
|
+
say "Criticality: ", :red
|
120
|
+
case advisory.criticality
|
121
|
+
when :low then say "Low"
|
122
|
+
when :medium then say "Medium", :yellow
|
123
|
+
when :high then say "High", [:red, :bold]
|
124
|
+
else say "Unknown"
|
125
|
+
end
|
126
|
+
|
127
|
+
say "URL: ", :red
|
128
|
+
say advisory.url
|
129
|
+
|
130
|
+
if options.verbose?
|
131
|
+
say "Description:", :red
|
132
|
+
say
|
133
|
+
|
134
|
+
print_wrapped advisory.description, :indent => 2
|
135
|
+
say
|
136
|
+
else
|
137
|
+
|
138
|
+
say "Title: ", :red
|
139
|
+
say advisory.title
|
140
|
+
end
|
141
|
+
|
142
|
+
unless advisory.patched_versions.empty?
|
143
|
+
say "Solution: upgrade to ", :red
|
144
|
+
say advisory.patched_versions.join(', ')
|
145
|
+
else
|
146
|
+
say "Solution: ", :red
|
147
|
+
say "remove or disable this gem until a patch is available!", [:red, :bold]
|
148
|
+
end
|
149
|
+
|
150
|
+
say
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013-2019 Hal Brodigan (postmodern.mod3 at gmail.com)
|
3
|
+
#
|
4
|
+
# bundler-audit is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# bundler-audit is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with bundler-audit. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'bundler/audit/advisory'
|
19
|
+
|
20
|
+
require 'time'
|
21
|
+
require 'yaml'
|
22
|
+
|
23
|
+
module Bundler
|
24
|
+
module Audit
|
25
|
+
#
|
26
|
+
# Represents the directory of advisories, grouped by gem name
|
27
|
+
# and CVE number.
|
28
|
+
#
|
29
|
+
class Database
|
30
|
+
|
31
|
+
# Git URL of the ruby-advisory-db
|
32
|
+
URL = 'https://github.com/rubysec/ruby-advisory-db.git'
|
33
|
+
|
34
|
+
# Default path to the ruby-advisory-db
|
35
|
+
VENDORED_PATH = File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','data','ruby-advisory-db'))
|
36
|
+
|
37
|
+
# Timestamp for when the database was last updated
|
38
|
+
VENDORED_TIMESTAMP = Time.parse(File.read("#{VENDORED_PATH}.ts")).utc
|
39
|
+
|
40
|
+
# Path to the user's copy of the ruby-advisory-db
|
41
|
+
USER_PATH = File.expand_path(File.join(ENV['HOME'],'.local','share','ruby-advisory-db'))
|
42
|
+
|
43
|
+
# The path to the advisory database
|
44
|
+
attr_reader :path
|
45
|
+
|
46
|
+
#
|
47
|
+
# Initializes the Advisory Database.
|
48
|
+
#
|
49
|
+
# @param [String] path
|
50
|
+
# The path to the advisory database.
|
51
|
+
#
|
52
|
+
# @raise [ArgumentError]
|
53
|
+
# The path was not a directory.
|
54
|
+
#
|
55
|
+
def initialize(path=self.class.path)
|
56
|
+
unless File.directory?(path)
|
57
|
+
raise(ArgumentError,"#{path.dump} is not a directory")
|
58
|
+
end
|
59
|
+
|
60
|
+
@path = path
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# The default path for the database.
|
65
|
+
#
|
66
|
+
# @return [String]
|
67
|
+
# The path to the database directory.
|
68
|
+
#
|
69
|
+
def self.path
|
70
|
+
if File.directory?(USER_PATH)
|
71
|
+
t1 = Dir.chdir(USER_PATH) { Time.parse(`git log --date=iso8601 --pretty="%cd" -1`) }
|
72
|
+
t2 = VENDORED_TIMESTAMP
|
73
|
+
|
74
|
+
if t1 >= t2 then USER_PATH
|
75
|
+
else VENDORED_PATH
|
76
|
+
end
|
77
|
+
else
|
78
|
+
VENDORED_PATH
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Updates the ruby-advisory-db.
|
84
|
+
#
|
85
|
+
# @param [Boolean, quiet]
|
86
|
+
# Specify whether `git` should be `--quiet`.
|
87
|
+
#
|
88
|
+
# @return [Boolean, nil]
|
89
|
+
# Specifies whether the update was successful.
|
90
|
+
# A `nil` indicates no update was performed.
|
91
|
+
#
|
92
|
+
# @note
|
93
|
+
# Requires network access.
|
94
|
+
#
|
95
|
+
# @since 0.3.0
|
96
|
+
#
|
97
|
+
def self.update!(options={})
|
98
|
+
raise "Invalid option(s)" unless (options.keys - [:quiet]).empty?
|
99
|
+
if File.directory?(USER_PATH)
|
100
|
+
if File.directory?(File.join(USER_PATH, ".git"))
|
101
|
+
Dir.chdir(USER_PATH) do
|
102
|
+
command = %w(git pull --no-rebase)
|
103
|
+
command << '--quiet' if options[:quiet]
|
104
|
+
command << 'origin' << 'master'
|
105
|
+
system *command
|
106
|
+
end
|
107
|
+
end
|
108
|
+
else
|
109
|
+
command = %w(git clone)
|
110
|
+
command << '--quiet' if options[:quiet]
|
111
|
+
command << URL << USER_PATH
|
112
|
+
system *command
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# Enumerates over every advisory in the database.
|
118
|
+
#
|
119
|
+
# @yield [advisory]
|
120
|
+
# If a block is given, it will be passed each advisory.
|
121
|
+
#
|
122
|
+
# @yieldparam [Advisory] advisory
|
123
|
+
# An advisory from the database.
|
124
|
+
#
|
125
|
+
# @return [Enumerator]
|
126
|
+
# If no block is given, an Enumerator will be returned.
|
127
|
+
#
|
128
|
+
def advisories(&block)
|
129
|
+
return enum_for(__method__) unless block_given?
|
130
|
+
|
131
|
+
each_advisory_path do |path|
|
132
|
+
yield Advisory.load(path)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
#
|
137
|
+
# Enumerates over advisories for the given gem.
|
138
|
+
#
|
139
|
+
# @param [String] name
|
140
|
+
# The gem name to lookup.
|
141
|
+
#
|
142
|
+
# @yield [advisory]
|
143
|
+
# If a block is given, each advisory for the given gem will be yielded.
|
144
|
+
#
|
145
|
+
# @yieldparam [Advisory] advisory
|
146
|
+
# An advisory for the given gem.
|
147
|
+
#
|
148
|
+
# @return [Enumerator]
|
149
|
+
# If no block is given, an Enumerator will be returned.
|
150
|
+
#
|
151
|
+
def advisories_for(name)
|
152
|
+
return enum_for(__method__,name) unless block_given?
|
153
|
+
|
154
|
+
each_advisory_path_for(name) do |path|
|
155
|
+
yield Advisory.load(path)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
#
|
160
|
+
# Verifies whether the gem is effected by any advisories.
|
161
|
+
#
|
162
|
+
# @param [Gem::Specification] gem
|
163
|
+
# The gem to verify.
|
164
|
+
#
|
165
|
+
# @yield [advisory]
|
166
|
+
# If a block is given, it will be passed advisories that effect
|
167
|
+
# the gem.
|
168
|
+
#
|
169
|
+
# @yieldparam [Advisory] advisory
|
170
|
+
# An advisory that effects the specific version of the gem.
|
171
|
+
#
|
172
|
+
# @return [Enumerator]
|
173
|
+
# If no block is given, an Enumerator will be returned.
|
174
|
+
#
|
175
|
+
def check_gem(gem)
|
176
|
+
return enum_for(__method__,gem) unless block_given?
|
177
|
+
|
178
|
+
advisories_for(gem.name) do |advisory|
|
179
|
+
if advisory.vulnerable?(gem.version)
|
180
|
+
yield advisory
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
#
|
186
|
+
# The number of advisories within the database.
|
187
|
+
#
|
188
|
+
# @return [Integer]
|
189
|
+
# The number of advisories.
|
190
|
+
#
|
191
|
+
def size
|
192
|
+
each_advisory_path.count
|
193
|
+
end
|
194
|
+
|
195
|
+
#
|
196
|
+
# Converts the database to a String.
|
197
|
+
#
|
198
|
+
# @return [String]
|
199
|
+
# The path to the database.
|
200
|
+
#
|
201
|
+
def to_s
|
202
|
+
@path
|
203
|
+
end
|
204
|
+
|
205
|
+
#
|
206
|
+
# Inspects the database.
|
207
|
+
#
|
208
|
+
# @return [String]
|
209
|
+
# The inspected database.
|
210
|
+
#
|
211
|
+
def inspect
|
212
|
+
"#<#{self.class}:#{self}>"
|
213
|
+
end
|
214
|
+
|
215
|
+
protected
|
216
|
+
|
217
|
+
#
|
218
|
+
# Enumerates over every advisory path in the database.
|
219
|
+
#
|
220
|
+
# @yield [path]
|
221
|
+
# The given block will be passed each advisory path.
|
222
|
+
#
|
223
|
+
# @yieldparam [String] path
|
224
|
+
# A path to an advisory `.yml` file.
|
225
|
+
#
|
226
|
+
def each_advisory_path(&block)
|
227
|
+
Dir.glob(File.join(@path,'gems','*','*.yml'),&block)
|
228
|
+
end
|
229
|
+
|
230
|
+
#
|
231
|
+
# Enumerates over the advisories for the given gem.
|
232
|
+
#
|
233
|
+
# @param [String] name
|
234
|
+
# The gem of the gem.
|
235
|
+
#
|
236
|
+
# @yield [path]
|
237
|
+
# The given block will be passed each advisory path.
|
238
|
+
#
|
239
|
+
# @yieldparam [String] path
|
240
|
+
# A path to an advisory `.yml` file.
|
241
|
+
#
|
242
|
+
def each_advisory_path_for(name,&block)
|
243
|
+
Dir.glob(File.join(@path,'gems',name,'*.yml'),&block)
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|