aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
authorPrem Sichanugrist <s@sikac.hu>2019-03-23 16:47:26 +0900
committerPrem Sichanugrist <s@sikac.hu>2019-03-23 19:31:03 +0900
commitb27105252bce6a69f6d57c05d4ea28d20e84f8ae (patch)
tree13072d72ae90d7c83597b6c832799454aba13b75 /railties
parentefb706daad0e2e1039c6abb4879c837ef8bf4d10 (diff)
downloadrails-b27105252bce6a69f6d57c05d4ea28d20e84f8ae.tar.gz
rails-b27105252bce6a69f6d57c05d4ea28d20e84f8ae.tar.bz2
rails-b27105252bce6a69f6d57c05d4ea28d20e84f8ae.zip
Add config.disable_sandbox option to Rails console
A long-running `rails console --sandbox` could cause a database server to become out-of-memory as it's holding on to changes that happen on the database. Given that it's common for Ruby on Rails application with huge traffic to have separate write database and read database, we should allow the developers to disable this sandbox option to prevent someone from accidentally causing the Denial-of-Service on their server.
Diffstat (limited to 'railties')
-rw-r--r--railties/CHANGELOG.md8
-rw-r--r--railties/lib/rails/application/configuration.rb4
-rw-r--r--railties/lib/rails/commands/console/console_command.rb6
-rw-r--r--railties/test/application/configuration_test.rb16
-rw-r--r--railties/test/application/console_test.rb21
-rw-r--r--railties/test/commands/console_test.rb2
6 files changed, 52 insertions, 5 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 226b949b34..1fb0a94b2d 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,11 @@
+* Add `config.disable_sandbox` option to Rails console.
+
+ This setting will disable `rails console --sandbox` mode, preventing
+ developer from accidentally starting a sandbox console, left it inactive,
+ and cause the database server to run out of memory.
+
+ *Prem Sichanugrist*
+
* Add `-e/--environment` option to `rails initializers`.
*Yuji Yaginuma*
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 83a7b6cf01..b79dbdbc6f 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -18,7 +18,8 @@ module Rails
:session_options, :time_zone, :reload_classes_only_on_change,
:beginning_of_week, :filter_redirect, :x, :enable_dependency_loading,
:read_encrypted_secrets, :log_level, :content_security_policy_report_only,
- :content_security_policy_nonce_generator, :require_master_key, :credentials
+ :content_security_policy_nonce_generator, :require_master_key, :credentials,
+ :disable_sandbox
attr_reader :encoding, :api_only, :loaded_config_version, :autoloader
@@ -65,6 +66,7 @@ module Rails
@credentials.content_path = default_credentials_content_path
@credentials.key_path = default_credentials_key_path
@autoloader = :classic
+ @disable_sandbox = false
end
def load_defaults(target_version)
diff --git a/railties/lib/rails/commands/console/console_command.rb b/railties/lib/rails/commands/console/console_command.rb
index e35faa5b01..7a9eaefea1 100644
--- a/railties/lib/rails/commands/console/console_command.rb
+++ b/railties/lib/rails/commands/console/console_command.rb
@@ -26,6 +26,12 @@ module Rails
@options = options
app.sandbox = sandbox?
+
+ if sandbox? && app.config.disable_sandbox
+ puts "Error: Unable to start console in sandbox mode as sandbox mode is disabled (config.disable_sandbox is true)."
+ exit 1
+ end
+
app.load_console
@console = app.config.console || IRB
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index e34c075a1c..b8e167b488 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -2476,6 +2476,22 @@ module ApplicationTests
assert_includes Rails.application.config.hosts, ".localhost"
end
+ test "disable_sandbox is false by default" do
+ app "development"
+
+ assert_equal false, Rails.configuration.disable_sandbox
+ end
+
+ test "disable_sandbox can be overridden" do
+ add_to_config <<-RUBY
+ config.disable_sandbox = true
+ RUBY
+
+ app "development"
+
+ assert Rails.configuration.disable_sandbox
+ end
+
private
def force_lazy_load_hooks
yield # Tasty clarifying sugar, homie! We only need to reference a constant to load it.
diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb
index b6270525f0..db16f4cc56 100644
--- a/railties/test/application/console_test.rb
+++ b/railties/test/application/console_test.rb
@@ -123,13 +123,17 @@ class FullStackConsoleTest < ActiveSupport::TestCase
assert_output "> ", @primary
end
- def spawn_console(options)
- Process.spawn(
+ def spawn_console(options, wait_for_prompt: true)
+ pid = Process.spawn(
"#{app_path}/bin/rails console #{options}",
in: @replica, out: @replica, err: @replica
)
- assert_output "> ", @primary, 30
+ if wait_for_prompt
+ assert_output "> ", @primary, 30
+ end
+
+ pid
end
def test_sandbox
@@ -148,6 +152,17 @@ class FullStackConsoleTest < ActiveSupport::TestCase
@primary.puts "quit"
end
+ def test_sandbox_when_sandbox_is_disabled
+ add_to_config <<-RUBY
+ config.disable_sandbox = true
+ RUBY
+
+ output = `#{app_path}/bin/rails console --sandbox`
+
+ assert_includes output, "sandbox mode is disabled"
+ assert_equal 1, $?.exitstatus
+ end
+
def test_environment_option_and_irb_option
spawn_console("-e test -- --verbose")
diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb
index 1941c83d6d..f6df2b694a 100644
--- a/railties/test/commands/console_test.rb
+++ b/railties/test/commands/console_test.rb
@@ -129,7 +129,7 @@ class Rails::ConsoleTest < ActiveSupport::TestCase
def build_app(console)
mocked_console = Class.new do
attr_accessor :sandbox
- attr_reader :console
+ attr_reader :console, :disable_sandbox
def initialize(console)
@console = console