zanzibar 0.1.27 → 0.2.0
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.
- checksums.yaml +8 -8
- data/.codeclimate.yml +21 -0
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +24 -0
- data/README.md +5 -1
- data/Rakefile +11 -1
- data/lib/zanzibar.rb +97 -138
- data/lib/zanzibar/actions/base.rb +6 -0
- data/lib/zanzibar/actions/bundle.rb +32 -13
- data/lib/zanzibar/actions/get.rb +18 -2
- data/lib/zanzibar/actions/init.rb +6 -1
- data/lib/zanzibar/cli.rb +25 -4
- data/lib/zanzibar/client.rb +91 -0
- data/lib/zanzibar/defaults.rb +19 -9
- data/lib/zanzibar/ui.rb +19 -0
- data/lib/zanzibar/version.rb +2 -1
- data/spec/lib/zanzibar/actions/bundle_spec.rb +9 -9
- data/spec/lib/zanzibar_spec.rb +8 -8
- data/zanzibar.gemspec +5 -5
- metadata +11 -8
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YWI3MWY3ZGUyNzM2ZWI1MjU1NzBmNzE3YTdkYzdmZWE0ZDA3YTg0ZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NDBmNGY5OGUwZDhkYzZjMjY0ZTJlYmE0ZDAyMzU3Yjk1MWQyYzEwMA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZWM3MzZhM2MwYjI5MzY2ZTg1Y2YxMzk1Y2NkYTk2NmM3MzJjNDIyYjc1NDI3
|
10
|
+
ZWZiZTIxOGUxYmRkZWZjMmVjYzMzMzAyMzQ3MjI5MDBkMzkxNGQ2OGRiOGY4
|
11
|
+
ZmU3OTRlNWYxYjcxN2I0ZjU5OWNlNDYzZDM3YjNlZTBhM2FhY2Y=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZThhZjY3YzM3ZjBjMTUwNjYwMjQzOTkwNTNkZmY0ZTNiZDY4NDVhOWIzZjRj
|
14
|
+
Mjk1Njg4OTJmZmVhNGFjZjAwYTFhM2VmOTE1NzU5MDU3ZDkwOTE0ODZkMGNm
|
15
|
+
YTA0NDc5ZTlhODY0Nzc1NmI3Y2I0YmJlYzEyNjA5ZmUwYWY2MjA=
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
---
|
2
|
+
engines:
|
3
|
+
bundler-audit:
|
4
|
+
enabled: false
|
5
|
+
duplication:
|
6
|
+
enabled: true
|
7
|
+
config:
|
8
|
+
languages:
|
9
|
+
- ruby
|
10
|
+
fixme:
|
11
|
+
enabled: true
|
12
|
+
rubocop:
|
13
|
+
enabled: true
|
14
|
+
ratings:
|
15
|
+
paths:
|
16
|
+
- Gemfile.lock
|
17
|
+
- "**.rb"
|
18
|
+
exclude_paths:
|
19
|
+
- spec/
|
20
|
+
- templates/
|
21
|
+
- doc/
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Change Log
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
|
+
|
5
|
+
## [Unreleased]
|
6
|
+
|
7
|
+
## [0.2.0] - 2016-05-18
|
8
|
+
### Changed
|
9
|
+
- Upgraded dependencies
|
10
|
+
- `rubyntlm`: ~>0.4.0 to ~>0.6.0
|
11
|
+
- `savon`: ~>2.10.0 to ~>2.11.0
|
12
|
+
- `rubocop`: ~>0.28.0 to ~>0.39.0
|
13
|
+
- Lots of rubocop-y code cleanup
|
14
|
+
- Converted from code climate classic to code climate platform
|
15
|
+
- Added rake task to run code climate platform locally
|
16
|
+
- Broke low-level secret server operations into `zanzibar/client`
|
17
|
+
|
18
|
+
## [0.1.27] - 2016-04-15
|
19
|
+
### Added
|
20
|
+
- `zanzibar get` can fetch field values for fields other than password
|
21
|
+
- This ability has not been added to Zanzifiles yet.
|
22
|
+
|
23
|
+
[0.2.0]: https://github.com/Cimpress-MCP/Zanzibar/compare/v0.1.27...v0.2.0
|
24
|
+
[Unreleased]: https://github.com/Cimpress-MCP/Zanzibar/compare/v0.2.0...HEAD
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Zanzibar
|
2
2
|
[](http://badge.fury.io/rb/zanzibar)
|
3
|
+
[](https://codeclimate.com/github/Cimpress-MCP/zanzibar)
|
4
|
+
[](https://codeclimate.com/github/Cimpress-MCP/zanzibar/coverage)
|
5
|
+
[](https://gemnasium.com/github.com/Cimpress-MCP/zanzibar)
|
6
|
+
[](http://inch-ci.org/github/cimpress-mcp/zanzibar)
|
3
7
|
|
4
8
|
Zanzibar is a utility to retrieve secrets from a Secret Server installation. It supports retrieval of a password, public/private key, or secret attachment.
|
5
9
|
|
@@ -98,7 +102,7 @@ When it downloads a file, it gets added to `Zanzifile.resolved`. And next time
|
|
98
102
|
`resolved` file, it will not attempt to re-download. `zanzibar update` will attempt
|
99
103
|
to re-download all secrets.
|
100
104
|
|
101
|
-
Subdirectories under the root directory `secret_dir` can be created for individual keys by specifying a `prefix` path for that secret. Secrets will default to be downloaded to the root `secret_dir` directory otherwise.
|
105
|
+
Subdirectories under the root directory `secret_dir` can be created for individual keys by specifying a `prefix` path for that secret. Secrets will default to be downloaded to the root `secret_dir` directory otherwise.
|
102
106
|
|
103
107
|
Note: `zanzibar get` can fetch passwords or files, but `zanzibar bundle` can
|
104
108
|
only operate on secret files.
|
data/Rakefile
CHANGED
@@ -7,5 +7,15 @@ require 'rubocop/rake_task'
|
|
7
7
|
task default: [:test]
|
8
8
|
|
9
9
|
RSpec::Core::RakeTask.new(:test)
|
10
|
-
|
11
10
|
RuboCop::RakeTask.new
|
11
|
+
|
12
|
+
task :cc_local do
|
13
|
+
command = 'docker run '
|
14
|
+
command << '--interactive --tty --rm '
|
15
|
+
command << '--env CODECLIMATE_CODE="$PWD" '
|
16
|
+
command << '--volume "$PWD":/code '
|
17
|
+
command << '--volume /var/run/docker.sock:/var/run/docker.sock '
|
18
|
+
command << '--volume /tmp/cc:/tmp/cc '
|
19
|
+
command << 'codeclimate/codeclimate analyze'
|
20
|
+
sh command
|
21
|
+
end
|
data/lib/zanzibar.rb
CHANGED
@@ -3,216 +3,175 @@ require 'savon'
|
|
3
3
|
require 'io/console'
|
4
4
|
require 'fileutils'
|
5
5
|
require 'yaml'
|
6
|
+
require 'zanzibar/client'
|
6
7
|
|
7
8
|
module Zanzibar
|
8
9
|
##
|
9
|
-
#
|
10
|
+
# High-level operations for downloading things from Secret Server
|
10
11
|
class Zanzibar
|
11
12
|
##
|
12
13
|
# @param args{:domain, :wsdl, :pwd, :username, :globals{}}
|
13
|
-
|
14
14
|
def initialize(args = {})
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
else
|
20
|
-
@@username = ENV['USER']
|
21
|
-
end
|
22
|
-
|
23
|
-
if args[:wsdl]
|
24
|
-
@@wsdl = args[:wsdl]
|
25
|
-
else
|
26
|
-
@@wsdl = get_wsdl_location
|
27
|
-
end
|
28
|
-
|
29
|
-
if args[:pwd]
|
30
|
-
@@password = args[:pwd]
|
31
|
-
elsif ENV['ZANZIBAR_PASSWORD']
|
32
|
-
@@password = ENV['ZANZIBAR_PASSWORD']
|
33
|
-
else
|
34
|
-
@@password = prompt_for_password
|
35
|
-
end
|
36
|
-
|
37
|
-
if args[:domain]
|
38
|
-
@@domain = args[:domain]
|
39
|
-
else
|
40
|
-
@@domain = prompt_for_domain
|
41
|
-
end
|
15
|
+
@username = resolve_username(args)
|
16
|
+
@wsdl = resolve_wsdl(args)
|
17
|
+
@password = resolve_password(args)
|
18
|
+
@domain = resolve_domain(args)
|
42
19
|
args[:globals] = {} unless args[:globals]
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
def get_client_username
|
47
|
-
@@username
|
48
|
-
end
|
49
|
-
|
50
|
-
def get_client_password
|
51
|
-
@@password
|
20
|
+
@client = Client.new(@username, @password, @domain, @wsdl, args[:globals])
|
52
21
|
end
|
53
22
|
|
54
|
-
##
|
55
|
-
#
|
56
|
-
|
57
|
-
def init_client(globals = {})
|
58
|
-
globals = {} if globals.nil?
|
59
|
-
@@client = Savon.client(globals) do
|
60
|
-
wsdl @@wsdl
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
## Gets the user's password if none is provided in the constructor.
|
23
|
+
##
|
24
|
+
# Gets the user's password if none is provided in the constructor.
|
65
25
|
# @return [String] the password for the current user
|
66
|
-
|
67
26
|
def prompt_for_password
|
68
|
-
puts "Please enter password for #{
|
27
|
+
puts "Please enter password for #{@username}:"
|
69
28
|
STDIN.noecho(&:gets).chomp.tap do
|
70
|
-
puts
|
29
|
+
puts 'Using password to login...'
|
71
30
|
end
|
72
31
|
end
|
73
32
|
|
74
|
-
##
|
33
|
+
##
|
34
|
+
# Gets the wsdl document location if none is provided in the constructor
|
75
35
|
# @return [String] the location of the WDSL document
|
76
|
-
|
77
36
|
def prompt_for_wsdl_location
|
78
37
|
puts 'Enter the URL of the Secret Server WSDL:'
|
79
38
|
STDIN.gets.chomp
|
80
39
|
end
|
81
40
|
|
82
|
-
##
|
41
|
+
##
|
42
|
+
# Gets the domain of the Secret Server installation if none is provided in the constructor
|
83
43
|
# @return [String] the domain of the secret server installation
|
84
|
-
|
85
44
|
def prompt_for_domain
|
86
45
|
puts 'Enter the domain of your Secret Server:'
|
87
46
|
STDIN.gets.chomp
|
88
47
|
end
|
89
48
|
|
90
|
-
##
|
91
|
-
#
|
92
|
-
# @return the authentication token for the current user.
|
93
|
-
|
94
|
-
def get_token
|
95
|
-
response = @@client.call(:authenticate, message: { username: @@username, password: @@password, organization: '', domain: @@domain })
|
96
|
-
.hash[:envelope][:body][:authenticate_response][:authenticate_result]
|
97
|
-
fail "Error generating the authentication token for user #{@@username}: #{response[:errors][:string]}" if response[:errors]
|
98
|
-
response[:token]
|
99
|
-
rescue Savon::Error => err
|
100
|
-
raise "There was an error generating the authentiaton token for user #{@@username}: #{err}"
|
101
|
-
end
|
102
|
-
|
103
|
-
## Get a secret returned as a hash
|
104
|
-
# Will raise an error if there was an issue getting the secret
|
105
|
-
# @param [Integer] the secret id
|
106
|
-
# @return [Hash] the secret hash retrieved from the wsdl
|
107
|
-
|
108
|
-
def get_secret(scrt_id, token = nil)
|
109
|
-
secret = @@client.call(:get_secret, message: { token: token || get_token, secretId: scrt_id }).hash[:envelope][:body][:get_secret_response][:get_secret_result]
|
110
|
-
fail "There was an error getting secret #{scrt_id}: #{secret[:errors][:string]}" if secret[:errors]
|
111
|
-
return secret
|
112
|
-
rescue Savon::Error => err
|
113
|
-
raise "There was an error getting the secret with id #{scrt_id}: #{err}"
|
114
|
-
end
|
115
|
-
|
116
|
-
## Retrieve the value from a field label of a secret
|
49
|
+
##
|
50
|
+
# Retrieve the value from a field label of a secret
|
117
51
|
# Will raise an error if there are any issues
|
118
52
|
# @param [Integer] the secret id
|
119
53
|
# @param [String] the field label to get, defaults to Password
|
120
54
|
# @return [String] the value for the given field label
|
121
55
|
def get_fieldlabel_value(scrt_id, fieldlabel = 'Password')
|
122
|
-
secret = get_secret(scrt_id)
|
56
|
+
secret = @client.get_secret(scrt_id)
|
123
57
|
secret_items = secret[:secret][:items][:secret_item]
|
124
|
-
return get_secret_item_by_field_name(secret_items, fieldlabel)[:value]
|
58
|
+
return @client.get_secret_item_by_field_name(secret_items, fieldlabel)[:value]
|
125
59
|
rescue Savon::Error => err
|
126
60
|
raise "There was an error getting '#{fieldlabel}' for secret #{scrt_id}: #{err}"
|
127
61
|
end
|
128
62
|
|
129
|
-
##
|
63
|
+
##
|
64
|
+
# Retrieve a simple password from a secret
|
130
65
|
# Calls get get_fieldlabel_value()
|
131
66
|
# @param [Integer] the secret id
|
132
67
|
# @return [String] the password for the given secret
|
133
68
|
def get_password(scrt_id)
|
134
|
-
|
69
|
+
get_fieldlabel_value(scrt_id)
|
135
70
|
end
|
136
71
|
|
137
|
-
##
|
72
|
+
##
|
73
|
+
# Get the password, save it to a file, and return the path to the file.
|
138
74
|
def get_username_and_password_and_save(scrt_id, path, name)
|
139
|
-
secret_items = get_secret(scrt_id)[:secret][:items][:secret_item]
|
140
|
-
password = get_secret_item_by_field_name(secret_items, 'Password')[:value]
|
141
|
-
username = get_secret_item_by_field_name(secret_items, 'Username')[:value]
|
75
|
+
secret_items = @client.get_secret(scrt_id)[:secret][:items][:secret_item]
|
76
|
+
password = @client.get_secret_item_by_field_name(secret_items, 'Password')[:value]
|
77
|
+
username = @client.get_secret_item_by_field_name(secret_items, 'Username')[:value]
|
142
78
|
save_username_and_password_to_file(password, username, path, name)
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
|
-
def write_secret_to_file(path, secret_response)
|
147
|
-
File.open(File.join(path, secret_response[:file_name]), 'wb') do |file|
|
148
|
-
file.puts Base64.decode64(secret_response[:file_attachment])
|
149
|
-
end
|
79
|
+
File.join(path, name)
|
150
80
|
end
|
151
81
|
|
152
|
-
##
|
82
|
+
##
|
83
|
+
# Write the password to a file. Intended for use with a Zanzifile
|
153
84
|
def save_username_and_password_to_file(password, username, path, name)
|
154
|
-
user_pass = {'username' => username.to_s, 'password' => password.to_s}.to_yaml
|
85
|
+
user_pass = { 'username' => username.to_s, 'password' => password.to_s }.to_yaml
|
155
86
|
File.open(File.join(path, name), 'wb') do |file|
|
156
87
|
file.print user_pass
|
157
88
|
end
|
158
89
|
end
|
159
90
|
|
160
|
-
|
161
|
-
|
162
|
-
return item if item[:field_name] == field_name
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
## Get the secret item id that relates to a key file or attachment.
|
167
|
-
# Will raise on error
|
168
|
-
# @param [Integer] the secret id
|
169
|
-
# @param [String] the type of secret item to get, one of privatekey, publickey, attachment
|
170
|
-
# @return [Integer] the secret item id
|
171
|
-
|
172
|
-
def get_scrt_item_id(scrt_id, type, token)
|
173
|
-
secret = get_secret(scrt_id, token)
|
174
|
-
secret_items = secret[:secret][:items][:secret_item]
|
175
|
-
begin
|
176
|
-
return get_secret_item_by_field_name(secret_items, type)[:id]
|
177
|
-
rescue
|
178
|
-
raise "Unknown type, #{type}."
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
## Downloads a file for a secret and places it where Zanzibar is running, or :path if specified
|
91
|
+
##
|
92
|
+
# Downloads a file for a secret and places it where Zanzibar is running, or :path if specified
|
183
93
|
# Raise on error
|
184
94
|
# @param [Hash] args, :scrt_id, :type (one of "Private Key", "Public Key", "Attachment"), :scrt_item_id - optional, :path - optional
|
185
|
-
|
186
95
|
def download_secret_file(args = {})
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
{ token: token, secretId: args[:scrt_id], secretItemId: args[:scrt_item_id] || get_scrt_item_id(args[:scrt_id], args[:type], token) })
|
193
|
-
.hash[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result]
|
194
|
-
fail "There was an error getting the #{args[:type]} for secret #{args[:scrt_id]}: #{response[:errors][:string]}" if response[:errors]
|
195
|
-
write_secret_to_file(path, response)
|
196
|
-
return File.join(path, response[:file_name])
|
197
|
-
rescue Savon::Error => err
|
198
|
-
raise "There was an error getting the #{args[:type]} for secret #{args[:scrt_id]}: #{err}"
|
199
|
-
end
|
96
|
+
response = @client.download_file_attachment_by_item_id(args[:scrt_id], args[:scrt_item_id], args[:type])
|
97
|
+
raise "There was an error getting the #{args[:type]} for secret #{args[:scrt_id]}: #{response[:errors][:string]}" if response[:errors]
|
98
|
+
return write_secret_to_file(args[:path], response)
|
99
|
+
rescue Savon::Error => err
|
100
|
+
raise "There was an error getting the #{args[:type]} for secret #{args[:scrt_id]}: #{err}"
|
200
101
|
end
|
201
102
|
|
202
|
-
##
|
103
|
+
##
|
104
|
+
# Download a private key secret
|
105
|
+
# @deprecated
|
203
106
|
def download_private_key(args = {})
|
204
107
|
args[:type] = 'Private Key'
|
205
108
|
download_secret_file(args)
|
206
109
|
end
|
207
110
|
|
111
|
+
##
|
112
|
+
# Download a public key secret
|
113
|
+
# @deprecated
|
208
114
|
def download_public_key(args = {})
|
209
115
|
args[:type] = 'Public Key'
|
210
116
|
download_secret_file(args)
|
211
117
|
end
|
212
118
|
|
119
|
+
##
|
120
|
+
# Download an arbitrary secret attachment
|
121
|
+
# @deprecated
|
213
122
|
def download_attachment(args = {})
|
214
123
|
args[:type] = 'Attachment'
|
215
124
|
download_secret_file(args)
|
216
125
|
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def make_or_find_path(path = nil)
|
130
|
+
FileUtils.mkdir_p(path) if path
|
131
|
+
path || '.'
|
132
|
+
end
|
133
|
+
|
134
|
+
def resolve_username(args = {})
|
135
|
+
if args[:username]
|
136
|
+
args[:username]
|
137
|
+
elsif ENV['ZANZIBAR_USER']
|
138
|
+
ENV['ZANZIBAR_USER']
|
139
|
+
else
|
140
|
+
ENV['USER']
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def resolve_wsdl(args = {})
|
145
|
+
args[:wsdl]
|
146
|
+
end
|
147
|
+
|
148
|
+
def resolve_password(args = {})
|
149
|
+
if args[:pwd]
|
150
|
+
args[:pwd]
|
151
|
+
elsif ENV['ZANZIBAR_PASSWORD']
|
152
|
+
ENV['ZANZIBAR_PASSWORD']
|
153
|
+
else
|
154
|
+
prompt_for_password
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def resolve_domain(args = {})
|
159
|
+
if args[:domain]
|
160
|
+
args[:domain]
|
161
|
+
else
|
162
|
+
prompt_for_domain
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def write_secret_to_file(path, secret_response)
|
167
|
+
path = make_or_find_path(path)
|
168
|
+
filepath = File.join(path, secret_response[:file_name])
|
169
|
+
|
170
|
+
File.open(filepath, 'wb') do |file|
|
171
|
+
file.puts Base64.decode64(secret_response[:file_attachment])
|
172
|
+
end
|
173
|
+
|
174
|
+
filepath
|
175
|
+
end
|
217
176
|
end
|
218
177
|
end
|
@@ -2,12 +2,18 @@ module Zanzibar
|
|
2
2
|
module Actions
|
3
3
|
# Basic plumbing for all actions
|
4
4
|
class Base
|
5
|
+
##
|
6
|
+
# The options passed in from the Thor action
|
5
7
|
attr_accessor :options
|
6
8
|
private :options=
|
7
9
|
|
10
|
+
##
|
11
|
+
# The logger that Thor is using for this run
|
8
12
|
attr_accessor :logger
|
9
13
|
private :logger=
|
10
14
|
|
15
|
+
##
|
16
|
+
# Initialize the basic components used by all actions
|
11
17
|
def initialize(logger, options = {})
|
12
18
|
self.logger = logger
|
13
19
|
self.options = options
|
@@ -6,17 +6,35 @@ module Zanzibar
|
|
6
6
|
module Actions
|
7
7
|
# Download or verify the secrets in a Zanzifile
|
8
8
|
class Bundle < Base
|
9
|
+
##
|
10
|
+
# The settings defined in the Zanzifile
|
9
11
|
attr_accessor :settings
|
12
|
+
|
13
|
+
##
|
14
|
+
# The unresolved secrets from the Zanzifile
|
10
15
|
attr_accessor :remote_secrets
|
16
|
+
|
17
|
+
##
|
18
|
+
# The resolved secrets from the Zanzifile.resolved
|
11
19
|
attr_accessor :local_secrets
|
20
|
+
|
21
|
+
##
|
22
|
+
# Whether to disregard local secrets and re-download regardness
|
12
23
|
attr_accessor :update
|
24
|
+
|
25
|
+
##
|
26
|
+
# Our Zanzibar client
|
13
27
|
attr_accessor :zanzibar
|
14
28
|
|
29
|
+
##
|
30
|
+
# An action that will fetch secrets defined in a Zanzifile
|
15
31
|
def initialize(ui, options, args = {})
|
16
32
|
super(ui, options)
|
17
33
|
@update = args[:update]
|
18
34
|
end
|
19
35
|
|
36
|
+
##
|
37
|
+
# Coordinate downloading to secrets (or skipping ones we already have)
|
20
38
|
def run
|
21
39
|
ensure_zanzifile
|
22
40
|
load_required_secrets
|
@@ -39,7 +57,7 @@ module Zanzibar
|
|
39
57
|
end
|
40
58
|
|
41
59
|
def ensure_zanzifile
|
42
|
-
|
60
|
+
raise Error, NO_ZANZIFILE_ERROR unless File.exist? ZANZIFILE_NAME
|
43
61
|
debug { "#{ZANZIFILE_NAME} located..." }
|
44
62
|
end
|
45
63
|
|
@@ -47,7 +65,7 @@ module Zanzibar
|
|
47
65
|
## Make sure the directory exists and that a .gitignore is there to ignore it
|
48
66
|
if @settings['secret_dir']
|
49
67
|
FileUtils.mkdir_p(@settings['secret_dir'])
|
50
|
-
|
68
|
+
unless File.exist? "#{@settings['secret_dir']}/.gitignore"
|
51
69
|
File.open("#{@settings['secret_dir']}/.gitignore", 'w') do |file|
|
52
70
|
file.puts '*'
|
53
71
|
file.puts '!.gitignore'
|
@@ -69,7 +87,7 @@ module Zanzibar
|
|
69
87
|
|
70
88
|
def validate_environment
|
71
89
|
return unless @settings.empty? || @remote_secrets.empty?
|
72
|
-
|
90
|
+
raise Error, INVALID_ZANZIFILE_ERROR
|
73
91
|
end
|
74
92
|
|
75
93
|
def load_resolved_secrets
|
@@ -94,12 +112,9 @@ module Zanzibar
|
|
94
112
|
|
95
113
|
downloaded_secrets = {}
|
96
114
|
remote_secrets.each do |key, secret|
|
97
|
-
full_path = secret.
|
98
|
-
downloaded_secrets[key] = download_one_secret(secret['id'],
|
99
|
-
secret
|
100
|
-
full_path,
|
101
|
-
args,
|
102
|
-
secret['name'] || "#{secret['id']}_password")
|
115
|
+
full_path = secret.key?('prefix') ? File.join(@settings['secret_dir'], secret['prefix']) : @settings['secret_dir']
|
116
|
+
downloaded_secrets[key] = download_one_secret(secret['id'], secret['label'], full_path,
|
117
|
+
args, secret_filename(secret))
|
103
118
|
|
104
119
|
debug { "Downloaded secret: #{key} to #{@settings['secret_dir']}..." }
|
105
120
|
end
|
@@ -110,13 +125,13 @@ module Zanzibar
|
|
110
125
|
def download_one_secret(scrt_id, label, path, args, name = nil)
|
111
126
|
if label == 'Password'
|
112
127
|
path = zanzibar(args).get_username_and_password_and_save(scrt_id, path, name)
|
113
|
-
{ path: path, hash: Digest::MD5.file(path).hexdigest }
|
114
128
|
else
|
115
129
|
path = zanzibar(args).download_secret_file(scrt_id: scrt_id,
|
116
|
-
|
117
|
-
|
118
|
-
{ path: path, hash: Digest::MD5.file(path).hexdigest }
|
130
|
+
type: label,
|
131
|
+
path: path)
|
119
132
|
end
|
133
|
+
|
134
|
+
{ path: path, hash: Digest::MD5.file(path).hexdigest }
|
120
135
|
end
|
121
136
|
|
122
137
|
def update_resolved_file(new_secrets)
|
@@ -134,6 +149,10 @@ module Zanzibar
|
|
134
149
|
domain: @settings['domain'],
|
135
150
|
globals: args)
|
136
151
|
end
|
152
|
+
|
153
|
+
def secret_filename(secret)
|
154
|
+
secret['name'] || "#{secret['id']}_password"
|
155
|
+
end
|
137
156
|
end
|
138
157
|
end
|
139
158
|
end
|
data/lib/zanzibar/actions/get.rb
CHANGED
@@ -7,15 +7,24 @@ module Zanzibar
|
|
7
7
|
module Actions
|
8
8
|
# Fetch a single secret
|
9
9
|
class Get < Base
|
10
|
+
##
|
11
|
+
# The options to use when initializing our Zanzibar client
|
10
12
|
attr_accessor :zanibar_options
|
13
|
+
|
14
|
+
##
|
15
|
+
# The id of the secret to download
|
11
16
|
attr_accessor :scrt_id
|
12
17
|
|
18
|
+
##
|
19
|
+
# Initialize the action
|
13
20
|
def initialize(ui, options, scrt_id)
|
14
21
|
super(ui, options)
|
15
22
|
@scrt_id = scrt_id
|
16
23
|
@zanzibar_options = {}
|
17
24
|
end
|
18
25
|
|
26
|
+
##
|
27
|
+
# Ensure we have the options we need and download the secret
|
19
28
|
def run
|
20
29
|
construct_options
|
21
30
|
ensure_options
|
@@ -23,6 +32,8 @@ module Zanzibar
|
|
23
32
|
fetch_secret(@scrt_id)
|
24
33
|
end
|
25
34
|
|
35
|
+
##
|
36
|
+
# Actually download the secret
|
26
37
|
def fetch_secret(scrt_id)
|
27
38
|
scrt = ::Zanzibar::Zanzibar.new(@zanzibar_options)
|
28
39
|
|
@@ -32,9 +43,10 @@ module Zanzibar
|
|
32
43
|
else
|
33
44
|
scrt.get_fieldlabel_value(scrt_id, @zanzibar_options[:fieldlabel])
|
34
45
|
end
|
35
|
-
|
36
46
|
end
|
37
47
|
|
48
|
+
##
|
49
|
+
# Coalesce our options and some defaults to ensure we are ready to run
|
38
50
|
def construct_options
|
39
51
|
@zanzibar_options[:wsdl] = construct_wsdl
|
40
52
|
@zanzibar_options[:globals] = { ssl_verify_mode: :none } if options['ignoressl']
|
@@ -45,6 +57,8 @@ module Zanzibar
|
|
45
57
|
@zanzibar_options[:filelabel] = options['filelabel'] if options['filelabel']
|
46
58
|
end
|
47
59
|
|
60
|
+
##
|
61
|
+
# Construct a WSDL URL from the server hostname if necessary
|
48
62
|
def construct_wsdl
|
49
63
|
if options['wsdl'].nil? && options['server']
|
50
64
|
DEFAULT_WSDL % options['server']
|
@@ -53,9 +67,11 @@ module Zanzibar
|
|
53
67
|
end
|
54
68
|
end
|
55
69
|
|
70
|
+
##
|
71
|
+
# Make sure a proper WSDL was constructed
|
56
72
|
def ensure_options
|
57
73
|
return if @zanzibar_options[:wsdl]
|
58
|
-
|
74
|
+
raise Error, NO_WSDL_ERROR
|
59
75
|
end
|
60
76
|
end
|
61
77
|
end
|
@@ -8,6 +8,8 @@ module Zanzibar
|
|
8
8
|
module Actions
|
9
9
|
# Create a new Zanzifile
|
10
10
|
class Init < Base
|
11
|
+
##
|
12
|
+
# Make sure we don't already have a Zanzifile, then template one
|
11
13
|
def run
|
12
14
|
check_for_zanzifile
|
13
15
|
write_template
|
@@ -17,7 +19,7 @@ module Zanzibar
|
|
17
19
|
|
18
20
|
def check_for_zanzifile
|
19
21
|
return unless File.exist?(ZANZIFILE_NAME) && !options['force']
|
20
|
-
|
22
|
+
raise Error, ALREADY_EXISTS_ERROR
|
21
23
|
end
|
22
24
|
|
23
25
|
def write_template
|
@@ -28,9 +30,12 @@ module Zanzibar
|
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
33
|
+
##
|
31
34
|
# Allows us to easily feed our options hash
|
32
35
|
# to an ERB
|
33
36
|
class TemplateRenderer < OpenStruct
|
37
|
+
##
|
38
|
+
# Render an ERB template to a string
|
34
39
|
def render(template)
|
35
40
|
ERB.new(template).result(binding)
|
36
41
|
end
|
data/lib/zanzibar/cli.rb
CHANGED
@@ -8,12 +8,18 @@ require 'zanzibar/error'
|
|
8
8
|
require 'zanzibar/defaults'
|
9
9
|
|
10
10
|
module Zanzibar
|
11
|
-
|
11
|
+
##
|
12
|
+
# The `zanzibar` binary/thor application main class.
|
13
|
+
# See http://whatisthor.com/ for information on syntax.
|
12
14
|
class Cli < Thor
|
13
15
|
include Thor::Actions
|
14
16
|
|
17
|
+
##
|
18
|
+
# The stream to which we are writing messages (usually stdout)
|
15
19
|
attr_accessor :ui
|
16
20
|
|
21
|
+
##
|
22
|
+
# Initialize the application and set some logging defaults
|
17
23
|
def initialize(*)
|
18
24
|
super
|
19
25
|
the_shell = (options['no-color'] ? Thor::Shell::Basic.new : shell)
|
@@ -24,11 +30,15 @@ module Zanzibar
|
|
24
30
|
debug_header
|
25
31
|
end
|
26
32
|
|
33
|
+
##
|
34
|
+
# Print the version of the application
|
27
35
|
desc 'version', 'Display your Zanzibar verion'
|
28
36
|
def version
|
29
37
|
say "#{APPLICATION_NAME} Version: #{VERSION}"
|
30
38
|
end
|
31
39
|
|
40
|
+
##
|
41
|
+
# Generate a new blank Zanzifile
|
32
42
|
desc 'init', "Create an empty #{ZANZIFILE_NAME} in the current directory."
|
33
43
|
option 'verbose', type: :boolean, default: false, aliases: :v
|
34
44
|
option 'wsdl', type: :string, aliases: :w,
|
@@ -46,21 +56,29 @@ module Zanzibar
|
|
46
56
|
run_action { init! }
|
47
57
|
end
|
48
58
|
|
59
|
+
##
|
60
|
+
# Fetch secrets declared in a local Zanzifle
|
61
|
+
|
49
62
|
desc 'bundle', "Fetch secrets declared in your #{ZANZIFILE_NAME}"
|
50
63
|
option 'verbose', type: :boolean, default: false, aliases: :v
|
64
|
+
|
51
65
|
def bundle
|
52
66
|
run_action { bundle! }
|
53
67
|
end
|
54
68
|
|
55
|
-
desc 'plunder', "Alias to `#{APPLICATION_NAME} bundle`", :
|
69
|
+
desc 'plunder', "Alias to `#{APPLICATION_NAME} bundle`", hide: true
|
56
70
|
option 'verbose', type: :boolean, default: false, aliases: :v
|
57
|
-
|
71
|
+
alias plunder bundle
|
58
72
|
|
59
73
|
desc 'install', "Alias to `#{APPLICATION_NAME} bundle`"
|
60
|
-
|
74
|
+
alias install bundle
|
75
|
+
|
76
|
+
##
|
77
|
+
# Redownload Zazifile secrets
|
61
78
|
|
62
79
|
desc 'update', "Redownload all secrets in your #{ZANZIFILE_NAME}"
|
63
80
|
option 'verbose', type: :boolean, default: false, aliases: :v
|
81
|
+
|
64
82
|
def update
|
65
83
|
run_action { update! }
|
66
84
|
end
|
@@ -80,6 +98,8 @@ module Zanzibar
|
|
80
98
|
desc: 'Specify a field (by label) to get'
|
81
99
|
option 'username', type: :string, aliases: :u
|
82
100
|
option 'password', type: :string, aliases: :p
|
101
|
+
##
|
102
|
+
# Fetch a single secret specified on the commandline
|
83
103
|
def get(scrt_id)
|
84
104
|
run_action { get! scrt_id }
|
85
105
|
end
|
@@ -93,6 +113,7 @@ module Zanzibar
|
|
93
113
|
@ui.debug { "#{APPLICATION_NAME} Version: #{VERSION}" }
|
94
114
|
end
|
95
115
|
|
116
|
+
##
|
96
117
|
# Run the specified action and rescue errors we
|
97
118
|
# explicitly send back to format them
|
98
119
|
def run_action(&_block)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'zanzibar/version'
|
2
|
+
require 'savon'
|
3
|
+
require 'io/console'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module Zanzibar
|
8
|
+
##
|
9
|
+
# Class for performing low-level WSDL actions against Secret Server
|
10
|
+
class Client
|
11
|
+
##
|
12
|
+
# Initializes the Savon client class variable with the wdsl document location and optional global variables
|
13
|
+
# @param globals{}, optional
|
14
|
+
def initialize(username, password, domain, wsdl, globals = {})
|
15
|
+
@username = username
|
16
|
+
@password = password
|
17
|
+
@domain = domain
|
18
|
+
|
19
|
+
globals = {} if globals.nil?
|
20
|
+
|
21
|
+
wsdl_loc = wsdl
|
22
|
+
@client = Savon.client(globals) do
|
23
|
+
wsdl wsdl_loc
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Get an authentication token for interacting with Secret Server. These are only good for about 10 minutes so just get a new one each time.
|
29
|
+
# Will raise an error if there is an issue with the authentication.
|
30
|
+
# @return the authentication token for the current user.
|
31
|
+
def generate_token
|
32
|
+
response = @client.call(:authenticate, message: { username: @username, password: @password, organization: '', domain: @domain })
|
33
|
+
.hash[:envelope][:body][:authenticate_response][:authenticate_result]
|
34
|
+
raise "Error generating the authentication token for user #{@username}: #{response[:errors][:string]}" if response[:errors]
|
35
|
+
response[:token]
|
36
|
+
rescue Savon::Error => err
|
37
|
+
raise "There was an error generating the authentiaton token for user #{@username}: #{err}"
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Get a secret returned as a hash
|
42
|
+
# Will raise an error if there was an issue getting the secret
|
43
|
+
# @param [Integer] the secret id
|
44
|
+
# @return [Hash] the secret hash retrieved from the wsdl
|
45
|
+
def get_secret(scrt_id, token = nil)
|
46
|
+
secret = @client.call(:get_secret, message: { token: token || generate_token, secretId: scrt_id }).hash[:envelope][:body][:get_secret_response][:get_secret_result]
|
47
|
+
raise "There was an error getting secret #{scrt_id}: #{secret[:errors][:string]}" if secret[:errors]
|
48
|
+
return secret
|
49
|
+
rescue Savon::Error => err
|
50
|
+
raise "There was an error getting the secret with id #{scrt_id}: #{err}"
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Get the secret item id that relates to a key file or attachment.
|
55
|
+
# Will raise on error
|
56
|
+
# @param [Integer] the secret id
|
57
|
+
# @param [String] the type of secret item to get, one of privatekey, publickey, attachment
|
58
|
+
# @return [Integer] the secret item id
|
59
|
+
def get_scrt_item_id(scrt_id, type, token)
|
60
|
+
secret = get_secret(scrt_id, token)
|
61
|
+
secret_items = secret[:secret][:items][:secret_item]
|
62
|
+
begin
|
63
|
+
return get_secret_item_by_field_name(secret_items, type)[:id]
|
64
|
+
rescue => e
|
65
|
+
|
66
|
+
raise "Unknown type, #{type}. #{e}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Get an "Attachment"-type file from a secret
|
72
|
+
# @param [Integer] the id of the secret
|
73
|
+
# @param [Integer] the id of the attachment on the secret
|
74
|
+
# @param [String] the type of the item being downloaded
|
75
|
+
# @return [Hash] contents and metadata of the downloaded file
|
76
|
+
def download_file_attachment_by_item_id(scrt_id, secret_item_id, item_type, token = nil)
|
77
|
+
token = generate_token unless token
|
78
|
+
@client.call(:download_file_attachment_by_item_id, message:
|
79
|
+
{ token: token, secretId: scrt_id, secretItemId: secret_item_id || get_scrt_item_id(scrt_id, item_type, token) })
|
80
|
+
.hash[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result]
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Extract an item from a secret based on field name
|
85
|
+
def get_secret_item_by_field_name(secret_items, field_name)
|
86
|
+
secret_items.each do |item|
|
87
|
+
return item if item[:field_name] == field_name
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/zanzibar/defaults.rb
CHANGED
@@ -2,15 +2,25 @@ require 'pathname'
|
|
2
2
|
|
3
3
|
# Definitions for various strings used throughout the gem
|
4
4
|
module Zanzibar
|
5
|
+
# The name of the binstub that invoked this code
|
5
6
|
APPLICATION_NAME = Pathname.new($PROGRAM_NAME).basename
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
# The filename of the Zanzifile
|
8
|
+
ZANZIFILE_NAME = 'Zanzifile'.freeze
|
9
|
+
# The filename of the resolved Zanzifile
|
10
|
+
RESOLVED_NAME = 'Zanzifile.resolved'.freeze
|
11
|
+
# The template to use when writing the Zanzifile
|
12
|
+
TEMPLATE_NAME = 'templates/Zanzifile.erb'.freeze
|
13
|
+
# The default value of the server when writing the Zanzifile
|
14
|
+
DEFAULT_SERVER = 'secret.example.com'.freeze
|
15
|
+
# The default WSDL location for the Zanzifile template
|
16
|
+
DEFAULT_WSDL = 'https://%s/webservices/sswebservice.asmx?wsdl'.freeze
|
11
17
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
18
|
+
# Error thrown when trying to overwrite an existing Zanzifile
|
19
|
+
ALREADY_EXISTS_ERROR = "#{ZANZIFILE_NAME} already exists! Aborting...".freeze
|
20
|
+
# Error thrown when unable to construct the WSDL location
|
21
|
+
NO_WSDL_ERROR = 'Could not construct WSDL URL. Please provide either --server or --wsdl'.freeze
|
22
|
+
# Error thrown when trying to download secrets from a Zanzifile that doesn't exist
|
23
|
+
NO_ZANZIFILE_ERROR = "You don't have a #{ZANZIFILE_NAME}! Run `#{APPLICATION_NAME} init` first!".freeze
|
24
|
+
# Error thrown when a Zanzifile is missing necessary information
|
25
|
+
INVALID_ZANZIFILE_ERROR = "Unable to load your #{ZANZIFILE_NAME}. Please ensure it is valid YAML.".freeze
|
16
26
|
end
|
data/lib/zanzibar/ui.rb
CHANGED
@@ -1,40 +1,59 @@
|
|
1
1
|
require 'rubygems/user_interaction'
|
2
2
|
|
3
3
|
module Zanzibar
|
4
|
+
##
|
4
5
|
# Prints messages out to stdout
|
5
6
|
class Shell
|
7
|
+
##
|
8
|
+
# The stream to write log messages (usually stdout)
|
6
9
|
attr_writer :shell
|
7
10
|
|
11
|
+
##
|
12
|
+
# Logging options and initializing stream
|
8
13
|
def initialize(shell)
|
9
14
|
@shell = shell
|
10
15
|
@quiet = false
|
11
16
|
@debug = ENV['DEBUG']
|
12
17
|
end
|
13
18
|
|
19
|
+
##
|
20
|
+
# Write a debug message if debug is enabled
|
14
21
|
def debug(message = nil)
|
15
22
|
@shell.say(message || yield) if @debug && !@quiet
|
16
23
|
end
|
17
24
|
|
25
|
+
##
|
26
|
+
# Write an info message unless we have silenced output
|
18
27
|
def info(message = nil)
|
19
28
|
@shell.say(message || yield) unless @quiet
|
20
29
|
end
|
21
30
|
|
31
|
+
##
|
32
|
+
# Ask the user for confirmation unless we have silenced output
|
22
33
|
def confirm(message = nil)
|
23
34
|
@shell.say(message || yield, :green) unless @quiet
|
24
35
|
end
|
25
36
|
|
37
|
+
##
|
38
|
+
# Print a warning
|
26
39
|
def warn(message = nil)
|
27
40
|
@shell.say(message || yield, :yellow)
|
28
41
|
end
|
29
42
|
|
43
|
+
##
|
44
|
+
# Print an error
|
30
45
|
def error(message = nil)
|
31
46
|
@shell.say(message || yield, :red)
|
32
47
|
end
|
33
48
|
|
49
|
+
##
|
50
|
+
# Enable silent mode
|
34
51
|
def be_quiet!
|
35
52
|
@quiet = true
|
36
53
|
end
|
37
54
|
|
55
|
+
##
|
56
|
+
# Enable debug mode
|
38
57
|
def debug!
|
39
58
|
@debug = true
|
40
59
|
end
|
data/lib/zanzibar/version.rb
CHANGED
@@ -24,12 +24,12 @@ describe Zanzibar::Cli do
|
|
24
24
|
FakeFS::FileSystem.clone files
|
25
25
|
|
26
26
|
stub_request(:any, 'https://www.zanzitest.net/webservices/sswebservice.asmx')
|
27
|
-
.to_return(
|
28
|
-
.to_return(
|
29
|
-
.to_return(
|
30
|
-
.to_return(
|
31
|
-
.to_return(
|
32
|
-
.to_return(
|
27
|
+
.to_return(body: AUTH_XML, status: 200).then
|
28
|
+
.to_return(body: SECRET_WITH_KEY_XML, status: 200).then
|
29
|
+
.to_return(body: PRIVATE_KEY_XML, status: 200).then
|
30
|
+
.to_return(body: AUTH_XML, status: 200).then
|
31
|
+
.to_return(body: SECRET_WITH_KEY_XML, status: 200).then
|
32
|
+
.to_return(body: PRIVATE_KEY_XML, status: 200)
|
33
33
|
|
34
34
|
Dir.chdir File.join(source_root, 'spec', 'files')
|
35
35
|
end
|
@@ -87,9 +87,9 @@ describe Zanzibar::Cli do
|
|
87
87
|
|
88
88
|
WebMock.reset!
|
89
89
|
stub_request(:any, 'https://www.zanzitest.net/webservices/sswebservice.asmx')
|
90
|
-
.to_return(
|
91
|
-
.to_return(
|
92
|
-
.to_return(
|
90
|
+
.to_return(body: AUTH_XML, status: 200).then
|
91
|
+
.to_return(body: SECRET_WITH_KEY_XML, status: 200).then
|
92
|
+
.to_return(body: PRIVATE_KEY_XML, status: 200).then
|
93
93
|
.to_return(body: AUTH_XML, status: 200).then
|
94
94
|
.to_return(body: SECRET_WITH_KEY_XML, status: 200).then
|
95
95
|
.to_return(body: PRIVATE_KEY_XML, status: 200)
|
data/spec/lib/zanzibar_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe 'Zanzibar Test' do
|
|
13
13
|
stub_request(:any, 'https://www.zanzitest.net/webservices/sswebservice.asmx')
|
14
14
|
.to_return(body: AUTH_XML, status: 200)
|
15
15
|
|
16
|
-
expect(client.
|
16
|
+
expect(client.instance_variable_get(:@client).generate_token).to eq('imatoken')
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'should get a secret' do
|
@@ -21,7 +21,7 @@ describe 'Zanzibar Test' do
|
|
21
21
|
.to_return(body: AUTH_XML, status: 200).then
|
22
22
|
.to_return(body: SECRET_XML, status: 200)
|
23
23
|
|
24
|
-
expect(client.get_secret(1234)[:secret][:name]).to eq('Zanzi Test Secret')
|
24
|
+
expect(client.instance_variable_get(:@client).get_secret(1234)[:secret][:name]).to eq('Zanzi Test Secret')
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'should get a password' do
|
@@ -109,18 +109,18 @@ describe 'Zanzibar Test' do
|
|
109
109
|
.to_return(body: AUTH_XML, status: 200).then
|
110
110
|
.to_return(body: SECRET_XML, status: 200)
|
111
111
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
client.get_username_and_password_and_save(1234, '.', 'zanziTestCreds')
|
113
|
+
expect(File.exist? 'zanziTestCreds')
|
114
|
+
expect(File.read('zanziTestCreds')).to eq({ 'username' => 'ZanziUser', 'password' => 'zanziUserPassword' }.to_yaml)
|
115
|
+
File.delete('zanziTestCreds')
|
116
116
|
end
|
117
117
|
|
118
118
|
it 'should use environment variables for credentials' do
|
119
119
|
ENV['ZANZIBAR_USER'] = 'environment_user'
|
120
120
|
ENV['ZANZIBAR_PASSWORD'] = 'environment_password'
|
121
121
|
client = Zanzibar::Zanzibar.new(domain: 'zanzitest.net', wsdl: 'spec/scrt.wsdl')
|
122
|
-
expect(client.
|
123
|
-
expect(client.
|
122
|
+
expect(client.instance_variable_get(:@username)).to eq(ENV['ZANZIBAR_USER'])
|
123
|
+
expect(client.instance_variable_get(:@password)).to eq(ENV['ZANZIBAR_PASSWORD'])
|
124
124
|
ENV.delete 'ZANZIBAR_PASSWORD'
|
125
125
|
ENV.delete 'ZANZIBAR_USER'
|
126
126
|
end
|
data/zanzibar.gemspec
CHANGED
@@ -14,13 +14,13 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.license = 'Apache 2.0'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
17
|
-
spec.executables = spec.files.grep(
|
18
|
-
spec.test_files = spec.files.grep(
|
17
|
+
spec.executables = spec.files.grep(%r{^bin\/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)\/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
21
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
22
22
|
spec.add_development_dependency 'rake', '~> 10.0'
|
23
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
23
|
+
spec.add_development_dependency 'rubocop', '~> 0.39.0'
|
24
24
|
spec.add_development_dependency 'savon_spec', '~> 0.1.6'
|
25
25
|
spec.add_development_dependency 'rspec', '~> 3.1.0'
|
26
26
|
spec.add_development_dependency 'webmock', '~> 1.20.4'
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency 'fakefs', '~> 0.6.4'
|
29
29
|
spec.add_development_dependency 'simplecov', '~> 0.9.1'
|
30
30
|
|
31
|
-
spec.add_runtime_dependency 'savon', '~> 2.
|
32
|
-
spec.add_runtime_dependency 'rubyntlm', '~> 0.
|
31
|
+
spec.add_runtime_dependency 'savon', '~> 2.11.0'
|
32
|
+
spec.add_runtime_dependency 'rubyntlm', '~> 0.6.0'
|
33
33
|
spec.add_runtime_dependency 'thor', '~> 0.19.0'
|
34
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zanzibar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Davis-Cooke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: 0.39.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.
|
54
|
+
version: 0.39.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: savon_spec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,28 +142,28 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - ~>
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 2.
|
145
|
+
version: 2.11.0
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - ~>
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 2.
|
152
|
+
version: 2.11.0
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: rubyntlm
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
157
|
- - ~>
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: 0.
|
159
|
+
version: 0.6.0
|
160
160
|
type: :runtime
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
164
|
- - ~>
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version: 0.
|
166
|
+
version: 0.6.0
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
168
|
name: thor
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -187,10 +187,12 @@ executables:
|
|
187
187
|
extensions: []
|
188
188
|
extra_rdoc_files: []
|
189
189
|
files:
|
190
|
+
- .codeclimate.yml
|
190
191
|
- .gitignore
|
191
192
|
- .rspec
|
192
193
|
- .rubocop.yml
|
193
194
|
- .travis.yml
|
195
|
+
- CHANGELOG.md
|
194
196
|
- Gemfile
|
195
197
|
- LICENSE.txt
|
196
198
|
- README.md
|
@@ -204,6 +206,7 @@ files:
|
|
204
206
|
- lib/zanzibar/actions/get.rb
|
205
207
|
- lib/zanzibar/actions/init.rb
|
206
208
|
- lib/zanzibar/cli.rb
|
209
|
+
- lib/zanzibar/client.rb
|
207
210
|
- lib/zanzibar/defaults.rb
|
208
211
|
- lib/zanzibar/error.rb
|
209
212
|
- lib/zanzibar/ui.rb
|