secvault 2.7.0 → 2.7.1
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 +4 -4
- data/lib/secvault/rails_secrets.rb +4 -10
- data/lib/secvault/secrets.rb +27 -49
- data/lib/secvault/version.rb +1 -1
- data/lib/secvault.rb +55 -43
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3f3f850252ea738c99ee2fd7bb7c2e9a2688082abc78245f0ac1ae4f262c9f57
|
|
4
|
+
data.tar.gz: 95c9d1b54bdf4fdeaf490e7bbf4bd1bb13411d50ce9a11291f89848049258636
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a2399e023247f056496230dc96da152b5c9fcdd1db98b5f7359a5406f9ce45dc190ce0c93cd5dc4736abb16e7396043d78482b0879785faa60353fe0a1d773dd
|
|
7
|
+
data.tar.gz: e3deef79404b1c382c2e6167e6cb2b2981f511b6e9058fdf4fc484d8b9fce0f041551121631165f60f2220ee1d3be0ef444fb12296dac803a58afb4800b18ce0
|
|
@@ -46,15 +46,9 @@ module Secvault
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
# Monkey patch to restore Rails::Secrets interface for backwards compatibility
|
|
49
|
-
#
|
|
50
|
-
if defined?(Rails)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# Only alias for Rails 7.2+ to avoid conflicts with native Rails::Secrets in 7.1
|
|
55
|
-
if major > 7 || (major == 7 && minor >= 2)
|
|
56
|
-
module Rails
|
|
57
|
-
Secrets = Secvault::RailsSecrets
|
|
58
|
-
end
|
|
49
|
+
# Works consistently across all Rails versions with warning suppression
|
|
50
|
+
if defined?(Rails)
|
|
51
|
+
module Rails
|
|
52
|
+
Secrets = Secvault::RailsSecrets
|
|
59
53
|
end
|
|
60
54
|
end
|
data/lib/secvault/secrets.rb
CHANGED
|
@@ -11,62 +11,48 @@ module Secvault
|
|
|
11
11
|
class Secrets
|
|
12
12
|
class << self
|
|
13
13
|
def setup(app)
|
|
14
|
-
#
|
|
15
|
-
return unless rails_7_2_or_later?
|
|
16
|
-
|
|
14
|
+
# Auto-setup for all Rails versions with consistent behavior
|
|
17
15
|
secrets_path = app.root.join("config/secrets.yml")
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
# Use a more reliable approach that works in all environments
|
|
21
|
-
app.config.before_configuration do
|
|
22
|
-
current_env = ENV["RAILS_ENV"] || Rails.env || "development"
|
|
23
|
-
setup_secrets_immediately(app, secrets_path, current_env)
|
|
24
|
-
end
|
|
17
|
+
return unless secrets_path.exist?
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
setup_secrets_immediately(app, secrets_path, current_env)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
19
|
+
# Use a reliable approach that works in all environments
|
|
20
|
+
app.config.before_configuration do
|
|
21
|
+
current_env = ENV["RAILS_ENV"] || Rails.env || "development"
|
|
22
|
+
setup_secrets_immediately(app, secrets_path, current_env)
|
|
33
23
|
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Manual setup method for Rails 7.1 (opt-in)
|
|
37
|
-
def setup_for_rails_71!(app)
|
|
38
|
-
secrets_path = app.root.join("config/secrets.yml")
|
|
39
24
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
25
|
+
# Also try during to_prepare as a fallback
|
|
26
|
+
app.config.to_prepare do
|
|
27
|
+
current_env = Rails.env
|
|
28
|
+
unless Rails.application.respond_to?(:secrets) && !Rails.application.secrets.empty?
|
|
43
29
|
setup_secrets_immediately(app, secrets_path, current_env)
|
|
44
30
|
end
|
|
45
31
|
end
|
|
46
32
|
end
|
|
47
33
|
|
|
48
|
-
def setup_secrets_immediately(
|
|
34
|
+
def setup_secrets_immediately(_app, secrets_path, env)
|
|
49
35
|
# Set up secrets if they exist
|
|
50
36
|
secrets = read_secrets(secrets_path, env)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
37
|
+
return unless secrets
|
|
38
|
+
|
|
39
|
+
# Rails 8.0+ compatibility: Add secrets accessor that initializes on first access
|
|
40
|
+
unless Rails.application.respond_to?(:secrets)
|
|
41
|
+
Rails.application.define_singleton_method(:secrets) do
|
|
42
|
+
@secrets ||= begin
|
|
43
|
+
current_secrets = ActiveSupport::OrderedOptions.new
|
|
44
|
+
# Re-read secrets to ensure we have the right environment
|
|
45
|
+
env_secrets = Secvault::Secrets.read_secrets(secrets_path, Rails.env)
|
|
46
|
+
current_secrets.merge!(env_secrets) if env_secrets
|
|
47
|
+
current_secrets
|
|
62
48
|
end
|
|
63
49
|
end
|
|
64
|
-
|
|
65
|
-
# If secrets accessor already exists, merge the secrets
|
|
66
|
-
if Rails.application.respond_to?(:secrets) && Rails.application.secrets.respond_to?(:merge!)
|
|
67
|
-
Rails.application.secrets.merge!(secrets)
|
|
68
|
-
end
|
|
69
50
|
end
|
|
51
|
+
|
|
52
|
+
# If secrets accessor already exists, merge the secrets
|
|
53
|
+
return unless Rails.application.respond_to?(:secrets) && Rails.application.secrets.respond_to?(:merge!)
|
|
54
|
+
|
|
55
|
+
Rails.application.secrets.merge!(secrets)
|
|
70
56
|
end
|
|
71
57
|
|
|
72
58
|
# Classic Rails::Secrets.parse implementation
|
|
@@ -103,14 +89,6 @@ module Secvault
|
|
|
103
89
|
|
|
104
90
|
{}
|
|
105
91
|
end
|
|
106
|
-
|
|
107
|
-
private
|
|
108
|
-
|
|
109
|
-
def rails_7_2_or_later?
|
|
110
|
-
rails_version = Rails.version
|
|
111
|
-
major, minor = rails_version.split(".").map(&:to_i)
|
|
112
|
-
major > 7 || (major == 7 && minor >= 2)
|
|
113
|
-
end
|
|
114
92
|
end
|
|
115
93
|
end
|
|
116
94
|
end
|
data/lib/secvault/version.rb
CHANGED
data/lib/secvault.rb
CHANGED
|
@@ -13,33 +13,20 @@ loader.setup
|
|
|
13
13
|
|
|
14
14
|
# Secvault - Simple secrets management for Rails
|
|
15
15
|
#
|
|
16
|
-
# Secvault restores the classic Rails secrets.yml functionality
|
|
17
|
-
#
|
|
18
|
-
#
|
|
16
|
+
# Secvault restores the classic Rails secrets.yml functionality using simple,
|
|
17
|
+
# plain YAML files for environment-specific secrets management. Works consistently
|
|
18
|
+
# across all Rails versions with automatic deprecation warning suppression.
|
|
19
19
|
#
|
|
20
20
|
# ## Rails Version Support:
|
|
21
|
-
# - Rails 7.1
|
|
22
|
-
# - Rails 7.2+:
|
|
21
|
+
# - Rails 7.1+: Full compatibility with automatic setup
|
|
22
|
+
# - Rails 7.2+: Drop-in replacement for removed functionality
|
|
23
23
|
# - Rails 8.0+: Full compatibility
|
|
24
24
|
#
|
|
25
|
-
# ##
|
|
26
|
-
#
|
|
25
|
+
# ## Quick Start:
|
|
26
|
+
# Add this to an initializer:
|
|
27
27
|
#
|
|
28
28
|
# # config/initializers/secvault.rb
|
|
29
|
-
#
|
|
30
|
-
# remove_const(:Secrets) if defined?(Secrets)
|
|
31
|
-
# Secrets = Secvault::RailsSecrets
|
|
32
|
-
# end
|
|
33
|
-
#
|
|
34
|
-
# Rails.application.config.after_initialize do
|
|
35
|
-
# secrets_path = Rails.root.join("config/secrets.yml")
|
|
36
|
-
# if secrets_path.exist?
|
|
37
|
-
# loaded_secrets = Rails::Secrets.parse([secrets_path], env: Rails.env)
|
|
38
|
-
# secrets_object = ActiveSupport::OrderedOptions.new
|
|
39
|
-
# secrets_object.merge!(loaded_secrets)
|
|
40
|
-
# Rails.application.define_singleton_method(:secrets) { secrets_object }
|
|
41
|
-
# end
|
|
42
|
-
# end
|
|
29
|
+
# Secvault.setup!
|
|
43
30
|
#
|
|
44
31
|
# ## Usage:
|
|
45
32
|
# Rails.application.secrets.api_key
|
|
@@ -83,26 +70,30 @@ module Secvault
|
|
|
83
70
|
require "secvault/rails_secrets"
|
|
84
71
|
end
|
|
85
72
|
|
|
86
|
-
#
|
|
87
|
-
# This provides
|
|
88
|
-
#
|
|
73
|
+
# Set up Secvault for all Rails versions
|
|
74
|
+
# This provides a universal way to integrate Secvault into Rails apps
|
|
75
|
+
# with consistent behavior across all Rails versions.
|
|
89
76
|
#
|
|
90
77
|
# Usage in an initializer:
|
|
91
|
-
# Secvault.
|
|
78
|
+
# Secvault.setup!
|
|
79
|
+
# Secvault.setup!(suppress_warnings: false)
|
|
92
80
|
#
|
|
93
81
|
# This will:
|
|
94
|
-
# 1.
|
|
82
|
+
# 1. Set up Rails::Secrets with Secvault implementation
|
|
95
83
|
# 2. Replace Rails.application.secrets with Secvault-powered functionality
|
|
96
84
|
# 3. Load secrets from config/secrets.yml automatically
|
|
97
|
-
|
|
85
|
+
# 4. Suppress Rails deprecation warnings about secrets (default: true)
|
|
86
|
+
# 5. Set Rails.application.config.secret_key_base from secrets (default: true)
|
|
87
|
+
def setup!(suppress_warnings: true, set_secret_key_base: true)
|
|
98
88
|
# Override native Rails::Secrets
|
|
99
|
-
if defined?(Rails::Secrets)
|
|
100
|
-
Rails.send(:remove_const, :Secrets)
|
|
101
|
-
end
|
|
89
|
+
Rails.send(:remove_const, :Secrets) if defined?(Rails::Secrets)
|
|
102
90
|
Rails.const_set(:Secrets, Secvault::RailsSecrets)
|
|
103
91
|
|
|
104
92
|
# Set up Rails.application.secrets replacement
|
|
105
93
|
Rails.application.config.after_initialize do
|
|
94
|
+
# Suppress Rails deprecation warnings about secrets if requested
|
|
95
|
+
suppress_secrets_deprecation_warning! if suppress_warnings
|
|
96
|
+
|
|
106
97
|
secrets_path = Rails.root.join("config/secrets.yml")
|
|
107
98
|
|
|
108
99
|
if secrets_path.exist?
|
|
@@ -118,9 +109,17 @@ module Secvault
|
|
|
118
109
|
secrets_object
|
|
119
110
|
end
|
|
120
111
|
|
|
112
|
+
# Set secret_key_base in Rails config to avoid accessing it from secrets
|
|
113
|
+
if set_secret_key_base && loaded_secrets.key?("secret_key_base")
|
|
114
|
+
Rails.application.config.secret_key_base = loaded_secrets["secret_key_base"]
|
|
115
|
+
unless Rails.env.production?
|
|
116
|
+
Rails.logger&.info "[Secvault] Set Rails.application.config.secret_key_base from secrets.yml"
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
121
120
|
# Log integration success (except in production)
|
|
122
121
|
unless Rails.env.production?
|
|
123
|
-
Rails.logger&.info "[Secvault]
|
|
122
|
+
Rails.logger&.info "[Secvault] Integration complete. Loaded #{loaded_secrets.keys.size} secret keys."
|
|
124
123
|
end
|
|
125
124
|
else
|
|
126
125
|
Rails.logger&.warn "[Secvault] No secrets.yml file found at #{secrets_path}"
|
|
@@ -142,9 +141,12 @@ module Secvault
|
|
|
142
141
|
# - files: Array of file paths (String or Pathname)
|
|
143
142
|
# - reload_method: Add a reload helper method (default: true in development)
|
|
144
143
|
# - logger: Enable/disable logging (default: true except in production)
|
|
145
|
-
|
|
144
|
+
# - suppress_warnings: Suppress Rails deprecation warnings about secrets (default: true)
|
|
145
|
+
# - set_secret_key_base: Set Rails.application.config.secret_key_base from secrets (default: true)
|
|
146
|
+
def setup_multi_file!(files, reload_method: Rails.env.development?, logger: !Rails.env.production?,
|
|
147
|
+
suppress_warnings: true, set_secret_key_base: true)
|
|
146
148
|
# Ensure Secvault integration is active
|
|
147
|
-
|
|
149
|
+
setup!(suppress_warnings: suppress_warnings, set_secret_key_base: set_secret_key_base) unless active?
|
|
148
150
|
|
|
149
151
|
# Convert strings to Pathname objects and resolve relative to Rails.root
|
|
150
152
|
file_paths = Array(files).map do |file|
|
|
@@ -153,13 +155,14 @@ module Secvault
|
|
|
153
155
|
|
|
154
156
|
# Set up the multi-file loading
|
|
155
157
|
Rails.application.config.after_initialize do
|
|
156
|
-
load_multi_file_secrets!(file_paths, logger: logger
|
|
158
|
+
load_multi_file_secrets!(file_paths, logger: logger, suppress_warnings: suppress_warnings,
|
|
159
|
+
set_secret_key_base: set_secret_key_base)
|
|
157
160
|
end
|
|
158
161
|
|
|
159
162
|
# Add reload helper in development
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
+
return unless reload_method
|
|
164
|
+
|
|
165
|
+
add_reload_helper!(file_paths)
|
|
163
166
|
end
|
|
164
167
|
|
|
165
168
|
# Load secrets into Secvault.secrets only (no Rails integration)
|
|
@@ -195,10 +198,14 @@ module Secvault
|
|
|
195
198
|
end
|
|
196
199
|
|
|
197
200
|
# Load secrets from multiple files and merge them (with Rails integration)
|
|
198
|
-
def load_multi_file_secrets!(file_paths, logger: !Rails.env.production
|
|
201
|
+
def load_multi_file_secrets!(file_paths, logger: !Rails.env.production?, suppress_warnings: true,
|
|
202
|
+
set_secret_key_base: true)
|
|
199
203
|
existing_files = file_paths.select(&:exist?)
|
|
200
204
|
|
|
201
205
|
if existing_files.any?
|
|
206
|
+
# Suppress Rails deprecation warnings about secrets if requested
|
|
207
|
+
suppress_secrets_deprecation_warning! if suppress_warnings
|
|
208
|
+
|
|
202
209
|
# Load and merge all secrets files
|
|
203
210
|
merged_secrets = Rails::Secrets.parse(existing_files, env: Rails.env)
|
|
204
211
|
|
|
@@ -209,6 +216,12 @@ module Secvault
|
|
|
209
216
|
# Replace Rails.application.secrets
|
|
210
217
|
Rails.application.define_singleton_method(:secrets) { secrets_object }
|
|
211
218
|
|
|
219
|
+
# Set secret_key_base in Rails config to avoid accessing it from secrets
|
|
220
|
+
if set_secret_key_base && merged_secrets.key?("secret_key_base")
|
|
221
|
+
Rails.application.config.secret_key_base = merged_secrets["secret_key_base"]
|
|
222
|
+
Rails.logger&.info "[Secvault Multi-File] Set Rails.application.config.secret_key_base from secrets" if logger
|
|
223
|
+
end
|
|
224
|
+
|
|
212
225
|
# Log successful loading
|
|
213
226
|
if logger
|
|
214
227
|
file_names = existing_files.map(&:basename)
|
|
@@ -272,9 +285,7 @@ module Secvault
|
|
|
272
285
|
begin
|
|
273
286
|
# Set up Rails::Secrets to use Secvault's parser (only when integrating)
|
|
274
287
|
unless rails_integrated?
|
|
275
|
-
if defined?(Rails::Secrets)
|
|
276
|
-
Rails.send(:remove_const, :Secrets)
|
|
277
|
-
end
|
|
288
|
+
Rails.send(:remove_const, :Secrets) if defined?(Rails::Secrets)
|
|
278
289
|
Rails.const_set(:Secrets, Secvault::RailsSecrets)
|
|
279
290
|
end
|
|
280
291
|
|
|
@@ -292,8 +303,9 @@ module Secvault
|
|
|
292
303
|
end
|
|
293
304
|
|
|
294
305
|
# Backward compatibility aliases
|
|
295
|
-
alias_method :
|
|
296
|
-
alias_method :
|
|
306
|
+
alias_method :setup_backward_compatibility_with_older_rails!, :setup! # Legacy name
|
|
307
|
+
alias_method :setup_rails_71_integration!, :setup! # Legacy name
|
|
308
|
+
alias_method :setup_multi_files!, :setup_multi_file! # Alternative name
|
|
297
309
|
end
|
|
298
310
|
|
|
299
311
|
Secvault.install! if defined?(Rails)
|