holepicker 0.1

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ holepicker (0.1)
5
+ json (>= 1.7.7)
6
+ rainbow (>= 1.1.4)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ json (1.7.7)
12
+ rainbow (1.1.4)
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ holepicker!
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Jakub Suder
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,94 @@
1
+ # HolePicker
2
+
3
+ HolePicker is a Ruby gem for quickly checking all your `Gemfile.lock` files for gem versions with known vulnerabilities.
4
+
5
+
6
+ ## The story
7
+
8
+ The beginning of 2013 was a [really bad time](http://www.kalzumeus.com/2013/01/31/what-the-rails-security-issue-means-for-your-startup/) for the Ruby community. In the first few weeks of the year at least 7 serious security issues were found, and Rails had to be updated 4 times so far because of this. It's probably not the end. It's hard to keep track of all the issues and remember which gem versions are OK and which aren't, especially if you have several older and newer Ruby or Rails projects to maintain. So I wrote this tool in order to help with identifying which gems in your projects' gemfiles need to be updated.
9
+
10
+
11
+ ## Details
12
+
13
+ The idea is that there is a [JSON file](https://github.com/psionides/holepicker/blob/master/lib/holepicker/data/data.json)\* stored in this repository that lists all the recent security-related updates to popular gems: date of the release, URL of the announcement, and a list of affected gems and updated versions. HolePicker provides a command line tool that **downloads the latest data file from GitHub every time**, scans your `Gemfile.lock` files and checks if they contain vulnerable gem versions.
14
+
15
+ The reason I've done it this way is to make it easier to run the checks against the very latest version of the vulnerability list. It's kind of important to be sure that you haven't missed any last minute updates, and it would be annoying to have to check for new gem versions every time you want to run the tool (and you might not even remember to do that).
16
+
17
+ If for some reason you don't want to download the JSON file every time, you can use the [`-o` option](#full-option-list). Also, the JSON file specifies the minimum compatible gem version that it can work with, so if new kind of information is added to the file that requires the gem to be updated in order to parse it, the gem will let you know.
18
+
19
+ Of course the whole system still relies on me manually adding entries to the JSON file and pushing it to GitHub. I'll try to do that quickly, my trusty [@rails_bot](https://github.com/psionides/rails-retweeter-bot) notifies me pretty quickly when something really bad is happening. If for some reason I don't update the list in time, by all means please send me a pull request.
20
+
21
+ (\*) YAML obviously wouldn't be appropriate, if you know what I mean.
22
+
23
+
24
+ ## Running the tool
25
+
26
+ To install the tool, just run:
27
+
28
+ gem install holepicker
29
+
30
+ There are two main modes of operation:
31
+
32
+ ### Scanning projects directly
33
+
34
+ This can be used to scan project directories on your development machine:
35
+
36
+ holepicker ~/Projects
37
+
38
+ You can also scan all apps deployed to a production or demo server; in this case, it's recommended to use the `-c` (`--current`) option in order to skip the old releases in `releases` directories and only scan the `current` directories (I'm assuming you use Capistrano for deployment, because who doesn't?).
39
+
40
+ holepicker -c /var/www
41
+
42
+ ### Scanning Nginx/Apache config directory
43
+
44
+ You might have a lot of random apps deployed in the `/var/www` directory, but only some of them currently enabled in the Nginx config files. In this case, you might want to only check the apps that are actually running. To do that, use the `-f` (`--follow-roots`) option and point HolePicker to your HTTP server's config directory. It will find all the `root` or `DocumentRoot` directives and follow the paths to find the gemfiles of enabled apps.
45
+
46
+ holepicker -f /etc/nginx/sites-enabled
47
+
48
+
49
+ ## Results
50
+
51
+ This is more or less what you will get if you run HolePicker in a directory with some old Rails projects:
52
+
53
+ ![screenshot](http://f.cl.ly/items/1l3C2c2s0r1k3v033B34/Screen%20Shot%202013-02-16%20at%2001.43.39.png)
54
+
55
+
56
+ ## Full option list
57
+
58
+ `-a`, `--all`
59
+
60
+ By default, HolePicker will skip directories like `.git`, `tmp`, `cached-copy` etc. when searching for gemfiles. This option turns this feature off.
61
+
62
+ `-c`, `--current`
63
+
64
+ Look only for gemfiles that are located directly in a `current` directory.
65
+
66
+ `-f`, `--follow-roots`
67
+
68
+ Look for `root`/`DocumentRoot` directives in config files at given locations instead of gemfiles directly.
69
+
70
+ `-i`, `--ignore gem1,gem2,gem3`
71
+
72
+ Ignore the gems passed in the parameter.
73
+
74
+ `-o`, `--offline`
75
+
76
+ Use an offline copy of the data file - useful if you really need to run the tool, but the network or GitHub is down.
77
+
78
+
79
+ ## Similar projects
80
+
81
+ The [bundler-audit](https://github.com/postmodern/bundler-audit) project that was also created this week has a similar purpose, but it only uses an offline issue list and it only scans the current project.
82
+
83
+ The [gemcanary](https://gemcanary.com/) project might be something similar, but it hasn't been released yet (as of 16.02).
84
+
85
+ It might make sense to agree on a shared list of vulnerabilities in the future that these and other projects could share - no point having the same information in a few different places maintained by a few people in parallel.
86
+
87
+
88
+ ## Credits & contributing
89
+
90
+ Created by [Jakub Suder](http://psionides.eu), licensed under MIT License.
91
+
92
+ Any feedback and help is welcome, if you have an idea how to improve this tool, let me know or send me an issue or a pull request.
93
+
94
+ And BTW, big thanks to all the smart people that find and fix all these issues - I hope you won't find much more, but please keep looking.
data/bin/holepicker ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'holepicker'
7
+ require 'optparse'
8
+
9
+ options = {}
10
+
11
+ OptionParser.new do |opts|
12
+ opts.banner = "Usage: #{File.basename($0)} [options] paths..."
13
+
14
+ opts.on("-a", "--all", "Don't skip directories like .git or tmp while looking for gemfiles") do
15
+ options[:dont_skip] = true
16
+ end
17
+
18
+ opts.on("-c", "--current", "Look for gemfiles only in 'current' directories") do
19
+ options[:current] = true
20
+ end
21
+
22
+ opts.on("-f", "--follow-roots", "Follow root/DocumentRoot paths in Nginx/Apache configs to find gemfiles") do
23
+ options[:follow_roots] = true
24
+ end
25
+
26
+ opts.on("-i", "--ignore gem1,gem2,gem3", Array, "Ignore given gems") do |names|
27
+ options[:ignored_gems] = names
28
+ end
29
+
30
+ opts.on("-o", "--offline", "Use an offline copy of the data.json file") do
31
+ options[:offline] = true
32
+ end
33
+
34
+ opts.on("-h", "--help", "Display this help") do
35
+ puts opts
36
+ exit
37
+ end
38
+
39
+ opts.on("-v", "--version", "Print gem version") do
40
+ puts HolePicker::VERSION
41
+ exit
42
+ end
43
+
44
+ opts.parse!
45
+ end
46
+
47
+ if ARGV.empty?
48
+ abort "Please choose at least one directory to scan for gemfiles."
49
+ end
50
+
51
+ success = HolePicker::Scanner.new(ARGV, options).scan
52
+
53
+ exit(success ? 0 : 1)
@@ -0,0 +1,54 @@
1
+ {
2
+ "min_version": "0.1",
3
+ "vulnerabilities": [
4
+ {
5
+ "gems": {
6
+ "rails": ["3.2.12", "3.1.11", "2.3.17"]
7
+ },
8
+ "url": "http://weblog.rubyonrails.org/2013/2/11/SEC-ANN-Rails-3-2-12-3-1-11-and-2-3-17-have-been-released/",
9
+ "date": "2013-02-11T18:40Z"
10
+ },
11
+ {
12
+ "gems": {
13
+ "json": ["1.7.7", "1.6.8", "1.5.5"]
14
+ },
15
+ "url": "https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-security/4_YvCpLzL58",
16
+ "date": "2013-02-11T18:26Z"
17
+ },
18
+ {
19
+ "gems": {
20
+ "rack": ["1.5.2", "1.4.5", "1.3.10", "1.2.8", "1.1.6"]
21
+ },
22
+ "url": "http://rack.github.com/",
23
+ "date": "2013-02-08T03:14Z"
24
+ },
25
+ {
26
+ "gems": {
27
+ "rails": ["3.0.20", "2.3.16"]
28
+ },
29
+ "url": "http://weblog.rubyonrails.org/2013/1/28/Rails-3-0-20-and-2-3-16-have-been-released/",
30
+ "date": "2013-01-28T21:08Z"
31
+ },
32
+ {
33
+ "gems": {
34
+ "devise": ["2.2.3", "2.1.3", "2.0.5", "1.5.4"]
35
+ },
36
+ "url": "http://blog.plataformatec.com.br/2013/01/security-announcement-devise-v2-2-3-v2-1-3-v2-0-5-and-v1-5-3-released/",
37
+ "date": "2013-01-28T15:03Z"
38
+ },
39
+ {
40
+ "gems": {
41
+ "rails": ["3.2.11", "3.1.10", "3.0.19", "2.3.15"]
42
+ },
43
+ "url": "http://weblog.rubyonrails.org/2013/1/8/Rails-3-2-11-3-1-10-3-0-19-and-2-3-15-have-been-released/",
44
+ "date": "2013-01-08T20:26Z"
45
+ },
46
+ {
47
+ "gems": {
48
+ "rails": ["3.2.10", "3.1.9", "3.0.18", "2.3.15"]
49
+ },
50
+ "url": "http://weblog.rubyonrails.org/2013/1/2/Rails-3-2-10--3-1-9--and-3-0-18-have-been-released/",
51
+ "date": "2013-01-02T21:39Z"
52
+ }
53
+ ]
54
+ }
@@ -0,0 +1,22 @@
1
+ require 'holepicker/vulnerability'
2
+ require 'json'
3
+ require 'rubygems'
4
+
5
+ module HolePicker
6
+ class Database
7
+ attr_reader :vulnerabilities
8
+
9
+ def self.load_from_json_file(data)
10
+ new(JSON.parse(data))
11
+ end
12
+
13
+ def initialize(json)
14
+ @vulnerabilities = json['vulnerabilities'].reverse.map { |v| Vulnerability.new(v) }
15
+ @min_version = ::Gem::Version.new(json['min_version'])
16
+ end
17
+
18
+ def compatible?
19
+ HolePicker.version >= @min_version
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+
3
+ module HolePicker
4
+ class Gem
5
+ GEM_LINE_PATTERN = /([\w\-]+) \(([^)]+)\)/
6
+
7
+ attr_reader :name, :version
8
+
9
+ def initialize(line)
10
+ result = line.match(GEM_LINE_PATTERN)
11
+ raise "Invalid gem format: #{line}" unless result
12
+
13
+ @name = result[1]
14
+ @version = ::Gem::Version.new(result[2])
15
+ end
16
+
17
+ def to_s
18
+ "#{name} (#{version})"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ require 'holepicker/database'
2
+
3
+ module HolePicker
4
+ class OfflineDatabase < Database
5
+ OFFLINE_JSON_FILE = File.expand_path('../data/data.json', __FILE__)
6
+
7
+ def self.load
8
+ load_from_json_file(File.read(OFFLINE_JSON_FILE))
9
+ rescue Exception => e
10
+ puts "Can't load local data file: #{e}"
11
+ exit 1
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,56 @@
1
+ require 'holepicker/database'
2
+ require 'holepicker/utils'
3
+ require 'net/http'
4
+
5
+ module HolePicker
6
+ class OnlineDatabase < Database
7
+ # TODO temporary link
8
+ URL='http://pastie.org/pastes/6183429/download?key=qryhowarb9i7hoqqyvy0q'
9
+
10
+ def self.load
11
+ puts "Fetching list of vulnerabilities..."
12
+
13
+ load_from_json_file(http_get(URL)).tap do |db|
14
+ db.check_compatibility
15
+ db.report_new_vulnerabilities
16
+ end
17
+ rescue SystemExit
18
+ raise
19
+ rescue Exception => e
20
+ puts "Can't download latest data file: #{e}"
21
+ exit 1
22
+ end
23
+
24
+ def self.http_get(url)
25
+ uri = URI(url)
26
+ http = Net::HTTP.new(uri.host, uri.port)
27
+ http.use_ssl = url.start_with?('https')
28
+
29
+ response = http.get(uri.request_uri)
30
+ response.body
31
+ end
32
+
33
+ def check_compatibility
34
+ unless compatible?
35
+ puts "You need to upgrade holepicker to version #{@min_version} or later."
36
+ exit 1
37
+ end
38
+ end
39
+
40
+ def report_new_vulnerabilities
41
+ new_vulnerabilities = @vulnerabilities.select(&:recent?)
42
+ count = new_vulnerabilities.length
43
+
44
+ if count > 0
45
+ puts "#{count} new #{Utils.pluralize(count, 'vulnerability')} found in the last " +
46
+ "#{Vulnerability::NEW_VULNERABILITY_DAYS} days:"
47
+
48
+ new_vulnerabilities.each do |v|
49
+ puts "#{v.day} (#{v.gem_names.join(', ')}): #{v.url}"
50
+ end
51
+
52
+ puts
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,128 @@
1
+ require 'holepicker/gem'
2
+ require 'holepicker/offline_database'
3
+ require 'holepicker/online_database'
4
+ require 'holepicker/utils'
5
+ require 'rainbow'
6
+ require 'set'
7
+
8
+ module HolePicker
9
+ class Scanner
10
+ SKIPPED_DIRECTORIES = ["-name cached-copy", "-path '*/bundle/ruby'", "-name tmp", "-name '.*'"]
11
+ ROOT_LINE_PATTERN = %r{\b(?:root|DocumentRoot)\s+(.*)/public\b}
12
+ GEMFILE_GEM_PATTERN = %r(^ {4}[^ ])
13
+
14
+ def initialize(paths, options = {})
15
+ @paths = paths.is_a?(Array) ? paths : [paths]
16
+
17
+ @database = options[:offline] ? OfflineDatabase.load : OnlineDatabase.load
18
+
19
+ @ignored = options[:ignored_gems] || []
20
+ @skip = !options[:dont_skip]
21
+ @current = options[:current]
22
+ @roots = options[:follow_roots]
23
+ end
24
+
25
+ def scan
26
+ puts "Looking for gemfiles..."
27
+
28
+ @found_vulnerabilities = Set.new
29
+ @matched_gemfiles = 0
30
+ @matched_gems = 0
31
+
32
+ @paths.each { |p| scan_path(p) }
33
+
34
+ print_report
35
+
36
+ @matched_gems == 0
37
+ end
38
+
39
+
40
+ private
41
+
42
+ def vulnerabilities_for_gem(gem)
43
+ @database.vulnerabilities.select { |v| v.gem_vulnerable?(gem) }
44
+ end
45
+
46
+ def find_gemfiles_in_path(path)
47
+ skips = SKIPPED_DIRECTORIES.join(" -or ")
48
+ gemfiles = @current ? "-path '*/current/Gemfile.lock'" : "-name 'Gemfile.lock'"
49
+
50
+ command = if @skip
51
+ "find -L #{path} \\( #{skips} \\) -prune -or #{gemfiles} -print"
52
+ else
53
+ "find -L #{path} #{gemfiles}"
54
+ end
55
+
56
+ run_and_read_lines(command)
57
+ end
58
+
59
+ def find_gemfiles_in_configs(path)
60
+ configs = run_and_read_lines("find -L #{path} -type f -or -type l")
61
+ configs = select_existing(configs)
62
+
63
+ directories = configs.map { |f| File.read(f).scan(ROOT_LINE_PATTERN) }
64
+ gemfiles = directories.flatten.map { |dir| "#{dir}/Gemfile.lock" }
65
+
66
+ select_existing(gemfiles)
67
+ end
68
+
69
+ def read_gemfile(path)
70
+ File.readlines(path).select { |l| l =~ GEMFILE_GEM_PATTERN }.map { |l| Gem.new(l) }
71
+ end
72
+
73
+ def scan_path(path)
74
+ gemfiles = @roots ? find_gemfiles_in_configs(path) : find_gemfiles_in_path(path)
75
+ gemfiles.each { |f| scan_gemfile(f) }
76
+ end
77
+
78
+ def scan_gemfile(path)
79
+ print "#{path}: "
80
+
81
+ gems = read_gemfile(path)
82
+ gems.delete_if { |g| @ignored.include?(g.name) }
83
+
84
+ vulnerable_gems = gems.map { |g| [g, vulnerabilities_for_gem(g)] }
85
+ vulnerable_gems.delete_if { |g, v| v.empty? }
86
+
87
+ count = vulnerable_gems.length
88
+
89
+ if count == 0
90
+ puts "OK"
91
+ else
92
+ puts "#{count} vulnerable #{Utils.pluralize(count, 'gem')} found!".color(:red)
93
+
94
+ vulnerable_gems.each do |gem, vulnerabilities|
95
+ puts "- #{gem} [#{vulnerabilities.map(&:tag).join(',')}]"
96
+
97
+ @found_vulnerabilities.merge(vulnerabilities)
98
+ @matched_gems += 1
99
+ end
100
+
101
+ @matched_gemfiles += 1
102
+
103
+ puts
104
+ end
105
+ end
106
+
107
+ def print_report
108
+ if @matched_gemfiles == 0
109
+ puts "No vulnerabilities found."
110
+ else
111
+ puts ("#{@matched_gems} vulnerable #{Utils.pluralize(@matched_gems, 'gem')} found in " +
112
+ "#{@matched_gemfiles} #{Utils.pluralize(@matched_gemfiles, 'gemfile')}!").color(:red) + "\n\n"
113
+
114
+ @found_vulnerabilities.sort_by(&:id).each do |v|
115
+ puts "[#{v.tag}] #{v.day}: #{v.url}"
116
+ end
117
+ end
118
+ end
119
+
120
+ def select_existing(files)
121
+ files.select { |f| File.exist?(f) }
122
+ end
123
+
124
+ def run_and_read_lines(command)
125
+ %x(#{command}).lines.map(&:strip)
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,11 @@
1
+ module HolePicker
2
+ module Utils
3
+ def self.pluralize(count, name)
4
+ if count == 1
5
+ name
6
+ else
7
+ name.gsub(/y$/, 'ie') + 's'
8
+ end
9
+ end
10
+ end
11
+ end
File without changes
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+
3
+ module HolePicker
4
+ VERSION = "0.1"
5
+
6
+ def self.version
7
+ ::Gem::Version.new(VERSION)
8
+ end
9
+ end
@@ -0,0 +1,66 @@
1
+ require 'rubygems'
2
+ require 'time'
3
+
4
+ module HolePicker
5
+ class Vulnerability
6
+ NEW_VULNERABILITY_DAYS = 7
7
+ NEW_VULNERABILITY_TIME = NEW_VULNERABILITY_DAYS * 86400
8
+
9
+ attr_reader :id, :date, :url, :gems
10
+
11
+ def self.next_id
12
+ @@count ||= 0
13
+ @@count += 1
14
+ end
15
+
16
+ def initialize(json)
17
+ @gems = {}
18
+
19
+ json['gems'].each do |name, versions|
20
+ @gems[name] = versions.map { |v| ::Gem::Version.new(v) }
21
+ end
22
+
23
+ @id = self.class.next_id
24
+ @url = json['url']
25
+ @date = Time.parse(json['date'])
26
+ end
27
+
28
+ def day
29
+ @date.strftime("%Y-%m-%d")
30
+ end
31
+
32
+ def recent?
33
+ date > Time.now - NEW_VULNERABILITY_TIME
34
+ end
35
+
36
+ def tag
37
+ "##{@id}"
38
+ end
39
+
40
+ def gem_names
41
+ @gems.keys
42
+ end
43
+
44
+ def gem_vulnerable?(gem)
45
+ !gem_safe?(gem)
46
+ end
47
+
48
+ def gem_safe?(gem)
49
+ fixes = @gems[gem.name]
50
+ !fixes || fixes.any? { |fix| fix_included?(fix, gem) } || fixes.all? { |fix| gem.version > fix }
51
+ end
52
+
53
+
54
+ private
55
+
56
+ def fix_included?(fix, gem)
57
+ gem.version == fix || (gem.version > fix && same_level?(fix, gem))
58
+ end
59
+
60
+ def same_level?(fix, gem)
61
+ segments_count = fix.segments.length
62
+
63
+ fix.segments[0...segments_count-1] == gem.version.segments[0...segments_count-1]
64
+ end
65
+ end
66
+ end
data/lib/holepicker.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'holepicker/scanner'
2
+ require 'holepicker/version'
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: holepicker
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jakub Suder
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.7.7
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.7.7
30
+ - !ruby/object:Gem::Dependency
31
+ name: rainbow
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.1.4
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.1.4
46
+ description:
47
+ email: jakub.suder@gmail.com
48
+ executables:
49
+ - holepicker
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - MIT-LICENSE.txt
54
+ - README.markdown
55
+ - Changelog.markdown
56
+ - Gemfile
57
+ - Gemfile.lock
58
+ - lib/holepicker/data/data.json
59
+ - lib/holepicker/database.rb
60
+ - lib/holepicker/gem.rb
61
+ - lib/holepicker/offline_database.rb
62
+ - lib/holepicker/online_database.rb
63
+ - lib/holepicker/scanner.rb
64
+ - lib/holepicker/utils.rb
65
+ - lib/holepicker/validator.rb
66
+ - lib/holepicker/version.rb
67
+ - lib/holepicker/vulnerability.rb
68
+ - lib/holepicker.rb
69
+ - bin/holepicker
70
+ homepage: http://github.com/psionides/holepicker
71
+ licenses: []
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 1.8.24
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: A tool for checking gem versions in Gemfile.lock files for known vulnerabilities
94
+ test_files: []