holepicker 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog.markdown CHANGED
@@ -1,3 +1,9 @@
1
+ #### Version 0.3.0 (13.04.2013)
2
+
3
+ * silent option
4
+ * no-color option
5
+ * added vulnerabilities for ftpd, dragonfly, rdoc
6
+
1
7
  #### Version 0.2.2 (29.03.2013)
2
8
 
3
9
  * fixed Capistrano recipe
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- holepicker (0.2.2)
4
+ holepicker (0.3.0)
5
5
  json (>= 1.7.7)
6
6
  rainbow (>= 1.1.4)
7
7
 
data/README.markdown CHANGED
@@ -53,6 +53,24 @@ You might have a lot of random apps deployed in the `/var/www` directory, but on
53
53
  holepicker -f /etc/nginx/sites-enabled
54
54
 
55
55
 
56
+ ## Results
57
+
58
+ This is more or less what you will get if you run HolePicker in a directory with some old Rails projects:
59
+
60
+ ![screenshot](http://f.cl.ly/items/1l3C2c2s0r1k3v033B34/Screen%20Shot%202013-02-16%20at%2001.43.39.png)
61
+
62
+
63
+ ## Running on app startup
64
+
65
+ If you want to check your gems when your app is started, add HolePicker to your Gemfile and then call `HolePicker::Scanner#scan` in a file that's loaded at app startup (e.g. in Rails projects you can add an initializer in `config/initializers`):
66
+
67
+ ```rb
68
+ HolePicker::Scanner.new('Gemfile.lock').scan or abort
69
+ ```
70
+
71
+ You may want to pass `:offline` or `:ignored_gems` options or change logger settings too - see [`bin/holepicker` source](https://github.com/jsuder/holepicker/blob/master/bin/holepicker) for more info.
72
+
73
+
56
74
  ## Integration with capistrano
57
75
 
58
76
  To automatically check for vulnerabilities before deployment, you can add the HolePicker Capistrano recipe:
@@ -62,12 +80,6 @@ To automatically check for vulnerabilities before deployment, you can add the Ho
62
80
 
63
81
  This will introduce a `cap holepicker` task which will be executed before the deploy.
64
82
 
65
- ## Results
66
-
67
- This is more or less what you will get if you run HolePicker in a directory with some old Rails projects:
68
-
69
- ![screenshot](http://f.cl.ly/items/1l3C2c2s0r1k3v033B34/Screen%20Shot%202013-02-16%20at%2001.43.39.png)
70
-
71
83
 
72
84
  ## Full option list
73
85
 
@@ -87,16 +99,24 @@ Look for `root`/`DocumentRoot` directives in config files at given locations ins
87
99
 
88
100
  Ignore the gems passed in the parameter.
89
101
 
102
+ `--no-color`
103
+
104
+ Disable output coloring (by default green is used for good gemfiles and red is used for bad gemfiles and errors).
105
+
90
106
  `-o`, `--offline`
91
107
 
92
108
  Use an offline copy of the data file - useful if you really need to run the tool, but the network or GitHub is down.
93
109
 
110
+ `-s`, `--silent`
111
+
112
+ Silent mode - disable info-level messages ("Looking for gemfiles...") and only print errors and found vulnerabilities.
113
+
94
114
 
95
115
  ## Similar projects
96
116
 
97
117
  There are a few other projects with a similar purpose, take a look if HolePicker isn't exactly what you need:
98
118
 
99
- * [bundler-audit](https://github.com/postmodern/bundler-audit) - scans the current project when the app is loaded
119
+ * [bundler-audit](https://github.com/postmodern/bundler-audit) - lets you scan the project in current directory
100
120
  * [bundler-organization_audit](https://github.com/grosser/bundler-organization_audit) - scans all your projects on GitHub
101
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
102
122
  * [gemcanary](https://gemcanary.com/) - some kind of web service, not released yet (as of 23.02)
data/bin/holepicker CHANGED
@@ -27,17 +27,25 @@ OptionParser.new do |opts|
27
27
  options[:ignored_gems] = names
28
28
  end
29
29
 
30
+ opts.on("--no-color", "Disable output coloring") do
31
+ HolePicker.logger.color = false
32
+ end
33
+
30
34
  opts.on("-o", "--offline", "Use an offline copy of the data.json file") do
31
35
  options[:offline] = true
32
36
  end
33
37
 
38
+ opts.on("-s", "--silent", "Silent mode - disable info-level logging, only print errors") do
39
+ HolePicker.logger.level = Logger::ERROR
40
+ end
41
+
34
42
  opts.on("-h", "--help", "Display this help") do
35
- puts opts
43
+ HolePicker.logger.info(opts)
36
44
  exit
37
45
  end
38
46
 
39
47
  opts.on("-v", "--version", "Print gem version") do
40
- puts HolePicker::VERSION
48
+ HolePicker.logger.info(HolePicker::VERSION)
41
49
  exit
42
50
  end
43
51
 
@@ -45,7 +53,8 @@ OptionParser.new do |opts|
45
53
  end
46
54
 
47
55
  if ARGV.empty?
48
- abort "Please choose at least one directory to scan for gemfiles."
56
+ HolePicker.logger.error "Please choose at least one directory to scan for gemfiles."
57
+ exit 1
49
58
  end
50
59
 
51
60
  success = HolePicker::Scanner.new(ARGV, options).scan
data/lib/holepicker.rb CHANGED
@@ -1,2 +1,3 @@
1
+ require 'holepicker/logger'
1
2
  require 'holepicker/scanner'
2
3
  require 'holepicker/version'
@@ -9,6 +9,20 @@
9
9
  "date": "2013-03-18T17:21Z",
10
10
  "note": "Warning: there are several issues with Rails 3.2.13, affecting view performance and other things; see http://blog.bugsnag.com/2013/03/20/rails-3-2-13-performance-regressions-major-bugs/ for more info."
11
11
  },
12
+ {
13
+ "gems": {
14
+ "ftpd": ["0.2.2"]
15
+ },
16
+ "url": "http://seclists.org/bugtraq/2013/Mar/10",
17
+ "date": "2013-03-03T05:45Z"
18
+ },
19
+ {
20
+ "gems": {
21
+ "dragonfly": ["0.9.14"]
22
+ },
23
+ "url": "https://groups.google.com/d/msg/dragonfly-users/3c3WIU3VQTo/ccasejdDjcAJ",
24
+ "date": "2013-02-19T08:39Z"
25
+ },
12
26
  {
13
27
  "gems": {
14
28
  "rails": ["3.2.12", "3.1.11", "2.3.17"]
@@ -31,6 +45,13 @@
31
45
  "url": "http://rack.github.com/",
32
46
  "date": "2013-02-08T03:14Z"
33
47
  },
48
+ {
49
+ "gems": {
50
+ "rdoc": ["4.0.0.rc.2", "3.12.1", "3.9.5"]
51
+ },
52
+ "url": "http://rdoc.rubyforge.org/CVE-2013-0256_rdoc.html",
53
+ "date": "2013-02-07T05:49Z"
54
+ },
34
55
  {
35
56
  "gems": {
36
57
  "rails": ["3.0.20", "2.3.16"]
@@ -50,7 +71,7 @@
50
71
  "httparty": ["0.10.0"],
51
72
  "extlib": ["0.9.16"],
52
73
  "crack": ["0.3.2"],
53
- "nori": ["2.0.2", "1.1.4", "1.0.3"]
74
+ "nori": ["2.0.3", "1.1.4", "1.0.3"]
54
75
  },
55
76
  "url": "https://support.cloud.engineyard.com/entries/22915701-January-14-2013-Security-vulnerabilities-httparty-extlib-crack-nori-Update-these-gems-immediately",
56
77
  "date": "2013-01-15T13:10Z"
@@ -0,0 +1,44 @@
1
+ require 'logger'
2
+ require 'rainbow'
3
+
4
+ module HolePicker
5
+ class Logger < ::Logger
6
+ attr_accessor :color
7
+
8
+ def initialize(io)
9
+ super
10
+ self.level = INFO
11
+ self.color = true
12
+ end
13
+
14
+ def format_message(level, datetime, progname, message)
15
+ progname == 'print' ? message.to_s : "#{message}\n"
16
+ end
17
+
18
+ def print(message, level = INFO)
19
+ add(level, message, 'print')
20
+ end
21
+
22
+ def fail(message)
23
+ error(color ? message.color(:red) : message)
24
+ end
25
+
26
+ def success(message)
27
+ info(color ? message.color(:green) : message)
28
+ end
29
+ end
30
+
31
+ module HasLogger
32
+ def logger
33
+ HolePicker.logger
34
+ end
35
+
36
+ def self.included(c)
37
+ c.extend(self)
38
+ end
39
+ end
40
+
41
+ def self.logger
42
+ @logger ||= Logger.new(STDOUT)
43
+ end
44
+ end
@@ -1,13 +1,16 @@
1
1
  require 'holepicker/database'
2
+ require 'holepicker/logger'
2
3
 
3
4
  module HolePicker
4
5
  class OfflineDatabase < Database
6
+ include HasLogger
7
+
5
8
  OFFLINE_JSON_FILE = File.expand_path('../data/data.json', __FILE__)
6
9
 
7
10
  def self.load
8
11
  load_from_json_file(File.read(OFFLINE_JSON_FILE))
9
12
  rescue Exception => e
10
- puts "Can't load local data file: #{e}"
13
+ logger.fail "Can't load local data file: #{e}"
11
14
  exit 1
12
15
  end
13
16
  end
@@ -1,26 +1,36 @@
1
1
  require 'holepicker/database'
2
+ require 'holepicker/logger'
2
3
  require 'holepicker/utils'
3
4
  require 'net/http'
4
5
  require 'net/https'
5
6
 
6
7
  module HolePicker
7
8
  class OnlineDatabase < Database
8
- URL='https://raw.github.com/jsuder/holepicker/master/lib/holepicker/data/data.json'
9
+ include HasLogger
10
+
11
+ URL = 'https://raw.github.com/jsuder/holepicker/master/lib/holepicker/data/data.json'
9
12
 
10
13
  def self.load
11
- puts "Fetching list of vulnerabilities..."
14
+ logger.info "Fetching list of vulnerabilities..."
12
15
 
13
- load_from_json_file(http_get(URL)).tap do |db|
14
- db.check_compatibility
15
- db.report_new_vulnerabilities
16
- end
16
+ load_from_json_file(http_get(URL))
17
17
  rescue SystemExit
18
18
  raise
19
19
  rescue Exception => e
20
- puts "Can't download latest data file: #{e}"
20
+ logger.fail "Can't download latest data file: #{e}"
21
21
  exit 1
22
22
  end
23
23
 
24
+ def initialize(json)
25
+ super
26
+
27
+ check_compatibility
28
+ report_new_vulnerabilities
29
+ end
30
+
31
+
32
+ private
33
+
24
34
  def self.http_get(url)
25
35
  uri = URI(url)
26
36
  http = Net::HTTP.new(uri.host, uri.port)
@@ -32,7 +42,7 @@ module HolePicker
32
42
 
33
43
  def check_compatibility
34
44
  unless compatible?
35
- puts "You need to upgrade holepicker to version #{@min_version} or later."
45
+ logger.fail "You need to upgrade holepicker to version #{@min_version} or later."
36
46
  exit 1
37
47
  end
38
48
  end
@@ -42,14 +52,14 @@ module HolePicker
42
52
  count = new_vulnerabilities.length
43
53
 
44
54
  if count > 0
45
- puts "#{count} new #{Utils.pluralize(count, 'vulnerability')} found in the last " +
55
+ logger.info "#{count} new #{Utils.pluralize(count, 'vulnerability')} found in the last " +
46
56
  "#{Vulnerability::NEW_VULNERABILITY_DAYS} days:"
47
57
 
48
58
  new_vulnerabilities.each do |v|
49
- puts "#{v.day} (#{v.gem_names.join(', ')}): #{v.url}"
59
+ logger.info "#{v.day} (#{v.gem_names.join(', ')}): #{v.url}"
50
60
  end
51
61
 
52
- puts
62
+ logger.info
53
63
  end
54
64
  end
55
65
  end
@@ -3,14 +3,16 @@
3
3
  require 'holepicker/gem'
4
4
  require 'holepicker/config_gemfile_finder'
5
5
  require 'holepicker/direct_gemfile_finder'
6
+ require 'holepicker/logger'
6
7
  require 'holepicker/offline_database'
7
8
  require 'holepicker/online_database'
8
9
  require 'holepicker/utils'
9
- require 'rainbow'
10
10
  require 'set'
11
11
 
12
12
  module HolePicker
13
13
  class Scanner
14
+ include HasLogger
15
+
14
16
  GEMFILE_GEM_PATTERN = %r(^ {4}[^ ])
15
17
 
16
18
  def initialize(paths, options = {})
@@ -31,7 +33,7 @@ module HolePicker
31
33
  end
32
34
 
33
35
  def scan
34
- puts "Looking for gemfiles..."
36
+ logger.info "Looking for gemfiles..."
35
37
 
36
38
  @found_vulnerabilities = Set.new
37
39
  @scanned_gemfiles = 0
@@ -61,8 +63,6 @@ module HolePicker
61
63
  end
62
64
 
63
65
  def scan_gemfile(path)
64
- print "#{path}: "
65
-
66
66
  gems = read_gemfile(path)
67
67
  gems.delete_if { |g| @ignored.include?(g.name) }
68
68
 
@@ -72,12 +72,14 @@ module HolePicker
72
72
  count = vulnerable_gems.length
73
73
 
74
74
  if count == 0
75
- puts "".color(:green)
75
+ logger.print "#{path}: "
76
+ logger.success "✔"
76
77
  else
77
- puts "#{count} vulnerable #{Utils.pluralize(count, 'gem')} found!".color(:red)
78
+ logger.print "#{path}: ", Logger::ERROR
79
+ logger.fail "#{count} vulnerable #{Utils.pluralize(count, 'gem')} found!"
78
80
 
79
81
  vulnerable_gems.each do |gem, vulnerabilities|
80
- puts "- #{gem} [#{vulnerabilities.map(&:tag).join(',')}]"
82
+ logger.error "- #{gem} [#{vulnerabilities.map(&:tag).join(',')}]"
81
83
 
82
84
  @found_vulnerabilities.merge(vulnerabilities)
83
85
  @matched_gems += 1
@@ -85,7 +87,7 @@ module HolePicker
85
87
 
86
88
  @matched_gemfiles += 1
87
89
 
88
- puts
90
+ logger.error
89
91
  end
90
92
 
91
93
  @scanned_gemfiles += 1
@@ -93,25 +95,24 @@ module HolePicker
93
95
 
94
96
  def print_report
95
97
  if @scanned_gemfiles == 0
96
- puts "No gemfiles found - are you sure the paths are correct?".color(:red)
98
+ logger.warn "No gemfiles found - are you sure the paths are correct?"
97
99
  elsif @matched_gemfiles == 0
98
- puts "No vulnerabilities found."
100
+ logger.info "No vulnerabilities found."
99
101
  else
100
102
  gems = Utils.pluralize(@matched_gems, 'gem')
101
103
  gemfiles = Utils.pluralize(@matched_gemfiles, 'gemfile')
102
104
 
103
- warning = "#{@matched_gems} vulnerable #{gems} found in #{@matched_gemfiles} #{gemfiles}!\n"
104
- puts warning.color(:red)
105
+ logger.fail "#{@matched_gems} vulnerable #{gems} found in #{@matched_gemfiles} #{gemfiles}!\n"
105
106
 
106
107
  @found_vulnerabilities.sort_by(&:id).each do |v|
107
- puts "[#{v.tag}] #{v.day}: #{v.url}"
108
+ logger.error "[#{v.tag}] #{v.day}: #{v.url}"
108
109
  end
109
110
 
110
111
  if @found_vulnerabilities.any?(&:note)
111
- puts
112
+ logger.error
112
113
 
113
114
  @found_vulnerabilities.select(&:note).each do |v|
114
- puts "[#{v.tag}] #{v.note}"
115
+ logger.error "[#{v.tag}] #{v.note}"
115
116
  end
116
117
  end
117
118
  end
@@ -1,7 +1,7 @@
1
1
  require 'rubygems'
2
2
 
3
3
  module HolePicker
4
- VERSION = "0.2.2"
4
+ VERSION = "0.3.0"
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.2.2
4
+ version: 0.3.0
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-03-29 00:00:00.000000000 Z
12
+ date: 2013-04-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
@@ -63,6 +63,7 @@ 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/logger.rb
66
67
  - lib/holepicker/offline_database.rb
67
68
  - lib/holepicker/online_database.rb
68
69
  - lib/holepicker/scanner.rb