ejson-rails 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31b8ead062c2323086dbdaa211878c04ce3cb3ee3203882ca13efa9b6ba8f3a3
4
- data.tar.gz: 3bc548e0db8eac2a33ccdf849e0fb2dbcddd7fe7ea0a537cab1e6e153fccb01e
3
+ metadata.gz: d6d62b4bf362a99bed1a71b0a16cc83bd610157b8e3a06d8998a8c4d1a9479f9
4
+ data.tar.gz: b74ef1b02227276aed05fc815d876218046bdef4533013d4ca61c0287a79e22a
5
5
  SHA512:
6
- metadata.gz: 03b463b72d2a9efdf4e8e9f461a4146e60c52ba53a4d0c17554b4ff1582aa34d332310c70f5f73061279486963f199900002d29b23356fc84411b2e230913a58
7
- data.tar.gz: 42f3dc896ce52a593c67e65fe7c72dd5b6ec4d3cc22690350cd9a964ee06c6799cc362390e938f8e1dbcee01259c48195aed2632f84342460ab089c9476ef018
6
+ metadata.gz: d8d136c6ef01aaf7011c0f8edb1f301654e813de2de0cff764422dabb929cea9b8df2e73eea3cb5f5a991a67166004f6bd62f0c0419984071fa8bc8b3009d549
7
+ data.tar.gz: 325e1a3e46fb0abfdd33b85002359768318dfac8fa6682cc9c09a17130604aa445aa98efcce57156a94cf9abda1d5bbec1315b4178b8830fe1e5e1d0f596f98a
@@ -10,13 +10,13 @@ jobs:
10
10
  matrix:
11
11
  entry:
12
12
  - name: Minimum Rails
13
- ruby: '2.7'
13
+ ruby: '3.1'
14
14
  gemfile: Gemfile.rails-min
15
15
  - name: Latest Rails
16
- ruby: '3.2'
16
+ ruby: '3.3'
17
17
  gemfile: Gemfile.rails-latest
18
18
  - name: Edge Rails
19
- ruby: '3.2'
19
+ ruby: '3.3'
20
20
  gemfile: "Gemfile.rails-edge"
21
21
 
22
22
  name: ${{ matrix.entry.name }}
data/.rubocop.yml CHANGED
@@ -4,6 +4,5 @@ inherit_gem:
4
4
  AllCops:
5
5
  NewCops: disable
6
6
  SuggestExtensions: false
7
- TargetRubyVersion: 3.2
8
7
  Exclude:
9
8
  - vendor/bundle/**/*
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.2.0
1
+ 3.3.0
data/Gemfile.lock CHANGED
@@ -1,108 +1,141 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ejson-rails (0.2.0)
4
+ ejson-rails (0.2.2)
5
5
  ejson
6
- railties (>= 5.2)
6
+ railties (>= 6.1)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actionpack (7.0.6)
12
- actionview (= 7.0.6)
13
- activesupport (= 7.0.6)
14
- rack (~> 2.0, >= 2.2.4)
11
+ actionpack (7.1.3.2)
12
+ actionview (= 7.1.3.2)
13
+ activesupport (= 7.1.3.2)
14
+ nokogiri (>= 1.8.5)
15
+ racc
16
+ rack (>= 2.2.4)
17
+ rack-session (>= 1.0.1)
15
18
  rack-test (>= 0.6.3)
16
- rails-dom-testing (~> 2.0)
17
- rails-html-sanitizer (~> 1.0, >= 1.2.0)
18
- actionview (7.0.6)
19
- activesupport (= 7.0.6)
19
+ rails-dom-testing (~> 2.2)
20
+ rails-html-sanitizer (~> 1.6)
21
+ actionview (7.1.3.2)
22
+ activesupport (= 7.1.3.2)
20
23
  builder (~> 3.1)
21
- erubi (~> 1.4)
22
- rails-dom-testing (~> 2.0)
23
- rails-html-sanitizer (~> 1.1, >= 1.2.0)
24
- activesupport (7.0.6)
24
+ erubi (~> 1.11)
25
+ rails-dom-testing (~> 2.2)
26
+ rails-html-sanitizer (~> 1.6)
27
+ activesupport (7.1.3.2)
28
+ base64
29
+ bigdecimal
25
30
  concurrent-ruby (~> 1.0, >= 1.0.2)
31
+ connection_pool (>= 2.2.5)
32
+ drb
26
33
  i18n (>= 1.6, < 2)
27
34
  minitest (>= 5.1)
35
+ mutex_m
28
36
  tzinfo (~> 2.0)
29
37
  ast (2.4.2)
38
+ base64 (0.2.0)
39
+ bigdecimal (3.1.6)
30
40
  builder (3.2.4)
31
- concurrent-ruby (1.2.2)
41
+ concurrent-ruby (1.2.3)
42
+ connection_pool (2.4.1)
32
43
  crass (1.0.6)
33
- diff-lcs (1.4.4)
34
- ejson (1.3.1)
44
+ diff-lcs (1.5.1)
45
+ drb (2.2.1)
46
+ ejson (1.4.1)
35
47
  erubi (1.12.0)
36
48
  i18n (1.14.1)
37
49
  concurrent-ruby (~> 1.0)
38
- json (2.6.3)
39
- loofah (2.21.3)
50
+ io-console (0.6.0)
51
+ irb (1.10.0)
52
+ rdoc
53
+ reline (>= 0.3.8)
54
+ json (2.7.1)
55
+ language_server-protocol (3.17.0.3)
56
+ loofah (2.22.0)
40
57
  crass (~> 1.0.2)
41
58
  nokogiri (>= 1.12.0)
42
- method_source (1.0.0)
43
- mini_portile2 (2.8.4)
44
- minitest (5.18.1)
45
- nokogiri (1.15.3)
59
+ mini_portile2 (2.8.5)
60
+ minitest (5.22.2)
61
+ mutex_m (0.2.0)
62
+ nokogiri (1.15.6)
46
63
  mini_portile2 (~> 2.8.2)
47
64
  racc (~> 1.4)
48
- parallel (1.22.1)
49
- parser (3.2.0.0)
65
+ parallel (1.24.0)
66
+ parser (3.3.0.5)
50
67
  ast (~> 2.4.1)
51
- racc (1.7.1)
52
- rack (2.2.7)
68
+ racc
69
+ psych (5.1.2)
70
+ stringio
71
+ racc (1.7.3)
72
+ rack (3.0.9.1)
73
+ rack-session (2.0.0)
74
+ rack (>= 3.0.0)
53
75
  rack-test (2.1.0)
54
76
  rack (>= 1.3)
55
- rails-dom-testing (2.1.1)
77
+ rackup (2.1.0)
78
+ rack (>= 3)
79
+ webrick (~> 1.8)
80
+ rails-dom-testing (2.2.0)
56
81
  activesupport (>= 5.0.0)
57
82
  minitest
58
83
  nokogiri (>= 1.6)
59
84
  rails-html-sanitizer (1.6.0)
60
85
  loofah (~> 2.21)
61
86
  nokogiri (~> 1.14)
62
- railties (7.0.6)
63
- actionpack (= 7.0.6)
64
- activesupport (= 7.0.6)
65
- method_source
87
+ railties (7.1.3.2)
88
+ actionpack (= 7.1.3.2)
89
+ activesupport (= 7.1.3.2)
90
+ irb
91
+ rackup (>= 1.0.0)
66
92
  rake (>= 12.2)
67
- thor (~> 1.0)
68
- zeitwerk (~> 2.5)
93
+ thor (~> 1.0, >= 1.2.2)
94
+ zeitwerk (~> 2.6)
69
95
  rainbow (3.1.1)
70
96
  rake (13.0.6)
71
- regexp_parser (2.6.1)
72
- rexml (3.2.5)
73
- rspec (3.10.0)
74
- rspec-core (~> 3.10.0)
75
- rspec-expectations (~> 3.10.0)
76
- rspec-mocks (~> 3.10.0)
77
- rspec-core (3.10.1)
78
- rspec-support (~> 3.10.0)
79
- rspec-expectations (3.10.1)
97
+ rdoc (6.6.3.1)
98
+ psych (>= 4.0.0)
99
+ regexp_parser (2.9.0)
100
+ reline (0.4.1)
101
+ io-console (~> 0.5)
102
+ rexml (3.2.6)
103
+ rspec (3.12.0)
104
+ rspec-core (~> 3.12.0)
105
+ rspec-expectations (~> 3.12.0)
106
+ rspec-mocks (~> 3.12.0)
107
+ rspec-core (3.12.2)
108
+ rspec-support (~> 3.12.0)
109
+ rspec-expectations (3.12.3)
80
110
  diff-lcs (>= 1.2.0, < 2.0)
81
- rspec-support (~> 3.10.0)
82
- rspec-mocks (3.10.2)
111
+ rspec-support (~> 3.12.0)
112
+ rspec-mocks (3.12.6)
83
113
  diff-lcs (>= 1.2.0, < 2.0)
84
- rspec-support (~> 3.10.0)
85
- rspec-support (3.10.2)
86
- rubocop (1.43.0)
114
+ rspec-support (~> 3.12.0)
115
+ rspec-support (3.12.1)
116
+ rubocop (1.62.1)
87
117
  json (~> 2.3)
118
+ language_server-protocol (>= 3.17.0)
88
119
  parallel (~> 1.10)
89
- parser (>= 3.2.0.0)
120
+ parser (>= 3.3.0.2)
90
121
  rainbow (>= 2.2.2, < 4.0)
91
122
  regexp_parser (>= 1.8, < 3.0)
92
123
  rexml (>= 3.2.5, < 4.0)
93
- rubocop-ast (>= 1.24.1, < 2.0)
124
+ rubocop-ast (>= 1.31.1, < 2.0)
94
125
  ruby-progressbar (~> 1.7)
95
126
  unicode-display_width (>= 2.4.0, < 3.0)
96
- rubocop-ast (1.24.1)
97
- parser (>= 3.1.1.0)
127
+ rubocop-ast (1.31.2)
128
+ parser (>= 3.3.0.4)
98
129
  rubocop-shopify (2.11.1)
99
130
  rubocop (~> 1.42)
100
- ruby-progressbar (1.11.0)
101
- thor (1.2.2)
131
+ ruby-progressbar (1.13.0)
132
+ stringio (3.1.0)
133
+ thor (1.3.0)
102
134
  tzinfo (2.0.6)
103
135
  concurrent-ruby (~> 1.0)
104
- unicode-display_width (2.4.2)
105
- zeitwerk (2.6.8)
136
+ unicode-display_width (2.5.0)
137
+ webrick (1.8.1)
138
+ zeitwerk (2.6.12)
106
139
 
107
140
  PLATFORMS
108
141
  ruby
@@ -115,4 +148,4 @@ DEPENDENCIES
115
148
  rubocop-shopify
116
149
 
117
150
  BUNDLED WITH
118
- 2.3.17
151
+ 2.5.7
data/README.md CHANGED
@@ -20,39 +20,90 @@ Or install it yourself as:
20
20
 
21
21
  $ gem install ejson-rails
22
22
 
23
+ ## Configuration
24
+
25
+ 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.
26
+
27
+ 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:
28
+
29
+ ```ruby
30
+ # config/application.rb
31
+
32
+ # This must be placed BEFORE your application constant which inherits from Rails::Application
33
+ EJSON::Rails::Railtie.ejson_secret_source = FooBar::SecretCredentialReader
34
+
35
+ # Custom credential reader that lives somewhere else
36
+ module FooBar
37
+ class SecretCredentialReader
38
+ class << self
39
+ def call
40
+ '{"secret": "secret_from_ejson_secret_source"}'
41
+ end
42
+ end
43
+ end
44
+ end
45
+ ```
46
+
47
+ For simple cases, you can use a `proc`:
48
+
49
+ ```ruby
50
+ EJSON::Rails::Railtie.ejson_secret_source = proc { '{"secret": "secret_from_ejson_secret_source"}' }
51
+ ```
52
+
23
53
  ## Usage
24
54
 
25
- Decrypted secrets 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:
55
+ Decrypted secrets and credentials will be accessible via `Rails.application.secrets`. For example:
56
+
57
+ `# project/config/secrets.json`
26
58
 
27
59
  ```json
28
- // project/config/secrets.json
29
60
  { "some_secret": "key" }
30
61
  ```
31
62
 
32
- will be accessible via `Rails.application.secrets.some_secret` or `Rails.application.secrets[:some_secret]` on boot. JSON files are loaded once and contents are `deep_merge`'d into your app's existing rails secrets.
63
+ 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.
33
64
 
34
65
  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.
35
66
 
67
+ 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.
68
+
36
69
  NOTE: This gem does not decrypt ejson for you. You will need to configure this as part of your deployment pipeline.
37
70
 
38
71
  ## Migrating to credentials
39
72
 
40
73
  Rails 7.1 has deprecated application secrets in favor of credentials. ejson-rails can migrate secrets to application credentials.
41
74
 
42
- Even before running Rails 7.1, you can migrate your secrets in a few steps.
75
+ Even before running Rails 7.1, you can migrate your secrets in several steps:
76
+
77
+ 1. Convert secrets from YAML to JSON
78
+ 2. Move any ERB embedded within the YAML to the corresponding environment file
79
+ 3. Use `Rails.application.credentials` in place of Rails secrets
80
+
81
+ ### 1. Convert secrets from config/secrets.yml to config/secrets.json
43
82
 
44
- First, move the development and test secrets to JSON secrets:
83
+ 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.
84
+ In that case, the easiest way to migrate is to use the test secrets in all local environments, and override for development as needed:
45
85
 
46
86
  ```sh-session
47
- bin/rails runner 'Rails.root.join("config/secrets.#{Rails.env}.json").write(JSON.pretty_generate(Rails.application.secrets.to_h.without(:secret_key_base)))'
48
- 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)))'
87
+ # Recommended
88
+ bin/rails runner -e test 'Rails.root.join("config/secrets.json").write(JSON.pretty_generate(Rails.application.secrets.to_h.without(:secret_key_base)))'
49
89
  ```
50
90
 
51
- Secrets support ERB while EJSON secrets don't, so if your secrets contain ERB, you will need to move that logic to the environment configurations:
91
+ > [!NOTE]
92
+ > Alternatively, if its necessary to configure distinct values between the development/test environment, you can use separate JSON files for the development/test environments:
93
+ >
94
+ > ```sh-session
95
+ > bin/rails runner 'Rails.root.join("config/secrets.#{Rails.env}.json").write(JSON.pretty_generate(Rails.application.secrets.to_h.without(:secret_key_base)))'
96
+ > 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)))'
97
+ > ```
98
+
99
+ ### 2. Move any ERB into the corresponding environment files
100
+
101
+ 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:
52
102
 
53
103
  **Before**:
54
104
 
55
105
  `config/secrets.yml`
106
+
56
107
  ```yaml
57
108
  development:
58
109
  some_external_service:
@@ -61,7 +112,8 @@ development:
61
112
 
62
113
  **After**:
63
114
 
64
- `config/secrets.development.json` as generated by the command above.
115
+ `config/secrets.json` as generated by the _recommended_ command above.
116
+
65
117
  ```json
66
118
  {
67
119
  "some_external_service": {
@@ -72,19 +124,20 @@ development:
72
124
  ```
73
125
 
74
126
  `config/environments/development.rb`
127
+
75
128
  ```ruby
76
129
  Rails.application.configure do
77
130
  # elided
78
131
 
79
- # credential should be set using []=, not the dynamic accessors
80
- credentials[:some_external_service][:api_token] = ENV.fetch("SOME_EXTERNAL_SERVICE_API_TOKEN", "12345")
81
-
82
- # top-level values must be set through `credentials.config`
83
- credentials.config[:something_else_entirely] = ENV.fetch("SOMETHING_ELSE_ENTIRELY", "abc")
132
+ credentials.some_external_service.api_token = ENV.fetch("SOME_EXTERNAL_SERVICE_API_TOKEN", "12345")
133
+ credentials.something_else_entirely = ENV.fetch("SOMETHING_ELSE_ENTIRELY", "abc")
84
134
  end
85
135
  ```
86
136
 
87
- Note that the code accesses the credentials 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:
137
+ #### Rails 7.0 Note
138
+
139
+ > [!NOTE]
140
+ > 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:
88
141
 
89
142
  ```ruby
90
143
  Rails.application.credentials.some_external_service.api_token = "foo"
@@ -106,7 +159,9 @@ Rails.application.credentials[:some_external_service][:api_token] = "foo"
106
159
  Rails.application.credentials.some_external_service.api_token # => "12345"
107
160
  ```
108
161
 
109
- You're now ready to use credentials instead of secrets:
162
+ ### 3. Use `Rails.application.credentials`
163
+
164
+ You are now ready to replace Rails secrets with Rails credentials:
110
165
 
111
166
  ```sh-session
112
167
  git ls-files | xargs ruby -pi -e 'gsub("Rails.application.secrets", "Rails.application.credentials")' --
@@ -118,7 +173,7 @@ To avoid the deprecation warning from the use of secrets in `ejson-rails` once y
118
173
  gem 'ejson-rails', require: 'ejson/rails/skip_secrets'
119
174
  ```
120
175
 
121
- This will no longer merge secrets from JSON in `Rails.application.secrets`. This will be the default in the next major version.
176
+ 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.
122
177
 
123
178
  ## Development
124
179
 
data/ejson-rails.gemspec CHANGED
@@ -23,10 +23,10 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.metadata = { "allowed_push_host" => "https://rubygems.org" }
25
25
 
26
- spec.required_ruby_version = ">= 2.7.0"
26
+ spec.required_ruby_version = ">= 3.1.0"
27
27
 
28
28
  spec.add_dependency("ejson")
29
- spec.add_dependency("railties", ">= 5.2")
29
+ spec.add_dependency("railties", ">= 6.1")
30
30
 
31
31
  spec.add_development_dependency("rake", "~> 13.0")
32
32
  spec.add_development_dependency("rspec", "~> 3.0")
@@ -2,4 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  eval_gemfile('../Gemfile')
4
4
 
5
- gem 'railties', '5.2'
5
+ gem 'railties', '6.1'
@@ -6,25 +6,41 @@ module EJSON
6
6
  private_constant :Rails
7
7
 
8
8
  class Railtie < Rails::Railtie
9
- singleton_class.attr_accessor(:set_secrets)
9
+ singleton_class.attr_accessor(:ejson_secret_source, :set_secrets)
10
10
  @set_secrets = true
11
11
 
12
12
  config.before_configuration do
13
- json_file = json_files.detect { |file| valid?(file) }
14
- next unless json_file
13
+ secrets = load_secrets_from_config || load_secrets_from_disk
14
+ next unless secrets
15
+
16
+ secrets = JSON.parse(secrets, symbolize_names: true)
15
17
 
16
- secrets = JSON.parse(json_file.read, symbolize_names: true)
17
18
  Rails.application.secrets.deep_merge!(secrets) if set_secrets
18
19
  # Merging into `credentials.config` because in Rails 7.0, reading a credential with
19
20
  # Rails.application.credentials[:some_credential] won't work otherwise.
20
21
  Rails.application.credentials.config.deep_merge!(secrets) do |key|
21
22
  raise "A credential already exists with the same name: #{key}"
22
23
  end
24
+
25
+ # Delete the loaded JSON files so they are no longer readable by the app.
26
+ if ENV["EJSON_RAILS_DELETE_SECRETS"] == "true"
27
+ json_files.each do |pathname|
28
+ File.delete(pathname) if File.writable?(pathname)
29
+ end
30
+ end
23
31
  end
24
32
 
25
33
  class << self
26
34
  private
27
35
 
36
+ def load_secrets_from_config
37
+ ejson_secret_source&.call
38
+ end
39
+
40
+ def load_secrets_from_disk
41
+ json_files.detect { |file| valid?(file) }&.read
42
+ end
43
+
28
44
  def valid?(pathname)
29
45
  pathname.exist?
30
46
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module EJSON
4
4
  module Rails
5
- VERSION = "0.2.0"
5
+ VERSION = "0.2.2"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ejson-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gannon McGibbon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-24 00:00:00.000000000 Z
11
+ date: 2024-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ejson
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '5.2'
33
+ version: '6.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '5.2'
40
+ version: '6.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -109,14 +109,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
109
109
  requirements:
110
110
  - - ">="
111
111
  - !ruby/object:Gem::Version
112
- version: 2.7.0
112
+ version: 3.1.0
113
113
  required_rubygems_version: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
118
  requirements: []
119
- rubygems_version: 3.4.16
119
+ rubygems_version: 3.5.10
120
120
  signing_key:
121
121
  specification_version: 4
122
122
  summary: Asymmetric keywise encryption for JSON on Rails