secvault 2.2.0 → 2.4.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/CHANGELOG.md +22 -0
- data/README.md +186 -28
- data/lib/secvault/version.rb +1 -1
- data/lib/secvault.rb +13 -5
- 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: 18d7c81d380aa63a8092f4bd91a438ee3e02282695b6fcbe6841ffbb81a30a9b
|
|
4
|
+
data.tar.gz: 2dbe018b171e0840e9a6047027fcf8e60ef73ec60867e4f6f4f97240df74f126
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c864336bbb71f184bf09e9f3bc0c191cbd7f7d750ee5a9c541cc3711b0ddc0cc608103e574dffd940b64dc814b4d5b5f433940ef0adf6235e3d17caf9f5784ce
|
|
7
|
+
data.tar.gz: 6c62bb91d5a9a0ca1ac0a984f94c92d11c9815d8832e371b7b362d2d6142e1a5f6ea5b058ce8d7762708c271c4cfe848b753d8ea2c6c1dbf47ace950c6df16fd
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [2.3.0] - 2025-09-22
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Better method naming**: Renamed `setup_rails_71_integration!` to `setup_backward_compatibility_with_older_rails!`
|
|
8
|
+
- **More generic approach**: New method name works for any older Rails version, not just 7.1
|
|
9
|
+
- **Updated documentation**: README now uses "Older Rails Integration" instead of "Rails 7.1 Integration"
|
|
10
|
+
- **Clearer version support**: Documentation now shows "Rails 7.1 and older" for better clarity
|
|
11
|
+
|
|
12
|
+
### Backward Compatibility
|
|
13
|
+
|
|
14
|
+
- ✅ **Old method name still works**: `setup_rails_71_integration!` is aliased to the new method
|
|
15
|
+
- ✅ **No breaking changes**: All existing code continues to work
|
|
16
|
+
- ✅ **Updated test apps**: Rails 7.1 test app uses the new, cleaner method name
|
|
17
|
+
|
|
18
|
+
### Benefits
|
|
19
|
+
|
|
20
|
+
- **Future-proof naming**: Works for Rails 7.1, 7.0, 6.x, or any version with native secrets
|
|
21
|
+
- **Clearer intent**: Method name clearly indicates it's for backward compatibility
|
|
22
|
+
- **Better documentation**: More generic approach in README and code comments
|
|
23
|
+
- **Maintained compatibility**: Existing users don't need to change anything
|
|
24
|
+
|
|
3
25
|
## [2.2.0] - 2025-09-22
|
|
4
26
|
|
|
5
27
|
### Added
|
data/README.md
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
# Secvault
|
|
2
2
|
|
|
3
|
-
Restores the classic Rails `secrets.yml` functionality that was removed in Rails 7.2. Uses simple, plain YAML files for environment-specific secrets management.
|
|
3
|
+
Restores the classic Rails `secrets.yml` functionality that was removed in Rails 7.2. Uses simple, plain YAML files for environment-specific secrets management with powerful features like YAML defaults, ERB interpolation, and multi-file configurations.
|
|
4
4
|
|
|
5
5
|
**Rails Version Support:**
|
|
6
|
-
- **Rails 7.1**: Manual setup (see Rails
|
|
6
|
+
- **Rails 7.1 and older**: Manual setup (see Older Rails Integration below)
|
|
7
7
|
- **Rails 7.2+**: Automatic setup
|
|
8
8
|
- **Rails 8.0+**: Full compatibility
|
|
9
9
|
|
|
10
|
+
## ✨ Key Features
|
|
11
|
+
|
|
12
|
+
- 🔗 **YAML Anchor/Alias Support**: Use `default: &default` for shared configuration
|
|
13
|
+
- 🌍 **ERB Interpolation**: Environment variables with type conversion (`ENV['VAR'].to_i`, boolean logic)
|
|
14
|
+
- 📁 **Multi-File Loading**: Merge multiple YAML files (e.g., base + OAuth + local overrides)
|
|
15
|
+
- 🔄 **Environment Switching**: Load different environments dynamically
|
|
16
|
+
- 🛠️ **Development Tools**: Hot-reload secrets without server restart
|
|
17
|
+
- 🔍 **Utility Methods**: `Secvault.active?` to check integration status
|
|
18
|
+
- 🏗️ **Flexible Organization**: Feature-based, environment-based, or namespace-based file structures
|
|
19
|
+
|
|
10
20
|
## Installation
|
|
11
21
|
|
|
12
22
|
```ruby
|
|
@@ -34,32 +44,91 @@ Rails.application.secrets.api_key
|
|
|
34
44
|
Rails.application.secrets.database_password
|
|
35
45
|
```
|
|
36
46
|
|
|
37
|
-
**Example secrets.yml:**
|
|
47
|
+
**Example secrets.yml with YAML defaults and ERB:**
|
|
38
48
|
```yaml
|
|
49
|
+
# YAML defaults - inherited by all environments
|
|
50
|
+
default: &default
|
|
51
|
+
app_name: "My Application"
|
|
52
|
+
database:
|
|
53
|
+
adapter: "postgresql"
|
|
54
|
+
pool: 5
|
|
55
|
+
timeout: 5000
|
|
56
|
+
api:
|
|
57
|
+
timeout: 30
|
|
58
|
+
retries: 3
|
|
59
|
+
|
|
39
60
|
development:
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
<<: *default # Inherit defaults
|
|
62
|
+
api_key: "dev_api_key_123"
|
|
63
|
+
database:
|
|
64
|
+
host: "localhost"
|
|
65
|
+
name: "myapp_development"
|
|
66
|
+
api:
|
|
67
|
+
base_url: "http://localhost:3000" # Override default
|
|
42
68
|
|
|
43
69
|
production:
|
|
70
|
+
<<: *default # Inherit defaults
|
|
44
71
|
api_key: <%= ENV['API_KEY'] %>
|
|
45
|
-
|
|
72
|
+
database:
|
|
73
|
+
host: <%= ENV['DATABASE_HOST'] %>
|
|
74
|
+
name: <%= ENV['DATABASE_NAME'] %>
|
|
75
|
+
pool: <%= ENV.fetch('DATABASE_POOL', '10').to_i %> # Type conversion
|
|
76
|
+
api:
|
|
77
|
+
base_url: <%= ENV['API_BASE_URL'] %>
|
|
78
|
+
|
|
79
|
+
# Boolean conversion
|
|
80
|
+
features:
|
|
81
|
+
new_ui: <%= ENV.fetch('FEATURE_NEW_UI', 'true') == 'true' %>
|
|
82
|
+
|
|
83
|
+
# Array conversion
|
|
84
|
+
oauth_scopes: <%= ENV.fetch('OAUTH_SCOPES', 'email,profile').split(',') %>
|
|
46
85
|
```
|
|
47
86
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
87
|
+
## Multi-File Configuration
|
|
88
|
+
|
|
89
|
+
Organize secrets across multiple files for better maintainability:
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
# config/initializers/secvault.rb
|
|
93
|
+
require "secvault"
|
|
94
|
+
Secvault.setup_backward_compatibility_with_older_rails!
|
|
95
|
+
|
|
96
|
+
Rails.application.config.after_initialize do
|
|
97
|
+
# Load multiple files in order (later files override earlier ones)
|
|
98
|
+
secrets_files = [
|
|
99
|
+
Rails.root.join('config', 'secrets.yml'), # Base secrets
|
|
100
|
+
Rails.root.join('config', 'secrets.oauth.yml'), # OAuth & APIs
|
|
101
|
+
Rails.root.join('config', 'secrets.local.yml') # Local overrides
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
existing_files = secrets_files.select(&:exist?)
|
|
105
|
+
|
|
106
|
+
if existing_files.any?
|
|
107
|
+
merged_secrets = Rails::Secrets.parse(existing_files, env: Rails.env)
|
|
108
|
+
secrets_object = ActiveSupport::OrderedOptions.new
|
|
109
|
+
secrets_object.merge!(merged_secrets)
|
|
110
|
+
Rails.application.define_singleton_method(:secrets) { secrets_object }
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**File organization example:**
|
|
116
|
+
```
|
|
117
|
+
config/
|
|
118
|
+
├── secrets.yml # Base application secrets
|
|
119
|
+
├── secrets.oauth.yml # OAuth providers & external APIs
|
|
120
|
+
├── secrets.local.yml # Local development overrides (gitignored)
|
|
52
121
|
```
|
|
53
122
|
|
|
54
123
|
## Advanced Usage
|
|
55
124
|
|
|
56
|
-
**
|
|
125
|
+
**Manual multi-file parsing:**
|
|
57
126
|
```ruby
|
|
58
127
|
# Parse multiple files - later files override earlier ones
|
|
59
128
|
secrets = Rails::Secrets.parse([
|
|
60
129
|
'config/secrets.yml',
|
|
61
|
-
'config/secrets.
|
|
62
|
-
'config/secrets.
|
|
130
|
+
'config/secrets.oauth.yml',
|
|
131
|
+
'config/secrets.local.yml'
|
|
63
132
|
], env: Rails.env)
|
|
64
133
|
```
|
|
65
134
|
|
|
@@ -72,25 +141,58 @@ production_secrets = Rails::Secrets.load(env: 'production')
|
|
|
72
141
|
dev_secrets = Rails::Secrets.load(env: 'development')
|
|
73
142
|
```
|
|
74
143
|
|
|
75
|
-
**
|
|
144
|
+
**Environment-specific loading:**
|
|
76
145
|
```ruby
|
|
77
|
-
#
|
|
78
|
-
|
|
146
|
+
# Load production secrets in any environment
|
|
147
|
+
production_secrets = Rails::Secrets.load(env: 'production')
|
|
79
148
|
|
|
80
|
-
#
|
|
81
|
-
|
|
82
|
-
Rails.root.join('config', 'secrets.yml'),
|
|
83
|
-
Rails.root.join('config', 'deploy', 'secrets.yml')
|
|
84
|
-
], env: Rails.env)
|
|
149
|
+
# Load development secrets
|
|
150
|
+
dev_secrets = Rails::Secrets.load(env: 'development')
|
|
85
151
|
```
|
|
86
152
|
|
|
87
|
-
##
|
|
153
|
+
## ERB Features & Type Conversion
|
|
88
154
|
|
|
89
|
-
|
|
155
|
+
Secvault supports powerful ERB templating with automatic type conversion:
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
production:
|
|
159
|
+
# String interpolation
|
|
160
|
+
api_key: <%= ENV['API_KEY'] %>
|
|
161
|
+
|
|
162
|
+
# Integer conversion
|
|
163
|
+
database_pool: <%= ENV.fetch('DB_POOL', '10').to_i %>
|
|
164
|
+
|
|
165
|
+
# Boolean conversion
|
|
166
|
+
debug_enabled: <%= ENV.fetch('DEBUG', 'false') == 'true' %>
|
|
167
|
+
|
|
168
|
+
# Array conversion
|
|
169
|
+
allowed_hosts: <%= ENV.fetch('HOSTS', 'localhost,127.0.0.1').split(',') %>
|
|
170
|
+
|
|
171
|
+
# Fallback values
|
|
172
|
+
timeout: <%= ENV.fetch('TIMEOUT', '30').to_i %>
|
|
173
|
+
adapter: <%= ENV.fetch('DB_ADAPTER', 'postgresql') %>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Development Tools
|
|
177
|
+
|
|
178
|
+
**Hot-reload secrets (development only):**
|
|
179
|
+
```ruby
|
|
180
|
+
# In Rails console or code
|
|
181
|
+
reload_secrets! # Reloads all secrets files without server restart
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Check integration status:**
|
|
185
|
+
```ruby
|
|
186
|
+
Secvault.active? # Returns true if Secvault is managing secrets
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Older Rails Integration
|
|
190
|
+
|
|
191
|
+
For Rails versions with existing secrets functionality (like Rails 7.1), use Secvault to test before upgrading:
|
|
90
192
|
|
|
91
193
|
```ruby
|
|
92
194
|
# config/initializers/secvault.rb
|
|
93
|
-
Secvault.
|
|
195
|
+
Secvault.setup_backward_compatibility_with_older_rails!
|
|
94
196
|
```
|
|
95
197
|
|
|
96
198
|
This replaces Rails.application.secrets with Secvault functionality. Your existing Rails 7.1 code works unchanged:
|
|
@@ -102,12 +204,68 @@ Rails::Secrets.load # ✅ Load default config/secrets.yml
|
|
|
102
204
|
Rails::Secrets.parse(['custom.yml'], env: Rails.env) # ✅ Parse custom files
|
|
103
205
|
```
|
|
104
206
|
|
|
207
|
+
**Check if Secvault is active:**
|
|
208
|
+
```ruby
|
|
209
|
+
if Secvault.active?
|
|
210
|
+
puts "Using Secvault for secrets management"
|
|
211
|
+
else
|
|
212
|
+
puts "Using default Rails secrets functionality"
|
|
213
|
+
end
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Usage Examples
|
|
217
|
+
|
|
218
|
+
**Basic usage:**
|
|
219
|
+
```ruby
|
|
220
|
+
# Access secrets
|
|
221
|
+
Rails.application.secrets.api_key
|
|
222
|
+
Rails.application.secrets.database.host
|
|
223
|
+
Rails.application.secrets.oauth.google.client_id
|
|
224
|
+
|
|
225
|
+
# With YAML defaults, you get deep merging:
|
|
226
|
+
Rails.application.secrets.database.adapter # "postgresql" (from default)
|
|
227
|
+
Rails.application.secrets.database.host # "localhost" (from environment)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Multi-file merging:**
|
|
231
|
+
```ruby
|
|
232
|
+
# Files loaded in order: base → oauth → local
|
|
233
|
+
# Later files override earlier ones for the same keys
|
|
234
|
+
# Hash values are deep merged, scalars are replaced
|
|
235
|
+
|
|
236
|
+
Rails.application.secrets.api_key # Could be from base or local file
|
|
237
|
+
Rails.application.secrets.oauth.google # From oauth file
|
|
238
|
+
Rails.application.secrets.features.debug # From local file override
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Security Best Practices
|
|
242
|
+
|
|
243
|
+
### ⚠️ Production Security
|
|
244
|
+
- **Never commit production secrets** to version control
|
|
245
|
+
- **Use environment variables** in production with ERB: `<%= ENV['SECRET'] %>`
|
|
246
|
+
- **Use ENV.fetch()** with fallbacks: `<%= ENV.fetch('SECRET', 'default') %>`
|
|
105
247
|
|
|
106
|
-
|
|
248
|
+
### 📝 File Management
|
|
249
|
+
- **Add sensitive files** to `.gitignore`:
|
|
250
|
+
```gitignore
|
|
251
|
+
config/secrets.yml # If contains sensitive data
|
|
252
|
+
config/secrets.local.yml # Local development overrides
|
|
253
|
+
config/secrets.production.yml # If used
|
|
254
|
+
```
|
|
107
255
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
✅
|
|
256
|
+
### 🔑 Recommended Structure
|
|
257
|
+
```yaml
|
|
258
|
+
# ✅ GOOD: Base file with safe defaults
|
|
259
|
+
development:
|
|
260
|
+
api_key: "safe_dev_key_for_team"
|
|
261
|
+
|
|
262
|
+
production:
|
|
263
|
+
api_key: <%= ENV['API_KEY'] %> # ✅ From environment
|
|
264
|
+
|
|
265
|
+
# ❌ BAD: Secrets hardcoded in base file
|
|
266
|
+
production:
|
|
267
|
+
api_key: "super_secret_production_key" # ❌ Never do this
|
|
268
|
+
```
|
|
111
269
|
|
|
112
270
|
## License
|
|
113
271
|
|
data/lib/secvault/version.rb
CHANGED
data/lib/secvault.rb
CHANGED
|
@@ -58,6 +58,11 @@ module Secvault
|
|
|
58
58
|
|
|
59
59
|
extend self
|
|
60
60
|
|
|
61
|
+
# Check if Secvault is currently active in the Rails application
|
|
62
|
+
def active?
|
|
63
|
+
defined?(Rails) && Rails::Secrets == Secvault::RailsSecrets
|
|
64
|
+
end
|
|
65
|
+
|
|
61
66
|
def install!
|
|
62
67
|
return if defined?(Rails::Railtie).nil?
|
|
63
68
|
|
|
@@ -65,18 +70,18 @@ module Secvault
|
|
|
65
70
|
require "secvault/rails_secrets"
|
|
66
71
|
end
|
|
67
72
|
|
|
68
|
-
# Helper method to set up Secvault for Rails
|
|
69
|
-
# This provides an easy way to integrate Secvault into Rails
|
|
70
|
-
# that still have native Rails::Secrets functionality.
|
|
73
|
+
# Helper method to set up Secvault for older Rails versions
|
|
74
|
+
# This provides an easy way to integrate Secvault into older Rails apps
|
|
75
|
+
# that still have native Rails::Secrets functionality (like Rails 7.1).
|
|
71
76
|
#
|
|
72
77
|
# Usage in an initializer:
|
|
73
|
-
# Secvault.
|
|
78
|
+
# Secvault.setup_backward_compatibility_with_older_rails!
|
|
74
79
|
#
|
|
75
80
|
# This will:
|
|
76
81
|
# 1. Override native Rails::Secrets with Secvault implementation
|
|
77
82
|
# 2. Replace Rails.application.secrets with Secvault-powered functionality
|
|
78
83
|
# 3. Load secrets from config/secrets.yml automatically
|
|
79
|
-
def
|
|
84
|
+
def setup_backward_compatibility_with_older_rails!
|
|
80
85
|
# Override native Rails::Secrets
|
|
81
86
|
if defined?(Rails::Secrets)
|
|
82
87
|
Rails.send(:remove_const, :Secrets)
|
|
@@ -109,6 +114,9 @@ module Secvault
|
|
|
109
114
|
end
|
|
110
115
|
end
|
|
111
116
|
end
|
|
117
|
+
|
|
118
|
+
# Backward compatibility alias
|
|
119
|
+
alias_method :setup_rails_71_integration!, :setup_backward_compatibility_with_older_rails!
|
|
112
120
|
end
|
|
113
121
|
|
|
114
122
|
Secvault.install! if defined?(Rails)
|