holepicker 0.3.0 → 0.3.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.
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