Skip to content

Commit 694deb9

Browse files
committed
Fix spawn_on_env vars leaking from server to app
Previously, variables specified by `spawn_on_env` would behave inconsistently when the Spring server was created with one of those variables set: ``` VAR_FROM_BOOT=before bin/rails ... ``` would cause future clients' apps to be booted with `VAR_FROM_BOOT=before` set, even if the client is created without that variable: ``` bin/rails ... ``` and additionally, Spring would hide that the app was _booted_ with that var set by _unsetting_ it when the client attached to its app (making it look like the correct ENV). The issue was caused by how `spawn_on_env` was passed from client to server to app: - The client would slice `spawn_on_env` keys from its `ENV`, meaning `bin/rails ...` would have an empty `spawn_on_env` hash. - The server (which has `VAR_FROM_BOOT` set), forks an app with `spawn_on_env` values set (none, because its an empty hash) - The forked app inherits its parent's `ENV`, so it boots with `VAR_FROM_BOOT` set - The client gets a forked app process, and cleans up environment variables from the server process This is specifically an issue for `spawn_on_env` because the goal is to have apps booted with different environments. This commit fixes the issue by always passing all `Spring.spawn_on_env` values from the client to the server (including `nil` ones) so that the forked app will have those values cleared if necessary. `compact` is added to the `SPRING_SPAWN_ENV` value because it is only used to display the `spawn_on_env` values in `spring status` and showing all of the `nil` values is noisy/unnecessary.
1 parent 13ba7d3 commit 694deb9

File tree

3 files changed

+16
-2
lines changed

3 files changed

+16
-2
lines changed

lib/spring/application_manager.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def start_child(preload = false)
102102
"RACK_ENV" => app_env,
103103
"SPRING_ORIGINAL_ENV" => JSON.dump(Spring::ORIGINAL_ENV),
104104
"SPRING_PRELOAD" => preload ? "1" : "0",
105-
"SPRING_SPAWN_ENV" => JSON.dump(spawn_env),
105+
"SPRING_SPAWN_ENV" => JSON.dump(spawn_env.compact),
106106
**spawn_env,
107107
},
108108
"ruby",

lib/spring/client/run.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,9 @@ def default_rails_env
254254
end
255255

256256
def spawn_env
257-
ENV.slice(*Spring.spawn_on_env)
257+
Spring.spawn_on_env.to_h do |key|
258+
[key, ENV[key]]
259+
end
258260
end
259261
end
260262
end

test/support/acceptance_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,18 @@ def exec_name
663663
assert_success %(bin/rails runner 'p ENV.key?("FOO")'), stdout: "false"
664664
end
665665

666+
test "spawn_on_env variables are cleared when unset" do
667+
File.write(app.spring_client_config, "Spring.spawn_on_env << 'VAR_FROM_BOOT'")
668+
File.write(app.application_config, "#{app.application_config.read}\nRails.configuration.x.var_from_boot = ENV['VAR_FROM_BOOT']")
669+
670+
app.env["VAR_FROM_BOOT"] = "before"
671+
assert_success %(bin/rails runner 'p Rails.configuration.x.var_from_boot.inspect'), stdout: "before"
672+
673+
app.env.delete "VAR_FROM_BOOT"
674+
675+
assert_success %(bin/rails runner 'p Rails.configuration.x.var_from_boot.inspect'), stdout: "nil"
676+
end
677+
666678
test "Kernel.raise remains private" do
667679
expr = "p Kernel.private_instance_methods.include?(:raise)"
668680
assert_success %(bin/rails runner '#{expr}'), stdout: "true"

0 commit comments

Comments
 (0)