-
Notifications
You must be signed in to change notification settings - Fork 21.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rails 7.2 "secret_key_base must be a type of String" issue when running tests in parallel in a CI build #53661
Comments
This fails on 8.0.0 as well as master, I believe due to a race-condition in railties I'm working on a solution for this currently. We could introduce a new |
It sounds like there may be two things that could potentially be changed:
I don't think a new ENV should be necessary |
I agree that reading from credentials should be optimal. I can put together a PR for this, unless the removal IS in fact intentional. |
@frederikspang Thanks for looking into this. I wonder if something like this could be used to make the https://stackoverflow.com/questions/1461253/mutex-for-rails-processes |
Since 0c76f17 a `tmp/local_secret.txt` is always used for `Rails.config.secret_key_base` in the test and development environments, where previously `ENV["SECRET_KEY_BASE"]` or `Rails.application.credentials.secret_key_base` were used if present. The race condition in generating the local secret file, as reported in rails#53661, should be avoided by setting `ENV["SECRET_KEY_BASE"]` or `Rails.application.credentials.secret_key_base`, but this currently doesn't work. When ENV["SECRET_KEY_BASE"] or `Rails.application.credentials.secret_key_base` is set for test or development, it should be used for the `Rails.config.secret_key_base`, instead of generating a `tmp/local_secret.txt`.
Since 0c76f17 a `tmp/local_secret.txt` is always used for `Rails.config.secret_key_base` in the test and development environments, where previously `ENV["SECRET_KEY_BASE"]` or `Rails.application.credentials.secret_key_base` were used if present. The race condition in generating the local secret file, as reported in rails#53661, should be avoided by setting `ENV["SECRET_KEY_BASE"]` or `Rails.application.credentials.secret_key_base`, but this currently doesn't work. When ENV["SECRET_KEY_BASE"] or `Rails.application.credentials.secret_key_base` is set for test or development, it should be used for the `Rails.config.secret_key_base`, instead of generating a `tmp/local_secret.txt`.
Ever since we upgraded our Rails app to Rails
7.2
, we have been experiencing a randomraise ArgumentError, "'secret_key_base' for #{Rails.env} environment must be a type of String"
error in our CI/CD build when running the app's tests. This issue doesn't always occur. When it does, sometimes just restarting the build works. Other times you have to restart the build several times before you get a successful build.The stack trace in the build log shows that when the issue happens, it happens on this line of code in railties:
https://github.com/rails/rails/blob/v7.2.1.2/railties/lib/rails/application/configuration.rb#L517
Digging into this, I found that Rails 7.2 removed support for the legacy way that secrets were managed in a Rails app, e.g. via
Rails.application.secrets
, leavingRails.application.credentials
as the Rails-approved way to manage secrets in your Rails app.Here is the PR in Rails 7.2 that removed support for
Rails.application.secrets
.It turns out that this PR caused some regressions that were found during beta testing of Rails 7.2, and were corrected in this PR. Most importantly, this second PR introduced the behavior that when
Rails.env.local?
returnstrue
, which it does when the rails environment istest
(such as when running tests in a CI build), railties will now always generate a localsecret_key_base
stored in a file undertmp/local_secret.txt
, and not use the one that is defined inconfig/credentials.yml.enc
, which was the behavior in Rails 7.1 when we didn't have this CI issue.Here is the code in railties that generates the secret for local Rails environments:
I believe the reason why our CI build randomly experiences the
raise ArgumentError, "'secret_key_base' for #{Rails.env} environment must be a type of String"
error is that thegenerate_local_secret
method above is not thread-safe, and our CI build runs the app's tests in multiple processes using the parallel_tests gem. See below:One process must be opening the
tmp/local_secret.txt
file and another process must be reading the file before the first process has written to the file and closed it.To work around this issue, we added the following to our CI build process to force the creation of the
tmp/local_secret.txt
file prior to running the tests in parallel:Once we made this change we have not experienced the issue with any subsequent CI builds (there have been 25+ builds).
Steps to reproduce
Run a Rails app's tests in parallel using the
parallel_tests
gem, making sure that two or more processes are used. The issue doesn't always happen, but happens frequently enough that it becomes annoying.Expected behavior
The
generate_local_secret
method in railties should work in a use case that is using multiple processes on a build machine to run the Rails app's tests.Here's a thought - our Rails app defines a
secret_key_base
inconfig/credentials.yml.enc
for all environments, including thetest
environment. The behavior in versions of Rails <7.2
of usingsecret_key_base
inconfig/credentials.yml.enc
if it exists worked for our use case. Could that behavior be restored?Actual behavior
Railties occasionally fails during app startup and throws an
raise ArgumentError, "'secret_key_base' for #{Rails.env} environment must be a type of String"
error.System configuration
Rails version: We are using
7.2.1.2
, but started noticing this issue when we first upgraded to7.2
Ruby version: We are using
3.3.5
, but I don't believe the Ruby version has any effect on this issueThe text was updated successfully, but these errors were encountered: