zanzibar 0.1.27 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/zanzibar.svg)](http://badge.fury.io/rb/zanzibar)
|
3
|
+
[![Code Climate](https://codeclimate.com/github/Cimpress-MCP/zanzibar/badges/gpa.svg?1=1)](https://codeclimate.com/github/Cimpress-MCP/zanzibar)
|
4
|
+
[![Test Coverage](https://codeclimate.com/github/Cimpress-MCP/zanzibar/badges/coverage.svg)](https://codeclimate.com/github/Cimpress-MCP/zanzibar/coverage)
|
5
|
+
[![Dependency Status](https://gemnasium.com/badges/github.com/Cimpress-MCP/zanzibar.svg)](https://gemnasium.com/github.com/Cimpress-MCP/zanzibar)
|
6
|
+
[![Inline docs](http://inch-ci.org/github/cimpress-mcp/zanzibar.svg?branch=master)](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
|