Skip to content

ActiveSupport::MessageEncryptor migration path to 7.1 defaults #48118

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

Closed
etiennebarrie opened this issue May 3, 2023 · 1 comment · Fixed by #48170
Closed

ActiveSupport::MessageEncryptor migration path to 7.1 defaults #48118

etiennebarrie opened this issue May 3, 2023 · 1 comment · Fixed by #48170
Assignees
Milestone

Comments

@etiennebarrie
Copy link
Contributor

etiennebarrie commented May 3, 2023

Steps to reproduce

  • With a 7.0 app, generate a encrypted message with ActiveSupport::MessageEncryptor.
  • Upgrade the app 7.1 keeping 7.0 defaults: you can decode the message, generate a new message.
  • Use the 7.1 defaults: you can't decode the message.

I created a small example app which you can clone with git clone https://github.com/etiennebarrie/rails-app.git --single-branch --branch message-encryptor-7.1-compat. With this app, the steps are:

$ bundle
$ bin/rails server
# navigate to http://127.0.0.1:3000/
# optionally click "Verify" to ensure the message roundtrip works on 7.0
# keep the window open to verify a 7.0 message with 7.1
$ BUNDLE_GEMFILE=Gemfile.main bundle
$ BUNDLE_GEMFILE=Gemfile.main bin/rails s
# now click "Verify" to verify the 7.0 generated message with 7.1 with 7.0 defaults
# it works!
# keep the window open
$ RAILS_71_DEFAULTS=1 BUNDLE_GEMFILE=Gemfile.main bin/rails s
# click "Verify"
# verification failed

I know there are more steps mentioned in https://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html, but out-of-the-box this should work. Instead multiple steps are necessary.

Expected behavior

The application is upgraded and the message should be verified.

Actual behavior

Message verification fails.


For each line in these tables, you should check what is generated and the fact that it is verifiable by the line above and the line below.
The approach right now can be resumed to this:

Application configuration Generation Can verify Marshal Can verify JSON
7.0 Marshal 𐄂
7.1 with 7.0 defaults Marshal 𐄂
7.1 with 7.1 defaults JSON 𐄂

We can see the incompatibility by looking at what each steps generates and what each next step can verify. The step 2 to 3 is incompatible.

The approach recommended in the upgrading guide:

Application configuration Generation Can verify Marshal Can verify JSON
7.0 Marshal 𐄂
7.1 with 7.0 defaults, default_message_encryptor_serializer = :marshal Marshal 𐄂
7.1 with 7.0 defaults, default_message_encryptor_serializer = :hybrid Marshal
7.1 with 7.1 defaults, default_message_encryptor_serializer = :hybrid, use_marshal_serialization = false JSON
7.1 with 7.1 defaults JSON 𐄂

This shows it's compatible, but adds multiple steps to the upgrade. The second step is not necessary, but still described in the upgrading guide.

What I think we should do, in line with the way we usually use defaults:

Application configuration Generation Can verify Marshal Can verify JSON
7.0 Marshal 𐄂
7.1 with 7.0 defaults Marshal
7.1 with 7.1 defaults JSON
7.1 with 7.1 defaults, default_message_encryptor_serializer = :json JSON 𐄂

That last line, with default_message_encryptor_serializer = :json can become the default in 7.2, and can be enabled earlier to make sure no Marshal is accepted before then.

@etiennebarrie etiennebarrie changed the title ActiveSupport::Encryptor migration path to 7.1 defaults ActiveSupport::MessageEncryptor migration path to 7.1 defaults May 3, 2023
@byroot byroot added this to the 7.1.0 milestone May 4, 2023
@jonathanhefner
Copy link
Member

This issue also applies to ActiveSupport::MessageVerifier / config.active_support.default_message_verifier_serializer.

#47963 will not fix this issue, but I think it is a step in the right direction. If #47963 is merged, there will be a single setting (config.active_support.message_serializer) that can default to :json_allow_marshal in 7.1, and provide the described behaviors for both MessageEncryptor and MessageVerifier. Then, as you said, we can change the default to :json in 7.2.

jonathanhefner added a commit to jonathanhefner/rails that referenced this issue May 8, 2023
Prior to this commit, `config.load_defaults 7.1` would cause old
messages (or messages from older apps) to become unreadable, and
developers were encouraged to manually set
`config.active_support.message_serializer = :json_allow_marshal` in
order to prevent this.

This commit changes the default message serializer set by
`config.load_defaults 7.1` from `:json` to `:json_allow_marshal` so that
upgraded apps can continue to read old messages without additional
configuration.

The intention is to eventually change the default to `:json` (with no
`Marshal` fallback) in Rails 7.2, after some time has passed with apps
generating JSON-serialized messages.

Apps can opt in to JSON-only serialization before Rails 7.2 by manually
setting `config.active_support.message_serializer = :json`.

Fixes rails#48118.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants