Class: Secvault::Secrets
- Inherits:
-
Object
- Object
- Secvault::Secrets
- Defined in:
- lib/secvault/secrets.rb
Constant Summary collapse
- PERMITTED_YAML_CLASSES =
Define permitted classes for YAML.safe_load - commonly used in Rails secrets
[ Symbol, Date, Time, DateTime, BigDecimal, Range, Regexp ].tap do |classes| # Add ActiveSupport classes if available begin require "active_support/time_with_zone" classes << ActiveSupport::TimeWithZone rescue LoadError # ActiveSupport not available, skip end begin require "active_support/duration" classes << ActiveSupport::Duration rescue LoadError # ActiveSupport not available, skip end end.freeze
Class Method Summary collapse
-
.parse(paths, env:) ⇒ Object
Classic Rails::Secrets.parse implementation Parses plain YAML secrets files for specific environment.
- .read_secrets(secrets_path, env) ⇒ Object
- .setup(app) ⇒ Object
- .setup_secrets_immediately(_app, secrets_path, env) ⇒ Object
Class Method Details
.parse(paths, env:) ⇒ Object
Classic Rails::Secrets.parse implementation Parses plain YAML secrets files for specific environment
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/secvault/secrets.rb', line 88 def parse(paths, env:) paths.each_with_object({}) do |path, all_secrets| # Handle string paths by converting to Pathname path = Pathname.new(path) unless path.respond_to?(:exist?) next unless path.exist? # Read and process the plain YAML file content source = path.read # Process ERB and parse YAML - using same method as Rails erb_result = ERB.new(source).result secrets = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(erb_result) : YAML.safe_load(erb_result, aliases: true, permitted_classes: PERMITTED_YAML_CLASSES) secrets ||= {} # Only load environment-specific section (YAML anchors handle sharing) all_secrets.deep_merge!(secrets[env].deep_symbolize_keys) if secrets[env] end end |
.read_secrets(secrets_path, env) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/secvault/secrets.rb', line 108 def read_secrets(secrets_path, env) if secrets_path.exist? # Handle plain YAML secrets.yml only - using same method as Rails erb_result = ERB.new(secrets_path.read).result all_secrets = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(erb_result) : YAML.safe_load(erb_result, aliases: true, permitted_classes: PERMITTED_YAML_CLASSES) env_secrets = all_secrets[env.to_s] return env_secrets.deep_symbolize_keys if env_secrets end {} end |
.setup(app) ⇒ Object
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/secvault/secrets.rb', line 41 def setup(app) # Auto-setup for all Rails versions with consistent behavior secrets_path = app.root.join("config/secrets.yml") return unless secrets_path.exist? # Use a reliable approach that works in all environments app.config.before_configuration do current_env = ENV["RAILS_ENV"] || Rails.env || "development" setup_secrets_immediately(app, secrets_path, current_env) end # Also try during to_prepare as a fallback app.config.to_prepare do current_env = Rails.env unless Rails.application.respond_to?(:secrets) && !Rails.application.secrets.empty? setup_secrets_immediately(app, secrets_path, current_env) end end end |
.setup_secrets_immediately(_app, secrets_path, env) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/secvault/secrets.rb', line 62 def setup_secrets_immediately(_app, secrets_path, env) # Set up secrets if they exist secrets = read_secrets(secrets_path, env) return unless secrets # Rails 8.0+ compatibility: Add secrets accessor that initializes on first access unless Rails.application.respond_to?(:secrets) Rails.application.define_singleton_method(:secrets) do @secrets ||= begin current_secrets = ActiveSupport::OrderedOptions.new # Re-read secrets to ensure we have the right environment env_secrets = Secvault::Secrets.read_secrets(secrets_path, Rails.env) current_secrets.merge!(env_secrets) if env_secrets current_secrets end end end # If secrets accessor already exists, merge the secrets return unless Rails.application.respond_to?(:secrets) && Rails.application.secrets.respond_to?(:merge!) Rails.application.secrets.merge!(secrets) end |