README.md in ejson-rails-0.2.1 vs README.md in ejson-rails-1.0.0

- old
+ new

@@ -1,10 +1,10 @@ # EJSON::Rails [![Build Status](https://github.com/Shopify/ejson-rails/workflows/CI/badge.svg?branch=main)](https://github.com/Shopify/ejson-rails/actions?query=branch%3Amain) -Automatically injects [`ejson`](https://github.com/Shopify/ejson) decrypted secrets into your `Rails.application.secrets`. +Automatically injects [`ejson`](https://github.com/Shopify/ejson) decrypted secrets into your `Rails.application.credentials`. ## Installation Add this line to your application's Gemfile: @@ -18,127 +18,60 @@ Or install it yourself as: $ gem install ejson-rails -## Usage +## Configuration -Decrypted secrets and credentials from `project/config/secrets.json` (or `project/config/secrets.{current_rails_environment}.json` if that doesn't exist) will be accessible via `Rails.application.secrets`. For example: +By default, the gem will look for decrypted secrets in `project/config/secrets.json` or `project/config/secrets.{current_rails_environment}.json` if that doesn't exist. -`# project/config/secrets.json` -```json -{ "some_secret": "key" } -``` +If your application or environment has a unique way of retrieving decrypted secrets, you can do so by setting `EJSON::Rails::Railtie.ejson_secret_source` to a callable object in `config/application.rb`. For example: -will be accessible via `Rails.application.secrets.some_secret` or `Rails.application.secrets[:some_secret]` upon booting. JSON files are loaded once and contents are `deep_merge`'d into your app's existing rails secrets. - -Secrets will also be accessible via `Rails.application.credentials`, e.g. `Rails.application.credentials.some_secret` or `Rails.application.credentials[:some_secret]`. To avoid subtle compatibility issues, if a credential already exists, an error will occur. - -If you set the `EJSON_RAILS_DELETE_SECRETS` environment variable to `true` the gem will automatically delete the secrets from the filesystem after loading them into Rails. It will delete both paths (`project/config/secrets.json` and `project/config/secrets.{current_rails_environment}.json`) if the files exist and are writable. - -NOTE: This gem does not decrypt ejson for you. You will need to configure this as part of your deployment pipeline. - -## Migrating to credentials - -Rails 7.1 has deprecated application secrets in favor of credentials. ejson-rails can migrate secrets to application credentials. - -Even before running Rails 7.1, you can migrate your secrets in several steps: -1. Convert secrets from YAML to JSON -2. Move any ERB embedded within the YAML to the corresponding environment file -3. Use `Rails.application.credentials` in place of Rails secrets - -### 1. Convert secrets from config/secrets.yml to config/secrets.json - -Typically, secrets share the same structure across different environments. While test secrets are often placeholders, development secrets may sometimes use environment variables to communicate with external services. -In that case, the easiest way to migrate is to use the test secrets in all local environments, and override for development as needed: - -```sh-session -# Recommended -bin/rails runner -e test 'Rails.root.join("config/secrets.json").write(JSON.pretty_generate(Rails.application.secrets.to_h.without(:secret_key_base)))' -``` - -> [!NOTE] -> Alternatively, if its necessary to configure distinct values between the development/test environment, you can use separate JSON files for the development/test environments: -> -> ```sh-session -> bin/rails runner 'Rails.root.join("config/secrets.#{Rails.env}.json").write(JSON.pretty_generate(Rails.application.secrets.to_h.without(:secret_key_base)))' -> bin/rails runner -e test 'Rails.root.join("config/secrets.#{Rails.env}.json").write(JSON.pretty_generate(Rails.application.secrets.to_h.without(:secret_key_base)))' -> ``` - -### 2. Move any ERB into the corresponding environment files - -YAML supports ERB while JSON secrets do not. If your secrets contain ERB, you will need to move that logic to the corresponding environment file: - -**Before**: - -`config/secrets.yml` -```yaml -development: - some_external_service: - api_token: <%= ENV.fetch(SOME_EXTERNAL_SERVICE_API_TOKEN, "12345") %> -``` - -**After**: - -`config/secrets.json` as generated by the *recommended* command above. -```json -{ - "some_external_service": { - "api_token": "12345" - }, - "something_else_entirely": "abc" -} -``` - -`config/environments/development.rb` ```ruby -Rails.application.configure do - # elided +# config/application.rb - credentials.some_external_service.api_token = ENV.fetch("SOME_EXTERNAL_SERVICE_API_TOKEN", "12345") - credentials.something_else_entirely = ENV.fetch("SOMETHING_ELSE_ENTIRELY", "abc") +# This must be placed BEFORE your application constant which inherits from Rails::Application +EJSON::Rails::Railtie.ejson_secret_source = FooBar::SecretCredentialReader + +# Custom credential reader that lives somewhere else +module FooBar + class SecretCredentialReader + class << self + def call + '{"secret": "secret_from_ejson_secret_source"}' + end + end + end end ``` -#### Rails 7.0 Note -> [!NOTE] -> In Rails 7.0, credentials are accessed as a Hash with [] and []=.. This is important because the dynamic accessor methods will set values in a different object, and credentials will behave inconsistently after that: +For simple cases, you can use a `proc`: ```ruby -Rails.application.credentials.some_external_service.api_token = "foo" -Rails.application.credentials[:some_external_service][:api_token] # => "12345" +EJSON::Rails::Railtie.ejson_secret_source = proc { '{"secret": "secret_from_ejson_secret_source"}' } ``` -Also note the code sets top-level values through `credentials.config`, because `credentials#[]=(key, value)` sets values in a different object. +## Usage -```ruby -Rails.application.credentials[:something_else_entirely] = "foo" -Rails.application.credentials[:something_else_entirely] # => "abc" -``` +Decrypted secrets will be accessible via `Rails.application.credentials`. For example: -Make sure there's no code using the dynamic accessors before setting the configuration in the Hash, or the values won't be accessible from the dynamic accessor: +`# project/config/secrets.json` -```ruby -Rails.application.credentials.something_else_entirely # just accessing is enough to cause the issue -Rails.application.credentials[:some_external_service][:api_token] = "foo" -Rails.application.credentials.some_external_service.api_token # => "12345" +```json +{ "some_secret": "key" } ``` -### 3. Use `Rails.application.credentials` +will be accessible via `Rails.application.credentials.some_secret` or `Rails.application.credentials[:some_secret]` upon booting. JSON files are loaded once and contents are `deep_merge`'d into your app's existing Rails credentials. -You are now ready to replace Rails secrets with Rails credentials: +To avoid subtle compatibility issues, if a credential already exists, an error will occur. -```sh-session -git ls-files | xargs ruby -pi -e 'gsub("Rails.application.secrets", "Rails.application.credentials")' -- -``` +If you set the `EJSON_RAILS_DELETE_SECRETS` environment variable to `true` the gem will automatically delete the secrets from the filesystem after loading them into Rails. It will delete both paths (`project/config/secrets.json` and `project/config/secrets.{current_rails_environment}.json`) if the files exist and are writable. -To avoid the deprecation warning from the use of secrets in `ejson-rails` once you're running Rails 7.1, require another file from your Gemfile: +NOTE: This gem does not decrypt ejson for you. You will need to configure this as part of your deployment pipeline. -```ruby -gem 'ejson-rails', require: 'ejson/rails/skip_secrets' -``` +## Migrating to credentials -With this require, ejson-rails will no longer merge secrets from JSON into `Rails.application.secrets`. This will be the default in the next major version. +Rails 7.1 has deprecated application secrets in favor of credentials. `ejson-rails` no longer writes to Rails secrets to avoid crashing given Rails 7.2 removal of the feature. See the README for the last version that supports secrets to read more about migrating: [`ejson-rails` v0.2.2 – Migrating to credentials](https://github.com/Shopify/ejson-rails/tree/v0.2.2#migrating-to-credentials). ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.