aptible-cli 0.26.5 → 0.26.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13c94bbbfe4b853700fec4e895ab0eebd02f0c5ffcddf6cfd0a597c42f665d37
4
- data.tar.gz: c495f4582ca15271799caa1b71a3922c3e5bbaafa692eda9476862465971556e
3
+ metadata.gz: 96e4d08173fd6d471b8a0a4f625d5bc1b3cf22af4c6cf2bb71fb3da109bc27af
4
+ data.tar.gz: 53ff531ac50e1a925a7c6ddc01bf5cdc7c972333e4f7ef72e5af83b0001c5ae0
5
5
  SHA512:
6
- metadata.gz: eb5b9e8adc78ba955f5125ca6c673894fea37fb8dd9a61775b4f44f87b9afc2c7fd9dbf8c645cd380af6fca7f754f03654a139539d9180060c6475544320b864
7
- data.tar.gz: d86d87bb3c7d8dd6c57692c63c0592b99f950cd96b8b6bce1038678678a0c983c6b734ef380852b6edb8bb1e4e205fa6938b5045c8d5337f82fd4c40fb5aac2e
6
+ metadata.gz: dec6c2d62bbe07eb89627dad9c1984133e7768f4b87316ac3029a1fd94f71d22418ca6b3ad73efa445425e60cd620d75d9653b23e4da10c7f28a62b6fc460d69
7
+ data.tar.gz: fd1b7ab666de7e4e13300ba4057d265edf919f40abaddcac96a90f9437b8ad23144775f4fc49124bae2af06f668aea57bdf976eeffa1fab60a7e01abb5ffd241
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- aptible-cli (0.26.5)
4
+ aptible-cli (0.26.6)
5
5
  activesupport (>= 4.0, < 6.0)
6
6
  aptible-api (~> 1.12)
7
7
  aptible-auth (~> 1.4)
@@ -14,6 +14,35 @@ module Aptible
14
14
  alb
15
15
  ).freeze
16
16
 
17
+ SSL_PROTOCOL_VALUES = [
18
+ 'TLSv1 TLSv1.1 TLSv1.2',
19
+ 'TLSv1 TLSv1.1 TLSv1.2 PFS',
20
+ 'TLSv1.1 TLSv1.2',
21
+ 'TLSv1.1 TLSv1.2 PFS',
22
+ 'TLSv1.2',
23
+ 'TLSv1.2 PFS',
24
+ 'TLSv1.2 PFS TLSv1.3',
25
+ 'TLSv1.3'
26
+ ].freeze
27
+
28
+ ALB_PROTOCOL_VALUES = SSL_PROTOCOL_VALUES
29
+
30
+ ELB_PROTOCOL_VALUES =
31
+ SSL_PROTOCOL_VALUES.reject { |v| v.include?(' PFS') }.freeze
32
+
33
+ SSL_PROTOCOL_ALB_DESC = (
34
+ 'Specify the allowed SSL protocols. Valid options: ' +
35
+ ALB_PROTOCOL_VALUES.map { |v| "\"#{v}\"" }.join(', ') +
36
+ '. PFS options require an HTTPS (ALB) endpoint. ' \
37
+ 'Use "default" to reset to the platform default'
38
+ ).freeze
39
+
40
+ SSL_PROTOCOL_ELB_DESC = (
41
+ 'Specify the allowed SSL protocols. Valid options: ' +
42
+ ELB_PROTOCOL_VALUES.map { |v| "\"#{v}\"" }.join(', ') +
43
+ '. Use "default" to reset to the platform default'
44
+ ).freeze
45
+
17
46
  def initialize(&block)
18
47
  FLAGS.each { |f| instance_variable_set("@#{f}", false) }
19
48
  instance_exec(&block) if block
@@ -53,6 +82,14 @@ module Aptible
53
82
  )
54
83
  end
55
84
 
85
+ option(
86
+ :idle_timeout,
87
+ type: :string,
88
+ desc: 'Timeout (seconds) to enforce idle timeouts while ' \
89
+ 'sending and receiving responses. Use "default" to ' \
90
+ 'reset to the platform default'
91
+ )
92
+
56
93
  if builder.alb?
57
94
  option(
58
95
  :load_balancing_algorithm_type,
@@ -69,6 +106,50 @@ module Aptible
69
106
  desc: "Share this Endpoint's load balancer with other " \
70
107
  'Endpoints'
71
108
  )
109
+
110
+ option(
111
+ :force_ssl,
112
+ type: :boolean,
113
+ desc: 'Redirect all HTTP requests to HTTPS, and ' \
114
+ 'enable the Strict-Transport-Security header (HSTS)'
115
+ )
116
+
117
+ option(
118
+ :maintenance_page_url,
119
+ type: :string,
120
+ desc: 'The URL of a maintenance page to cache and serve ' \
121
+ 'when requests time out, or your app is unhealthy. ' \
122
+ 'Use "default" to reset to the platform default'
123
+ )
124
+
125
+ option(
126
+ :release_healthcheck_timeout,
127
+ type: :string,
128
+ desc: 'Timeout (seconds) to wait for your app to ' \
129
+ 'respond to a release health check. Use "default" ' \
130
+ 'to reset to the platform default'
131
+ )
132
+
133
+ option(
134
+ :show_elb_healthchecks,
135
+ type: :boolean,
136
+ desc: 'Show all runtime health check requets in the ' \
137
+ "endpoint's logs"
138
+ )
139
+
140
+ option(
141
+ :ssl_protocols_override,
142
+ type: :string,
143
+ desc: SSL_PROTOCOL_ALB_DESC
144
+ )
145
+
146
+ option(
147
+ :strict_health_checks,
148
+ type: :boolean,
149
+ desc: 'Require containers to respond to health checks ' \
150
+ 'with a 200 OK HTTP response.'
151
+ )
152
+
72
153
  end
73
154
  end
74
155
 
@@ -128,6 +209,27 @@ module Aptible
128
209
  desc: 'The fingerprint of an existing Certificate to use ' \
129
210
  'on this Endpoint'
130
211
  )
212
+
213
+ unless builder.alb?
214
+ option(
215
+ :ssl_protocols_override,
216
+ type: :string,
217
+ desc: SSL_PROTOCOL_ELB_DESC
218
+ )
219
+
220
+ option(
221
+ :ssl_ciphers_override,
222
+ type: :string,
223
+ desc: 'Specify the allowed SSL ciphers. ' \
224
+ 'Use "default" to reset to the platform default'
225
+ )
226
+
227
+ option(
228
+ :disable_weak_cipher_suites,
229
+ type: :boolean,
230
+ desc: 'Block the SSLv3 protocol and RC4 ciphers'
231
+ )
232
+ end
131
233
  end
132
234
  end
133
235
  end
@@ -137,6 +239,7 @@ module Aptible
137
239
  verify_option_conflicts(options)
138
240
 
139
241
  params = {}
242
+ settings = {}
140
243
 
141
244
  params[:ip_whitelist] = options.delete(:ip_whitelist) do
142
245
  create? ? [] : nil
@@ -203,6 +306,56 @@ module Aptible
203
306
  params[:shared] = options.delete(:shared)
204
307
  end
205
308
 
309
+ if (proto = options[:ssl_protocols_override]) &&
310
+ proto != 'default'
311
+ unless ALB_PROTOCOL_VALUES.include?(proto)
312
+ raise Thor::Error,
313
+ "Invalid --ssl-protocols-override: \"#{proto}\". " \
314
+ "Valid options are: #{ALB_PROTOCOL_VALUES.join(', ')}"
315
+ end
316
+
317
+ if !ELB_PROTOCOL_VALUES.include?(proto) && !alb?
318
+ raise Thor::Error,
319
+ "Invalid --ssl-protocols-override: \"#{proto}\". " \
320
+ 'PFS options are only valid for an HTTPS (ALB) endpoint. ' \
321
+ "Valid options are: #{ELB_PROTOCOL_VALUES.join(', ')}"
322
+ end
323
+ end
324
+
325
+ vhost_settings = %i(
326
+ idle_timeout
327
+ maintenance_page_url
328
+ release_healthcheck_timeout
329
+ ssl_protocols_override
330
+ ssl_ciphers_override
331
+ )
332
+
333
+ vhost_settings.each do |key|
334
+ val = options.delete(key)
335
+ next if val.nil?
336
+
337
+ settings[key.to_s.upcase] = case val
338
+ when 'default'
339
+ ''
340
+ else
341
+ val
342
+ end
343
+ end
344
+
345
+ boolean_vhost_settings = %i(
346
+ force_ssl
347
+ show_elb_healthchecks
348
+ strict_health_checks
349
+ disable_weak_cipher_suites
350
+ )
351
+
352
+ boolean_vhost_settings.each do |key|
353
+ value = options.delete(key)
354
+ next if value.nil?
355
+
356
+ settings[key.to_s.upcase] = value.to_s
357
+ end
358
+
206
359
  options.delete(:environment)
207
360
 
208
361
  # NOTE: This is here to ensure that specs don't test for options
@@ -210,7 +363,7 @@ module Aptible
210
363
  # this.
211
364
  raise "Unexpected options: #{options}" if options.any?
212
365
 
213
- params.delete_if { |_, v| v.nil? }
366
+ [params.delete_if { |_, v| v.nil? }, settings]
214
367
  end
215
368
 
216
369
  FLAGS.each do |f|
@@ -2,8 +2,11 @@ module Aptible
2
2
  module CLI
3
3
  module Helpers
4
4
  module Vhost
5
- def provision_vhost_and_explain(service, vhost)
6
- op = vhost.create_operation!(type: 'provision')
5
+ def provision_vhost_and_explain(service, vhost, settings)
6
+ op = vhost.create_operation!(
7
+ type: 'provision',
8
+ **(settings.empty? ? {} : { settings: settings })
9
+ )
7
10
  attach_to_operation_logs(op)
8
11
 
9
12
  Formatter.render(Renderer.current) do |root|
@@ -7,7 +7,9 @@ module Aptible
7
7
  POST_PROCESSED_KEYS = {
8
8
  'Tls' => 'TLS',
9
9
  'Dns' => 'DNS',
10
- 'Ip' => 'IP'
10
+ 'Ip' => 'IP',
11
+ 'Ssl' => 'SSL',
12
+ 'Elb' => 'ELB'
11
13
  }.freeze
12
14
 
13
15
  def visit(node, io)
@@ -213,6 +213,12 @@ module Aptible
213
213
 
214
214
  node.value('internal', vhost.internal)
215
215
 
216
+ unless vhost.current_setting.nil?
217
+ vhost.current_setting.settings.each do |k, v|
218
+ node.value(k.downcase, v)
219
+ end
220
+ end
221
+
216
222
  ip_whitelist = if vhost.ip_whitelist.any?
217
223
  vhost.ip_whitelist.join(' ')
218
224
  else
@@ -27,13 +27,18 @@ module Aptible
27
27
  service = database.service
28
28
  raise Thor::Error, 'Database is not provisioned' if service.nil?
29
29
 
30
+ prepared_params, settings = database_create_flags.prepare(
31
+ database.account,
32
+ options
33
+ )
34
+
30
35
  vhost = service.create_vhost!(
31
36
  type: 'tcp',
32
37
  platform: 'elb',
33
- **database_create_flags.prepare(database.account, options)
38
+ **prepared_params
34
39
  )
35
40
 
36
- provision_vhost_and_explain(service, vhost)
41
+ provision_vhost_and_explain(service, vhost, settings)
37
42
  end
38
43
 
39
44
  database_modify_flags = Helpers::Vhost::OptionSetBuilder.new do
@@ -49,9 +54,14 @@ module Aptible
49
54
 
50
55
  database = ensure_database(options.merge(db: options[:database]))
51
56
  vhost = find_vhost(each_service(database), hostname)
52
- vhost.update!(**database_modify_flags.prepare(database.account,
53
- options))
54
- provision_vhost_and_explain(vhost.service, vhost)
57
+
58
+ prepared_params, settings = database_modify_flags.prepare(
59
+ database.account,
60
+ options
61
+ )
62
+
63
+ vhost.update!(**prepared_params)
64
+ provision_vhost_and_explain(vhost.service, vhost, settings)
55
65
  end
56
66
 
57
67
  tcp_create_flags = Helpers::Vhost::OptionSetBuilder.new do
@@ -246,18 +256,26 @@ module Aptible
246
256
  no_commands do
247
257
  def create_app_vhost(flags, options, process_type, **attrs)
248
258
  service = ensure_service(options, process_type)
259
+
260
+ prepared_params, settings =
261
+ flags.prepare(service.account, options)
262
+
249
263
  vhost = service.create_vhost!(
250
- **flags.prepare(service.account, options),
264
+ **prepared_params,
251
265
  **attrs
252
266
  )
253
- provision_vhost_and_explain(service, vhost)
267
+ provision_vhost_and_explain(service, vhost, settings)
254
268
  end
255
269
 
256
270
  def modify_app_vhost(flags, options, hostname)
257
271
  app = ensure_app(options)
258
272
  vhost = find_vhost(each_service(app), hostname)
259
- vhost.update!(**flags.prepare(vhost.service.account, options))
260
- provision_vhost_and_explain(vhost.service, vhost)
273
+
274
+ prepared_params, settings =
275
+ flags.prepare(vhost.service.account, options)
276
+
277
+ vhost.update!(**prepared_params)
278
+ provision_vhost_and_explain(vhost.service, vhost, settings)
261
279
  end
262
280
  end
263
281
  end
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module CLI
3
- VERSION = '0.26.5'.freeze
3
+ VERSION = '0.26.6'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe Aptible::CLI::Helpers::Vhost::OptionSetBuilder do
4
+ def register_options(builder)
5
+ klass = Class.new(Thor) { include Aptible::CLI::Helpers::App }
6
+ builder.declare_options(klass)
7
+ klass.instance_variable_get(:@method_options)
8
+ end
9
+
10
+ describe '--ssl-protocols-override option description' do
11
+ context 'HTTPS endpoints (ALB, alb! flag set)' do
12
+ let(:builder) do
13
+ described_class.new do
14
+ app!
15
+ tls!
16
+ alb!
17
+ end
18
+ end
19
+
20
+ it 'includes PFS values' do
21
+ desc = register_options(builder)[:ssl_protocols_override].description
22
+ expect(desc).to include('PFS')
23
+ end
24
+ end
25
+
26
+ context 'TLS endpoints (ELB, tls! without alb!)' do
27
+ let(:builder) do
28
+ described_class.new do
29
+ app!
30
+ tls!
31
+ end
32
+ end
33
+
34
+ it 'does not include PFS values' do
35
+ desc = register_options(builder)[:ssl_protocols_override].description
36
+ expect(desc).not_to include('PFS')
37
+ end
38
+
39
+ it 'is still present' do
40
+ expect(register_options(builder)).to have_key(:ssl_protocols_override)
41
+ end
42
+ end
43
+
44
+ context 'gRPC endpoints (ELB, tls! without alb!)' do
45
+ let(:builder) do
46
+ described_class.new do
47
+ app!
48
+ port!
49
+ tls!
50
+ end
51
+ end
52
+
53
+ it 'does not include PFS values' do
54
+ desc = register_options(builder)[:ssl_protocols_override].description
55
+ expect(desc).not_to include('PFS')
56
+ end
57
+ end
58
+
59
+ context 'TCP endpoints (no tls! flag)' do
60
+ let(:builder) do
61
+ described_class.new do
62
+ app!
63
+ ports!
64
+ end
65
+ end
66
+
67
+ it 'is absent' do
68
+ expect(register_options(builder)).not_to have_key(:ssl_protocols_override)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe 'SSL_PROTOCOL_ALB_DESC' do
74
+ subject { described_class::SSL_PROTOCOL_ALB_DESC }
75
+
76
+ it 'lists all PFS protocol values' do
77
+ pfs_values = described_class::SSL_PROTOCOL_VALUES.select { |v| v.include?('PFS') }
78
+ pfs_values.each { |v| is_expected.to include(v) }
79
+ end
80
+ end
81
+
82
+ describe 'SSL_PROTOCOL_ELB_DESC' do
83
+ subject { described_class::SSL_PROTOCOL_ELB_DESC }
84
+
85
+ it 'contains no PFS values' do
86
+ is_expected.not_to include('PFS')
87
+ end
88
+
89
+ it 'lists all non-PFS protocol values' do
90
+ non_pfs_values = described_class::SSL_PROTOCOL_VALUES.reject { |v| v.include?('PFS') }
91
+ non_pfs_values.each { |v| is_expected.to include(v) }
92
+ end
93
+ end
94
+ end
@@ -25,6 +25,9 @@ describe Aptible::CLI::ResourceFormatter do
25
25
  shared: false
26
26
  )
27
27
 
28
+ vhost.current_configuration = Fabricate(:setting, settings: {},
29
+ vhost: vhost)
30
+
28
31
  expected = [
29
32
  'Id: 12',
30
33
  'Hostname: foo.io',
@@ -25,12 +25,12 @@ describe Aptible::CLI::Agent do
25
25
  end
26
26
  end
27
27
 
28
- def expect_create_vhost(service, options)
28
+ def expect_create_vhost(service, options, settings: nil)
29
29
  expect(service).to receive(:create_vhost!).with(
30
30
  hash_including(options)
31
31
  ) do |args|
32
32
  Fabricate(:vhost, service: service, **args).tap do |v|
33
- expect_operation(v, 'provision')
33
+ expect_operation(v, 'provision', settings: settings)
34
34
  expect(v).to receive(:reload).and_return(v)
35
35
  expect(Aptible::CLI::ResourceFormatter).to receive(:inject_vhost)
36
36
  .with(an_instance_of(Aptible::CLI::Formatter::Object), v, service)
@@ -49,8 +49,16 @@ describe Aptible::CLI::Agent do
49
49
  end
50
50
  end
51
51
 
52
- def expect_operation(vhost, type)
53
- expect(vhost).to receive(:create_operation!).with(type: type) do
52
+ def expect_operation(vhost, type, settings: nil)
53
+ expect(vhost).to receive(:create_operation!) do |args|
54
+ expect(args[:type]).to eq(type)
55
+
56
+ if settings.nil?
57
+ expect(args).not_to have_key(:settings)
58
+ else
59
+ expect(args[:settings]).to eq(settings)
60
+ end
61
+
54
62
  Fabricate(:operation).tap do |o|
55
63
  expect(subject).to receive(:attach_to_operation_logs).with(o)
56
64
  end
@@ -170,7 +178,13 @@ describe Aptible::CLI::Agent do
170
178
  it 'lists Endpoints' do
171
179
  s = Fabricate(:service, database: db)
172
180
  v1 = Fabricate(:vhost, service: s)
181
+ v1.current_setting = Fabricate(:setting,
182
+ settings: { 'IDLE_TIMEOUT' => '123' },
183
+ vhost: v1)
173
184
  v2 = Fabricate(:vhost, service: s)
185
+ v2.current_setting = Fabricate(:setting,
186
+ settings: { 'FORCE_SSL' => 'true' },
187
+ vhost: v2)
174
188
 
175
189
  stub_options(database: db.handle)
176
190
  subject.send('endpoints:list')
@@ -179,6 +193,8 @@ describe Aptible::CLI::Agent do
179
193
 
180
194
  expect(lines).to include("Hostname: #{v1.external_host}")
181
195
  expect(lines).to include("Hostname: #{v2.external_host}")
196
+ expect(lines).to include('Idle Timeout: 123')
197
+ expect(lines).to include('Force SSL: true')
182
198
 
183
199
  expect(lines[0]).not_to eq("\n")
184
200
  expect(lines[-1]).not_to eq("\n")
@@ -243,6 +259,105 @@ describe Aptible::CLI::Agent do
243
259
  stub_options
244
260
  end
245
261
 
262
+ shared_examples 'shared create and modify ALB settings examples' do |method|
263
+ context 'App Vhost Settings (string)' do
264
+ string_options = %i(
265
+ idle_timeout
266
+ maintenance_page_url
267
+ release_healthcheck_timeout
268
+ )
269
+
270
+ let(:value) { 'some value' }
271
+
272
+ string_options.each do |option|
273
+ context "--#{option.to_s.tr('_', '-')}" do
274
+ it 'passes a value if provided' do
275
+ wanted = { option.to_s.upcase => value }
276
+ expect_create_vhost(service, {}, { settings: wanted })
277
+ stub_options(option => value)
278
+ subject.send(method, 'web')
279
+ end
280
+
281
+ it 'passes nothing if not provided' do
282
+ expect_create_vhost(service, {})
283
+ subject.send(method, 'web')
284
+ end
285
+
286
+ context 'reverting to default' do
287
+ it 'sends an empty string if passed an empty string' do
288
+ wanted = { option.to_s.upcase => '' }
289
+ expect_create_vhost(service, {}, { settings: wanted })
290
+ stub_options(option => '')
291
+ subject.send(method, 'web')
292
+ end
293
+
294
+ it 'sends an empty string if passed the string "default"' do
295
+ wanted = { option.to_s.upcase => '' }
296
+ expect_create_vhost(service, {}, { settings: wanted })
297
+ stub_options(option => 'default')
298
+ subject.send(method, 'web')
299
+ end
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ context '--ssl-protocols-override' do
306
+ it 'passes a valid non-PFS value' do
307
+ wanted = { 'SSL_PROTOCOLS_OVERRIDE' => 'TLSv1.2' }
308
+ expect_create_vhost(service, {}, { settings: wanted })
309
+ stub_options(ssl_protocols_override: 'TLSv1.2')
310
+ subject.send(method, 'web')
311
+ end
312
+
313
+ it 'passes a valid PFS value' do
314
+ wanted = { 'SSL_PROTOCOLS_OVERRIDE' => 'TLSv1.2 PFS' }
315
+ expect_create_vhost(service, {}, { settings: wanted })
316
+ stub_options(ssl_protocols_override: 'TLSv1.2 PFS')
317
+ subject.send(method, 'web')
318
+ end
319
+
320
+ it 'raises an error for an invalid value' do
321
+ stub_options(ssl_protocols_override: 'TLSv1.0')
322
+ expect { subject.send(method, 'web') }
323
+ .to raise_error(/invalid --ssl-protocols-override/im)
324
+ end
325
+
326
+ it 'passes nothing if not provided' do
327
+ expect_create_vhost(service, {})
328
+ subject.send(method, 'web')
329
+ end
330
+
331
+ it 'sends an empty string if passed the string "default"' do
332
+ wanted = { 'SSL_PROTOCOLS_OVERRIDE' => '' }
333
+ expect_create_vhost(service, {}, { settings: wanted })
334
+ stub_options(ssl_protocols_override: 'default')
335
+ subject.send(method, 'web')
336
+ end
337
+ end
338
+
339
+ context 'App Vhost Settings (boolean)' do
340
+ boolean_options = %i(
341
+ force_ssl
342
+ show_elb_healthchecks
343
+ strict_health_checks
344
+ )
345
+
346
+ boolean_options.each do |option|
347
+ [true, false].each do |value|
348
+ context "--#{value ? '' : 'no-'}#{option.to_s.tr('_', '-')}" do
349
+ it "sets the value to the string '#{value}'" do
350
+ wanted = { option.to_s.upcase => value.to_s }
351
+ expect_create_vhost(service, {}, { settings: wanted })
352
+ stub_options(option => value)
353
+ subject.send(method, 'web')
354
+ end
355
+ end
356
+ end
357
+ end
358
+ end
359
+ end
360
+
246
361
  shared_examples 'shared create app vhost examples' do |method|
247
362
  context 'App Vhost Options' do
248
363
  it 'fails if the app does not exist' do
@@ -440,10 +555,64 @@ describe Aptible::CLI::Agent do
440
555
  end
441
556
  end
442
557
 
558
+ shared_examples 'shared create idle timeout examples' do |method|
559
+ context 'IDLE_TIMEOUT' do
560
+ it 'passes idle_timeout if provided' do
561
+ expect_create_vhost(service, {}, { settings: { 'IDLE_TIMEOUT' => '30' } })
562
+ stub_options(idle_timeout: '30')
563
+ subject.send(method, 'web')
564
+ end
565
+ end
566
+ end
567
+
568
+ shared_examples 'shared create non-alb tls settings examples' do |method|
569
+ context '--ssl-protocols-override' do
570
+ it 'passes a valid non-PFS value' do
571
+ wanted = { 'SSL_PROTOCOLS_OVERRIDE' => 'TLSv1.2' }
572
+ expect_create_vhost(service, {}, { settings: wanted })
573
+ stub_options(ssl_protocols_override: 'TLSv1.2')
574
+ subject.send(method, 'web')
575
+ end
576
+
577
+ it 'raises an error for a PFS value' do
578
+ stub_options(ssl_protocols_override: 'TLSv1.2 PFS')
579
+ expect { subject.send(method, 'web') }
580
+ .to raise_error(/pfs.*only.*alb/im)
581
+ end
582
+
583
+ it 'raises an error for an invalid value' do
584
+ stub_options(ssl_protocols_override: 'TLSv1.0')
585
+ expect { subject.send(method, 'web') }
586
+ .to raise_error(/invalid --ssl-protocols-override/im)
587
+ end
588
+ end
589
+
590
+ context 'SSL_CIPHERS_OVERRIDE' do
591
+ it 'passes ssl_ciphers_override if provided' do
592
+ wanted = { 'SSL_CIPHERS_OVERRIDE' => 'HIGH:!aNULL' }
593
+ expect_create_vhost(service, {}, { settings: wanted })
594
+ stub_options(ssl_ciphers_override: 'HIGH:!aNULL')
595
+ subject.send(method, 'web')
596
+ end
597
+ end
598
+
599
+ context 'DISABLE_WEAK_CIPHER_SUITES' do
600
+ [true, false].each do |value|
601
+ it "sets disable_weak_cipher_suites to '#{value}'" do
602
+ wanted = { 'DISABLE_WEAK_CIPHER_SUITES' => value.to_s }
603
+ expect_create_vhost(service, {}, { settings: wanted })
604
+ stub_options(disable_weak_cipher_suites: value)
605
+ subject.send(method, 'web')
606
+ end
607
+ end
608
+ end
609
+ end
610
+
443
611
  describe 'endpoints:tcp:create' do
444
612
  m = 'endpoints:tcp:create'
445
613
  include_examples 'shared create app vhost examples', m
446
614
  include_examples 'shared create tcp vhost examples', m
615
+ include_examples 'shared create idle timeout examples', m
447
616
 
448
617
  it 'creates a TCP Endpoint' do
449
618
  expect_create_vhost(
@@ -465,6 +634,8 @@ describe Aptible::CLI::Agent do
465
634
  include_examples 'shared create app vhost examples', m
466
635
  include_examples 'shared create tcp vhost examples', m
467
636
  include_examples 'shared create tls vhost examples', m
637
+ include_examples 'shared create idle timeout examples', m
638
+ include_examples 'shared create non-alb tls settings examples', m
468
639
 
469
640
  it 'creates a TLS Endpoint' do
470
641
  expect_create_vhost(
@@ -484,6 +655,7 @@ describe Aptible::CLI::Agent do
484
655
  m = 'endpoints:https:create'
485
656
  include_examples 'shared create app vhost examples', m
486
657
  include_examples 'shared create tls vhost examples', m
658
+ include_examples 'shared create and modify ALB settings examples', m
487
659
 
488
660
  it 'creates a HTTP Endpoint' do
489
661
  expect_create_vhost(
@@ -516,6 +688,8 @@ describe Aptible::CLI::Agent do
516
688
  m = 'endpoints:grpc:create'
517
689
  include_examples 'shared create app vhost examples', m
518
690
  include_examples 'shared create tls vhost examples', m
691
+ include_examples 'shared create idle timeout examples', m
692
+ include_examples 'shared create non-alb tls settings examples', m
519
693
 
520
694
  it 'creates a gRPC Endpoint' do
521
695
  expect_create_vhost(
@@ -0,0 +1,8 @@
1
+ class StubSetting < StubAptibleResource; end
2
+
3
+ Fabricator(:setting, from: :stub_setting) do
4
+ settings { {} }
5
+ sensitive_settings { {} }
6
+
7
+ after_create { |setting| vhost.settings << setting }
8
+ end
@@ -8,6 +8,8 @@ Fabricator(:vhost, from: :stub_vhost) do
8
8
  ip_whitelist { [] }
9
9
  container_ports { [] }
10
10
  created_at { Time.now }
11
+ settings { [] }
12
+ current_setting { nil }
11
13
 
12
14
  after_create { |vhost| vhost.service.vhosts << vhost }
13
15
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aptible-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.5
4
+ version: 0.26.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Macreery
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-12 00:00:00.000000000 Z
11
+ date: 2026-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -563,6 +563,7 @@ files:
563
563
  - spec/aptible/cli/helpers/ssh_spec.rb
564
564
  - spec/aptible/cli/helpers/token_spec.rb
565
565
  - spec/aptible/cli/helpers/tunnel_spec.rb
566
+ - spec/aptible/cli/helpers/vhost/option_set_builder_spec.rb
566
567
  - spec/aptible/cli/renderer/json_spec.rb
567
568
  - spec/aptible/cli/renderer/text_spec.rb
568
569
  - spec/aptible/cli/resource_formatter_spec.rb
@@ -608,6 +609,7 @@ files:
608
609
  - spec/fabricators/operation_fabricator.rb
609
610
  - spec/fabricators/service_fabricator.rb
610
611
  - spec/fabricators/service_sizing_policy_fabricator.rb
612
+ - spec/fabricators/setting_fabricator.rb
611
613
  - spec/fabricators/stack_fabricator.rb
612
614
  - spec/fabricators/vhost_fabricator.rb
613
615
  - spec/mock/git
@@ -657,6 +659,7 @@ test_files:
657
659
  - spec/aptible/cli/helpers/ssh_spec.rb
658
660
  - spec/aptible/cli/helpers/token_spec.rb
659
661
  - spec/aptible/cli/helpers/tunnel_spec.rb
662
+ - spec/aptible/cli/helpers/vhost/option_set_builder_spec.rb
660
663
  - spec/aptible/cli/renderer/json_spec.rb
661
664
  - spec/aptible/cli/renderer/text_spec.rb
662
665
  - spec/aptible/cli/resource_formatter_spec.rb
@@ -702,6 +705,7 @@ test_files:
702
705
  - spec/fabricators/operation_fabricator.rb
703
706
  - spec/fabricators/service_fabricator.rb
704
707
  - spec/fabricators/service_sizing_policy_fabricator.rb
708
+ - spec/fabricators/setting_fabricator.rb
705
709
  - spec/fabricators/stack_fabricator.rb
706
710
  - spec/fabricators/vhost_fabricator.rb
707
711
  - spec/mock/git