secvault 2.7.0 → 3.0.0
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/README.md +389 -34
- 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 +108 -192
- 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: 7e9d55bf6f12233064ea7ced4e9b40c84f8f3a6ce38d6b5b79d5f0e8f4a7214a
|
|
4
|
+
data.tar.gz: 7ade516b0c550c0b3c98f04fc39ff1079d5c46436da6a7fd6153bdc1d9eac4fb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b2939f3acd3e9525d000b7195fd9967a4e8f80c04800e4cbac9da774625bc1cae7b26e1f0320d4d57d53abbf1bdb53a3899977deb9625880fd84458c7c302277
|
|
7
|
+
data.tar.gz: 84de3b9f8ecd84e820668d3ac2bd7fedeb7946e2707f88e00cd7219f258d597417b025a72b889dc93bf6e408c2686b2c444b90e1d2eaee856f1040d9f5b8d63a
|
data/README.md
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
# Secvault
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Secvault restores the classic Rails `secrets.yml` functionality using simple, plain YAML files for environment-specific secrets management. Compatible with all modern Rails versions (7.1+, 7.2+, 8.0+).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://rubygems.org/gems/secvault)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **Rails
|
|
7
|
+
## Why Secvault?
|
|
8
|
+
|
|
9
|
+
- **Drop-in replacement** for Rails 7.2+'s removed `secrets.yml` functionality
|
|
10
|
+
- **Universal compatibility** across Rails 7.1+, 7.2+, and 8.0+
|
|
11
|
+
- **ERB templating** support for environment variables
|
|
12
|
+
- **Multi-file support** with deep merging capabilities
|
|
13
|
+
- **Shared sections** for common configuration across environments
|
|
14
|
+
- **Simple YAML** - no complex credential management required
|
|
10
15
|
|
|
11
16
|
## Installation
|
|
12
17
|
|
|
@@ -15,87 +20,437 @@ Restores Rails `secrets.yml` functionality for environment-specific secrets mana
|
|
|
15
20
|
gem 'secvault'
|
|
16
21
|
```
|
|
17
22
|
|
|
23
|
+
```bash
|
|
24
|
+
bundle install
|
|
25
|
+
```
|
|
26
|
+
|
|
18
27
|
## Quick Start
|
|
19
28
|
|
|
29
|
+
### 1. Simple Setup
|
|
30
|
+
|
|
31
|
+
Create `config/initializers/secvault.rb`:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
# The simplest setup - works across all Rails versions
|
|
35
|
+
Secvault.start!
|
|
36
|
+
```
|
|
37
|
+
|
|
20
38
|
Create `config/secrets.yml`:
|
|
21
39
|
|
|
22
40
|
```yaml
|
|
41
|
+
shared:
|
|
42
|
+
app_name: "My Rails App"
|
|
43
|
+
timeout: 30
|
|
44
|
+
|
|
23
45
|
development:
|
|
46
|
+
secret_key_base: "dev_secret_key_here"
|
|
24
47
|
api_key: "dev_key_123"
|
|
25
48
|
database_url: "postgresql://localhost/myapp_dev"
|
|
49
|
+
debug: true
|
|
50
|
+
|
|
51
|
+
test:
|
|
52
|
+
secret_key_base: "test_secret_key_here"
|
|
53
|
+
api_key: "test_key_123"
|
|
26
54
|
|
|
27
55
|
production:
|
|
56
|
+
secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
|
|
28
57
|
api_key: <%= ENV['API_KEY'] %>
|
|
29
58
|
database_url: <%= ENV['DATABASE_URL'] %>
|
|
59
|
+
debug: false
|
|
30
60
|
```
|
|
31
61
|
|
|
32
|
-
|
|
62
|
+
### 2. Access Your Secrets
|
|
33
63
|
|
|
34
64
|
```ruby
|
|
65
|
+
# In your Rails application
|
|
35
66
|
Rails.application.secrets.api_key
|
|
67
|
+
Rails.application.secrets.app_name
|
|
36
68
|
Rails.application.secrets.database_url
|
|
69
|
+
|
|
70
|
+
# Nested secrets work too
|
|
71
|
+
Rails.application.secrets.database.host
|
|
72
|
+
Rails.application.secrets.features.analytics
|
|
37
73
|
```
|
|
38
74
|
|
|
39
|
-
##
|
|
75
|
+
## Setup Methods
|
|
76
|
+
|
|
77
|
+
### Unified start! Method
|
|
40
78
|
|
|
41
|
-
|
|
79
|
+
Secvault now uses a single, simplified `start!` method for all use cases:
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
# Simplest setup - loads config/secrets.yml with Rails integration
|
|
83
|
+
Secvault.start!
|
|
84
|
+
|
|
85
|
+
# Custom single file
|
|
86
|
+
Secvault.start!(files: ['custom.yml'])
|
|
87
|
+
|
|
88
|
+
# Multiple files with hot reload
|
|
89
|
+
Secvault.start!(
|
|
90
|
+
files: ['config/secrets.yml', 'config/secrets.local.yml'],
|
|
91
|
+
hot_reload: true
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# All available options
|
|
95
|
+
Secvault.start!(
|
|
96
|
+
files: ['config/secrets.yml'], # Default: ['config/secrets.yml']
|
|
97
|
+
integrate_with_rails: true, # Default: true
|
|
98
|
+
set_secret_key_base: true, # Default: true
|
|
99
|
+
hot_reload: true, # Default: true in development
|
|
100
|
+
logger: true # Default: true except production
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Advanced Usage
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
# Load without Rails integration (standalone mode)
|
|
108
|
+
Secvault.start!(integrate_with_rails: false)
|
|
109
|
+
# Access via: Secvault.secrets.your_key
|
|
110
|
+
|
|
111
|
+
# Multi-file with hot reload for development
|
|
112
|
+
Secvault.start!(
|
|
113
|
+
files: [
|
|
114
|
+
'config/secrets.yml',
|
|
115
|
+
'config/secrets.oauth.yml',
|
|
116
|
+
'config/secrets.local.yml' # Git-ignored local overrides
|
|
117
|
+
],
|
|
118
|
+
hot_reload: true,
|
|
119
|
+
logger: true
|
|
120
|
+
)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
## Advanced Features
|
|
125
|
+
|
|
126
|
+
### ERB Templating
|
|
127
|
+
|
|
128
|
+
Secvault supports full ERB templating for dynamic configuration:
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
production:
|
|
132
|
+
secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
|
|
133
|
+
api_key: <%= ENV['API_KEY'] %>
|
|
134
|
+
pool_size: <%= ENV.fetch('DB_POOL', '5').to_i %>
|
|
135
|
+
|
|
136
|
+
# Complex expressions
|
|
137
|
+
features:
|
|
138
|
+
enabled: <%= ENV.fetch('FEATURES_ON', 'false') == 'true' %>
|
|
139
|
+
analytics: <%= Rails.env.production? && ENV['ANALYTICS'] != 'false' %>
|
|
140
|
+
|
|
141
|
+
# Arrays and complex data structures
|
|
142
|
+
allowed_hosts: <%= ENV.fetch('ALLOWED_HOSTS', 'localhost').split(',') %>
|
|
143
|
+
|
|
144
|
+
# Conditional values
|
|
145
|
+
redis_url: <%=
|
|
146
|
+
if ENV['REDIS_URL']
|
|
147
|
+
ENV['REDIS_URL']
|
|
148
|
+
else
|
|
149
|
+
"redis://localhost:6379/#{Rails.env}"
|
|
150
|
+
end
|
|
151
|
+
%>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Shared Sections
|
|
155
|
+
|
|
156
|
+
Define common secrets that apply to all environments:
|
|
157
|
+
|
|
158
|
+
```yaml
|
|
159
|
+
shared:
|
|
160
|
+
app_name: "MyApp"
|
|
161
|
+
version: "2.1.0"
|
|
162
|
+
timeout: 30
|
|
163
|
+
features:
|
|
164
|
+
analytics: true
|
|
165
|
+
|
|
166
|
+
development:
|
|
167
|
+
secret_key_base: "dev_secret"
|
|
168
|
+
features:
|
|
169
|
+
debug: true # Merges with shared.features
|
|
170
|
+
|
|
171
|
+
production:
|
|
172
|
+
secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
|
|
173
|
+
features:
|
|
174
|
+
analytics: false # Overrides shared.features.analytics
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Multi-File Configuration
|
|
178
|
+
|
|
179
|
+
Organize your secrets across multiple files for better maintainability:
|
|
42
180
|
|
|
43
181
|
```ruby
|
|
44
|
-
# config/initializers/secvault.rb
|
|
45
182
|
Secvault.setup_multi_file!([
|
|
46
|
-
'config/secrets.yml',
|
|
47
|
-
'config/secrets.oauth.yml',
|
|
48
|
-
'config/secrets.
|
|
183
|
+
'config/secrets.yml', # Base secrets
|
|
184
|
+
'config/secrets.oauth.yml', # OAuth provider settings
|
|
185
|
+
'config/secrets.database.yml', # Database configurations
|
|
186
|
+
'config/secrets.local.yml' # Local overrides (git-ignored)
|
|
49
187
|
])
|
|
50
188
|
```
|
|
51
189
|
|
|
52
|
-
|
|
190
|
+
**File merging behavior:**
|
|
191
|
+
- Files are processed in order
|
|
192
|
+
- Later files override earlier ones
|
|
193
|
+
- Deep merging for nested hashes
|
|
194
|
+
- Shared sections are merged first, then environment-specific
|
|
195
|
+
|
|
196
|
+
### Hot Reload (Development)
|
|
197
|
+
|
|
198
|
+
Secvault provides hot reload functionality for development:
|
|
199
|
+
|
|
200
|
+
```ruby
|
|
201
|
+
# Enable hot reload when starting Secvault
|
|
202
|
+
Secvault.start!(hot_reload: true) # Default: true in development
|
|
203
|
+
|
|
204
|
+
# Then reload secrets without restarting Rails
|
|
205
|
+
reload_secrets!
|
|
206
|
+
|
|
207
|
+
# Or via Rails.application
|
|
208
|
+
Rails.application.reload_secrets!
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Hot reload is automatically enabled in development mode and provides instant feedback when you change your secrets files.
|
|
53
212
|
|
|
54
213
|
## Manual API
|
|
55
214
|
|
|
215
|
+
For advanced use cases, you can use the lower-level API:
|
|
216
|
+
|
|
56
217
|
```ruby
|
|
57
218
|
# Parse specific files
|
|
58
|
-
secrets = Rails::Secrets.parse(['config/secrets.yml'], env:
|
|
219
|
+
secrets = Rails::Secrets.parse(['config/secrets.yml'], env: 'production')
|
|
220
|
+
|
|
221
|
+
# Load from default location
|
|
222
|
+
secrets = Rails::Secrets.load(env: 'development')
|
|
223
|
+
|
|
224
|
+
# Check if Secvault is active
|
|
225
|
+
Secvault.active? # => true/false
|
|
226
|
+
|
|
227
|
+
# Check if integrated with Rails
|
|
228
|
+
Secvault.rails_integrated? # => true/false
|
|
229
|
+
|
|
230
|
+
# Access loaded secrets directly
|
|
231
|
+
Secvault.secrets.api_key # Available after Secvault.start!
|
|
232
|
+
```
|
|
59
233
|
|
|
60
|
-
|
|
61
|
-
secrets = Rails::Secrets.load(env: 'production')
|
|
234
|
+
## Rails Version Compatibility
|
|
62
235
|
|
|
63
|
-
|
|
64
|
-
|
|
236
|
+
| Rails Version | Support Level | Notes |
|
|
237
|
+
|---------------|---------------|-------|
|
|
238
|
+
| **Rails 7.1+** | ✅ Full compatibility | Manual setup required |
|
|
239
|
+
| **Rails 7.2+** | ✅ Drop-in replacement | Automatic setup works |
|
|
240
|
+
| **Rails 8.0+** | ✅ Full compatibility | Future-proof |
|
|
241
|
+
|
|
242
|
+
### Rails 7.2+ Notes
|
|
243
|
+
Rails 7.2 removed the built-in `secrets.yml` functionality. Secvault provides a complete replacement with the same API.
|
|
244
|
+
|
|
245
|
+
### Rails 7.1 Notes
|
|
246
|
+
Rails 7.1 still has `secrets.yml` support but shows deprecation warnings. Secvault provides a consistent experience across Rails versions.
|
|
247
|
+
|
|
248
|
+
## Migration Guide
|
|
249
|
+
|
|
250
|
+
### From Previous Secvault Versions
|
|
251
|
+
|
|
252
|
+
**BREAKING CHANGE**: The API has been simplified. Update your initializers:
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
# Old API (no longer supported):
|
|
256
|
+
Secvault.setup!
|
|
257
|
+
Secvault.setup_multi_file!(['file1.yml', 'file2.yml'])
|
|
258
|
+
Secvault.integrate_with_rails!
|
|
259
|
+
|
|
260
|
+
# New unified API:
|
|
261
|
+
Secvault.start! # Simple case
|
|
262
|
+
Secvault.start!(files: ['file1.yml', 'file2.yml']) # Multi-file case
|
|
263
|
+
Secvault.start!(integrate_with_rails: false) # Standalone mode
|
|
65
264
|
```
|
|
66
265
|
|
|
67
|
-
|
|
266
|
+
### From Rails < 7.2 Built-in Secrets
|
|
267
|
+
|
|
268
|
+
1. **Add Secvault to your Gemfile**:
|
|
269
|
+
```ruby
|
|
270
|
+
gem 'secvault'
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
2. **Create initializer**:
|
|
274
|
+
```ruby
|
|
275
|
+
# config/initializers/secvault.rb
|
|
276
|
+
Secvault.start!
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
3. **Your existing `config/secrets.yml` works as-is** - no changes needed!
|
|
280
|
+
|
|
281
|
+
### From Rails Credentials
|
|
282
|
+
|
|
283
|
+
1. **Extract your credentials to YAML**:
|
|
284
|
+
```bash
|
|
285
|
+
# Export existing credentials
|
|
286
|
+
rails credentials:show > config/secrets.yml
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
2. **Format as environment-specific YAML**:
|
|
290
|
+
```yaml
|
|
291
|
+
development:
|
|
292
|
+
secret_key_base: "your_dev_secret"
|
|
293
|
+
# ... other secrets
|
|
294
|
+
|
|
295
|
+
production:
|
|
296
|
+
secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
|
|
297
|
+
# ... other secrets
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
3. **Set up Secvault**:
|
|
301
|
+
```ruby
|
|
302
|
+
# config/initializers/secvault.rb
|
|
303
|
+
Secvault.start!
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Configuration Examples
|
|
68
307
|
|
|
69
|
-
|
|
308
|
+
### Basic Application
|
|
309
|
+
|
|
310
|
+
```yaml
|
|
311
|
+
# config/secrets.yml
|
|
312
|
+
shared:
|
|
313
|
+
app_name: "MyApp"
|
|
314
|
+
|
|
315
|
+
development:
|
|
316
|
+
secret_key_base: "long_random_string_for_dev"
|
|
317
|
+
database_url: "postgresql://localhost/myapp_dev"
|
|
318
|
+
|
|
319
|
+
test:
|
|
320
|
+
secret_key_base: "long_random_string_for_test"
|
|
321
|
+
database_url: "postgresql://localhost/myapp_test"
|
|
322
|
+
|
|
323
|
+
production:
|
|
324
|
+
secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
|
|
325
|
+
database_url: <%= ENV['DATABASE_URL'] %>
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Multi-Service Application
|
|
70
329
|
|
|
71
330
|
```ruby
|
|
72
331
|
# config/initializers/secvault.rb
|
|
73
|
-
Secvault.
|
|
332
|
+
Secvault.start!(
|
|
333
|
+
files: [
|
|
334
|
+
'config/secrets.yml',
|
|
335
|
+
'config/secrets.oauth.yml',
|
|
336
|
+
'config/secrets.external_apis.yml',
|
|
337
|
+
'config/secrets.local.yml' # Git-ignored
|
|
338
|
+
],
|
|
339
|
+
hot_reload: true
|
|
340
|
+
)
|
|
74
341
|
```
|
|
75
342
|
|
|
76
|
-
|
|
343
|
+
```yaml
|
|
344
|
+
# config/secrets.yml (base)
|
|
345
|
+
shared:
|
|
346
|
+
app_name: "MyApp"
|
|
347
|
+
timeout: 30
|
|
348
|
+
|
|
349
|
+
development:
|
|
350
|
+
secret_key_base: "dev_secret"
|
|
351
|
+
debug: true
|
|
77
352
|
|
|
78
|
-
|
|
353
|
+
production:
|
|
354
|
+
secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
|
|
355
|
+
debug: false
|
|
356
|
+
```
|
|
79
357
|
|
|
80
358
|
```yaml
|
|
359
|
+
# config/secrets.oauth.yml
|
|
360
|
+
shared:
|
|
361
|
+
oauth:
|
|
362
|
+
google:
|
|
363
|
+
scope: "email profile"
|
|
364
|
+
|
|
365
|
+
development:
|
|
366
|
+
oauth:
|
|
367
|
+
google:
|
|
368
|
+
client_id: "dev_google_client_id"
|
|
369
|
+
client_secret: "dev_google_client_secret"
|
|
370
|
+
|
|
81
371
|
production:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
hosts: <%= ENV.fetch('ALLOWED_HOSTS', 'localhost').split(',') %>
|
|
372
|
+
oauth:
|
|
373
|
+
google:
|
|
374
|
+
client_id: <%= ENV['GOOGLE_CLIENT_ID'] %>
|
|
375
|
+
client_secret: <%= ENV['GOOGLE_CLIENT_SECRET'] %>
|
|
87
376
|
```
|
|
88
377
|
|
|
89
|
-
##
|
|
378
|
+
## Troubleshooting
|
|
90
379
|
|
|
91
|
-
|
|
380
|
+
### Common Issues
|
|
92
381
|
|
|
382
|
+
**1. "No secrets.yml file found"**
|
|
383
|
+
```bash
|
|
384
|
+
# Create the file
|
|
385
|
+
mkdir -p config
|
|
386
|
+
touch config/secrets.yml
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**2. "undefined method `secrets' for Rails.application"**
|
|
93
390
|
```ruby
|
|
94
|
-
#
|
|
95
|
-
|
|
96
|
-
|
|
391
|
+
# Make sure Secvault is set up in an initializer
|
|
392
|
+
# config/initializers/secvault.rb
|
|
393
|
+
Secvault.start!
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**3. "Secrets not loading in tests"**
|
|
397
|
+
```ruby
|
|
398
|
+
# In your test helper or rails_helper.rb
|
|
399
|
+
Secvault.start! if defined?(Secvault)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**4. "Environment variables not working"**
|
|
403
|
+
```yaml
|
|
404
|
+
# Make sure you're using ERB syntax
|
|
405
|
+
production:
|
|
406
|
+
api_key: <%= ENV['API_KEY'] %> # ✅ Correct
|
|
407
|
+
api_key: $API_KEY # ❌ Wrong
|
|
97
408
|
```
|
|
98
409
|
|
|
410
|
+
### Debug Mode
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
# Enable detailed logging (development/test only)
|
|
414
|
+
Secvault.start!(files: ['config/secrets.yml'], logger: true)
|
|
415
|
+
|
|
416
|
+
# Check if Secvault is working
|
|
417
|
+
Secvault.active? # Should return true
|
|
418
|
+
Secvault.rails_integrated? # Should return true
|
|
419
|
+
Rails.application.secrets # Should show your secrets
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## API Reference
|
|
423
|
+
|
|
424
|
+
### Setup Methods
|
|
425
|
+
|
|
426
|
+
- `Secvault.start!(files: [], integrate_with_rails: true, set_secret_key_base: true, hot_reload: auto, logger: auto)` - Main and only setup method
|
|
427
|
+
|
|
428
|
+
### Status Methods
|
|
429
|
+
|
|
430
|
+
- `Secvault.active?` - Check if secrets are loaded
|
|
431
|
+
- `Secvault.rails_integrated?` - Check if Rails integration is active
|
|
432
|
+
- `Secvault.secrets` - Access loaded secrets directly
|
|
433
|
+
|
|
434
|
+
### Rails API Compatibility
|
|
435
|
+
|
|
436
|
+
- `Rails::Secrets.parse(files, env:)` - Parse specific files
|
|
437
|
+
- `Rails::Secrets.load(env:)` - Load from default config/secrets.yml
|
|
438
|
+
- `Rails.application.secrets` - Access secrets (same as classic Rails)
|
|
439
|
+
|
|
440
|
+
### Legacy Aliases
|
|
441
|
+
|
|
442
|
+
- `Secvault.setup_backward_compatibility_with_older_rails!` (alias for `setup!`)
|
|
443
|
+
- `Secvault.setup_rails_71_integration!` (alias for `setup!`)
|
|
444
|
+
- `Secvault.setup_multi_files!` (alias for `setup_multi_file!`)
|
|
445
|
+
|
|
446
|
+
## Contributing
|
|
447
|
+
|
|
448
|
+
1. Fork it
|
|
449
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
450
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
451
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
452
|
+
5. Create new Pull Request
|
|
453
|
+
|
|
99
454
|
## License
|
|
100
455
|
|
|
101
|
-
MIT
|
|
456
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -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,44 +13,33 @@ 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.
|
|
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.start!
|
|
43
30
|
#
|
|
44
31
|
# ## Usage:
|
|
45
32
|
# Rails.application.secrets.api_key
|
|
46
33
|
# Rails.application.secrets.oauth_settings[:google_client_id]
|
|
34
|
+
# Secvault.secrets.your_key # Direct access
|
|
47
35
|
# Rails::Secrets.load(env: 'development') # Load default config/secrets.yml
|
|
48
36
|
# Rails::Secrets.parse(['custom.yml'], env: Rails.env) # Parse custom files
|
|
49
37
|
#
|
|
50
38
|
# ## Getting Started:
|
|
51
39
|
# 1. Create config/secrets.yml with your secrets
|
|
52
|
-
# 2.
|
|
53
|
-
# 3.
|
|
40
|
+
# 2. Call Secvault.start! in an initializer
|
|
41
|
+
# 3. Use Rails.application.secrets.your_secret in your app
|
|
42
|
+
# 4. For production, use environment variables with ERB syntax
|
|
54
43
|
#
|
|
55
44
|
# @see https://github.com/unnitallman/secvault
|
|
56
45
|
module Secvault
|
|
@@ -83,109 +72,78 @@ module Secvault
|
|
|
83
72
|
require "secvault/rails_secrets"
|
|
84
73
|
end
|
|
85
74
|
|
|
86
|
-
#
|
|
87
|
-
# This
|
|
88
|
-
# that still have native Rails::Secrets functionality (like Rails 7.1).
|
|
89
|
-
#
|
|
90
|
-
# Usage in an initializer:
|
|
91
|
-
# Secvault.setup_backward_compatibility_with_older_rails!
|
|
75
|
+
# Start Secvault with simplified, unified API
|
|
76
|
+
# This is the main entry point for all Secvault functionality
|
|
92
77
|
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if defined?(Rails::Secrets)
|
|
100
|
-
Rails.send(:remove_const, :Secrets)
|
|
101
|
-
end
|
|
102
|
-
Rails.const_set(:Secrets, Secvault::RailsSecrets)
|
|
103
|
-
|
|
104
|
-
# Set up Rails.application.secrets replacement
|
|
105
|
-
Rails.application.config.after_initialize do
|
|
106
|
-
secrets_path = Rails.root.join("config/secrets.yml")
|
|
107
|
-
|
|
108
|
-
if secrets_path.exist?
|
|
109
|
-
# Load secrets using Secvault
|
|
110
|
-
loaded_secrets = Rails::Secrets.parse([secrets_path], env: Rails.env)
|
|
111
|
-
|
|
112
|
-
# Create ActiveSupport::OrderedOptions object for compatibility
|
|
113
|
-
secrets_object = ActiveSupport::OrderedOptions.new
|
|
114
|
-
secrets_object.merge!(loaded_secrets)
|
|
115
|
-
|
|
116
|
-
# Replace Rails.application.secrets
|
|
117
|
-
Rails.application.define_singleton_method(:secrets) do
|
|
118
|
-
secrets_object
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
# Log integration success (except in production)
|
|
122
|
-
unless Rails.env.production?
|
|
123
|
-
Rails.logger&.info "[Secvault] Rails 7.1 integration complete. Loaded #{loaded_secrets.keys.size} secret keys."
|
|
124
|
-
end
|
|
125
|
-
else
|
|
126
|
-
Rails.logger&.warn "[Secvault] No secrets.yml file found at #{secrets_path}"
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
# Set up multi-file secrets loading with a clean API
|
|
132
|
-
# Just pass an array of file paths and Secvault handles the rest
|
|
78
|
+
# Usage examples:
|
|
79
|
+
# Secvault.start! # Simple: config/secrets.yml + Rails integration
|
|
80
|
+
# Secvault.start!(files: ['custom.yml']) # Custom single file
|
|
81
|
+
# Secvault.start!(files: ['base.yml', 'local.yml']) # Multiple files
|
|
82
|
+
# Secvault.start!(integrate_with_rails: false) # Load only, no Rails integration
|
|
83
|
+
# Secvault.start!(hot_reload: true) # Enable hot reload in development
|
|
133
84
|
#
|
|
134
|
-
#
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
-
# 'config/secrets.oauth.yml',
|
|
138
|
-
# 'config/secrets.local.yml'
|
|
139
|
-
# ])
|
|
85
|
+
# Access secrets:
|
|
86
|
+
# Rails.application.secrets.your_key # When integrate_rails: true (default)
|
|
87
|
+
# Secvault.secrets.your_key # Direct access (always available)
|
|
140
88
|
#
|
|
141
89
|
# Options:
|
|
142
|
-
# - files: Array of file paths (String or Pathname)
|
|
143
|
-
# -
|
|
144
|
-
# -
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
90
|
+
# - files: Array of file paths (String or Pathname). Defaults to ['config/secrets.yml']
|
|
91
|
+
# - integrate_with_rails: Integrate with Rails.application.secrets (default: true)
|
|
92
|
+
# - set_secret_key_base: Set Rails.application.config.secret_key_base from secrets (default: true)
|
|
93
|
+
# - hot_reload: Add reload_secrets! methods for development (default: true in development)
|
|
94
|
+
# - logger: Enable logging (default: true except production)
|
|
95
|
+
def start!(files: [], integrate_with_rails: true, set_secret_key_base: true,
|
|
96
|
+
hot_reload: (defined?(Rails) && Rails.env.respond_to?(:development?) ? Rails.env.development? : false),
|
|
97
|
+
logger: (defined?(Rails) && Rails.env.respond_to?(:production?) ? !Rails.env.production? : true))
|
|
98
|
+
|
|
99
|
+
# Default to config/secrets.yml if no files specified
|
|
100
|
+
files_to_load = files.empty? ? ["config/secrets.yml"] : Array(files)
|
|
101
|
+
|
|
102
|
+
# Convert to Pathname objects and resolve relative to Rails.root
|
|
103
|
+
file_paths = files_to_load.map do |file|
|
|
151
104
|
file.is_a?(Pathname) ? file : Rails.root.join(file)
|
|
152
105
|
end
|
|
153
|
-
|
|
154
|
-
#
|
|
155
|
-
|
|
156
|
-
|
|
106
|
+
|
|
107
|
+
# Load secrets into Secvault.secrets
|
|
108
|
+
load_secrets!(file_paths, logger: logger)
|
|
109
|
+
|
|
110
|
+
# Integrate with Rails if requested
|
|
111
|
+
if integrate_with_rails
|
|
112
|
+
setup_rails_integration!(file_paths, set_secret_key_base: set_secret_key_base, logger: logger)
|
|
157
113
|
end
|
|
158
|
-
|
|
159
|
-
# Add reload
|
|
160
|
-
if
|
|
161
|
-
|
|
114
|
+
|
|
115
|
+
# Add hot reload functionality if requested
|
|
116
|
+
if hot_reload
|
|
117
|
+
add_hot_reload!(file_paths)
|
|
162
118
|
end
|
|
119
|
+
|
|
120
|
+
true
|
|
121
|
+
rescue => e
|
|
122
|
+
Rails.logger&.error "[Secvault] Failed to start: #{e.message}" if defined?(Rails) && logger
|
|
123
|
+
false
|
|
163
124
|
end
|
|
164
125
|
|
|
165
|
-
|
|
166
|
-
def load_secrets_only!(files, logger: !Rails.env.production?)
|
|
167
|
-
# Convert strings to Pathname objects and resolve relative to Rails.root
|
|
168
|
-
file_paths = Array(files).map do |file|
|
|
169
|
-
file.is_a?(Pathname) ? file : Rails.root.join(file)
|
|
170
|
-
end
|
|
126
|
+
private
|
|
171
127
|
|
|
128
|
+
# Load secrets into Secvault.secrets (internal storage)
|
|
129
|
+
def load_secrets!(file_paths, logger: (defined?(Rails) && Rails.env.respond_to?(:production?) ? !Rails.env.production? : true))
|
|
172
130
|
existing_files = file_paths.select(&:exist?)
|
|
173
|
-
|
|
131
|
+
|
|
174
132
|
if existing_files.any?
|
|
175
|
-
# Load and merge all secrets files
|
|
133
|
+
# Load and merge all secrets files
|
|
176
134
|
merged_secrets = Secvault::Secrets.parse(existing_files, env: Rails.env)
|
|
177
|
-
|
|
178
|
-
# Store in
|
|
135
|
+
|
|
136
|
+
# Store in internal storage with ActiveSupport::OrderedOptions for compatibility
|
|
179
137
|
@@loaded_secrets = ActiveSupport::OrderedOptions.new
|
|
180
138
|
@@loaded_secrets.merge!(merged_secrets)
|
|
181
|
-
|
|
139
|
+
|
|
182
140
|
# Log successful loading
|
|
183
141
|
if logger
|
|
184
142
|
file_names = existing_files.map(&:basename)
|
|
185
143
|
Rails.logger&.info "[Secvault] Loaded #{existing_files.size} files: #{file_names.join(", ")}"
|
|
186
144
|
Rails.logger&.info "[Secvault] Parsed #{merged_secrets.keys.size} secret keys for #{Rails.env}"
|
|
187
145
|
end
|
|
188
|
-
|
|
146
|
+
|
|
189
147
|
true
|
|
190
148
|
else
|
|
191
149
|
Rails.logger&.warn "[Secvault] No secrets files found" if logger
|
|
@@ -193,107 +151,65 @@ module Secvault
|
|
|
193
151
|
false
|
|
194
152
|
end
|
|
195
153
|
end
|
|
196
|
-
|
|
197
|
-
#
|
|
198
|
-
def
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
154
|
+
|
|
155
|
+
# Set up Rails integration
|
|
156
|
+
def setup_rails_integration!(file_paths, set_secret_key_base: true, logger: (defined?(Rails) && Rails.env.respond_to?(:production?) ? !Rails.env.production? : true))
|
|
157
|
+
# Override native Rails::Secrets with Secvault implementation
|
|
158
|
+
Rails.send(:remove_const, :Secrets) if defined?(Rails::Secrets)
|
|
159
|
+
Rails.const_set(:Secrets, Secvault::RailsSecrets)
|
|
160
|
+
|
|
161
|
+
# Set up Rails.application.secrets replacement in after_initialize
|
|
162
|
+
Rails.application.config.after_initialize do
|
|
163
|
+
if @@loaded_secrets && !@@loaded_secrets.empty?
|
|
164
|
+
# Replace Rails.application.secrets with our loaded secrets
|
|
165
|
+
Rails.application.define_singleton_method(:secrets) do
|
|
166
|
+
@@loaded_secrets
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Set secret_key_base in Rails config to avoid accessing it from secrets
|
|
170
|
+
if set_secret_key_base && @@loaded_secrets.key?(:secret_key_base)
|
|
171
|
+
Rails.application.config.secret_key_base = @@loaded_secrets[:secret_key_base]
|
|
172
|
+
Rails.logger&.info "[Secvault] Set Rails.application.config.secret_key_base from secrets" if logger
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Log integration success (except in production)
|
|
176
|
+
if logger
|
|
177
|
+
Rails.logger&.info "[Secvault] Rails integration complete. #{@@loaded_secrets.keys.size} secret keys available."
|
|
178
|
+
end
|
|
179
|
+
else
|
|
180
|
+
Rails.logger&.warn "[Secvault] No secrets loaded for Rails integration" if logger
|
|
217
181
|
end
|
|
218
|
-
|
|
219
|
-
merged_secrets
|
|
220
|
-
else
|
|
221
|
-
Rails.logger&.warn "[Secvault Multi-File] No secrets files found" if logger
|
|
222
|
-
{}
|
|
223
182
|
end
|
|
224
183
|
end
|
|
225
|
-
|
|
226
|
-
# Add reload
|
|
227
|
-
def
|
|
184
|
+
|
|
185
|
+
# Add hot reload functionality for development
|
|
186
|
+
def add_hot_reload!(file_paths)
|
|
228
187
|
# Define reload method on Rails.application
|
|
229
188
|
Rails.application.define_singleton_method(:reload_secrets!) do
|
|
230
|
-
|
|
231
|
-
|
|
189
|
+
# Reload secrets
|
|
190
|
+
Secvault.send(:load_secrets!, file_paths, logger: true)
|
|
191
|
+
|
|
192
|
+
# Re-apply Rails integration if needed
|
|
193
|
+
if Secvault.rails_integrated? && @@loaded_secrets
|
|
194
|
+
Rails.application.define_singleton_method(:secrets) do
|
|
195
|
+
@@loaded_secrets
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
puts "🔄 Hot reloaded secrets from #{file_paths.size} files"
|
|
232
200
|
true
|
|
233
201
|
end
|
|
234
|
-
|
|
202
|
+
|
|
235
203
|
# Also make it available as a top-level method
|
|
236
204
|
Object.define_method(:reload_secrets!) do
|
|
237
205
|
Rails.application.reload_secrets!
|
|
238
206
|
end
|
|
207
|
+
|
|
208
|
+
Rails.logger&.info "[Secvault] Hot reload enabled. Use reload_secrets! to refresh secrets." unless (defined?(Rails) && Rails.env.respond_to?(:production?) && Rails.env.production?)
|
|
239
209
|
end
|
|
210
|
+
|
|
211
|
+
public
|
|
240
212
|
|
|
241
|
-
# Start Secvault and load secrets (without Rails integration)
|
|
242
|
-
#
|
|
243
|
-
# Usage:
|
|
244
|
-
# Secvault.start! # Uses config/secrets.yml only
|
|
245
|
-
# Secvault.start!(files: []) # Same as above
|
|
246
|
-
# Secvault.start!(files: ['path/to/secrets.yml']) # Custom single file
|
|
247
|
-
# Secvault.start!(files: ['gem.yml', 'app.yml']) # Multiple files
|
|
248
|
-
#
|
|
249
|
-
# Access loaded secrets via: Secvault.secrets.your_key
|
|
250
|
-
# To integrate with Rails.application.secrets, call: Secvault.integrate_with_rails!
|
|
251
|
-
#
|
|
252
|
-
# Options:
|
|
253
|
-
# - files: Array of file paths (String or Pathname). Defaults to ['config/secrets.yml']
|
|
254
|
-
# - logger: Enable logging (default: true except production)
|
|
255
|
-
def start!(files: [], logger: !Rails.env.production?)
|
|
256
|
-
# Default to host app's config/secrets.yml if no files specified
|
|
257
|
-
files_to_load = files.empty? ? ["config/secrets.yml"] : files
|
|
258
|
-
|
|
259
|
-
# Load secrets into Secvault.secrets (completely independent of Rails)
|
|
260
|
-
load_secrets_only!(files_to_load, logger: logger)
|
|
261
|
-
|
|
262
|
-
true
|
|
263
|
-
rescue => e
|
|
264
|
-
Rails.logger&.error "[Secvault] Failed to start: #{e.message}" if defined?(Rails)
|
|
265
|
-
false
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
# Integrate loaded secrets with Rails.application.secrets
|
|
269
|
-
def integrate_with_rails!
|
|
270
|
-
return false unless @@loaded_secrets
|
|
271
|
-
|
|
272
|
-
begin
|
|
273
|
-
# Set up Rails::Secrets to use Secvault's parser (only when integrating)
|
|
274
|
-
unless rails_integrated?
|
|
275
|
-
if defined?(Rails::Secrets)
|
|
276
|
-
Rails.send(:remove_const, :Secrets)
|
|
277
|
-
end
|
|
278
|
-
Rails.const_set(:Secrets, Secvault::RailsSecrets)
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
# Replace Rails.application.secrets with Secvault's loaded secrets
|
|
282
|
-
Rails.application.define_singleton_method(:secrets) do
|
|
283
|
-
Secvault.secrets
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
Rails.logger&.info "[Secvault] Integrated with Rails.application.secrets" unless Rails.env.production?
|
|
287
|
-
true
|
|
288
|
-
rescue => e
|
|
289
|
-
Rails.logger&.error "[Secvault] Failed to integrate with Rails: #{e.message}" if defined?(Rails)
|
|
290
|
-
false
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
# Backward compatibility aliases
|
|
295
|
-
alias_method :setup_rails_71_integration!, :setup_backward_compatibility_with_older_rails!
|
|
296
|
-
alias_method :setup_multi_files!, :setup_multi_file! # Alternative name
|
|
297
213
|
end
|
|
298
214
|
|
|
299
215
|
Secvault.install! if defined?(Rails)
|