holepicker 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog.markdown CHANGED
@@ -1,3 +1,7 @@
1
+ #### Version 0.3.1 (20.05.2013)
2
+
3
+ * stdin option
4
+
1
5
  #### Version 0.3.0 (13.04.2013)
2
6
 
3
7
  * silent option
@@ -7,10 +11,12 @@
7
11
  #### Version 0.2.2 (29.03.2013)
8
12
 
9
13
  * fixed Capistrano recipe
14
+ * updated Devise vulnerability info
10
15
 
11
16
  #### Version 0.2.1 (21.03.2013)
12
17
 
13
18
  * added possibility to display additional notes about specific vulnerabilities (see data.json)
19
+ * added multi_xml, httparty, extlib, crack and nori vulnerabilities
14
20
 
15
21
  #### Version 0.2.0 (7.03.2013)
16
22
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- holepicker (0.3.0)
4
+ holepicker (0.3.1)
5
5
  json (>= 1.7.7)
6
6
  rainbow (>= 1.1.4)
7
7
 
data/README.markdown CHANGED
@@ -6,7 +6,7 @@ HolePicker is a Ruby gem for quickly checking all your `Gemfile.lock` files for
6
6
   
7
7
  [![Build Status](https://travis-ci.org/jsuder/holepicker.png?branch=master)](https://travis-ci.org/jsuder/holepicker)
8
8
   
9
- [![Code Climate](https://codeclimate.com/github/jsuder/rails-retweeter-bot.png)](https://codeclimate.com/github/jsuder/rails-retweeter-bot)
9
+ [![Code Climate](https://codeclimate.com/github/jsuder/holepicker.png)](https://codeclimate.com/github/jsuder/holepicker)
10
10
 
11
11
  ## The story
12
12
 
@@ -119,7 +119,7 @@ There are a few other projects with a similar purpose, take a look if HolePicker
119
119
  * [bundler-audit](https://github.com/postmodern/bundler-audit) - lets you scan the project in current directory
120
120
  * [bundler-organization_audit](https://github.com/grosser/bundler-organization_audit) - scans all your projects on GitHub
121
121
  * [ruby-advisory-db](https://github.com/rubysec/ruby-advisory-db) - a shared database of vulnerabilities - I'll try to integrate holepicker with it later
122
- * [gemcanary](https://gemcanary.com/) - some kind of web service, not released yet (as of 23.02)
122
+ * [gemcanary](https://gemcanary.com/) - a web service that notifies you by email when a new vulnerability is found in a gem used by one of your apps
123
123
  * [gems-status](https://github.com/jordimassaguerpla/gems-status) - a more general tool for checking everything that might be wrong with your gems (work in progress)
124
124
 
125
125
  ## Credits & contributing
data/bin/holepicker CHANGED
@@ -39,6 +39,10 @@ OptionParser.new do |opts|
39
39
  HolePicker.logger.level = Logger::ERROR
40
40
  end
41
41
 
42
+ opts.on("--stdin", "Read a gemfile directly from STDIN instead of paths given in arguments") do
43
+ options[:stdin] = true
44
+ end
45
+
42
46
  opts.on("-h", "--help", "Display this help") do
43
47
  HolePicker.logger.info(opts)
44
48
  exit
@@ -52,7 +56,7 @@ OptionParser.new do |opts|
52
56
  opts.parse!
53
57
  end
54
58
 
55
- if ARGV.empty?
59
+ if ARGV.empty? && !options[:stdin]
56
60
  HolePicker.logger.error "Please choose at least one directory to scan for gemfiles."
57
61
  exit 1
58
62
  end
@@ -0,0 +1,17 @@
1
+ require 'holepicker/gem'
2
+
3
+ module HolePicker
4
+ class GemfileParser
5
+ GEM_PATTERN = %r(^ {4}[^ ])
6
+
7
+ def initialize(ignored_gems = nil)
8
+ @ignored_gems = ignored_gems || []
9
+ end
10
+
11
+ def parse_gemfile(data)
12
+ gem_lines = data.lines.select { |l| l =~ GEM_PATTERN }
13
+ gems = gem_lines.map { |l| Gem.new(l) }
14
+ gems.reject { |g| @ignored_gems.include?(g.name) }
15
+ end
16
+ end
17
+ end
@@ -30,11 +30,14 @@ module HolePicker
30
30
 
31
31
  module HasLogger
32
32
  def logger
33
- HolePicker.logger
33
+ @logger ||= HolePicker.logger
34
34
  end
35
35
 
36
36
  def self.included(c)
37
- c.extend(self)
37
+ c.class_eval do
38
+ attr_writer :logger
39
+ extend HasLogger
40
+ end
38
41
  end
39
42
  end
40
43
 
@@ -0,0 +1,73 @@
1
+ require 'holepicker/logger'
2
+ require 'holepicker/utils'
3
+ require 'set'
4
+
5
+ module HolePicker
6
+ class ScanReporter
7
+ include HasLogger
8
+
9
+ attr_reader :safe_gemfiles, :vulnerable_gems, :vulnerable_gemfiles, :vulnerabilities
10
+
11
+ def initialize
12
+ @safe_gemfiles = []
13
+ @vulnerable_gemfiles = []
14
+ @vulnerable_gems = []
15
+ @vulnerabilities = Set.new
16
+ end
17
+
18
+ def add_vulnerable_gem(gem, vulnerabilities)
19
+ @vulnerabilities.merge(vulnerabilities)
20
+ @vulnerable_gems << gem
21
+ end
22
+
23
+ def add_vulnerable_gemfile(path)
24
+ @vulnerable_gemfiles << path
25
+ end
26
+
27
+ def add_safe_gemfile(path)
28
+ @safe_gemfiles << path
29
+ end
30
+
31
+ def success?
32
+ @vulnerable_gems.empty?
33
+ end
34
+
35
+ def print_report
36
+ if success?
37
+ if @safe_gemfiles.empty?
38
+ logger.warn "No gemfiles found - are you sure the paths are correct?"
39
+ else
40
+ logger.info "No vulnerabilities found."
41
+ end
42
+ else
43
+ gem_count = @vulnerable_gems.length
44
+ gemfile_count = @vulnerable_gemfiles.length
45
+
46
+ gems = Utils.pluralize(gem_count, 'gem')
47
+ gemfiles = Utils.pluralize(gemfile_count, 'gemfile')
48
+
49
+ logger.fail "#{gem_count} vulnerable #{gems} found in #{gemfile_count} #{gemfiles}!\n"
50
+
51
+ report_vulnerabilities
52
+ print_notes if @vulnerabilities.any?(&:note)
53
+ end
54
+ end
55
+
56
+
57
+ private
58
+
59
+ def report_vulnerabilities
60
+ @vulnerabilities.sort_by(&:id).each do |v|
61
+ logger.error "[#{v.tag}] #{v.day}: #{v.url}"
62
+ end
63
+ end
64
+
65
+ def print_notes
66
+ logger.error
67
+
68
+ @vulnerabilities.select(&:note).each do |v|
69
+ logger.error "[#{v.tag}] #{v.note}"
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,22 +1,21 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'holepicker/gem'
4
3
  require 'holepicker/config_gemfile_finder'
5
4
  require 'holepicker/direct_gemfile_finder'
5
+ require 'holepicker/gemfile_parser'
6
6
  require 'holepicker/logger'
7
7
  require 'holepicker/offline_database'
8
8
  require 'holepicker/online_database'
9
+ require 'holepicker/scan_reporter'
9
10
  require 'holepicker/utils'
10
- require 'set'
11
11
 
12
12
  module HolePicker
13
13
  class Scanner
14
14
  include HasLogger
15
15
 
16
- GEMFILE_GEM_PATTERN = %r(^ {4}[^ ])
17
-
18
16
  def initialize(paths, options = {})
19
17
  @paths = paths.is_a?(Array) ? paths : [paths]
18
+ @stdin = options[:stdin]
20
19
 
21
20
  @database = options[:offline] ? OfflineDatabase.load : OnlineDatabase.load
22
21
 
@@ -29,22 +28,23 @@ module HolePicker
29
28
  )
30
29
  end
31
30
 
32
- @ignored = options[:ignored_gems] || []
31
+ @parser = GemfileParser.new(options[:ignored_gems])
33
32
  end
34
33
 
35
34
  def scan
36
- logger.info "Looking for gemfiles..."
35
+ @reporter = ScanReporter.new
37
36
 
38
- @found_vulnerabilities = Set.new
39
- @scanned_gemfiles = 0
40
- @matched_gemfiles = 0
41
- @matched_gems = 0
37
+ if @stdin
38
+ scan_gemfile(STDIN.read, nil)
39
+ else
40
+ logger.info "Looking for gemfiles..."
42
41
 
43
- @paths.each { |p| scan_path(p) }
42
+ @paths.each { |p| scan_path(p) }
43
+ end
44
44
 
45
- print_report
45
+ @reporter.print_report
46
46
 
47
- @matched_gems == 0
47
+ @reporter.success?
48
48
  end
49
49
 
50
50
 
@@ -54,68 +54,38 @@ module HolePicker
54
54
  @database.vulnerabilities.select { |v| v.gem_vulnerable?(gem) }
55
55
  end
56
56
 
57
- def read_gemfile(path)
58
- File.readlines(path).select { |l| l =~ GEMFILE_GEM_PATTERN }.map { |l| Gem.new(l) }
59
- end
60
-
61
57
  def scan_path(path)
62
- @finder.find_gemfiles(path).each { |f| scan_gemfile(f) }
58
+ @finder.find_gemfiles(path).each { |f| scan_gemfile(File.read(f), f) }
63
59
  end
64
60
 
65
- def scan_gemfile(path)
66
- gems = read_gemfile(path)
67
- gems.delete_if { |g| @ignored.include?(g.name) }
61
+ def scan_gemfile(data, path)
62
+ gems = @parser.parse_gemfile(data)
68
63
 
69
64
  vulnerable_gems = gems.map { |g| [g, vulnerabilities_for_gem(g)] }
70
65
  vulnerable_gems.delete_if { |g, v| v.empty? }
71
66
 
72
67
  count = vulnerable_gems.length
68
+ label = path || "Scanning gemfile"
73
69
 
74
70
  if count == 0
75
- logger.print "#{path}: "
71
+ logger.print "#{label}: "
76
72
  logger.success "✔"
73
+
74
+ @reporter.add_safe_gemfile(path)
77
75
  else
78
- logger.print "#{path}: ", Logger::ERROR
76
+ logger.print "#{label}: ", Logger::ERROR
79
77
  logger.fail "#{count} vulnerable #{Utils.pluralize(count, 'gem')} found!"
80
78
 
81
79
  vulnerable_gems.each do |gem, vulnerabilities|
82
80
  logger.error "- #{gem} [#{vulnerabilities.map(&:tag).join(',')}]"
83
81
 
84
- @found_vulnerabilities.merge(vulnerabilities)
85
- @matched_gems += 1
82
+ @reporter.add_vulnerable_gem(gem, vulnerabilities)
86
83
  end
87
84
 
88
- @matched_gemfiles += 1
85
+ @reporter.add_vulnerable_gemfile(path)
89
86
 
90
87
  logger.error
91
88
  end
92
-
93
- @scanned_gemfiles += 1
94
- end
95
-
96
- def print_report
97
- if @scanned_gemfiles == 0
98
- logger.warn "No gemfiles found - are you sure the paths are correct?"
99
- elsif @matched_gemfiles == 0
100
- logger.info "No vulnerabilities found."
101
- else
102
- gems = Utils.pluralize(@matched_gems, 'gem')
103
- gemfiles = Utils.pluralize(@matched_gemfiles, 'gemfile')
104
-
105
- logger.fail "#{@matched_gems} vulnerable #{gems} found in #{@matched_gemfiles} #{gemfiles}!\n"
106
-
107
- @found_vulnerabilities.sort_by(&:id).each do |v|
108
- logger.error "[#{v.tag}] #{v.day}: #{v.url}"
109
- end
110
-
111
- if @found_vulnerabilities.any?(&:note)
112
- logger.error
113
-
114
- @found_vulnerabilities.select(&:note).each do |v|
115
- logger.error "[#{v.tag}] #{v.note}"
116
- end
117
- end
118
- end
119
89
  end
120
90
  end
121
91
  end
@@ -1,7 +1,7 @@
1
1
  require 'rubygems'
2
2
 
3
3
  module HolePicker
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
 
6
6
  def self.version
7
7
  ::Gem::Version.new(VERSION)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: holepicker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-13 00:00:00.000000000 Z
12
+ date: 2013-05-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
@@ -63,9 +63,11 @@ files:
63
63
  - lib/holepicker/direct_gemfile_finder.rb
64
64
  - lib/holepicker/file_finder.rb
65
65
  - lib/holepicker/gem.rb
66
+ - lib/holepicker/gemfile_parser.rb
66
67
  - lib/holepicker/logger.rb
67
68
  - lib/holepicker/offline_database.rb
68
69
  - lib/holepicker/online_database.rb
70
+ - lib/holepicker/scan_reporter.rb
69
71
  - lib/holepicker/scanner.rb
70
72
  - lib/holepicker/utils.rb
71
73
  - lib/holepicker/version.rb