capistrano-ssh-doctor 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7f6a315084d957611956b98eb45770af4d663d31
4
+ data.tar.gz: 2ed9041723f8508c57e4e54d2166fee521d67dc9
5
+ SHA512:
6
+ metadata.gz: 736cb8e50188ecd0dc1144a7cd0d3624e5adbfd878623ad2f725ab3d7154aec681b6cfc19bda5d53154f098dc663743b8ba225d79c4bcc9a168bf3ab4d42774d
7
+ data.tar.gz: 67a494421f56b50a120a3527d9af164d9e40cdc37cf3f4f212ece7203705ffdf480a4fde641c19a07d286f787136fd3a3fd9820b374d6d0663126d583ebfc8ef
File without changes
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2014 Bruno Sutic
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the "Software"),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included
11
+ in all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
19
+ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,116 @@
1
+ # Capistrano SSH Doctor
2
+
3
+ This plugin helps you setup and debug `ssh-agent` forwarding for Capistrano
4
+ deployment.
5
+
6
+ It's created to complement the official [capistrano authentication guide](http://capistranorb.com/documentation/getting-started/authentication-and-authorisation/).
7
+
8
+ The following is presumed:
9
+ - you're using `git`
10
+ - you want to use passwordless ssh login to the servers
11
+ - you want to use the `ssh-agent` forwarding strategy for checking out code in
12
+ the remote repository (btw. good choice, it's a least hassle)
13
+
14
+ The plugin will report errors (and offer steps to solution) if you deviate from
15
+ this configuration. The above assumptions should hold true for 98% users.
16
+
17
+ `capistrano-ssh-doctor` works only with Capistrano **3+**.
18
+
19
+ ### Who should use it?
20
+
21
+ The plugin is made for beginners and users that are not sure if their setup is
22
+ good, so they want to confirm or debug it.
23
+
24
+ If you have enough knowldge/experience with `ssh` tool and you're sure you have
25
+ `ssh-agent` forwarding working for your server, you probably don't need this
26
+ plugin.
27
+
28
+ ### Installation
29
+
30
+ Put the following in your application's `Gemfile`:
31
+
32
+ group :development do
33
+ gem 'capistrano', '~> 3.1'
34
+ gem 'capistrano-ssh-doctor'
35
+ end
36
+
37
+ Then run in the console:
38
+
39
+ $ bundle install
40
+
41
+ Put the following in `Capfile` file:
42
+
43
+ require 'capistrano/ssh_doctor'
44
+
45
+ ### Usage
46
+
47
+ This plugin is intended to be used **before** any deployment task.
48
+
49
+ In the console run:
50
+
51
+ $ bundle exec cap production ssh:doctor
52
+
53
+ The plugin will perform a number of checks and output a report at the end.
54
+
55
+ **Solving Errors**
56
+
57
+ In case there are errors in your setup, specific instructions for next
58
+ steps will be provided in report output.
59
+
60
+ **Important:** errors should be tackled in the order of their output. So, if
61
+ you got errors 2, 5 and 7 in the report, start by solving error 2.
62
+
63
+ It is very probable that "solving" one or two initial errors will actually make
64
+ everything work. A lot of the checks are inter-dependent. So don't be
65
+ discouraged if you see a lot of the errors in the beginning.
66
+
67
+ Once you solved a problem, run the `ssh:doctor` task again to see the
68
+ progress.
69
+
70
+ Repeat the process until `ssh:doctor` task reports success for all the
71
+ tasks. You're ok with proceeding with the deployment then.
72
+
73
+ ### Which checks are performed?
74
+
75
+ 1. checks that you're using `git` repository protocol
76
+ 2. checks that ssh private key file exists locally
77
+ 3. checks if `ssh-agent` process is running locally
78
+ 4. checks that `ssh-add` process can communicate with `ssh-agent`
79
+ 5. checks that ssh private keys are loaded to `ssh-agent`
80
+ 6. checks that remote code repository is accessible from local machine
81
+ 7. checks passwordless ssh login is used for all servers
82
+ 8. checks `forward_agent` capistrano option is set to `true` for all servers
83
+ 9. checks `ssh-agent` is actually forwared to all the servers
84
+ 10. checks remote code repository is accessible from all the servers
85
+
86
+ You'll see the results for all the checks in the output of `ssh:doctor`
87
+ task.
88
+
89
+ ### More Capistrano automation?
90
+
91
+ If you'd like to streamline your Capistrano deploys, you might want to check
92
+ these zero-configuration, plug-n-play plugins:
93
+
94
+ - [capistrano-unicorn-nginx](https://github.com/bruno-/capistrano-unicorn-nginx)<br/>
95
+ no-configuration unicorn and nginx setup with sensible defaults
96
+ - [capistrano-postgresql](https://github.com/bruno-/capistrano-postgresql)<br/>
97
+ plugin that automates postgresql configuration and setup
98
+ - [capistrano-rbenv-install](https://github.com/bruno-/capistrano-rbenv-install)<br/>
99
+ would you like Capistrano to install rubies for you automatically?
100
+ - [capistrano-safe-deploy-to](https://github.com/bruno-/capistrano-safe-deploy-to)<br/>
101
+ if you're annoyed that Capistrano does **not** create a deployment path for the
102
+ app on the server (default `/var/www/myapp`), this is what you need!
103
+
104
+ ### Contributing and bug reports
105
+
106
+ If you got stuck at some point and really can't find a solution, please open a
107
+ [github issue](/issues) and maybe I can help you.
108
+
109
+ Also, I can use your problem to improve this plugin.
110
+
111
+ ### License
112
+
113
+ [MIT](LICENSE.md)
114
+
115
+ # TODO
116
+ - do not store text in report hash, store only success/fail there
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'capistrano/ssh_doctor/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'capistrano-ssh-doctor'
8
+ gem.version = Capistrano::SshDoctor::VERSION
9
+ gem.authors = ['Bruno Sutic']
10
+ gem.email = ['bruno.sutic@gmail.com']
11
+ gem.description = <<-EOF.gsub(/^\s+/, '')
12
+ This plugin helps you setup and debug `ssh-doctor` forwarding for Capistrano
13
+ deployment.
14
+
15
+ It peforms a number of checks on the local machine as well as on the
16
+ servers. Report output with suggested next steps is provided in case there
17
+ are any errors with the setup.
18
+ EOF
19
+ gem.summary = 'This plugin helps you setup and debug `ssh-doctor` forwarding for Capistrano deployment.'
20
+ gem.homepage = 'https://github.com/bruno-/capistrano-ssh-doctor'
21
+
22
+ gem.license = 'MIT'
23
+
24
+ gem.files = `git ls-files`.split($/)
25
+ gem.require_paths = ['lib']
26
+
27
+ gem.add_dependency 'capistrano', '>= 3.1'
28
+
29
+ gem.add_development_dependency 'rake'
30
+ end
File without changes
@@ -0,0 +1 @@
1
+ load File.expand_path('../tasks/ssh_doctor.rake', __FILE__)
@@ -0,0 +1,14 @@
1
+ require_relative 'report'
2
+
3
+ module Capistrano
4
+ module SshDoctor
5
+ module DSL
6
+
7
+ def report
8
+ Capistrano::SshDoctor::Report.report
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ self.extend Capistrano::SshDoctor::DSL
@@ -0,0 +1,67 @@
1
+ require_relative 'report/messages'
2
+
3
+ module Capistrano
4
+ module SshDoctor
5
+ class Report
6
+
7
+ include Capistrano::SshDoctor::Report::Messages
8
+
9
+ def self.report
10
+ @report ||= new
11
+ end
12
+
13
+ def initialize
14
+ @report_messages = default_messages
15
+ end
16
+
17
+ def report_error_for(key, hosts=nil)
18
+ error_message = send(key + "_error", hosts)
19
+ set_error(key.to_sym, error_message)
20
+ end
21
+
22
+ def print
23
+ print_header
24
+ @report_messages.each_with_index do |(key, message), index|
25
+ print_message(index + 1, message)
26
+ end
27
+ print_footer
28
+ end
29
+
30
+ private
31
+
32
+ def set_error(key, message)
33
+ @report_messages[key] = [ :error, message ]
34
+ end
35
+
36
+ def has_errors?
37
+ @report_messages.any? {|key, value| value[0] == :error }
38
+ end
39
+
40
+ def print_header
41
+ puts
42
+ puts "SSH agent forwarding report"
43
+ puts "---------------------------"
44
+ puts
45
+ end
46
+
47
+ def print_message(index, message)
48
+ puts "#{index}. [#{message[0]}] #{message[1]}"
49
+ puts
50
+ end
51
+
52
+ def print_footer
53
+ puts "----------------------"
54
+ puts
55
+ if has_errors?
56
+ puts "It seems SSH agent forwarding is not set up correctly."
57
+ puts "Follow the suggested steps described in error messages."
58
+ puts "Errors (if more than one) are ordered by importance, so always start with the first one."
59
+ else
60
+ puts "It seems SSH agent forwarding is set up correctly!"
61
+ puts "You can continue with the deployment process."
62
+ end
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,168 @@
1
+ module Capistrano
2
+ module SshDoctor
3
+ class Report
4
+ module Messages
5
+
6
+ def default_messages
7
+ {
8
+ config_repo_url: [
9
+ :success, '`repo_url` setting ok'
10
+ ],
11
+ local_private_key_exists: [
12
+ :success, 'ssh private key file exists'
13
+ ],
14
+ local_agent_running_env_var: [
15
+ :success, '`ssh-agent` process seems to be running locally'
16
+ ],
17
+ local_agent_running_ssh_add: [
18
+ :success, '`ssh-agent` process recognized by `ssh-add` command'
19
+ ],
20
+ local_keys_added_to_agent: [
21
+ :success, 'ssh private keys added to `ssh-agent`'
22
+ ],
23
+ local_repo_access: [
24
+ :success, 'application repository accessible from local machine'
25
+ ],
26
+ config_password: [
27
+ :success, 'all hosts using passwordless login'
28
+ ],
29
+ config_agent_forwarding: [
30
+ :success, '`forward_agent` ok for all hosts'
31
+ ],
32
+ remote_agent_running: [
33
+ :success, 'ssh agent successfully forwarded to remote hosts'
34
+ ],
35
+ remote_repo_access: [
36
+ :success, 'application repository accessible from remote hosts'
37
+ ]
38
+ }
39
+ end
40
+
41
+ def config_repo_url_error(_)
42
+ <<-EOF.gsub(/^\s+/, '')
43
+ It seems the git repository url in `repo_url` setting uses https
44
+ protocol. Https protocol prompts for password and so git protocol
45
+ should be used.
46
+
47
+ Actions:
48
+ - change `repo_url` setting in `config/deploy.rb` file to use git protocol.
49
+ Example for github: `git@github.com:username/repo.git`
50
+ EOF
51
+ end
52
+
53
+ def config_password_error(hosts)
54
+ msg = "It seems Capistrano connects to the following hosts using password login:\n"
55
+ msg << hosts.map(&:to_s).join(', ')
56
+ msg.concat "\n"
57
+ msg.concat <<-EOF.gsub(/^\s+/, '')
58
+ It is strongly suggested to use passwordless ssh login.
59
+
60
+ Actions:
61
+ - make sure you're *not* using password to connect to any of the servers.
62
+ - remove any password setting from `ssh_options` in Capistrano stage files
63
+ (e.g. `config/deploy/production.rb`).
64
+ By removing password configuration - the default, passwordless ssh
65
+ connection will be used.
66
+ - setup passwordless ssh connection for your servers
67
+ http://askubuntu.com/questions/4830/easiest-way-to-copy-ssh-keys-to-another-machine/4833#4833
68
+ EOF
69
+ end
70
+
71
+ def config_agent_forwarding_error(hosts)
72
+ msg = "It seems Capistrano connects without ssh agent forwarding to the following hosts:\n"
73
+ msg << hosts.join(', ')
74
+ msg.concat "\n"
75
+ msg.concat <<-EOF.gsub(/^\s+/, '')
76
+ Actions:
77
+ - make sure Capistrano uses the default ssh option for `forward_agent`.
78
+ Just remove any `forward_agent` setting from the stage file (e.g.
79
+ `config/deploy/production.rb`) and the default, `true` value will be used.
80
+ EOF
81
+ end
82
+
83
+ def local_private_key_exists_error(_)
84
+ <<-EOF.gsub(/^\s+/, '')
85
+ Uh, oh. It seems you do not have ssh private keys generated, or they're
86
+ not located in standard location.
87
+
88
+ Actions:
89
+ - here's a good guide how to generate ssh private keys and set them
90
+ up with github
91
+ https://help.github.com/articles/generating-ssh-keys
92
+ EOF
93
+ end
94
+
95
+ def local_agent_running_env_var_error(_)
96
+ <<-EOF.gsub(/^\s+/, '')
97
+ It seems `ssh-agent` is not running on local machine.
98
+
99
+ Actions:
100
+ - follow this guide
101
+ http://mah.everybody.org/docs/ssh
102
+ EOF
103
+ end
104
+
105
+ def local_agent_running_ssh_add_error(_)
106
+ <<-EOF.gsub(/^\s+/, '')
107
+ It seems ssh-add cannot make a connection with ssh-agent process
108
+ on local machine.
109
+
110
+ Actions:
111
+ - are you sure all the previous checks are passing? Make sure all
112
+ the above checks are successful before trying to make this one
113
+ pass
114
+ - try adding ssh keys to ssh-agent by executing
115
+ $ ssh-add ~/.ssh/id_rsa
116
+ - if the above does not work follow this guide to setup ssh-agent process
117
+ http://mah.everybody.org/docs/ssh
118
+ EOF
119
+ end
120
+
121
+ def local_keys_added_to_agent_error(_)
122
+ <<-EOF.gsub(/^\s+/, '')
123
+ It seems local ssh-agent process has no loaded keys.
124
+
125
+ Actions:
126
+ - add ssh private key to ssh-agent with this command
127
+ $ ssh-add /path/to/ssh_private_key
128
+ If ssh private key is in a standard location, then you most likely need this
129
+ $ ssh-add ~/.ssh/id_rsa
130
+ EOF
131
+ end
132
+
133
+ def local_repo_access_error(_)
134
+ <<-EOF.gsub(/^\s+/, '')
135
+ It seems git application repository cannot be accessed from local machine.
136
+
137
+ Actions:
138
+ - here's a guide to setting passwordless access to github repositories.
139
+ You should most likely follow just steps 3 and 4 from the guide if
140
+ all the previous checks are successful.
141
+ https://help.github.com/articles/generating-ssh-keys#step-3-add-your-ssh-key-to-github
142
+ EOF
143
+ end
144
+
145
+ def remote_agent_running_error(hosts)
146
+ msg = "It seems Capistrano did not succeed in making ssh agent forwarding for these hosts:\n"
147
+ msg << hosts.join(', ')
148
+ msg.concat "\n"
149
+ msg.concat <<-EOF.gsub(/^\s+/, '')
150
+ Actions:
151
+ - make sure all the previous checks pass
152
+ EOF
153
+ end
154
+
155
+ def remote_repo_access_error(hosts)
156
+ msg = "It seems Capistrano cannot access application git repository from these hosts:\n"
157
+ msg << hosts.join(', ')
158
+ msg.concat "\n"
159
+ msg.concat <<-EOF.gsub(/^\s+/, '')
160
+ Actions:
161
+ - make sure all the previous checks pass. That should make this one work too.
162
+ EOF
163
+ end
164
+
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,5 @@
1
+ module Capistrano
2
+ module SshDoctor
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,117 @@
1
+ require 'capistrano/ssh_doctor/dsl'
2
+
3
+ namespace :ssh do
4
+
5
+ namespace :config do
6
+
7
+ task :git do
8
+ unless fetch(:scm) == :git
9
+ puts 'It seems you are NOT using git as a Capistrano strategy. At the moment capistrano-ssh-doctor supports only git.'
10
+ puts 'Please change `scm` setting to `:git`.'
11
+ exit 1
12
+ end
13
+ end
14
+
15
+ task :repo_url do
16
+ if fetch(:repo_url) =~ /^http/
17
+ report.report_error_for('config_repo_url')
18
+ end
19
+ end
20
+
21
+ task :password do
22
+ hosts = []
23
+ on release_roles :all do
24
+ if host.netssh_options[:password]
25
+ hosts << host
26
+ end
27
+ end
28
+ report.report_error_for('config_password', hosts) if hosts.any?
29
+ end
30
+
31
+ task :agent_forwarding do
32
+ hosts = []
33
+ on release_roles :all do
34
+ unless host.netssh_options[:forward_agent]
35
+ hosts << host
36
+ end
37
+ end
38
+ report.report_error_for('config_agent_forwarding', hosts) if hosts.any?
39
+ end
40
+
41
+ end
42
+
43
+ namespace :local do
44
+
45
+ task :private_key_exists do
46
+ specified_keys = fetch(:ssh_options, {})[:keys] || ''
47
+ unless File.exists?(File.expand_path('~/.ssh/id_rsa')) ||
48
+ File.exists?(File.expand_path('~/.ssh/id_dsa')) ||
49
+ File.exists?(specified_keys)
50
+ report.report_error_for('local_private_key_exists')
51
+ end
52
+ end
53
+
54
+ task :agent_running_env_var do
55
+ unless ENV.include?('SSH_AUTH_SOCK')
56
+ report.report_error_for('local_agent_running_env_var')
57
+ end
58
+ end
59
+
60
+ task :agent_running_ssh_add do
61
+ if !system('ssh-add -l')
62
+ if $? == 2
63
+ report.report_error_for('local_agent_running_ssh_add')
64
+ elsif $? == 1
65
+ report.report_error_for('local_keys_added_to_agent')
66
+ end
67
+ end
68
+ end
69
+
70
+ task :repo_access do
71
+ unless system({ 'GIT_ASKPASS' => '/bin/echo' }, "git ls-remote #{fetch(:repo_url)}")
72
+ report.report_error_for('local_repo_access')
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ namespace :remote do
79
+
80
+ task :agent_running do
81
+ hosts = []
82
+ on release_roles :all do
83
+ if capture(:echo, '$SSH_AUTH_SOCK').empty?
84
+ hosts << host
85
+ end
86
+ end
87
+ report.report_error_for('remote_agent_running', hosts) if hosts.any?
88
+ end
89
+
90
+ task repo_access: :'git:wrapper' do
91
+ hosts = []
92
+ on release_roles :all do
93
+ with fetch(:git_environmental_variables) do
94
+ hosts << host unless strategy.check
95
+ end
96
+ end
97
+ report.report_error_for('remote_repo_access', hosts) if hosts.any?
98
+ end
99
+
100
+ end
101
+
102
+ desc 'Perform ssh doctor checks'
103
+ task :doctor do
104
+ invoke 'ssh:config:git'
105
+ invoke 'ssh:config:repo_url'
106
+ invoke 'ssh:config:password'
107
+ invoke 'ssh:config:agent_forwarding'
108
+ invoke 'ssh:local:private_key_exists'
109
+ invoke 'ssh:local:agent_running_env_var'
110
+ invoke 'ssh:local:agent_running_ssh_add'
111
+ invoke 'ssh:local:repo_access'
112
+ invoke 'ssh:remote:agent_running'
113
+ invoke 'ssh:remote:repo_access'
114
+ report.print
115
+ end
116
+
117
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-ssh-doctor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Bruno Sutic
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capistrano
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: |
42
+ This plugin helps you setup and debug `ssh-doctor` forwarding for Capistrano
43
+ deployment.
44
+ It peforms a number of checks on the local machine as well as on the
45
+ servers. Report output with suggested next steps is provided in case there
46
+ are any errors with the setup.
47
+ email:
48
+ - bruno.sutic@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - CHANGELOG.md
54
+ - LICENSE.md
55
+ - README.md
56
+ - Rakefile
57
+ - capistrano-ssh-doctor.gemspec
58
+ - lib/capistrano-ssh-doctor.rb
59
+ - lib/capistrano/ssh_doctor.rb
60
+ - lib/capistrano/ssh_doctor/dsl.rb
61
+ - lib/capistrano/ssh_doctor/report.rb
62
+ - lib/capistrano/ssh_doctor/report/messages.rb
63
+ - lib/capistrano/ssh_doctor/version.rb
64
+ - lib/capistrano/tasks/ssh_doctor.rake
65
+ homepage: https://github.com/bruno-/capistrano-ssh-doctor
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 2.1.5
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: This plugin helps you setup and debug `ssh-doctor` forwarding for Capistrano
89
+ deployment.
90
+ test_files: []