hybrid_platforms_conductor 33.3.0 → 33.4.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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +31 -2
  4. data/docs/config_dsl.md +43 -0
  5. data/lib/hybrid_platforms_conductor/bitbucket.rb +134 -90
  6. data/lib/hybrid_platforms_conductor/common_config_dsl/bitbucket.rb +12 -44
  7. data/lib/hybrid_platforms_conductor/common_config_dsl/github.rb +9 -31
  8. data/lib/hybrid_platforms_conductor/confluence.rb +93 -88
  9. data/lib/hybrid_platforms_conductor/credentials.rb +112 -95
  10. data/lib/hybrid_platforms_conductor/deployer.rb +2 -2
  11. data/lib/hybrid_platforms_conductor/github.rb +39 -0
  12. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +4 -2
  13. data/lib/hybrid_platforms_conductor/hpc_plugins/report/confluence.rb +3 -1
  14. data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/keepass.rb +2 -1
  15. data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/thycotic.rb +3 -1
  16. data/lib/hybrid_platforms_conductor/hpc_plugins/test/bitbucket_conf.rb +4 -1
  17. data/lib/hybrid_platforms_conductor/hpc_plugins/test/github_ci.rb +4 -1
  18. data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +6 -2
  19. data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +6 -2
  20. data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/confluence.rb +3 -1
  21. data/lib/hybrid_platforms_conductor/logger_helpers.rb +7 -1
  22. data/lib/hybrid_platforms_conductor/thycotic.rb +80 -75
  23. data/lib/hybrid_platforms_conductor/version.rb +1 -1
  24. data/spec/hybrid_platforms_conductor_test.rb +6 -0
  25. data/spec/hybrid_platforms_conductor_test/api/credentials_spec.rb +247 -0
  26. data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/keepass_spec.rb +280 -319
  27. data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/thycotic_spec.rb +2 -2
  28. data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/bitbucket_conf_spec.rb +49 -69
  29. data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/github_ci_spec.rb +29 -39
  30. metadata +18 -2
@@ -1,5 +1,6 @@
1
1
  require 'fileutils'
2
2
  require 'tmpdir'
3
+ require 'webmock/rspec'
3
4
  require 'hybrid_platforms_conductor/config'
4
5
  require 'hybrid_platforms_conductor/platforms_handler'
5
6
  require 'hybrid_platforms_conductor/actions_executor'
@@ -83,6 +84,9 @@ module HybridPlatformsConductorTest
83
84
  # Make sure the tested components are being reset before each test case
84
85
  RSpec.configure do |config|
85
86
  config.before do
87
+ # We allow for connections by default.
88
+ # Tests that need to test specifically connections at a given point call WebMock.disable_net_connect!
89
+ WebMock.allow_net_connect!
86
90
  @actions_executor = nil
87
91
  @cmd_runner = nil
88
92
  @config = nil
@@ -95,6 +99,8 @@ module HybridPlatformsConductorTest
95
99
  ENV.delete 'hpc_platforms'
96
100
  ENV.delete 'hpc_ssh_gateways_conf'
97
101
  ENV.delete 'hpc_ssh_gateway_user'
102
+ ENV.delete 'hpc_user_for_github'
103
+ ENV.delete 'hpc_password_for_github'
98
104
  ENV.delete 'hpc_user_for_proxmox'
99
105
  ENV.delete 'hpc_password_for_proxmox'
100
106
  ENV.delete 'hpc_realm_for_proxmox'
@@ -0,0 +1,247 @@
1
+ describe HybridPlatformsConductor::Credentials do
2
+
3
+ # Create a container class for the credential Mixin to be tested, as a plugin as credentials can be used in any plugin.
4
+ let(:credential_tester_class) do
5
+ Class.new(HybridPlatformsConductor::Plugin) do
6
+ include HybridPlatformsConductor::Credentials
7
+ end
8
+ end
9
+
10
+ # Expect credentials to be as a given user and password
11
+ #
12
+ # Parameters::
13
+ # * *expected_user* (String or nil): The expected user
14
+ # * *expected_password* (String or nil): The expected password
15
+ # * *resource* (String or nil): The resource for which we query the credentials, or nil if none [default: nil]
16
+ def expect_credentials_to_be(expected_user, expected_password, resource: nil)
17
+ creds = {}
18
+ credential_tester_class.new(logger: logger, logger_stderr: logger, config: test_config).instance_exec do
19
+ with_credentials_for(:test_credential, resource: resource) do |user, password|
20
+ creds = {
21
+ user: user,
22
+ # We clone the value as for security reasons it is removed when exiting the block
23
+ password: password.clone
24
+ }
25
+ end
26
+ end
27
+ expect(creds).to eq(
28
+ user: expected_user,
29
+ password: expected_password
30
+ )
31
+ end
32
+
33
+ it 'returns no credentials when they are not set' do
34
+ with_platforms '' do
35
+ # Check that .netrc won't be read
36
+ expect(::Netrc).not_to receive(:read)
37
+ expect_credentials_to_be nil, nil
38
+ end
39
+ end
40
+
41
+ it 'returns credentials taken from environment variables' do
42
+ with_platforms '' do
43
+ ENV['hpc_user_for_test_credential'] = 'env_test_user'
44
+ ENV['hpc_password_for_test_credential'] = 'env_test_password'
45
+ begin
46
+ # Check that .netrc won't be read
47
+ expect(::Netrc).not_to receive(:read)
48
+ expect_credentials_to_be 'env_test_user', 'env_test_password'
49
+ ensure
50
+ ENV.delete('hpc_user_for_test_credential')
51
+ ENV.delete('hpc_password_for_test_credential')
52
+ end
53
+ end
54
+ end
55
+
56
+ it 'erases the value of the password taken from environment variable after usage' do
57
+ with_platforms '' do
58
+ ENV['hpc_user_for_test_credential'] = 'env_test_user'
59
+ ENV['hpc_password_for_test_credential'] = 'env_test_password'
60
+ begin
61
+ leaked_password = nil
62
+ credential_tester_class.new(logger: logger, logger_stderr: logger, config: test_config).instance_exec do
63
+ with_credentials_for(:test_credential) do |_user, password|
64
+ leaked_password = password
65
+ end
66
+ end
67
+ expect(leaked_password).to eq 'gotyou!' * 100
68
+ ensure
69
+ ENV.delete('hpc_user_for_test_credential')
70
+ ENV.delete('hpc_password_for_test_credential')
71
+ end
72
+ end
73
+ end
74
+
75
+ it 'returns credentials taken from .netrc when a resource is specified' do
76
+ with_platforms '' do
77
+ expect(::Netrc).to receive(:read) do
78
+ mocked_netrc = instance_double(::Netrc)
79
+ expect(mocked_netrc).to receive(:[]).with('my_domain.com').and_return %w[test_user test_password]
80
+ expect(mocked_netrc).to receive(:instance_variable_get).with(:@data).and_return []
81
+ mocked_netrc
82
+ end
83
+ expect_credentials_to_be 'test_user', 'test_password', resource: 'http://My_Domain.com/path/to/resource'
84
+ end
85
+ end
86
+
87
+ it 'returns credentials taken from .netrc when a non-URL resource is specified' do
88
+ with_platforms '' do
89
+ expect(::Netrc).to receive(:read) do
90
+ mocked_netrc = instance_double(::Netrc)
91
+ expect(mocked_netrc).to receive(:[]).with('This is:not/ a URL!').and_return %w[test_user test_password]
92
+ expect(mocked_netrc).to receive(:instance_variable_get).with(:@data).and_return []
93
+ mocked_netrc
94
+ end
95
+ expect_credentials_to_be 'test_user', 'test_password', resource: 'This is:not/ a URL!'
96
+ end
97
+ end
98
+
99
+ it 'erases the value of the password taken from netrc' do
100
+ with_platforms '' do
101
+ netrc_data = [['mocked_data']]
102
+ expect(::Netrc).to receive(:read) do
103
+ mocked_netrc = instance_double(::Netrc)
104
+ expect(mocked_netrc).to receive(:[]).with('my_domain.com').and_return %w[test_user test_password]
105
+ expect(mocked_netrc).to receive(:instance_variable_get).with(:@data).and_return netrc_data
106
+ mocked_netrc
107
+ end
108
+ leaked_password = nil
109
+ credential_tester_class.new(logger: logger, logger_stderr: logger, config: test_config).instance_exec do
110
+ with_credentials_for(:test_credential, resource: 'http://My_Domain.com/path/to/resource') do |_user, password|
111
+ leaked_password = password
112
+ end
113
+ end
114
+ expect(leaked_password).to eq 'gotyou!' * 100
115
+ expect(netrc_data).to eq [['GotYou!!!' * 100]]
116
+ end
117
+ end
118
+
119
+ it 'returns credentials taken from config' do
120
+ with_platforms(
121
+ <<~'EO_CONFIG'
122
+ credentials_for(:test_credential) do |resource, requester|
123
+ requester.call "user_for_#{resource}", "password_for_#{resource}"
124
+ end
125
+ EO_CONFIG
126
+ ) do
127
+ # Check that netrc is not called when config is used, and that env vars are ignored
128
+ ENV['hpc_user_for_test_credential'] = 'env_test_user'
129
+ ENV['hpc_password_for_test_credential'] = 'env_test_password'
130
+ begin
131
+ # Check that .netrc won't be read
132
+ expect(::Netrc).not_to receive(:read)
133
+ expect_credentials_to_be 'user_for_', 'password_for_'
134
+ ensure
135
+ ENV.delete('hpc_user_for_test_credential')
136
+ ENV.delete('hpc_password_for_test_credential')
137
+ end
138
+ end
139
+ end
140
+
141
+ it 'returns credentials taken from config for a given resource' do
142
+ with_platforms(
143
+ <<~'EO_CONFIG'
144
+ credentials_for(:test_credential) do |resource, requester|
145
+ requester.call "user_for_#{resource}", "password_for_#{resource}"
146
+ end
147
+ EO_CONFIG
148
+ ) do
149
+ # Check that netrc is not called when config is used, and that env vars are ignored
150
+ ENV['hpc_user_for_test_credential'] = 'env_test_user'
151
+ ENV['hpc_password_for_test_credential'] = 'env_test_password'
152
+ begin
153
+ # Check that .netrc won't be read
154
+ expect(::Netrc).not_to receive(:read)
155
+ expect_credentials_to_be 'user_for_test_resource', 'password_for_test_resource', resource: 'test_resource'
156
+ ensure
157
+ ENV.delete('hpc_user_for_test_credential')
158
+ ENV.delete('hpc_password_for_test_credential')
159
+ end
160
+ end
161
+ end
162
+
163
+ it 'returns credentials taken from config for a given resource even when they are nil' do
164
+ with_platforms(
165
+ <<~'EO_CONFIG'
166
+ credentials_for(:test_credential) do |resource, requester|
167
+ requester.call nil, nil
168
+ end
169
+ EO_CONFIG
170
+ ) do
171
+ # Check that netrc is not called when config is used, and that env vars are ignored
172
+ ENV['hpc_user_for_test_credential'] = 'env_test_user'
173
+ ENV['hpc_password_for_test_credential'] = 'env_test_password'
174
+ begin
175
+ # Check that .netrc won't be read
176
+ expect(::Netrc).not_to receive(:read)
177
+ expect_credentials_to_be nil, nil, resource: 'test_resource'
178
+ ensure
179
+ ENV.delete('hpc_user_for_test_credential')
180
+ ENV.delete('hpc_password_for_test_credential')
181
+ end
182
+ end
183
+ end
184
+
185
+ it 'returns credentials taken from config after filtering the resource name' do
186
+ with_platforms(
187
+ <<~'EO_CONFIG'
188
+ credentials_for(:test_credential, resource: 'another_resource') do |resource, requester|
189
+ requester.call "wrong_user_for_#{resource}", "wrong_password_for_#{resource}"
190
+ end
191
+ credentials_for(:test_credential, resource: /test_.*/) do |resource, requester|
192
+ requester.call "wrong_user_for_#{resource}", "wrong_password_for_#{resource}"
193
+ end
194
+ credentials_for(:test_credential, resource: /_resource/) do |resource, requester|
195
+ requester.call "correct_user_for_#{resource}", "correct_password_for_#{resource}"
196
+ end
197
+ credentials_for(:test_credential, resource: 'test_resource2') do |resource, requester|
198
+ requester.call "wrong_user_for_#{resource}", "wrong_password_for_#{resource}"
199
+ end
200
+ EO_CONFIG
201
+ ) do
202
+ expect_credentials_to_be 'correct_user_for_test_resource', 'correct_password_for_test_resource', resource: 'test_resource'
203
+ end
204
+ end
205
+
206
+ it 'returns credentials taken from config after filtering the resource name when no resource is given' do
207
+ with_platforms(
208
+ <<~'EO_CONFIG'
209
+ credentials_for(:test_credential, resource: 'another_resource') do |resource, requester|
210
+ requester.call "wrong_user_for_#{resource}", "wrong_password_for_#{resource}"
211
+ end
212
+ credentials_for(:test_credential, resource: /test_.*/) do |resource, requester|
213
+ requester.call "wrong_user_for_#{resource}", "wrong_password_for_#{resource}"
214
+ end
215
+ credentials_for(:test_credential) do |resource, requester|
216
+ requester.call "correct_user_for_#{resource}", "correct_password_for_#{resource}"
217
+ end
218
+ credentials_for(:test_credential, resource: /_resource/) do |resource, requester|
219
+ requester.call "wrong_user_for_#{resource}", "wrong_password_for_#{resource}"
220
+ end
221
+ credentials_for(:test_credential, resource: 'test_resource2') do |resource, requester|
222
+ requester.call "wrong_user_for_#{resource}", "wrong_password_for_#{resource}"
223
+ end
224
+ EO_CONFIG
225
+ ) do
226
+ expect_credentials_to_be 'correct_user_for_', 'correct_password_for_'
227
+ end
228
+ end
229
+
230
+ it 'fails if the requester is not called from config' do
231
+ with_platforms(
232
+ <<~'EO_CONFIG'
233
+ credentials_for(:test_credential) do |resource, requester|
234
+ end
235
+ EO_CONFIG
236
+ ) do
237
+ expect do
238
+ credential_tester_class.new(logger: logger, logger_stderr: logger, config: test_config).instance_exec do
239
+ with_credentials_for(:test_credential) do |_user, _password|
240
+ nil
241
+ end
242
+ end
243
+ end.to raise_error 'Requester not called by the credentials provider for test_credential (resource: ) - Please check the credentials_for code in your configuration.'
244
+ end
245
+ end
246
+
247
+ end
@@ -57,12 +57,9 @@ describe HybridPlatformsConductor::Deployer do
57
57
  # * *additional_config* (String): Additional config
58
58
  # * *platform_info* (Hash): Platform configuration [default: 1 node having 1 service]
59
59
  # * *mock_keepass_password* (String): Password to be returned by credentials [default: 'test_keepass_password']
60
- # * *mock_xml* (String): XML to be mocked [default: xml_single_entry]
61
60
  # * *expect_key_file* (String or nil): Key file to be expected, or nil if none [default: nil]
62
61
  # * *expect_password_enc* (String or nil): Encrypted password to be expected, or nil if none [default: nil]
63
62
  # * *expect_kpscript_calls* (Boolean): Should we expect calls to KPScript? [default: true]
64
- # * *expect_nbr_credentials_calls* (Integer): How many calls to the credentials are expected? [default: 1]
65
- # * *block* (Proc): Code called when the platform is setup
66
63
  def with_test_platform_for_keepass_test(
67
64
  additional_config,
68
65
  platform_info: {
@@ -70,33 +67,35 @@ describe HybridPlatformsConductor::Deployer do
70
67
  deployable_services: %w[service]
71
68
  },
72
69
  mock_keepass_password: 'test_keepass_password',
73
- mock_xml: xml_single_entry,
70
+ mock_databases: { '/path/to/database.kdbx' => xml_single_entry },
74
71
  expect_key_file: nil,
75
72
  expect_password_enc: nil,
76
- expect_kpscript_calls: true,
77
- expect_nbr_credentials_calls: 1,
78
- &block
73
+ expect_kpscript_calls: true
79
74
  )
80
- expect(HybridPlatformsConductor::Credentials).to receive(:with_credentials_for).exactly(expect_nbr_credentials_calls).times do |id, _logger, _logger_stderr, url: nil, &client_code|
81
- expect(id).to eq :keepass
82
- client_code.call nil, mock_keepass_password
83
- end
84
- if expect_kpscript_calls
85
- expect_calls_to_kpscript [
86
- [
87
- %r{/path/to/kpscript "/path/to/database.kdbx"#{mock_keepass_password.nil? ? '' : " -pw:\"#{Regexp.escape(mock_keepass_password)}\""}#{expect_password_enc.nil? ? '' : " -pw-enc:\"#{Regexp.escape(expect_password_enc)}\""}#{expect_key_file.nil? ? '' : " -keyfile:\"#{Regexp.escape(expect_key_file)}\""} -c:Export -Format:"KeePass XML \(2.x\)" -OutFile:"/tmp/.+"},
88
- {
89
- stdout: 'OK: Operation completed successfully.',
90
- xml: mock_xml
91
- }
92
- ]
93
- ]
94
- end
95
75
  with_test_platform(
96
76
  platform_info,
97
- additional_config: "read_secrets_from :keepass\n#{additional_config}",
98
- &block
99
- )
77
+ additional_config: "read_secrets_from :keepass\n#{additional_config}"
78
+ ) do
79
+ mock_databases.each do |database, _xml|
80
+ expect(test_deployer.instance_variable_get(:@secrets_readers)[:keepass]).to receive(:with_credentials_for).with(:keepass, resource: database) do |_id, resource: nil, &client_code|
81
+ client_code.call nil, mock_keepass_password
82
+ end
83
+ end
84
+ if expect_kpscript_calls
85
+ expect_calls_to_kpscript(
86
+ mock_databases.map do |database, xml|
87
+ [
88
+ %r{/path/to/kpscript "#{Regexp.escape(database)}"#{mock_keepass_password.nil? ? '' : " -pw:\"#{Regexp.escape(mock_keepass_password)}\""}#{expect_password_enc.nil? ? '' : " -pw-enc:\"#{Regexp.escape(expect_password_enc)}\""}#{expect_key_file.nil? ? '' : " -keyfile:\"#{Regexp.escape(expect_key_file)}\""} -c:Export -Format:"KeePass XML \(2.x\)" -OutFile:"/tmp/.+"},
89
+ {
90
+ stdout: 'OK: Operation completed successfully.',
91
+ xml: xml
92
+ }
93
+ ]
94
+ end
95
+ )
96
+ end
97
+ yield
98
+ end
100
99
  end
101
100
 
102
101
  # Expect secrets to be set to given values
@@ -224,7 +223,7 @@ describe HybridPlatformsConductor::Deployer do
224
223
  <<~EO_CONFIG,
225
224
  secrets_from_keepass(database: '/path/to/database.kdbx')
226
225
  EO_CONFIG
227
- expect_nbr_credentials_calls: 0,
226
+ mock_databases: {},
228
227
  expect_kpscript_calls: false
229
228
  ) do
230
229
  expect { test_deployer.deploy_on(%w[node]) }.to raise_error 'Missing KPScript configuration. Please use use_kpscript_from to set it.'
@@ -237,63 +236,65 @@ describe HybridPlatformsConductor::Deployer do
237
236
  use_kpscript_from '/path/to/kpscript'
238
237
  secrets_from_keepass(database: '/path/to/database.kdbx')
239
238
  EO_CONFIG
240
- mock_xml: <<~EO_XML
241
- <KeePassFile>
242
- <Root>
243
- <Group>
244
- <Entry>
245
- <String>
246
- <Key>Password</Key>
247
- <Value ProtectInMemory="True">TestPassword0</Value>
248
- </String>
249
- <String>
250
- <Key>Title</Key>
251
- <Value>Secret 0</Value>
252
- </String>
253
- </Entry>
239
+ mock_databases: {
240
+ '/path/to/database.kdbx' => <<~EO_XML
241
+ <KeePassFile>
242
+ <Root>
254
243
  <Group>
255
- <Name>Group1</UUID>
256
244
  <Entry>
257
245
  <String>
258
246
  <Key>Password</Key>
259
- <Value ProtectInMemory="True">TestPassword1</Value>
247
+ <Value ProtectInMemory="True">TestPassword0</Value>
260
248
  </String>
261
249
  <String>
262
250
  <Key>Title</Key>
263
- <Value>Secret 1</Value>
251
+ <Value>Secret 0</Value>
264
252
  </String>
265
253
  </Entry>
266
254
  <Group>
267
- <Name>Group2</UUID>
255
+ <Name>Group1</UUID>
268
256
  <Entry>
269
257
  <String>
270
258
  <Key>Password</Key>
271
- <Value ProtectInMemory="True">TestPassword2</Value>
259
+ <Value ProtectInMemory="True">TestPassword1</Value>
272
260
  </String>
273
261
  <String>
274
262
  <Key>Title</Key>
275
- <Value>Secret 2</Value>
276
- </String>
277
- </Entry>
278
- </Group>
279
- <Group>
280
- <Name>Group3</UUID>
281
- <Entry>
282
- <String>
283
- <Key>Password</Key>
284
- <Value ProtectInMemory="True">TestPassword3</Value>
285
- </String>
286
- <String>
287
- <Key>Title</Key>
288
- <Value>Secret 3</Value>
263
+ <Value>Secret 1</Value>
289
264
  </String>
290
265
  </Entry>
266
+ <Group>
267
+ <Name>Group2</UUID>
268
+ <Entry>
269
+ <String>
270
+ <Key>Password</Key>
271
+ <Value ProtectInMemory="True">TestPassword2</Value>
272
+ </String>
273
+ <String>
274
+ <Key>Title</Key>
275
+ <Value>Secret 2</Value>
276
+ </String>
277
+ </Entry>
278
+ </Group>
279
+ <Group>
280
+ <Name>Group3</UUID>
281
+ <Entry>
282
+ <String>
283
+ <Key>Password</Key>
284
+ <Value ProtectInMemory="True">TestPassword3</Value>
285
+ </String>
286
+ <String>
287
+ <Key>Title</Key>
288
+ <Value>Secret 3</Value>
289
+ </String>
290
+ </Entry>
291
+ </Group>
291
292
  </Group>
292
293
  </Group>
293
- </Group>
294
- </Root>
295
- </KeePassFile>
296
- EO_XML
294
+ </Root>
295
+ </KeePassFile>
296
+ EO_XML
297
+ }
297
298
  ) do
298
299
  expect_secrets_to_be(
299
300
  'Secret 0' => { 'password' => 'TestPassword0' },
@@ -316,57 +317,59 @@ describe HybridPlatformsConductor::Deployer do
316
317
  use_kpscript_from '/path/to/kpscript'
317
318
  secrets_from_keepass(database: '/path/to/database.kdbx')
318
319
  EO_CONFIG
319
- mock_xml: <<~EO_XML
320
- <KeePassFile>
321
- <Meta>
322
- <Binaries>
323
- <Binary ID="0" Compressed="True">#{
324
- str = StringIO.new
325
- gz = Zlib::GzipWriter.new(str)
326
- gz.write('File 0 Content')
327
- gz.close
328
- Base64.encode64(str.string).strip
329
- }</Binary>
330
- <Binary ID="1">#{Base64.encode64('File 1 Content').strip}</Binary>
331
- </Binaries>
332
- </Meta>
333
- <Root>
334
- <Group>
335
- <Entry>
336
- <String>
337
- <Key>Password</Key>
338
- <Value ProtectInMemory="True">TestPassword0</Value>
339
- </String>
340
- <String>
341
- <Key>Title</Key>
342
- <Value>Secret 0</Value>
343
- </String>
344
- <Binary>
345
- <Key>file0.txt</Key>
346
- <Value Ref="0" />
347
- </Binary>
348
- </Entry>
320
+ mock_databases: {
321
+ '/path/to/database.kdbx' => <<~EO_XML
322
+ <KeePassFile>
323
+ <Meta>
324
+ <Binaries>
325
+ <Binary ID="0" Compressed="True">#{
326
+ str = StringIO.new
327
+ gz = Zlib::GzipWriter.new(str)
328
+ gz.write('File 0 Content')
329
+ gz.close
330
+ Base64.encode64(str.string).strip
331
+ }</Binary>
332
+ <Binary ID="1">#{Base64.encode64('File 1 Content').strip}</Binary>
333
+ </Binaries>
334
+ </Meta>
335
+ <Root>
349
336
  <Group>
350
- <Name>Group1</UUID>
351
337
  <Entry>
352
338
  <String>
353
339
  <Key>Password</Key>
354
- <Value ProtectInMemory="True">TestPassword1</Value>
340
+ <Value ProtectInMemory="True">TestPassword0</Value>
355
341
  </String>
356
342
  <String>
357
343
  <Key>Title</Key>
358
- <Value>Secret 1</Value>
344
+ <Value>Secret 0</Value>
359
345
  </String>
360
346
  <Binary>
361
- <Key>file1.txt</Key>
362
- <Value Ref="1" />
347
+ <Key>file0.txt</Key>
348
+ <Value Ref="0" />
363
349
  </Binary>
364
350
  </Entry>
351
+ <Group>
352
+ <Name>Group1</UUID>
353
+ <Entry>
354
+ <String>
355
+ <Key>Password</Key>
356
+ <Value ProtectInMemory="True">TestPassword1</Value>
357
+ </String>
358
+ <String>
359
+ <Key>Title</Key>
360
+ <Value>Secret 1</Value>
361
+ </String>
362
+ <Binary>
363
+ <Key>file1.txt</Key>
364
+ <Value Ref="1" />
365
+ </Binary>
366
+ </Entry>
367
+ </Group>
365
368
  </Group>
366
- </Group>
367
- </Root>
368
- </KeePassFile>
369
- EO_XML
369
+ </Root>
370
+ </KeePassFile>
371
+ EO_XML
372
+ }
370
373
  ) do
371
374
  expect_secrets_to_be(
372
375
  'Secret 0' => { 'file0.txt' => 'File 0 Content', 'password' => 'TestPassword0' },
@@ -410,47 +413,33 @@ describe HybridPlatformsConductor::Deployer do
410
413
  nodes: { 'node1' => { services: %w[service1] }, 'node2' => { services: %w[service2] } },
411
414
  deployable_services: %w[service1 service2]
412
415
  },
413
- expect_kpscript_calls: false,
414
- expect_nbr_credentials_calls: 2
416
+ mock_databases: {
417
+ '/path/to/database1.kdbx' => xml_single_entry,
418
+ '/path/to/database2.kdbx' => <<~EO_XML
419
+ <KeePassFile>
420
+ <Root>
421
+ <Group>
422
+ <Entry>
423
+ <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
424
+ <String>
425
+ <Key>Password</Key>
426
+ <Value ProtectInMemory="True">TestPassword2</Value>
427
+ </String>
428
+ <String>
429
+ <Key>Title</Key>
430
+ <Value>Test Secret 2</Value>
431
+ </String>
432
+ <String>
433
+ <Key>UserName</Key>
434
+ <Value>Test User Name 2</Value>
435
+ </String>
436
+ </Entry>
437
+ </Group>
438
+ </Root>
439
+ </KeePassFile>
440
+ EO_XML
441
+ }
415
442
  ) do
416
- expect_calls_to_kpscript [
417
- [
418
- %r{/path/to/kpscript "/path/to/database1.kdbx" -pw:"test_keepass_password" -c:Export -Format:"KeePass XML \(2.x\)" -OutFile:"/tmp/.+"},
419
- {
420
- stdout: 'OK: Operation completed successfully.',
421
- xml: xml_single_entry
422
- }
423
- ],
424
- [
425
- %r{/path/to/kpscript "/path/to/database2.kdbx" -pw:"test_keepass_password" -c:Export -Format:"KeePass XML \(2.x\)" -OutFile:"/tmp/.+"},
426
- {
427
- stdout: 'OK: Operation completed successfully.',
428
- xml: <<~EO_XML
429
- <KeePassFile>
430
- <Root>
431
- <Group>
432
- <Entry>
433
- <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
434
- <String>
435
- <Key>Password</Key>
436
- <Value ProtectInMemory="True">TestPassword2</Value>
437
- </String>
438
- <String>
439
- <Key>Title</Key>
440
- <Value>Test Secret 2</Value>
441
- </String>
442
- <String>
443
- <Key>UserName</Key>
444
- <Value>Test User Name 2</Value>
445
- </String>
446
- </Entry>
447
- </Group>
448
- </Root>
449
- </KeePassFile>
450
- EO_XML
451
- }
452
- ]
453
- ]
454
443
  expect(test_services_handler).to receive(:package).with(
455
444
  services: { 'node1' => %w[service1], 'node2' => %w[service2] },
456
445
  secrets: {
@@ -500,122 +489,108 @@ describe HybridPlatformsConductor::Deployer do
500
489
  nodes: { 'node1' => { services: %w[service1] }, 'node2' => { services: %w[service2] } },
501
490
  deployable_services: %w[service1 service2]
502
491
  },
503
- expect_kpscript_calls: false,
504
- expect_nbr_credentials_calls: 2
492
+ mock_databases: {
493
+ '/path/to/database1.kdbx' => <<~EO_XML,
494
+ <KeePassFile>
495
+ <Root>
496
+ <Group>
497
+ <Entry>
498
+ <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
499
+ <String>
500
+ <Key>Password</Key>
501
+ <Value ProtectInMemory="True">TestPassword1</Value>
502
+ </String>
503
+ <String>
504
+ <Key>Title</Key>
505
+ <Value>Test Secret 1</Value>
506
+ </String>
507
+ <String>
508
+ <Key>UserName</Key>
509
+ <Value>Test User Name 1</Value>
510
+ </String>
511
+ </Entry>
512
+ <Group>
513
+ <UUID>RsonCc3VHk+k85z5zHhZzQ==</UUID>
514
+ <Name>Group1</Name>
515
+ <Entry>
516
+ <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
517
+ <String>
518
+ <Key>Password</Key>
519
+ <Value ProtectInMemory="True">TestPassword3</Value>
520
+ </String>
521
+ <String>
522
+ <Key>Title</Key>
523
+ <Value>Test Secret 3</Value>
524
+ </String>
525
+ <String>
526
+ <Key>UserName</Key>
527
+ <Value>Test User Name 3</Value>
528
+ </String>
529
+ </Entry>
530
+ </Group>
531
+ </Group>
532
+ </Root>
533
+ </KeePassFile>
534
+ EO_XML
535
+ '/path/to/database2.kdbx' => <<~EO_XML
536
+ <KeePassFile>
537
+ <Root>
538
+ <Group>
539
+ <Entry>
540
+ <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
541
+ <String>
542
+ <Key>Password</Key>
543
+ <Value ProtectInMemory="True">TestPassword2</Value>
544
+ </String>
545
+ <String>
546
+ <Key>Title</Key>
547
+ <Value>Test Secret 2</Value>
548
+ </String>
549
+ <String>
550
+ <Key>UserName</Key>
551
+ <Value>Test User Name 2</Value>
552
+ </String>
553
+ </Entry>
554
+ <Group>
555
+ <UUID>RsonCc3VHk+k85z5zHhZzQ==</UUID>
556
+ <Name>Group1</Name>
557
+ <Entry>
558
+ <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
559
+ <String>
560
+ <Key>Password</Key>
561
+ <Value ProtectInMemory="True">TestPassword3</Value>
562
+ </String>
563
+ <String>
564
+ <Key>Title</Key>
565
+ <Value>Test Secret 3</Value>
566
+ </String>
567
+ <String>
568
+ <Key>Notes</Key>
569
+ <Value>Notes 3</Value>
570
+ </String>
571
+ </Entry>
572
+ <Entry>
573
+ <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
574
+ <String>
575
+ <Key>Password</Key>
576
+ <Value ProtectInMemory="True">TestPassword4</Value>
577
+ </String>
578
+ <String>
579
+ <Key>Title</Key>
580
+ <Value>Test Secret 4</Value>
581
+ </String>
582
+ <String>
583
+ <Key>UserName</Key>
584
+ <Value>Test User Name 4</Value>
585
+ </String>
586
+ </Entry>
587
+ </Group>
588
+ </Group>
589
+ </Root>
590
+ </KeePassFile>
591
+ EO_XML
592
+ }
505
593
  ) do
506
- expect_calls_to_kpscript [
507
- [
508
- %r{/path/to/kpscript "/path/to/database1.kdbx" -pw:"test_keepass_password" -c:Export -Format:"KeePass XML \(2.x\)" -OutFile:"/tmp/.+"},
509
- {
510
- stdout: 'OK: Operation completed successfully.',
511
- xml: <<~EO_XML
512
- <KeePassFile>
513
- <Root>
514
- <Group>
515
- <Entry>
516
- <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
517
- <String>
518
- <Key>Password</Key>
519
- <Value ProtectInMemory="True">TestPassword1</Value>
520
- </String>
521
- <String>
522
- <Key>Title</Key>
523
- <Value>Test Secret 1</Value>
524
- </String>
525
- <String>
526
- <Key>UserName</Key>
527
- <Value>Test User Name 1</Value>
528
- </String>
529
- </Entry>
530
- <Group>
531
- <UUID>RsonCc3VHk+k85z5zHhZzQ==</UUID>
532
- <Name>Group1</Name>
533
- <Entry>
534
- <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
535
- <String>
536
- <Key>Password</Key>
537
- <Value ProtectInMemory="True">TestPassword3</Value>
538
- </String>
539
- <String>
540
- <Key>Title</Key>
541
- <Value>Test Secret 3</Value>
542
- </String>
543
- <String>
544
- <Key>UserName</Key>
545
- <Value>Test User Name 3</Value>
546
- </String>
547
- </Entry>
548
- </Group>
549
- </Group>
550
- </Root>
551
- </KeePassFile>
552
- EO_XML
553
- }
554
- ],
555
- [
556
- %r{/path/to/kpscript "/path/to/database2.kdbx" -pw:"test_keepass_password" -c:Export -Format:"KeePass XML \(2.x\)" -OutFile:"/tmp/.+"},
557
- {
558
- stdout: 'OK: Operation completed successfully.',
559
- xml: <<~EO_XML
560
- <KeePassFile>
561
- <Root>
562
- <Group>
563
- <Entry>
564
- <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
565
- <String>
566
- <Key>Password</Key>
567
- <Value ProtectInMemory="True">TestPassword2</Value>
568
- </String>
569
- <String>
570
- <Key>Title</Key>
571
- <Value>Test Secret 2</Value>
572
- </String>
573
- <String>
574
- <Key>UserName</Key>
575
- <Value>Test User Name 2</Value>
576
- </String>
577
- </Entry>
578
- <Group>
579
- <UUID>RsonCc3VHk+k85z5zHhZzQ==</UUID>
580
- <Name>Group1</Name>
581
- <Entry>
582
- <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
583
- <String>
584
- <Key>Password</Key>
585
- <Value ProtectInMemory="True">TestPassword3</Value>
586
- </String>
587
- <String>
588
- <Key>Title</Key>
589
- <Value>Test Secret 3</Value>
590
- </String>
591
- <String>
592
- <Key>Notes</Key>
593
- <Value>Notes 3</Value>
594
- </String>
595
- </Entry>
596
- <Entry>
597
- <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
598
- <String>
599
- <Key>Password</Key>
600
- <Value ProtectInMemory="True">TestPassword4</Value>
601
- </String>
602
- <String>
603
- <Key>Title</Key>
604
- <Value>Test Secret 4</Value>
605
- </String>
606
- <String>
607
- <Key>UserName</Key>
608
- <Value>Test User Name 4</Value>
609
- </String>
610
- </Entry>
611
- </Group>
612
- </Group>
613
- </Root>
614
- </KeePassFile>
615
- EO_XML
616
- }
617
- ]
618
- ]
619
594
  expect(test_services_handler).to receive(:package).with(
620
595
  services: { 'node1' => %w[service1], 'node2' => %w[service2] },
621
596
  secrets: {
@@ -645,69 +620,55 @@ describe HybridPlatformsConductor::Deployer do
645
620
  nodes: { 'node1' => { services: %w[service1] }, 'node2' => { services: %w[service2] } },
646
621
  deployable_services: %w[service1 service2]
647
622
  },
648
- expect_kpscript_calls: false,
649
- expect_nbr_credentials_calls: 2
623
+ mock_databases: {
624
+ '/path/to/database1.kdbx' => <<~EO_XML,
625
+ <KeePassFile>
626
+ <Root>
627
+ <Group>
628
+ <Entry>
629
+ <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
630
+ <String>
631
+ <Key>Password</Key>
632
+ <Value ProtectInMemory="True">TestPassword1</Value>
633
+ </String>
634
+ <String>
635
+ <Key>Title</Key>
636
+ <Value>Test Secret 1</Value>
637
+ </String>
638
+ <String>
639
+ <Key>UserName</Key>
640
+ <Value>Test User Name 1</Value>
641
+ </String>
642
+ </Entry>
643
+ </Group>
644
+ </Root>
645
+ </KeePassFile>
646
+ EO_XML
647
+ '/path/to/database2.kdbx' => <<~EO_XML
648
+ <KeePassFile>
649
+ <Root>
650
+ <Group>
651
+ <Entry>
652
+ <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
653
+ <String>
654
+ <Key>Password</Key>
655
+ <Value ProtectInMemory="True">OtherTestPassword1</Value>
656
+ </String>
657
+ <String>
658
+ <Key>Title</Key>
659
+ <Value>Test Secret 1</Value>
660
+ </String>
661
+ <String>
662
+ <Key>UserName</Key>
663
+ <Value>Test User Name 1</Value>
664
+ </String>
665
+ </Entry>
666
+ </Group>
667
+ </Root>
668
+ </KeePassFile>
669
+ EO_XML
670
+ }
650
671
  ) do
651
- expect_calls_to_kpscript [
652
- [
653
- %r{/path/to/kpscript "/path/to/database1.kdbx" -pw:"test_keepass_password" -c:Export -Format:"KeePass XML \(2.x\)" -OutFile:"/tmp/.+"},
654
- {
655
- stdout: 'OK: Operation completed successfully.',
656
- xml: <<~EO_XML
657
- <KeePassFile>
658
- <Root>
659
- <Group>
660
- <Entry>
661
- <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
662
- <String>
663
- <Key>Password</Key>
664
- <Value ProtectInMemory="True">TestPassword1</Value>
665
- </String>
666
- <String>
667
- <Key>Title</Key>
668
- <Value>Test Secret 1</Value>
669
- </String>
670
- <String>
671
- <Key>UserName</Key>
672
- <Value>Test User Name 1</Value>
673
- </String>
674
- </Entry>
675
- </Group>
676
- </Root>
677
- </KeePassFile>
678
- EO_XML
679
- }
680
- ],
681
- [
682
- %r{/path/to/kpscript "/path/to/database2.kdbx" -pw:"test_keepass_password" -c:Export -Format:"KeePass XML \(2.x\)" -OutFile:"/tmp/.+"},
683
- {
684
- stdout: 'OK: Operation completed successfully.',
685
- xml: <<~EO_XML
686
- <KeePassFile>
687
- <Root>
688
- <Group>
689
- <Entry>
690
- <UUID>Iv3JjMzpPEaijOB+SFZpRw==</UUID>
691
- <String>
692
- <Key>Password</Key>
693
- <Value ProtectInMemory="True">OtherTestPassword1</Value>
694
- </String>
695
- <String>
696
- <Key>Title</Key>
697
- <Value>Test Secret 1</Value>
698
- </String>
699
- <String>
700
- <Key>UserName</Key>
701
- <Value>Test User Name 1</Value>
702
- </String>
703
- </Entry>
704
- </Group>
705
- </Root>
706
- </KeePassFile>
707
- EO_XML
708
- }
709
- ]
710
- ]
711
672
  expect { test_deployer.deploy_on(%w[node1 node2]) }.to raise_error 'Secret set at path Test Secret 1->password by /path/to/database2.kdbx for service service2 on node node2 has conflicting values (set debug for value details).'
712
673
  end
713
674
  end