secvault 3.0.0 → 3.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e9d55bf6f12233064ea7ced4e9b40c84f8f3a6ce38d6b5b79d5f0e8f4a7214a
4
- data.tar.gz: 7ade516b0c550c0b3c98f04fc39ff1079d5c46436da6a7fd6153bdc1d9eac4fb
3
+ metadata.gz: ff511b4da4c277844438956507222da90bd15416fd8e4adec1e973a4e5b73993
4
+ data.tar.gz: 45219a2e917ac366af2c94c8a848cc5557219b4856daab6fcd870d19898d1685
5
5
  SHA512:
6
- metadata.gz: b2939f3acd3e9525d000b7195fd9967a4e8f80c04800e4cbac9da774625bc1cae7b26e1f0320d4d57d53abbf1bdb53a3899977deb9625880fd84458c7c302277
7
- data.tar.gz: 84de3b9f8ecd84e820668d3ac2bd7fedeb7946e2707f88e00cd7219f258d597417b025a72b889dc93bf6e408c2686b2c444b90e1d2eaee856f1040d9f5b8d63a
6
+ metadata.gz: 45e5d96b9eaa32ea9396921451dfb2ed148e485992236ae45bf58acf9a380869cde8df8b3e93e621cdfe1bcd9710f4eccbeaee3880fa5436c73e336d063d866f
7
+ data.tar.gz: db91a660ae62430a0c27f311bd512d964efc485f4a224e42f958b9215d31c9c553db765b638b622413b18c9b236ab6865d14328594f8d6ab726452484eddc767
data/README.md CHANGED
@@ -1,456 +1,110 @@
1
1
  # Secvault
2
2
 
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+).
3
+ Simple YAML secrets management for Rails. Uses standard YAML anchors for sharing configuration.
4
4
 
5
5
  [![Gem Version](https://img.shields.io/gem/v/secvault.svg)](https://rubygems.org/gems/secvault)
6
-
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
6
+ [![CI](https://github.com/unnitallman/secvault/actions/workflows/ci.yml/badge.svg)](https://github.com/unnitallman/secvault/actions/workflows/ci.yml)
15
7
 
16
8
  ## Installation
17
9
 
18
10
  ```ruby
19
- # Gemfile
20
11
  gem 'secvault'
21
12
  ```
22
13
 
23
- ```bash
24
- bundle install
25
- ```
26
-
27
- ## Quick Start
28
-
29
- ### 1. Simple Setup
30
-
31
- Create `config/initializers/secvault.rb`:
14
+ ## Usage
32
15
 
16
+ **1. Add to initializer:**
33
17
  ```ruby
34
- # The simplest setup - works across all Rails versions
18
+ # config/initializers/secvault.rb
35
19
  Secvault.start!
36
20
  ```
37
21
 
38
- Create `config/secrets.yml`:
39
-
22
+ **2. Create secrets file:**
40
23
  ```yaml
41
- shared:
42
- app_name: "My Rails App"
43
- timeout: 30
24
+ # config/secrets.yml
25
+ defaults: &defaults
26
+ app_name: "MyApp"
44
27
 
45
28
  development:
46
- secret_key_base: "dev_secret_key_here"
47
- api_key: "dev_key_123"
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"
29
+ <<: *defaults
30
+ secret_key_base: "dev_secret"
31
+ api_key: "dev_key"
54
32
 
55
33
  production:
34
+ <<: *defaults
56
35
  secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
57
36
  api_key: <%= ENV['API_KEY'] %>
58
- database_url: <%= ENV['DATABASE_URL'] %>
59
- debug: false
60
- ```
61
-
62
- ### 2. Access Your Secrets
63
-
64
- ```ruby
65
- # In your Rails application
66
- Rails.application.secrets.api_key
67
- Rails.application.secrets.app_name
68
- Rails.application.secrets.database_url
69
-
70
- # Nested secrets work too
71
- Rails.application.secrets.database.host
72
- Rails.application.secrets.features.analytics
73
37
  ```
74
38
 
75
- ## Setup Methods
76
-
77
- ### Unified start! Method
78
-
79
- Secvault now uses a single, simplified `start!` method for all use cases:
80
-
39
+ **3. Use in your app:**
81
40
  ```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
- )
41
+ Secvault.secrets.api_key
42
+ Secvault.secrets.app_name
102
43
  ```
103
44
 
104
- ### Advanced Usage
45
+ ## Options
105
46
 
106
47
  ```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
48
  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
49
+ files: ['config/secrets.yml'], # Files to load (later files override earlier ones)
50
+ integrate_with_rails: false, # Add Rails.application.secrets
51
+ set_secret_key_base: true, # Auto-set Rails.application.config.secret_key_base from secrets
52
+ hot_reload: true, # Auto-reload in development
53
+ logger: true # Log loading activity
120
54
  )
121
55
  ```
122
56
 
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:
180
-
57
+ **Multiple files:**
181
58
  ```ruby
182
- Secvault.setup_multi_file!([
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)
187
- ])
59
+ # Later files override earlier ones
60
+ Secvault.start!(files: ['secrets.yml', 'local.yml'])
188
61
  ```
189
62
 
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
-
63
+ **Rails integration:**
200
64
  ```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.
212
-
213
- ## Manual API
214
-
215
- For advanced use cases, you can use the lower-level API:
216
-
217
- ```ruby
218
- # Parse specific files
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!
65
+ Secvault.start!(integrate_with_rails: true)
66
+ Rails.application.secrets.api_key # Now available
232
67
  ```
233
68
 
234
- ## Rails Version Compatibility
235
-
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
-
69
+ **Secret key base:**
254
70
  ```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
71
+ # If your secrets.yml has secret_key_base, it's automatically set
72
+ # This replaces the need for Rails.application.config.secret_key_base
73
+ Secvault.start!(set_secret_key_base: true) # Default behavior
264
74
  ```
265
75
 
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
76
 
306
- ## Configuration Examples
307
-
308
- ### Basic Application
77
+ ## Advanced
309
78
 
79
+ **ERB templating:**
310
80
  ```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
81
  production:
324
- secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
325
- database_url: <%= ENV['DATABASE_URL'] %>
326
- ```
327
-
328
- ### Multi-Service Application
329
-
330
- ```ruby
331
- # config/initializers/secvault.rb
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
- )
82
+ api_key: <%= ENV['API_KEY'] %>
83
+ pool_size: <%= ENV.fetch('DB_POOL', '5').to_i %>
341
84
  ```
342
85
 
86
+ **YAML anchors for sharing:**
343
87
  ```yaml
344
- # config/secrets.yml (base)
345
- shared:
88
+ defaults: &defaults
346
89
  app_name: "MyApp"
347
90
  timeout: 30
348
91
 
349
92
  development:
350
- secret_key_base: "dev_secret"
93
+ <<: *defaults
351
94
  debug: true
352
95
 
353
96
  production:
354
- secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
355
- debug: false
356
- ```
357
-
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
-
371
- production:
372
- oauth:
373
- google:
374
- client_id: <%= ENV['GOOGLE_CLIENT_ID'] %>
375
- client_secret: <%= ENV['GOOGLE_CLIENT_SECRET'] %>
376
- ```
377
-
378
- ## Troubleshooting
379
-
380
- ### Common Issues
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"**
390
- ```ruby
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
+ <<: *defaults
98
+ timeout: 10 # Override specific values
408
99
  ```
409
100
 
410
- ### Debug Mode
411
-
101
+ **Development helpers:**
412
102
  ```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
103
+ reload_secrets! # Reload files
104
+ Secvault.active? # Check status
420
105
  ```
421
106
 
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
107
 
454
108
  ## License
455
109
 
456
- MIT License. See [LICENSE](LICENSE) for details.
110
+ MIT
data/SECURITY.md ADDED
@@ -0,0 +1,98 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ We actively support the following versions of Secvault with security updates:
6
+
7
+ | Version | Supported |
8
+ | ------- | ------------------ |
9
+ | 3.1.x | :white_check_mark: |
10
+ | 3.0.x | :white_check_mark: |
11
+ | < 3.0 | :x: |
12
+
13
+ ## Reporting a Vulnerability
14
+
15
+ **Please do not report security vulnerabilities through public GitHub issues.**
16
+
17
+ Instead, please report security vulnerabilities by emailing **unnikrishnan.kp@bigbinary.com**.
18
+
19
+ You should receive a response within 48 hours. If the issue is confirmed, we will release a patch as soon as possible depending on complexity but typically within 7 days.
20
+
21
+ ### What to Include in Your Report
22
+
23
+ Please include the following information in your vulnerability report:
24
+
25
+ - Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
26
+ - Full paths of source file(s) related to the manifestation of the issue
27
+ - The location of the affected source code (tag/branch/commit or direct URL)
28
+ - Any special configuration required to reproduce the issue
29
+ - Step-by-step instructions to reproduce the issue
30
+ - Proof-of-concept or exploit code (if possible)
31
+ - Impact of the issue, including how an attacker might exploit the issue
32
+
33
+ This information will help us triage your report more quickly.
34
+
35
+ ## Security Best Practices
36
+
37
+ When using Secvault in your applications, please follow these security best practices:
38
+
39
+ ### 1. File Permissions
40
+ - Ensure your secrets files (`config/secrets.yml`, etc.) have restrictive file permissions (600 or 640)
41
+ - Never commit secrets files to version control
42
+ - Use `.gitignore` to exclude secrets files from your repository
43
+
44
+ ### 2. Environment Separation
45
+ - Use different secrets files for different environments (development, staging, production)
46
+ - Never use production secrets in development or testing environments
47
+ - Implement proper environment-specific configuration
48
+
49
+ ### 3. Secret Management
50
+ - Rotate secrets regularly
51
+ - Use strong, randomly generated secrets
52
+ - Avoid hardcoding secrets in application code
53
+ - Consider using external secret management services for production environments
54
+
55
+ ### 4. Access Control
56
+ - Limit access to secrets files to only necessary personnel and processes
57
+ - Use proper deployment practices that don't expose secrets in logs or process lists
58
+ - Implement proper access controls in your deployment infrastructure
59
+
60
+ ### 5. Monitoring and Auditing
61
+ - Monitor access to secrets files
62
+ - Implement logging for secrets access (without logging the actual secret values)
63
+ - Regular security audits of your secrets management practices
64
+
65
+ ## Dependencies and Supply Chain Security
66
+
67
+ Secvault has minimal dependencies to reduce attack surface:
68
+
69
+ - **Rails**: We require Rails >= 7.1.0 and stay updated with security patches
70
+ - **Zeitwerk**: Used for autoloading, maintained by the Rails core team
71
+
72
+ We regularly monitor our dependencies for security vulnerabilities and update them promptly when security issues are discovered.
73
+
74
+ ## Security Considerations
75
+
76
+ ### Hot Reload Feature
77
+ The hot reload feature (`reload_secrets!`) is designed for development environments only. It should not be enabled in production as it can potentially expose secrets through memory dumps or debugging tools.
78
+
79
+ ### Rails Integration
80
+ Secvault integrates deeply with Rails' secrets system. While this provides seamless functionality, it's important to understand that secrets are loaded into memory and may be visible to processes with sufficient privileges.
81
+
82
+ ### File System Security
83
+ Secvault reads secrets from the file system. Ensure your deployment environment has proper file system security controls in place.
84
+
85
+ ## Acknowledgments
86
+
87
+ We appreciate the security research community and responsible disclosure. Contributors who report valid security vulnerabilities will be acknowledged in our release notes (unless they prefer to remain anonymous).
88
+
89
+ ## Contact
90
+
91
+ For any security-related questions or concerns, please contact:
92
+
93
+ **Email**: unnikrishnan.kp@bigbinary.com
94
+ **Project**: https://github.com/unnitallman/secvault
95
+
96
+ ---
97
+
98
+ *This security policy is effective as of the date of the latest commit to this file and applies to all current and future versions of Secvault.*
@@ -1,54 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Secvault
4
- # Rails::Secrets compatibility module
4
+ # Rails::Secrets compatibility class
5
5
  # Provides the classic Rails::Secrets interface for backwards compatibility
6
- # This replicates the Rails < 7.2 Rails::Secrets module functionality
7
- module RailsSecrets
8
- extend self
6
+ # This replicates the Rails < 7.2 Rails::Secrets class functionality
7
+ class RailsSecrets
8
+ class << self
9
+ attr_accessor :root
9
10
 
10
- # Parse secrets from one or more YAML files
11
- #
12
- # Supports:
13
- # - ERB templating for environment variables
14
- # - Shared sections that apply to all environments
15
- # - Environment-specific sections
16
- # - Multiple files (merged in order)
17
- # - Deep symbolized keys
18
- #
19
- # Examples:
20
- # # Single file
21
- # Rails::Secrets.parse(['config/secrets.yml'], env: 'development')
22
- #
23
- # # Multiple files (merged in order)
24
- # Rails::Secrets.parse([
25
- # 'config/secrets.yml',
26
- # 'config/secrets.local.yml'
27
- # ], env: 'development')
28
- #
29
- # # Load default config/secrets.yml
30
- # Rails::Secrets.load # uses current Rails.env
31
- # Rails::Secrets.load(env: 'production')
32
- def parse(paths, env:)
33
- Secvault::Secrets.parse(paths, env: env.to_s)
34
- end
11
+ # Parse secrets from one or more YAML files
12
+ #
13
+ # Supports:
14
+ # - ERB templating for environment variables
15
+ # - Environment-specific sections (YAML anchors handle sharing)
16
+ # - Multiple files (merged in order)
17
+ # - Deep symbolized keys
18
+ #
19
+ # Examples:
20
+ # # Single file
21
+ # Rails::Secrets.parse(['config/secrets.yml'], env: 'development')
22
+ #
23
+ # # Multiple files (merged in order)
24
+ # Rails::Secrets.parse([
25
+ # 'config/secrets.yml',
26
+ # 'config/secrets.local.yml'
27
+ # ], env: 'development')
28
+ #
29
+ # # Load default config/secrets.yml
30
+ # Rails::Secrets.load # uses current Rails.env
31
+ # Rails::Secrets.load(env: 'production')
32
+ def parse(paths, env:)
33
+ Secvault::Secrets.parse(paths, env: env.to_s)
34
+ end
35
35
 
36
- # Load secrets from the default config/secrets.yml file
37
- def load(env: Rails.env)
38
- secrets_path = Rails.root.join("config/secrets.yml")
39
- parse([secrets_path], env: env)
40
- end
36
+ # Load secrets from the default config/secrets.yml file
37
+ def load(env: Rails.env)
38
+ secrets_path = Rails.root.join("config/secrets.yml")
39
+ parse([secrets_path], env: env)
40
+ end
41
41
 
42
- # Backward compatibility aliases (deprecated)
43
- alias_method :parse_default, :load
44
- alias_method :read, :load
42
+ # Backward compatibility aliases (deprecated)
43
+ alias_method :parse_default, :load
44
+ alias_method :read, :load
45
+ end
45
46
  end
46
47
  end
47
48
 
48
- # Monkey patch to restore Rails::Secrets interface for backwards compatibility
49
+ # Replace Rails::Secrets interface for backwards compatibility
49
50
  # Works consistently across all Rails versions with warning suppression
50
51
  if defined?(Rails)
51
52
  module Rails
53
+ # Remove existing constant to avoid warnings
54
+ remove_const(:Secrets) if const_defined?(:Secrets, false)
52
55
  Secrets = Secvault::RailsSecrets
53
56
  end
54
57
  end
@@ -2,34 +2,154 @@
2
2
 
3
3
  require "rails/railtie"
4
4
 
5
+ # Extremely early hook to set up Rails.application.secrets before Application class is defined
6
+ if defined?(Rails)
7
+ # Set up a robust Rails.application with secrets support
8
+ unless Rails.respond_to?(:application) && Rails.application.respond_to?(:secrets)
9
+ # Create a minimal application-like object
10
+ temp_app = Object.new
11
+
12
+ # Add secrets method with default empty secrets that include needed encryption keys
13
+ temp_app.define_singleton_method(:secrets) do
14
+ @secrets ||= begin
15
+ secrets = ActiveSupport::OrderedOptions.new
16
+
17
+ # Add empty encryption section to prevent NoMethodError
18
+ secrets.encryption = {
19
+ primary_key: nil,
20
+ deterministic_key: nil,
21
+ key_derivation_salt: nil
22
+ }
23
+
24
+ secrets
25
+ end
26
+ end
27
+
28
+ # Set up Rails.application if it doesn't exist
29
+ Rails.define_singleton_method(:application) { temp_app } unless Rails.respond_to?(:application)
30
+ end
31
+ end
32
+
5
33
  module Secvault
6
34
  class Railtie < Rails::Railtie
7
35
  railtie_name :secvault
8
36
 
37
+ # Hook to set up early secrets access before application configuration
38
+ config.before_configuration do |app|
39
+ Secvault::EarlyLoader.setup_early_secrets(app)
40
+ end
41
+
9
42
  initializer "secvault.initialize", before: :load_environment_hook do |app|
10
43
  Secvault::Secrets.setup(app)
11
44
  end
45
+ end
12
46
 
13
- # Ensure initialization happens early in all environments
14
- config.before_configuration do |app|
15
- secrets_path = app.root.join("config/secrets.yml")
47
+ # Early loader class to handle secrets before application configuration
48
+ class EarlyLoader
49
+ class << self
50
+ def setup_early_secrets(app)
51
+ puts "[Secvault Debug] setup_early_secrets called" unless Rails.env.production?
52
+
53
+ if Rails.application.respond_to?(:secrets) && !Rails.application.secrets.empty?
54
+ puts "[Secvault Debug] Secrets already exist, skipping early load" unless Rails.env.production?
55
+ return
56
+ end
57
+
58
+ # Look for Secvault configuration in the app
59
+ secrets_config = find_secvault_config(app)
60
+ puts "[Secvault Debug] Found config: #{secrets_config&.keys}" unless Rails.env.production?
61
+ return unless secrets_config
16
62
 
17
- if secrets_path.exist? && !Rails.application.respond_to?(:secrets)
18
- # Early initialization for test environment compatibility
19
- current_env = ENV["RAILS_ENV"] || "development"
20
- secrets = Secvault::Secrets.read_secrets(secrets_path, current_env)
63
+ begin
64
+ # Load secrets using the configuration found
65
+ all_secrets = Secvault::Secrets.parse(secrets_config[:files], env: Rails.env)
66
+ puts "[Secvault Debug] Loaded secrets keys: #{all_secrets.keys}" unless Rails.env.production?
21
67
 
22
- if secrets
68
+ # Set up Rails.application.secrets immediately
23
69
  Rails.application.define_singleton_method(:secrets) do
24
70
  @secrets ||= begin
25
71
  current_secrets = ActiveSupport::OrderedOptions.new
26
- env_secrets = Secvault::Secrets.read_secrets(secrets_path, Rails.env)
27
- current_secrets.merge!(env_secrets) if env_secrets
72
+ current_secrets.merge!(all_secrets)
73
+ puts "[Secvault Debug] Returning secrets with encryption: #{current_secrets.encryption}" unless Rails.env.production?
28
74
  current_secrets
29
75
  end
30
76
  end
77
+
78
+ # Test the secrets immediately
79
+ test_encryption = Rails.application.secrets.encryption
80
+ puts "[Secvault Debug] Test access - encryption: #{test_encryption.class} - #{test_encryption}" unless Rails.env.production?
81
+
82
+ Rails.logger&.info "[Secvault] Early secrets loaded from #{secrets_config[:files].size} files" unless Rails.env.production?
83
+ rescue => e
84
+ Rails.logger&.warn "[Secvault] Failed to load early secrets: #{e.message}"
31
85
  end
32
86
  end
87
+
88
+ private
89
+
90
+ def find_secvault_config(app)
91
+ # Look for Secvault configuration in various locations
92
+ config_locations = [
93
+ app.root.join("config/initializers/secvault.rb"),
94
+ app.root.join("config/secvault.rb")
95
+ ]
96
+
97
+ config_locations.each do |config_file|
98
+ next unless config_file.exist?
99
+
100
+ config = parse_secvault_config(config_file)
101
+ return config if config
102
+ end
103
+
104
+ # Fallback to default configuration
105
+ default_files = [app.root.join("config/secrets.yml")]
106
+
107
+ # Check if neeto-commons-backend is available for default config
108
+ if defined?(NeetoCommonsBackend) && NeetoCommonsBackend.respond_to?(:shared_secrets_file)
109
+ default_files.unshift(NeetoCommonsBackend.shared_secrets_file)
110
+ end
111
+
112
+ # Only return default if at least one file exists
113
+ existing_files = default_files.select(&:exist?)
114
+ return {files: existing_files} if existing_files.any?
115
+
116
+ nil
117
+ end
118
+
119
+ def parse_secvault_config(config_file)
120
+ # Read the configuration file and extract Secvault.start! parameters
121
+ content = config_file.read
122
+
123
+ # Look for Secvault.start! calls
124
+ if /Secvault\.start!\s*\(/m.match?(content)
125
+ # Try to extract the files parameter using a simple regex
126
+ files_match = content.match(/files:\s*\[(.*?)\]/m)
127
+ if files_match
128
+ # Parse the files array (basic string parsing)
129
+ files_content = files_match[1]
130
+ files = []
131
+
132
+ # Handle various file specification patterns
133
+ files_content.scan(/["'](.*?)["']|([A-Za-z_][\w.]*\([^)]*\))/) do |quoted, method_call|
134
+ if quoted
135
+ files << Rails.root.join(quoted.strip)
136
+ elsif method_call
137
+ # Handle method calls like NeetoCommonsBackend.shared_secrets_file
138
+ if method_call.include?("NeetoCommonsBackend.shared_secrets_file") && defined?(NeetoCommonsBackend)
139
+ files << NeetoCommonsBackend.shared_secrets_file
140
+ end
141
+ end
142
+ end
143
+
144
+ return {files: files.compact} if files.any?
145
+ end
146
+ end
147
+
148
+ nil
149
+ rescue => e
150
+ Rails.logger&.warn "[Secvault] Failed to parse config file #{config_file}: #{e.message}"
151
+ nil
152
+ end
33
153
  end
34
154
  end
35
155
  end
@@ -56,7 +56,7 @@ module Secvault
56
56
  end
57
57
 
58
58
  # Classic Rails::Secrets.parse implementation
59
- # Parses plain YAML secrets files and merges shared + environment-specific sections
59
+ # Parses plain YAML secrets files for specific environment
60
60
  def parse(paths, env:)
61
61
  paths.each_with_object({}) do |path, all_secrets|
62
62
  # Handle string paths by converting to Pathname
@@ -66,22 +66,22 @@ module Secvault
66
66
  # Read and process the plain YAML file content
67
67
  source = path.read
68
68
 
69
- # Process ERB and parse YAML
69
+ # Process ERB and parse YAML - using same method as Rails
70
70
  erb_result = ERB.new(source).result
71
- secrets = YAML.safe_load(erb_result, aliases: true, permitted_classes: [])
71
+ secrets = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(erb_result) : YAML.load(erb_result)
72
72
 
73
73
  secrets ||= {}
74
74
 
75
- # Merge shared secrets first, then environment-specific (using deep merge)
76
- all_secrets.deep_merge!(secrets["shared"].deep_symbolize_keys) if secrets["shared"]
75
+ # Only load environment-specific section (YAML anchors handle sharing)
77
76
  all_secrets.deep_merge!(secrets[env].deep_symbolize_keys) if secrets[env]
78
77
  end
79
78
  end
80
79
 
81
80
  def read_secrets(secrets_path, env)
82
81
  if secrets_path.exist?
83
- # Handle plain YAML secrets.yml only
84
- all_secrets = YAML.safe_load(ERB.new(secrets_path.read).result, aliases: true)
82
+ # Handle plain YAML secrets.yml only - using same method as Rails
83
+ erb_result = ERB.new(secrets_path.read).result
84
+ all_secrets = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(erb_result) : YAML.load(erb_result)
85
85
 
86
86
  env_secrets = all_secrets[env.to_s]
87
87
  return env_secrets.deep_symbolize_keys if env_secrets
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Secvault
4
- VERSION = "3.0.0"
4
+ VERSION = "3.2.0"
5
5
  end
data/lib/secvault.rb CHANGED
@@ -65,6 +65,67 @@ module Secvault
65
65
  defined?(Rails) && Rails::Secrets == Secvault::RailsSecrets
66
66
  end
67
67
 
68
+ # Early setup method for use in config/application.rb before other configuration
69
+ # This ensures Rails.application has secrets available during application class definition
70
+ def setup_early_application_secrets!(files: nil, application_class: nil)
71
+ return false unless defined?(Rails)
72
+
73
+ # Default files if not provided
74
+ files ||= begin
75
+ default_files = ["config/secrets.yml"]
76
+
77
+ # Add neeto-commons-backend file if available
78
+ if defined?(NeetoCommonsBackend) && NeetoCommonsBackend.respond_to?(:shared_secrets_file)
79
+ default_files.unshift(NeetoCommonsBackend.shared_secrets_file)
80
+ end
81
+
82
+ default_files
83
+ end
84
+
85
+ # Create a temporary Rails.application if it doesn't exist
86
+ unless Rails.respond_to?(:application) && Rails.application
87
+ # Create a temporary application-like object with secrets
88
+ temp_app = Object.new
89
+
90
+ # Add lazy secrets loading
91
+ temp_app.define_singleton_method(:secrets) do
92
+ @secrets ||= begin
93
+ # Convert to full paths and filter existing files
94
+ file_paths = files.map do |file|
95
+ file.is_a?(Pathname) ? file : Rails.root.join(file)
96
+ end.select(&:exist?)
97
+
98
+ if file_paths.any?
99
+ # Load secrets using Secvault
100
+ all_secrets = Secvault::Secrets.parse(file_paths, env: Rails.env)
101
+ current_secrets = ActiveSupport::OrderedOptions.new
102
+ current_secrets.merge!(all_secrets)
103
+ current_secrets
104
+ else
105
+ # Return empty secrets if no files found but include encryption structure
106
+ secrets = ActiveSupport::OrderedOptions.new
107
+ secrets.encryption = ActiveSupport::OrderedOptions.new
108
+ secrets.encryption.primary_key = nil
109
+ secrets.encryption.deterministic_key = nil
110
+ secrets.encryption.key_derivation_salt = nil
111
+ secrets
112
+ end
113
+ end
114
+ end
115
+
116
+ # Set up Rails.application to point to this temporary object
117
+ Rails.define_singleton_method(:application) { temp_app }
118
+ end
119
+
120
+ true
121
+ rescue => e
122
+ warn "[Secvault] Early application secrets setup failed: #{e.message}"
123
+ false
124
+ end
125
+
126
+ # Alias for backward compatibility
127
+ alias_method :setup_early_secrets!, :setup_early_application_secrets!
128
+
68
129
  def install!
69
130
  return if defined?(Rails::Railtie).nil?
70
131
 
@@ -88,35 +149,34 @@ module Secvault
88
149
  #
89
150
  # Options:
90
151
  # - files: Array of file paths (String or Pathname). Defaults to ['config/secrets.yml']
91
- # - integrate_with_rails: Integrate with Rails.application.secrets (default: true)
152
+ # - integrate_with_rails: Integrate with Rails.application.secrets (default: false)
92
153
  # - set_secret_key_base: Set Rails.application.config.secret_key_base from secrets (default: true)
93
154
  # - hot_reload: Add reload_secrets! methods for development (default: true in development)
94
155
  # - 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
-
156
+ def start!(files: [], integrate_with_rails: false, set_secret_key_base: true,
157
+ hot_reload: ((defined?(Rails) && Rails.env.respond_to?(:development?)) ? Rails.env.development? : false),
158
+ logger: ((defined?(Rails) && Rails.env.respond_to?(:production?)) ? !Rails.env.production? : true))
99
159
  # Default to config/secrets.yml if no files specified
100
160
  files_to_load = files.empty? ? ["config/secrets.yml"] : Array(files)
101
-
161
+
102
162
  # Convert to Pathname objects and resolve relative to Rails.root
103
163
  file_paths = files_to_load.map do |file|
104
164
  file.is_a?(Pathname) ? file : Rails.root.join(file)
105
165
  end
106
-
166
+
107
167
  # Load secrets into Secvault.secrets
108
168
  load_secrets!(file_paths, logger: logger)
109
-
169
+
110
170
  # Integrate with Rails if requested
111
171
  if integrate_with_rails
112
172
  setup_rails_integration!(file_paths, set_secret_key_base: set_secret_key_base, logger: logger)
113
173
  end
114
-
174
+
115
175
  # Add hot reload functionality if requested
116
176
  if hot_reload
117
177
  add_hot_reload!(file_paths)
118
178
  end
119
-
179
+
120
180
  true
121
181
  rescue => e
122
182
  Rails.logger&.error "[Secvault] Failed to start: #{e.message}" if defined?(Rails) && logger
@@ -126,24 +186,24 @@ module Secvault
126
186
  private
127
187
 
128
188
  # 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))
189
+ def load_secrets!(file_paths, logger: ((defined?(Rails) && Rails.env.respond_to?(:production?)) ? !Rails.env.production? : true))
130
190
  existing_files = file_paths.select(&:exist?)
131
-
191
+
132
192
  if existing_files.any?
133
193
  # Load and merge all secrets files
134
194
  merged_secrets = Secvault::Secrets.parse(existing_files, env: Rails.env)
135
-
195
+
136
196
  # Store in internal storage with ActiveSupport::OrderedOptions for compatibility
137
197
  @@loaded_secrets = ActiveSupport::OrderedOptions.new
138
198
  @@loaded_secrets.merge!(merged_secrets)
139
-
199
+
140
200
  # Log successful loading
141
201
  if logger
142
202
  file_names = existing_files.map(&:basename)
143
203
  Rails.logger&.info "[Secvault] Loaded #{existing_files.size} files: #{file_names.join(", ")}"
144
204
  Rails.logger&.info "[Secvault] Parsed #{merged_secrets.keys.size} secret keys for #{Rails.env}"
145
205
  end
146
-
206
+
147
207
  true
148
208
  else
149
209
  Rails.logger&.warn "[Secvault] No secrets files found" if logger
@@ -151,13 +211,13 @@ module Secvault
151
211
  false
152
212
  end
153
213
  end
154
-
214
+
155
215
  # 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))
216
+ def setup_rails_integration!(file_paths, set_secret_key_base: true, logger: ((defined?(Rails) && Rails.env.respond_to?(:production?)) ? !Rails.env.production? : true))
157
217
  # Override native Rails::Secrets with Secvault implementation
158
218
  Rails.send(:remove_const, :Secrets) if defined?(Rails::Secrets)
159
219
  Rails.const_set(:Secrets, Secvault::RailsSecrets)
160
-
220
+
161
221
  # Set up Rails.application.secrets replacement in after_initialize
162
222
  Rails.application.config.after_initialize do
163
223
  if @@loaded_secrets && !@@loaded_secrets.empty?
@@ -165,51 +225,99 @@ module Secvault
165
225
  Rails.application.define_singleton_method(:secrets) do
166
226
  @@loaded_secrets
167
227
  end
168
-
228
+
169
229
  # Set secret_key_base in Rails config to avoid accessing it from secrets
170
230
  if set_secret_key_base && @@loaded_secrets.key?(:secret_key_base)
171
231
  Rails.application.config.secret_key_base = @@loaded_secrets[:secret_key_base]
172
232
  Rails.logger&.info "[Secvault] Set Rails.application.config.secret_key_base from secrets" if logger
173
233
  end
174
-
234
+
175
235
  # Log integration success (except in production)
176
236
  if logger
177
237
  Rails.logger&.info "[Secvault] Rails integration complete. #{@@loaded_secrets.keys.size} secret keys available."
178
238
  end
179
- else
180
- Rails.logger&.warn "[Secvault] No secrets loaded for Rails integration" if logger
239
+ elsif logger
240
+ Rails.logger&.warn "[Secvault] No secrets loaded for Rails integration"
181
241
  end
182
242
  end
183
243
  end
184
-
244
+
185
245
  # Add hot reload functionality for development
186
246
  def add_hot_reload!(file_paths)
187
247
  # Define reload method on Rails.application
188
248
  Rails.application.define_singleton_method(:reload_secrets!) do
189
249
  # Reload secrets
190
250
  Secvault.send(:load_secrets!, file_paths, logger: true)
191
-
251
+
192
252
  # Re-apply Rails integration if needed
193
253
  if Secvault.rails_integrated? && @@loaded_secrets
194
254
  Rails.application.define_singleton_method(:secrets) do
195
255
  @@loaded_secrets
196
256
  end
197
257
  end
198
-
258
+
199
259
  puts "🔄 Hot reloaded secrets from #{file_paths.size} files"
200
260
  true
201
261
  end
202
-
262
+
203
263
  # Also make it available as a top-level method
204
264
  Object.define_method(:reload_secrets!) do
205
265
  Rails.application.reload_secrets!
206
266
  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?)
209
- end
210
-
211
- public
212
267
 
268
+ Rails.logger&.info "[Secvault] Hot reload enabled. Use reload_secrets! to refresh secrets." unless defined?(Rails) && Rails.env.respond_to?(:production?) && Rails.env.production?
269
+ end
213
270
  end
214
271
 
215
- Secvault.install! if defined?(Rails)
272
+ # Auto-install and setup when Rails is available
273
+ if defined?(Rails)
274
+ Secvault.install!
275
+
276
+ # Immediate setup for early access during application loading
277
+ begin
278
+ # Try to detect and load secrets immediately if Rails.root is available
279
+ if Rails.respond_to?(:root) && Rails.root
280
+ # Look for default secrets or configuration
281
+ default_secrets_file = Rails.root.join("config/secrets.yml")
282
+ commons_secrets_file = nil
283
+
284
+ # Check for neeto-commons-backend integration
285
+ if defined?(NeetoCommonsBackend) && NeetoCommonsBackend.respond_to?(:shared_secrets_file)
286
+ commons_secrets_file = NeetoCommonsBackend.shared_secrets_file
287
+ end
288
+
289
+ files_to_load = [commons_secrets_file, default_secrets_file].compact.select(&:exist?)
290
+
291
+ if files_to_load.any? && Rails.respond_to?(:env)
292
+ # Load secrets immediately
293
+ all_secrets = Secvault::Secrets.parse(files_to_load, env: Rails.env)
294
+
295
+ # Set up Rails.application.secrets if Rails.application exists
296
+ if Rails.respond_to?(:application) && Rails.application
297
+ Rails.application.define_singleton_method(:secrets) do
298
+ @secrets ||= begin
299
+ current_secrets = ActiveSupport::OrderedOptions.new
300
+ current_secrets.merge!(all_secrets)
301
+ current_secrets
302
+ end
303
+ end
304
+ else
305
+ # Create a minimal Rails.application for early access
306
+ temp_app = Object.new
307
+ temp_app.define_singleton_method(:secrets) do
308
+ @secrets ||= begin
309
+ current_secrets = ActiveSupport::OrderedOptions.new
310
+ current_secrets.merge!(all_secrets)
311
+ current_secrets
312
+ end
313
+ end
314
+
315
+ Rails.define_singleton_method(:application) { temp_app } unless Rails.respond_to?(:application)
316
+ end
317
+ end
318
+ end
319
+ rescue => e
320
+ # Silent fail - normal initialization will handle it
321
+ warn "[Secvault] Early auto-load failed: #{e.message}" unless Rails.env&.production?
322
+ end
323
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: secvault
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Unnikrishnan KP
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-09-23 00:00:00.000000000 Z
11
+ date: 2025-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec_junit_formatter
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
41
55
  description: Secvault restores the classic Rails secrets.yml functionality that was
42
56
  removed in Rails 7.2, using simple, plain YAML files for environment-specific secrets
43
57
  management. Compatible with Rails 7.1+, 7.2+ and 8.0+.
@@ -52,6 +66,7 @@ files:
52
66
  - LICENSE.txt
53
67
  - README.md
54
68
  - Rakefile
69
+ - SECURITY.md
55
70
  - lib/secvault.rb
56
71
  - lib/secvault/rails_secrets.rb
57
72
  - lib/secvault/railtie.rb
@@ -73,7 +88,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
73
88
  requirements:
74
89
  - - ">="
75
90
  - !ruby/object:Gem::Version
76
- version: 3.0.0
91
+ version: 3.2.0
77
92
  required_rubygems_version: !ruby/object:Gem::Requirement
78
93
  requirements:
79
94
  - - ">="