From 2da4db50f26f0b83274adb0a4c159ea1c691af6c Mon Sep 17 00:00:00 2001 From: Alex Kubacki Date: Thu, 8 Jan 2026 16:56:32 -0700 Subject: [PATCH 1/6] WIP --- Gemfile.lock | 12 +- aptible-cli.gemspec | 2 +- lib/aptible/cli/helpers/vhost.rb | 7 +- .../cli/helpers/vhost/option_set_builder.rb | 129 +++++++++++++++++- lib/aptible/cli/subcommands/endpoints.rb | 36 +++-- lib/aptible/cli/version.rb | 2 +- .../aptible/cli/subcommands/endpoints_spec.rb | 86 +++++++++++- 7 files changed, 252 insertions(+), 22 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3e85b63f..30ab148f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - aptible-cli (0.26.0) + aptible-cli (0.26.2) activesupport (>= 4.0, < 6.0) aptible-api (~> 1.12) aptible-auth (~> 1.4) @@ -20,6 +20,7 @@ PATH httpclient (~> 2.8.0) json (~> 2.5.0) jwt (~> 2.3.0) + pry rack (~> 1.0) stripe (< 5.0) term-ansicolor (~> 1.8.0) @@ -35,7 +36,7 @@ GEM tzinfo (~> 1.1) addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) - aptible-api (1.12.0) + aptible-api (1.12.1) aptible-auth aptible-resource gem_config @@ -100,6 +101,7 @@ GEM rainbow (>= 2.0.0) i18n (0.9.5) concurrent-ruby (~> 1.0) + io-console (0.8.2) jmespath (1.6.2) json (2.5.1) jwt (2.3.0) @@ -120,15 +122,18 @@ GEM parser (2.7.2.0) ast (~> 2.4.1) powerpack (0.1.3) - pry (0.14.2) + pry (0.16.0) coderay (~> 1.1) method_source (~> 1.0) + reline (>= 0.6.0) public_suffix (3.1.1) rack (1.6.13) rainbow (2.2.2) rake rake (12.3.3) rchardet (1.8.0) + reline (0.6.3) + io-console (~> 0.5) rexml (3.2.5) rspec (3.13.0) rspec-core (~> 3.13.0) @@ -187,7 +192,6 @@ DEPENDENCIES hashie (< 5.1) httplog (< 1.6) minitest (< 5.16) - pry rack (~> 1.0) rake rspec (~> 3.2) diff --git a/aptible-cli.gemspec b/aptible-cli.gemspec index 0d617bff..d1d652c6 100644 --- a/aptible-cli.gemspec +++ b/aptible-cli.gemspec @@ -51,7 +51,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'aptible-tasks', '~> 0.5.8' spec.add_development_dependency 'rake' spec.add_development_dependency 'rspec', '~> 3.2' - spec.add_development_dependency 'pry' + spec.add_dependency 'pry' spec.add_development_dependency 'climate_control', '= 0.0.3' spec.add_development_dependency 'fabrication', '~> 2.15.2' spec.add_development_dependency 'httplog', '< 1.6' diff --git a/lib/aptible/cli/helpers/vhost.rb b/lib/aptible/cli/helpers/vhost.rb index 7ec5c852..7d58551a 100644 --- a/lib/aptible/cli/helpers/vhost.rb +++ b/lib/aptible/cli/helpers/vhost.rb @@ -2,8 +2,11 @@ module Aptible module CLI module Helpers module Vhost - def provision_vhost_and_explain(service, vhost) - op = vhost.create_operation!(type: 'provision') + def provision_vhost_and_explain(service, vhost, settings) + op = vhost.create_operation!( + type: 'provision', + **(settings.empty? ? {} : { settings: settings }) + ) attach_to_operation_logs(op) Formatter.render(Renderer.current) do |root| diff --git a/lib/aptible/cli/helpers/vhost/option_set_builder.rb b/lib/aptible/cli/helpers/vhost/option_set_builder.rb index 22e3b9d8..29e14982 100644 --- a/lib/aptible/cli/helpers/vhost/option_set_builder.rb +++ b/lib/aptible/cli/helpers/vhost/option_set_builder.rb @@ -1,3 +1,5 @@ +require 'pry' + module Aptible module CLI module Helpers @@ -69,6 +71,76 @@ def declare_options(thor) desc: "Share this Endpoint's load balancer with other " \ 'Endpoints' ) + + option( + :client_body_timeout, + type: :string, + desc: 'Timeout (seconds) for receiving the request body, ' \ + 'applying only between successive read operations ' \ + 'rather than to the entire request body transmission' + ) + + option( + :force_ssl, + type: :boolean, + desc: 'Redirect all HTTP requests to HTTPS, and ' \ + 'enable the Strict-Transport-Security header (HSTS)' + ) + + option( + :idle_timeout, + type: :string, + desc: 'Timeout (seconds) to enforce idle timeouts while ' \ + 'sending and receiving responses' + ) + + option( + :ignore_invalid_headers, + type: :boolean, + desc: 'Controls whether header fields with invalid names ' \ + 'should be dropped by the endpoint' + ) + + option( + :maintenance_page_url, + type: :string, + desc: 'The URL of a maintenance page to cache and serve ' \ + 'when requests time out, or your app is unhealthy' + ) + + option( + :nginx_error_log_level, + type: :string, + desc: "Sets the log level for the endpoint's error logs" + ) + + option( + :release_healthcheck_timeout, + type: :string, + desc: 'Timeout (seconds) to wait for your app to ' \ + 'respond to a release health check' + ) + + option( + :show_elb_healthchecks, + type: :boolean, + desc: 'Show all runtime health check requets in the ' \ + "endpoint's logs" + ) + + option( + :ssl_protocols_override, + type: :string, + desc: 'Specify a list of allowed SSL protocols' + ) + + option( + :strict_health_checks, + type: :boolean, + desc: 'Require containers to respond to health checks ' \ + 'with a 200 OK HTTP response.' + ) + end end @@ -128,6 +200,18 @@ def declare_options(thor) desc: 'The fingerprint of an existing Certificate to use ' \ 'on this Endpoint' ) + + option( + :ssl_ciphers_override, + type: :string, + desc: 'Specify the allowed SSL ciphers' + ) + + option( + :ssl_protocols_override, + type: :string, + desc: 'Specify a list of allowed SSL protocols' + ) end end end @@ -137,6 +221,7 @@ def prepare(account, options) verify_option_conflicts(options) params = {} + settings = {} params[:ip_whitelist] = options.delete(:ip_whitelist) do create? ? [] : nil @@ -203,6 +288,46 @@ def prepare(account, options) params[:shared] = options.delete(:shared) end + vhost_settings = %i( + client_body_timeout + idle_timeout + maintenance_page_url + nginx_error_log_level + release_healthcheck_timeout + ssl_protocols_override + ) + + vhost_settings.each do |key| + val = options.delete(key) + next if val.nil? + + settings[key.to_s.upcase] = case val + when 'default' + '' + else + val + end + end + + boolean_vhost_settings = %i( + force_ssl + ignore_invalid_headers + show_elb_healthchecks + strict_health_checks + ) + + # TODO: there seems to be no Thor way to let the user unset/revert + # to the default sweetness behavior? + + boolean_vhost_settings.each do |key| + value = options.delete(key) + next if value.nil? + + settings[key.to_s.upcase] = value.to_s + end + + options.delete(:client_body_timeout) + options.delete(:environment) # NOTE: This is here to ensure that specs don't test for options @@ -210,7 +335,7 @@ def prepare(account, options) # this. raise "Unexpected options: #{options}" if options.any? - params.delete_if { |_, v| v.nil? } + [params.delete_if { |_, v| v.nil? }, settings] end FLAGS.each do |f| @@ -309,6 +434,8 @@ def verify_option_conflicts(options) %i(no-ip_whitelist), %i(ip_whitelist) ] + + # TODO: are there new conflicts? ] conflict_groups.each do |group| diff --git a/lib/aptible/cli/subcommands/endpoints.rb b/lib/aptible/cli/subcommands/endpoints.rb index eb57716d..f1578ec5 100644 --- a/lib/aptible/cli/subcommands/endpoints.rb +++ b/lib/aptible/cli/subcommands/endpoints.rb @@ -27,13 +27,18 @@ def self.included(thor) service = database.service raise Thor::Error, 'Database is not provisioned' if service.nil? + prepared_params, settings = database_create_flags.prepare( + database.account, + options + ) + vhost = service.create_vhost!( type: 'tcp', platform: 'elb', - **database_create_flags.prepare(database.account, options) + **prepared_params ) - provision_vhost_and_explain(service, vhost) + provision_vhost_and_explain(service, vhost, settings) end database_modify_flags = Helpers::Vhost::OptionSetBuilder.new do @@ -49,9 +54,14 @@ def self.included(thor) database = ensure_database(options.merge(db: options[:database])) vhost = find_vhost(each_service(database), hostname) - vhost.update!(**database_modify_flags.prepare(database.account, - options)) - provision_vhost_and_explain(vhost.service, vhost) + + prepared_params, settings = database_modify_flags.prepare( + database.account, + options + ) + + vhost.update!(**prepared_params) + provision_vhost_and_explain(vhost.service, vhost, settings) end tcp_create_flags = Helpers::Vhost::OptionSetBuilder.new do @@ -246,18 +256,26 @@ def self.included(thor) no_commands do def create_app_vhost(flags, options, process_type, **attrs) service = ensure_service(options, process_type) + + prepared_params, settings = + flags.prepare(service.account, options) + vhost = service.create_vhost!( - **flags.prepare(service.account, options), + **prepared_params, **attrs ) - provision_vhost_and_explain(service, vhost) + provision_vhost_and_explain(service, vhost, settings) end def modify_app_vhost(flags, options, hostname) app = ensure_app(options) vhost = find_vhost(each_service(app), hostname) - vhost.update!(**flags.prepare(vhost.service.account, options)) - provision_vhost_and_explain(vhost.service, vhost) + + prepared_params, settings = + flags.prepare(vhost.service.account, options) + + vhost.update!(**prepared_params) + provision_vhost_and_explain(vhost.service, vhost, settings) end end end diff --git a/lib/aptible/cli/version.rb b/lib/aptible/cli/version.rb index feaf6c51..bffa4bcc 100644 --- a/lib/aptible/cli/version.rb +++ b/lib/aptible/cli/version.rb @@ -1,5 +1,5 @@ module Aptible module CLI - VERSION = '0.26.0'.freeze + VERSION = '0.26.2'.freeze end end diff --git a/spec/aptible/cli/subcommands/endpoints_spec.rb b/spec/aptible/cli/subcommands/endpoints_spec.rb index 593b6742..3e21d0ea 100644 --- a/spec/aptible/cli/subcommands/endpoints_spec.rb +++ b/spec/aptible/cli/subcommands/endpoints_spec.rb @@ -22,12 +22,12 @@ def expect_create_certificate(account, options) end end - def expect_create_vhost(service, options) + def expect_create_vhost(service, options, settings: nil) expect(service).to receive(:create_vhost!).with( hash_including(options) ) do |args| Fabricate(:vhost, service: service, **args).tap do |v| - expect_operation(v, 'provision') + expect_operation(v, 'provision', settings: settings) expect(v).to receive(:reload).and_return(v) expect(Aptible::CLI::ResourceFormatter).to receive(:inject_vhost) .with(an_instance_of(Aptible::CLI::Formatter::Object), v, service) @@ -46,8 +46,16 @@ def expect_modify_vhost(vhost, options) end end - def expect_operation(vhost, type) - expect(vhost).to receive(:create_operation!).with(type: type) do + def expect_operation(vhost, type, settings: nil) + expect(vhost).to receive(:create_operation!) do |args| + expect(args[:type]).to eq(type) + + if settings.nil? + expect(args).not_to have_key(:settings) + else + expect(args[:settings]).to eq(settings) + end + Fabricate(:operation).tap do |o| expect(subject).to receive(:attach_to_operation_logs).with(o) end @@ -227,6 +235,75 @@ def stub_options(**opts) stub_options end + shared_examples 'shared create and modify ALB settings examples' do |method| + context 'App Vhost Settings (string)' do + string_options = %i( + client_body_timeout + idle_timeout + maintenance_page_url + nginx_error_log_level + release_healthcheck_timeout + ssl_protocols_override + ) + + let(:value) { 'some value' } + + string_options.each do |option| + context "--#{option.to_s.tr('_', '-')}" do + it 'passes a value if provided' do + wanted = { option.to_s.upcase => value } + expect_create_vhost(service, {}, { settings: wanted }) + stub_options(option => value) + subject.send(method, 'web') + end + + it 'passes nothing if not provided' do + expect_create_vhost(service, {}) + subject.send(method, 'web') + end + + context 'reverting to default' do + it 'sends an empty string if passed an empty string' do + wanted = { option.to_s.upcase => '' } + expect_create_vhost(service, {}, { settings: wanted }) + stub_options(option => '') + subject.send(method, 'web') + end + + it 'sends an empty string if passed the string "default"' do + wanted = { option.to_s.upcase => '' } + expect_create_vhost(service, {}, { settings: wanted }) + stub_options(option => 'default') + subject.send(method, 'web') + end + end + end + end + end + + context 'App Vhost Settings (boolean)' do + boolean_options = %i( + force_ssl + ignore_invalid_headers + show_elb_healthchecks + strict_health_checks + ) + + boolean_options.each do |option| + [true, false].each do |value| + context "--#{value ? '' : 'no-'}#{option.to_s.tr('_', '-')}" do + it "sets the value to the string '#{value}'" do + wanted = { option.to_s.upcase => value.to_s } + expect_create_vhost(service, {}, { settings: wanted }) + stub_options(option => value) + subject.send(method, 'web') + end + end + end + end + end + end + shared_examples 'shared create app vhost examples' do |method| context 'App Vhost Options' do it 'fails if the app does not exist' do @@ -468,6 +545,7 @@ def stub_options(**opts) m = 'endpoints:https:create' include_examples 'shared create app vhost examples', m include_examples 'shared create tls vhost examples', m + include_examples 'shared create and modify ALB settings examples', m it 'creates a HTTP Endpoint' do expect_create_vhost( From 0636b3efb61810bb8f9bc819c5c0d8fff06a99c2 Mon Sep 17 00:00:00 2001 From: Alex Kubacki Date: Thu, 8 Jan 2026 19:49:24 -0700 Subject: [PATCH 2/6] Tweaks --- lib/aptible/cli/helpers/vhost/option_set_builder.rb | 1 + lib/aptible/cli/renderer/text.rb | 4 +++- lib/aptible/cli/resource_formatter.rb | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/aptible/cli/helpers/vhost/option_set_builder.rb b/lib/aptible/cli/helpers/vhost/option_set_builder.rb index 29e14982..e21048ba 100644 --- a/lib/aptible/cli/helpers/vhost/option_set_builder.rb +++ b/lib/aptible/cli/helpers/vhost/option_set_builder.rb @@ -295,6 +295,7 @@ def prepare(account, options) nginx_error_log_level release_healthcheck_timeout ssl_protocols_override + ssl_ciphers_override ) vhost_settings.each do |key| diff --git a/lib/aptible/cli/renderer/text.rb b/lib/aptible/cli/renderer/text.rb index efa35f57..6f42afb6 100644 --- a/lib/aptible/cli/renderer/text.rb +++ b/lib/aptible/cli/renderer/text.rb @@ -7,7 +7,9 @@ class Text < Base POST_PROCESSED_KEYS = { 'Tls' => 'TLS', 'Dns' => 'DNS', - 'Ip' => 'IP' + 'Ip' => 'IP', + 'Ssl' => 'SSL' + 'Elb' => 'ELB' }.freeze def visit(node, io) diff --git a/lib/aptible/cli/resource_formatter.rb b/lib/aptible/cli/resource_formatter.rb index c8230a54..44632fa3 100644 --- a/lib/aptible/cli/resource_formatter.rb +++ b/lib/aptible/cli/resource_formatter.rb @@ -209,6 +209,10 @@ def inject_vhost(node, vhost, service) node.value('internal', vhost.internal) + vhost.current_setting.settings.each do |k, v| + node.value(k.downcase, v) + end + ip_whitelist = if vhost.ip_whitelist.any? vhost.ip_whitelist.join(' ') else From e7fbb9bd39f00f1f30fba542d4486a0241db8dfd Mon Sep 17 00:00:00 2001 From: Alex Kubacki Date: Fri, 9 Jan 2026 15:22:56 -0700 Subject: [PATCH 3/6] Fix --- lib/aptible/cli/renderer/text.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aptible/cli/renderer/text.rb b/lib/aptible/cli/renderer/text.rb index 6f42afb6..79e4e2f5 100644 --- a/lib/aptible/cli/renderer/text.rb +++ b/lib/aptible/cli/renderer/text.rb @@ -8,7 +8,7 @@ class Text < Base 'Tls' => 'TLS', 'Dns' => 'DNS', 'Ip' => 'IP', - 'Ssl' => 'SSL' + 'Ssl' => 'SSL', 'Elb' => 'ELB' }.freeze From 2e4ceb1ae7380b9ddcae74f4c532361a412f8593 Mon Sep 17 00:00:00 2001 From: Alex Kubacki Date: Wed, 21 Jan 2026 14:03:46 -0700 Subject: [PATCH 4/6] Wrap up --- Gemfile.lock | 8 ++------ lib/aptible/cli/helpers/vhost/option_set_builder.rb | 11 ++++++++++- lib/aptible/cli/version.rb | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 30ab148f..ffa099f9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - aptible-cli (0.26.2) + aptible-cli (0.27.0) activesupport (>= 4.0, < 6.0) aptible-api (~> 1.12) aptible-auth (~> 1.4) @@ -101,7 +101,6 @@ GEM rainbow (>= 2.0.0) i18n (0.9.5) concurrent-ruby (~> 1.0) - io-console (0.8.2) jmespath (1.6.2) json (2.5.1) jwt (2.3.0) @@ -122,18 +121,15 @@ GEM parser (2.7.2.0) ast (~> 2.4.1) powerpack (0.1.3) - pry (0.16.0) + pry (0.15.2) coderay (~> 1.1) method_source (~> 1.0) - reline (>= 0.6.0) public_suffix (3.1.1) rack (1.6.13) rainbow (2.2.2) rake rake (12.3.3) rchardet (1.8.0) - reline (0.6.3) - io-console (~> 0.5) rexml (3.2.5) rspec (3.13.0) rspec-core (~> 3.13.0) diff --git a/lib/aptible/cli/helpers/vhost/option_set_builder.rb b/lib/aptible/cli/helpers/vhost/option_set_builder.rb index e21048ba..992ea488 100644 --- a/lib/aptible/cli/helpers/vhost/option_set_builder.rb +++ b/lib/aptible/cli/helpers/vhost/option_set_builder.rb @@ -312,7 +312,6 @@ def prepare(account, options) boolean_vhost_settings = %i( force_ssl - ignore_invalid_headers show_elb_healthchecks strict_health_checks ) @@ -327,6 +326,16 @@ def prepare(account, options) settings[key.to_s.upcase] = value.to_s end + # this one we pass through to nginx, and "on" and "off" are the exected values + ignore_invalid_headers = options.delete(:ignore_invalid_headers) + unless ignore_invalid_headers.nil? + settings['IGNORE_INVALID_HEADERS'] = case ignore_invalid_headers + when true + 'on' + when false + 'off' + end + options.delete(:client_body_timeout) options.delete(:environment) diff --git a/lib/aptible/cli/version.rb b/lib/aptible/cli/version.rb index bffa4bcc..a12714ab 100644 --- a/lib/aptible/cli/version.rb +++ b/lib/aptible/cli/version.rb @@ -1,5 +1,5 @@ module Aptible module CLI - VERSION = '0.26.2'.freeze + VERSION = '0.27.0'.freeze end end From 7eb26f79a97396aa3155c207a5b53471d59ec09c Mon Sep 17 00:00:00 2001 From: Alex Kubacki Date: Wed, 21 Jan 2026 15:30:14 -0700 Subject: [PATCH 5/6] Cleanup --- Gemfile.lock | 2 +- aptible-cli.gemspec | 2 +- .../cli/helpers/vhost/option_set_builder.rb | 13 +++-------- lib/aptible/cli/resource_formatter.rb | 6 +++-- spec/aptible/cli/resource_formatter_spec.rb | 3 +++ .../aptible/cli/subcommands/endpoints_spec.rb | 22 ++++++++++++++++++- spec/fabricators/vhost_fabricator.rb | 2 ++ 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ffa099f9..080d42cc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -20,7 +20,6 @@ PATH httpclient (~> 2.8.0) json (~> 2.5.0) jwt (~> 2.3.0) - pry rack (~> 1.0) stripe (< 5.0) term-ansicolor (~> 1.8.0) @@ -188,6 +187,7 @@ DEPENDENCIES hashie (< 5.1) httplog (< 1.6) minitest (< 5.16) + pry rack (~> 1.0) rake rspec (~> 3.2) diff --git a/aptible-cli.gemspec b/aptible-cli.gemspec index d1d652c6..0d617bff 100644 --- a/aptible-cli.gemspec +++ b/aptible-cli.gemspec @@ -51,7 +51,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'aptible-tasks', '~> 0.5.8' spec.add_development_dependency 'rake' spec.add_development_dependency 'rspec', '~> 3.2' - spec.add_dependency 'pry' + spec.add_development_dependency 'pry' spec.add_development_dependency 'climate_control', '= 0.0.3' spec.add_development_dependency 'fabrication', '~> 2.15.2' spec.add_development_dependency 'httplog', '< 1.6' diff --git a/lib/aptible/cli/helpers/vhost/option_set_builder.rb b/lib/aptible/cli/helpers/vhost/option_set_builder.rb index 992ea488..49aef755 100644 --- a/lib/aptible/cli/helpers/vhost/option_set_builder.rb +++ b/lib/aptible/cli/helpers/vhost/option_set_builder.rb @@ -1,5 +1,3 @@ -require 'pry' - module Aptible module CLI module Helpers @@ -316,9 +314,6 @@ def prepare(account, options) strict_health_checks ) - # TODO: there seems to be no Thor way to let the user unset/revert - # to the default sweetness behavior? - boolean_vhost_settings.each do |key| value = options.delete(key) next if value.nil? @@ -326,7 +321,8 @@ def prepare(account, options) settings[key.to_s.upcase] = value.to_s end - # this one we pass through to nginx, and "on" and "off" are the exected values + # This one we pass through to nginx for whatever rason, so + # "on" and "off" are the exected values ignore_invalid_headers = options.delete(:ignore_invalid_headers) unless ignore_invalid_headers.nil? settings['IGNORE_INVALID_HEADERS'] = case ignore_invalid_headers @@ -335,8 +331,7 @@ def prepare(account, options) when false 'off' end - - options.delete(:client_body_timeout) + end options.delete(:environment) @@ -444,8 +439,6 @@ def verify_option_conflicts(options) %i(no-ip_whitelist), %i(ip_whitelist) ] - - # TODO: are there new conflicts? ] conflict_groups.each do |group| diff --git a/lib/aptible/cli/resource_formatter.rb b/lib/aptible/cli/resource_formatter.rb index 44632fa3..72158204 100644 --- a/lib/aptible/cli/resource_formatter.rb +++ b/lib/aptible/cli/resource_formatter.rb @@ -209,8 +209,10 @@ def inject_vhost(node, vhost, service) node.value('internal', vhost.internal) - vhost.current_setting.settings.each do |k, v| - node.value(k.downcase, v) + unless vhost.current_setting.nil? + vhost.current_setting.settings.each do |k, v| + node.value(k.downcase, v) + end end ip_whitelist = if vhost.ip_whitelist.any? diff --git a/spec/aptible/cli/resource_formatter_spec.rb b/spec/aptible/cli/resource_formatter_spec.rb index 43a8671d..57b8731f 100644 --- a/spec/aptible/cli/resource_formatter_spec.rb +++ b/spec/aptible/cli/resource_formatter_spec.rb @@ -25,6 +25,9 @@ def capture(m, *args) shared: false ) + vhost.current_configuration = Fabricate(:setting, settings: {}, + vhost: vhost) + expected = [ 'Id: 12', 'Hostname: foo.io', diff --git a/spec/aptible/cli/subcommands/endpoints_spec.rb b/spec/aptible/cli/subcommands/endpoints_spec.rb index 3e21d0ea..a08bdb25 100644 --- a/spec/aptible/cli/subcommands/endpoints_spec.rb +++ b/spec/aptible/cli/subcommands/endpoints_spec.rb @@ -169,7 +169,13 @@ def stub_options(**opts) it 'lists Endpoints' do s = Fabricate(:service, database: db) v1 = Fabricate(:vhost, service: s) + v1.current_setting = Fabricate(:setting, + settings: { 'IDLE_TIMEOUT' => '123' }, + vhost: v1) v2 = Fabricate(:vhost, service: s) + v2.current_setting = Fabricate(:setting, + settings: { 'FORCE_SSL' => 'true' }, + vhost: v2) stub_options(database: db.handle) subject.send('endpoints:list') @@ -178,6 +184,8 @@ def stub_options(**opts) expect(lines).to include("Hostname: #{v1.external_host}") expect(lines).to include("Hostname: #{v2.external_host}") + expect(lines).to include('Idle Timeout: 123') + expect(lines).to include('Force SSL: true') expect(lines[0]).not_to eq("\n") expect(lines[-1]).not_to eq("\n") @@ -284,7 +292,6 @@ def stub_options(**opts) context 'App Vhost Settings (boolean)' do boolean_options = %i( force_ssl - ignore_invalid_headers show_elb_healthchecks strict_health_checks ) @@ -302,6 +309,19 @@ def stub_options(**opts) end end end + + context 'Strange Vhost settings' do + { true => 'on', false => 'off' }.each do |bool, value| + context "--#{bool ? '' : 'no-'}ignore_invalid_headers" do + it "sets the value to the string '#{value}'" do + wanted = { 'IGNORE_INVALID_HEADERS' => value } + expect_create_vhost(service, {}, { settings: wanted }) + stub_options(ignore_invalid_headers: bool) + subject.send(method, 'web') + end + end + end + end end shared_examples 'shared create app vhost examples' do |method| diff --git a/spec/fabricators/vhost_fabricator.rb b/spec/fabricators/vhost_fabricator.rb index 1b4d6225..04b9ec75 100644 --- a/spec/fabricators/vhost_fabricator.rb +++ b/spec/fabricators/vhost_fabricator.rb @@ -8,6 +8,8 @@ class StubVhost < OpenStruct; end ip_whitelist { [] } container_ports { [] } created_at { Time.now } + settings { [] } + current_setting { nil } after_create { |vhost| vhost.service.vhosts << vhost } end From 750ff858d916995c12c956da3fa75644f0ff64ea Mon Sep 17 00:00:00 2001 From: Alex Kubacki Date: Wed, 21 Jan 2026 15:38:41 -0700 Subject: [PATCH 6/6] include the fab --- spec/fabricators/setting_fabricator.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 spec/fabricators/setting_fabricator.rb diff --git a/spec/fabricators/setting_fabricator.rb b/spec/fabricators/setting_fabricator.rb new file mode 100644 index 00000000..021131bf --- /dev/null +++ b/spec/fabricators/setting_fabricator.rb @@ -0,0 +1,9 @@ +class StubConfiguration < OpenStruct +end + +Fabricator(:setting, from: :stub_configuration) do + settings { {} } + sensitive_settings { {} } + + after_create { |setting| vhost.settings << setting } +end