secvault 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/lib/secvault/generators/secrets_generator.rb +25 -19
 - data/lib/secvault/rails_secrets.rb +53 -0
 - data/lib/secvault/railtie.rb +24 -1
 - data/lib/secvault/secrets.rb +64 -12
 - data/lib/secvault/tasks.rake +71 -38
 - data/lib/secvault/version.rb +1 -1
 - data/lib/secvault.rb +2 -1
 - metadata +4 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 05e6d8b6e701bdc5bd47c0ab65ea6af571f6476a056fea095bb9ab82085071fe
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 535caed7383f6c29c605ec8a68df0a0e0210a2d713ba898d03509a9ae68bca95
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: bb4b1cf849d5a319f2b2911c9764cec1383016a409dfcd05258d36e5d1c9d5426e107356962d1a7b2c07c896e7586ae034ec39a70966621894de33c28cd7aa25
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: d71b470eb2682412103c10224d27054ab4c768a8608065b8cd0d86cf3cda2a5c28a73f51097cdb4ff08e6e088e38c5f159e7c6df25893b114fd10f4322319bc3
         
     | 
| 
         @@ -9,9 +9,10 @@ module Secvault 
     | 
|
| 
       9 
9 
     | 
    
         
             
                class SecretsGenerator < Rails::Generators::Base
         
     | 
| 
       10 
10 
     | 
    
         
             
                  source_root File.expand_path("templates", __dir__)
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
                  desc "Creates a secrets.yml file for  
     | 
| 
      
 12 
     | 
    
         
            +
                  desc "Creates a secrets.yml file for secrets management"
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
                  class_option :force, type: :boolean, default: false, desc: "Overwrite existing secrets.yml"
         
     | 
| 
      
 15 
     | 
    
         
            +
                  class_option :encrypted, type: :boolean, default: false, desc: "Create encrypted secrets.yml (default: plain YAML)"
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
17 
     | 
    
         
             
                  def create_secrets_file
         
     | 
| 
       17 
18 
     | 
    
         
             
                    secrets_path = Rails.root.join("config/secrets.yml")
         
     | 
| 
         @@ -22,27 +23,32 @@ module Secvault 
     | 
|
| 
       22 
23 
     | 
    
         
             
                      return
         
     | 
| 
       23 
24 
     | 
    
         
             
                    end
         
     | 
| 
       24 
25 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                     
     | 
| 
       26 
     | 
    
         
            -
                    unless key_path.exist?
         
     | 
| 
       27 
     | 
    
         
            -
                      key = ActiveSupport::EncryptedFile.generate_key
         
     | 
| 
       28 
     | 
    
         
            -
                      File.write(key_path, key)
         
     | 
| 
       29 
     | 
    
         
            -
                      say "Generated encryption key in config/secrets.yml.key", :green
         
     | 
| 
       30 
     | 
    
         
            -
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
                    default_content = generate_default_secrets
         
     | 
| 
       31 
27 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                     
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                       
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
                    if options[:encrypted]
         
     | 
| 
      
 29 
     | 
    
         
            +
                      # Create encrypted secrets file
         
     | 
| 
      
 30 
     | 
    
         
            +
                      unless key_path.exist?
         
     | 
| 
      
 31 
     | 
    
         
            +
                        key = ActiveSupport::EncryptedFile.generate_key
         
     | 
| 
      
 32 
     | 
    
         
            +
                        File.write(key_path, key)
         
     | 
| 
      
 33 
     | 
    
         
            +
                        say "Generated encryption key in config/secrets.yml.key", :green
         
     | 
| 
      
 34 
     | 
    
         
            +
                      end
         
     | 
| 
       39 
35 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
      
 36 
     | 
    
         
            +
                      encrypted_file = ActiveSupport::EncryptedFile.new(
         
     | 
| 
      
 37 
     | 
    
         
            +
                        content_path: secrets_path,
         
     | 
| 
      
 38 
     | 
    
         
            +
                        key_path: key_path,
         
     | 
| 
      
 39 
     | 
    
         
            +
                        env_key: "RAILS_SECRETS_KEY",
         
     | 
| 
      
 40 
     | 
    
         
            +
                        raise_if_missing_key: true
         
     | 
| 
      
 41 
     | 
    
         
            +
                      )
         
     | 
| 
       43 
42 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
      
 43 
     | 
    
         
            +
                      encrypted_file.write(default_content)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      say "Created encrypted secrets.yml file", :green
         
     | 
| 
      
 45 
     | 
    
         
            +
                      say "Add config/secrets.yml.key to your .gitignore file", :yellow
         
     | 
| 
      
 46 
     | 
    
         
            +
                    else
         
     | 
| 
      
 47 
     | 
    
         
            +
                      # Create plain YAML secrets file
         
     | 
| 
      
 48 
     | 
    
         
            +
                      File.write(secrets_path, default_content)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      say "Created plain secrets.yml file", :green
         
     | 
| 
      
 50 
     | 
    
         
            +
                      say "Remember to add config/secrets.yml to your .gitignore if it contains sensitive data", :yellow
         
     | 
| 
      
 51 
     | 
    
         
            +
                    end
         
     | 
| 
       46 
52 
     | 
    
         
             
                  end
         
     | 
| 
       47 
53 
     | 
    
         | 
| 
       48 
54 
     | 
    
         
             
                  def add_to_gitignore
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Secvault
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Rails::Secrets compatibility module
         
     | 
| 
      
 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
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
                # Classic Rails::Secrets.parse method
         
     | 
| 
      
 11 
     | 
    
         
            +
                # 
         
     | 
| 
      
 12 
     | 
    
         
            +
                # Parses secrets files with support for:
         
     | 
| 
      
 13 
     | 
    
         
            +
                # - ERB templating 
         
     | 
| 
      
 14 
     | 
    
         
            +
                # - Shared sections that apply to all environments
         
     | 
| 
      
 15 
     | 
    
         
            +
                # - Environment-specific sections
         
     | 
| 
      
 16 
     | 
    
         
            +
                # - Deep symbolized keys
         
     | 
| 
      
 17 
     | 
    
         
            +
                #
         
     | 
| 
      
 18 
     | 
    
         
            +
                # Example usage:
         
     | 
| 
      
 19 
     | 
    
         
            +
                #   Rails::Secrets.parse([Pathname.new('config/secrets.yml')], env: 'development')
         
     | 
| 
      
 20 
     | 
    
         
            +
                #
         
     | 
| 
      
 21 
     | 
    
         
            +
                # Example secrets.yml structure:
         
     | 
| 
      
 22 
     | 
    
         
            +
                #   shared:
         
     | 
| 
      
 23 
     | 
    
         
            +
                #     common_key: shared_value
         
     | 
| 
      
 24 
     | 
    
         
            +
                #   
         
     | 
| 
      
 25 
     | 
    
         
            +
                #   development:
         
     | 
| 
      
 26 
     | 
    
         
            +
                #     secret_key_base: dev_secret
         
     | 
| 
      
 27 
     | 
    
         
            +
                #     api_key: dev_api_key
         
     | 
| 
      
 28 
     | 
    
         
            +
                #   
         
     | 
| 
      
 29 
     | 
    
         
            +
                #   production:
         
     | 
| 
      
 30 
     | 
    
         
            +
                #     secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
         
     | 
| 
      
 31 
     | 
    
         
            +
                #     api_key: <%= ENV["API_KEY"] %>
         
     | 
| 
      
 32 
     | 
    
         
            +
                #
         
     | 
| 
      
 33 
     | 
    
         
            +
                def parse(paths, env:)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  Secvault::Secrets.parse(paths, env: env.to_s)
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
                
         
     | 
| 
      
 37 
     | 
    
         
            +
                # Convenience method to parse the default secrets file
         
     | 
| 
      
 38 
     | 
    
         
            +
                def parse_default(env: Rails.env)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  secrets_path = Rails.root.join("config/secrets.yml")
         
     | 
| 
      
 40 
     | 
    
         
            +
                  parse([secrets_path], env: env)
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
                
         
     | 
| 
      
 43 
     | 
    
         
            +
                # Read and parse secrets for the current Rails environment
         
     | 
| 
      
 44 
     | 
    
         
            +
                def read(env: Rails.env)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  parse_default(env: env)
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
            end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            # Monkey patch to restore Rails::Secrets interface for backwards compatibility
         
     | 
| 
      
 51 
     | 
    
         
            +
            module Rails
         
     | 
| 
      
 52 
     | 
    
         
            +
              Secrets = Secvault::RailsSecrets
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/secvault/railtie.rb
    CHANGED
    
    | 
         @@ -6,9 +6,32 @@ module Secvault 
     | 
|
| 
       6 
6 
     | 
    
         
             
              class Railtie < Rails::Railtie
         
     | 
| 
       7 
7 
     | 
    
         
             
                railtie_name :secvault
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                initializer "secvault.initialize" do |app|
         
     | 
| 
      
 9 
     | 
    
         
            +
                initializer "secvault.initialize", before: :load_environment_hook do |app|
         
     | 
| 
       10 
10 
     | 
    
         
             
                  Secvault::Secrets.setup(app)
         
     | 
| 
       11 
11 
     | 
    
         
             
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                # Ensure initialization happens early in all environments
         
     | 
| 
      
 14 
     | 
    
         
            +
                config.before_configuration do |app|
         
     | 
| 
      
 15 
     | 
    
         
            +
                  secrets_path = app.root.join("config/secrets.yml")
         
     | 
| 
      
 16 
     | 
    
         
            +
                  key_path = app.root.join("config/secrets.yml.key")
         
     | 
| 
      
 17 
     | 
    
         
            +
                  
         
     | 
| 
      
 18 
     | 
    
         
            +
                  if secrets_path.exist? && !Rails.application.respond_to?(:secrets)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    # Early initialization for test environment compatibility
         
     | 
| 
      
 20 
     | 
    
         
            +
                    current_env = ENV['RAILS_ENV'] || 'development'
         
     | 
| 
      
 21 
     | 
    
         
            +
                    secrets = Secvault::Secrets.read_secrets(secrets_path, key_path, current_env)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    
         
     | 
| 
      
 23 
     | 
    
         
            +
                    if secrets
         
     | 
| 
      
 24 
     | 
    
         
            +
                      Rails.application.define_singleton_method(:secrets) do
         
     | 
| 
      
 25 
     | 
    
         
            +
                        @secrets ||= begin
         
     | 
| 
      
 26 
     | 
    
         
            +
                          current_secrets = ActiveSupport::OrderedOptions.new
         
     | 
| 
      
 27 
     | 
    
         
            +
                          env_secrets = Secvault::Secrets.read_secrets(secrets_path, key_path, Rails.env)
         
     | 
| 
      
 28 
     | 
    
         
            +
                          current_secrets.merge!(env_secrets) if env_secrets
         
     | 
| 
      
 29 
     | 
    
         
            +
                          current_secrets
         
     | 
| 
      
 30 
     | 
    
         
            +
                        end
         
     | 
| 
      
 31 
     | 
    
         
            +
                      end
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
       12 
35 
     | 
    
         | 
| 
       13 
36 
     | 
    
         
             
                generators do
         
     | 
| 
       14 
37 
     | 
    
         
             
                  require "secvault/generators/secrets_generator"
         
     | 
    
        data/lib/secvault/secrets.rb
    CHANGED
    
    | 
         @@ -3,6 +3,7 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require "active_support/encrypted_file"
         
     | 
| 
       4 
4 
     | 
    
         
             
            require "active_support/core_ext/hash/keys"
         
     | 
| 
       5 
5 
     | 
    
         
             
            require "active_support/core_ext/object/blank"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "active_support/ordered_options"
         
     | 
| 
       6 
7 
     | 
    
         
             
            require "pathname"
         
     | 
| 
       7 
8 
     | 
    
         
             
            require "erb"
         
     | 
| 
       8 
9 
     | 
    
         
             
            require "yaml"
         
     | 
| 
         @@ -15,27 +16,78 @@ module Secvault 
     | 
|
| 
       15 
16 
     | 
    
         
             
                    key_path = app.root.join("config/secrets.yml.key")
         
     | 
| 
       16 
17 
     | 
    
         | 
| 
       17 
18 
     | 
    
         
             
                    if secrets_path.exist?
         
     | 
| 
      
 19 
     | 
    
         
            +
                      # Use a more reliable approach that works in all environments
         
     | 
| 
       18 
20 
     | 
    
         
             
                      app.config.before_configuration do
         
     | 
| 
       19 
     | 
    
         
            -
                         
     | 
| 
       20 
     | 
    
         
            -
                         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
      
 21 
     | 
    
         
            +
                        current_env = ENV['RAILS_ENV'] || Rails.env || 'development'
         
     | 
| 
      
 22 
     | 
    
         
            +
                        setup_secrets_immediately(app, secrets_path, key_path, current_env)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      end
         
     | 
| 
      
 24 
     | 
    
         
            +
                      
         
     | 
| 
      
 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?
         
     | 
| 
      
 29 
     | 
    
         
            +
                          setup_secrets_immediately(app, secrets_path, key_path, current_env)
         
     | 
| 
      
 30 
     | 
    
         
            +
                        end
         
     | 
| 
      
 31 
     | 
    
         
            +
                      end
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def setup_secrets_immediately(app, secrets_path, key_path, env)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    # Set up secrets if they exist
         
     | 
| 
      
 37 
     | 
    
         
            +
                    secrets = read_secrets(secrets_path, key_path, env)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    if secrets
         
     | 
| 
      
 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, key_path, Rails.env)
         
     | 
| 
      
 46 
     | 
    
         
            +
                            current_secrets.merge!(env_secrets) if env_secrets
         
     | 
| 
      
 47 
     | 
    
         
            +
                            current_secrets
         
     | 
| 
      
 48 
     | 
    
         
            +
                          end
         
     | 
| 
      
 49 
     | 
    
         
            +
                        end
         
     | 
| 
      
 50 
     | 
    
         
            +
                      end
         
     | 
| 
      
 51 
     | 
    
         
            +
                      
         
     | 
| 
      
 52 
     | 
    
         
            +
                      # If secrets accessor already exists, merge the secrets
         
     | 
| 
      
 53 
     | 
    
         
            +
                      if Rails.application.respond_to?(:secrets) && Rails.application.secrets.respond_to?(:merge!)
         
     | 
| 
      
 54 
     | 
    
         
            +
                        Rails.application.secrets.merge!(secrets)
         
     | 
| 
       22 
55 
     | 
    
         
             
                      end
         
     | 
| 
       23 
56 
     | 
    
         
             
                    end
         
     | 
| 
       24 
57 
     | 
    
         
             
                  end
         
     | 
| 
       25 
58 
     | 
    
         | 
| 
      
 59 
     | 
    
         
            +
                  # Classic Rails::Secrets.parse implementation
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # Parses secrets files and merges shared + environment-specific sections
         
     | 
| 
       26 
61 
     | 
    
         
             
                  def parse(paths, env:)
         
     | 
| 
       27 
     | 
    
         
            -
                     
     | 
| 
       28 
     | 
    
         
            -
                       
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
      
 62 
     | 
    
         
            +
                    paths.each_with_object(Hash.new) do |path, all_secrets|
         
     | 
| 
      
 63 
     | 
    
         
            +
                      next unless path.exist?
         
     | 
| 
      
 64 
     | 
    
         
            +
                      
         
     | 
| 
      
 65 
     | 
    
         
            +
                      # Read and process the file content (handle both encrypted and plain)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      source = if encrypted?(path)
         
     | 
| 
      
 67 
     | 
    
         
            +
                        decrypt(path)
         
     | 
| 
      
 68 
     | 
    
         
            +
                      else
         
     | 
| 
      
 69 
     | 
    
         
            +
                        preprocess(path)
         
     | 
| 
      
 70 
     | 
    
         
            +
                      end
         
     | 
| 
      
 71 
     | 
    
         
            +
                      
         
     | 
| 
      
 72 
     | 
    
         
            +
                      # Process ERB and parse YAML
         
     | 
| 
      
 73 
     | 
    
         
            +
                      erb_result = ERB.new(source).result
         
     | 
| 
      
 74 
     | 
    
         
            +
                      secrets = if YAML.respond_to?(:unsafe_load)
         
     | 
| 
      
 75 
     | 
    
         
            +
                        YAML.unsafe_load(erb_result)
         
     | 
| 
       31 
76 
     | 
    
         
             
                      else
         
     | 
| 
       32 
     | 
    
         
            -
                         
     | 
| 
      
 77 
     | 
    
         
            +
                        YAML.load(erb_result)
         
     | 
| 
       33 
78 
     | 
    
         
             
                      end
         
     | 
| 
      
 79 
     | 
    
         
            +
                      
         
     | 
| 
      
 80 
     | 
    
         
            +
                      secrets ||= {}
         
     | 
| 
      
 81 
     | 
    
         
            +
                      
         
     | 
| 
      
 82 
     | 
    
         
            +
                      # Merge shared secrets first, then environment-specific
         
     | 
| 
      
 83 
     | 
    
         
            +
                      all_secrets.merge!(secrets["shared"].deep_symbolize_keys) if secrets["shared"]
         
     | 
| 
      
 84 
     | 
    
         
            +
                      all_secrets.merge!(secrets[env].deep_symbolize_keys) if secrets[env]
         
     | 
| 
       34 
85 
     | 
    
         
             
                    end
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
                  
         
     | 
| 
      
 88 
     | 
    
         
            +
                  # Helper method to preprocess plain YAML files (for ERB)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  def preprocess(path)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    path.read
         
     | 
| 
       39 
91 
     | 
    
         
             
                  end
         
     | 
| 
       40 
92 
     | 
    
         | 
| 
       41 
93 
     | 
    
         
             
                  def read_secrets(secrets_path, key_path, env)
         
     | 
    
        data/lib/secvault/tasks.rake
    CHANGED
    
    | 
         @@ -4,31 +4,24 @@ require "active_support/encrypted_file" 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require "securerandom"
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            namespace :secvault do
         
     | 
| 
       7 
     | 
    
         
            -
              desc "Setup  
     | 
| 
      
 7 
     | 
    
         
            +
              desc "Setup secrets.yml file (plain YAML by default)"
         
     | 
| 
       8 
8 
     | 
    
         
             
              task setup: :environment do
         
     | 
| 
       9 
9 
     | 
    
         
             
                secrets_path = Rails.root.join("config/secrets.yml")
         
     | 
| 
       10 
10 
     | 
    
         
             
                key_path = Rails.root.join("config/secrets.yml.key")
         
     | 
| 
      
 11 
     | 
    
         
            +
                encrypted = ENV["ENCRYPTED"] == "true"
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
       12 
13 
     | 
    
         
             
                if secrets_path.exist?
         
     | 
| 
       13 
14 
     | 
    
         
             
                  puts "Secrets file already exists at #{secrets_path}"
         
     | 
| 
       14 
15 
     | 
    
         
             
                else
         
     | 
| 
       15 
     | 
    
         
            -
                  # Generate key if it doesn't exist
         
     | 
| 
       16 
     | 
    
         
            -
                  unless key_path.exist?
         
     | 
| 
       17 
     | 
    
         
            -
                    key = ActiveSupport::EncryptedFile.generate_key
         
     | 
| 
       18 
     | 
    
         
            -
                    File.write(key_path, key)
         
     | 
| 
       19 
     | 
    
         
            -
                    puts "Generated encryption key in #{key_path}"
         
     | 
| 
       20 
     | 
    
         
            -
                  end
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                  # Create encrypted file with default content
         
     | 
| 
       23 
     | 
    
         
            -
                  encrypted_file = ActiveSupport::EncryptedFile.new(
         
     | 
| 
       24 
     | 
    
         
            -
                    content_path: secrets_path,
         
     | 
| 
       25 
     | 
    
         
            -
                    key_path: key_path,
         
     | 
| 
       26 
     | 
    
         
            -
                    env_key: "RAILS_SECRETS_KEY",
         
     | 
| 
       27 
     | 
    
         
            -
                    raise_if_missing_key: true
         
     | 
| 
       28 
     | 
    
         
            -
                  )
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
16 
     | 
    
         
             
                  default_content = <<~YAML
         
     | 
| 
       31 
17 
     | 
    
         
             
                    # Be sure to restart your server when you modify this file.
         
     | 
| 
      
 18 
     | 
    
         
            +
                    #
         
     | 
| 
      
 19 
     | 
    
         
            +
                    # Your secret key is used for verifying the integrity of signed cookies.
         
     | 
| 
      
 20 
     | 
    
         
            +
                    # If you change this key, all old signed cookies will become invalid!
         
     | 
| 
      
 21 
     | 
    
         
            +
                    #
         
     | 
| 
      
 22 
     | 
    
         
            +
                    # Make sure the secret is at least 30 characters and all random,
         
     | 
| 
      
 23 
     | 
    
         
            +
                    # no regular words or you'll be exposed to dictionary attacks.
         
     | 
| 
      
 24 
     | 
    
         
            +
                    # You can use `rails secret` to generate a secure secret key.
         
     | 
| 
       32 
25 
     | 
    
         | 
| 
       33 
26 
     | 
    
         
             
                    development:
         
     | 
| 
       34 
27 
     | 
    
         
             
                      secret_key_base: #{SecureRandom.hex(64)}
         
     | 
| 
         @@ -36,17 +29,39 @@ namespace :secvault do 
     | 
|
| 
       36 
29 
     | 
    
         
             
                    test:
         
     | 
| 
       37 
30 
     | 
    
         
             
                      secret_key_base: #{SecureRandom.hex(64)}
         
     | 
| 
       38 
31 
     | 
    
         | 
| 
      
 32 
     | 
    
         
            +
                    # Do not keep production secrets in the repository,
         
     | 
| 
      
 33 
     | 
    
         
            +
                    # instead read values from the environment.
         
     | 
| 
       39 
34 
     | 
    
         
             
                    production:
         
     | 
| 
       40 
35 
     | 
    
         
             
                      secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
         
     | 
| 
       41 
36 
     | 
    
         
             
                  YAML
         
     | 
| 
       42 
37 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                   
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
      
 38 
     | 
    
         
            +
                  if encrypted
         
     | 
| 
      
 39 
     | 
    
         
            +
                    # Create encrypted file
         
     | 
| 
      
 40 
     | 
    
         
            +
                    unless key_path.exist?
         
     | 
| 
      
 41 
     | 
    
         
            +
                      key = ActiveSupport::EncryptedFile.generate_key
         
     | 
| 
      
 42 
     | 
    
         
            +
                      File.write(key_path, key)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      puts "Generated encryption key in #{key_path}"
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    encrypted_file = ActiveSupport::EncryptedFile.new(
         
     | 
| 
      
 47 
     | 
    
         
            +
                      content_path: secrets_path,
         
     | 
| 
      
 48 
     | 
    
         
            +
                      key_path: key_path,
         
     | 
| 
      
 49 
     | 
    
         
            +
                      env_key: "RAILS_SECRETS_KEY",
         
     | 
| 
      
 50 
     | 
    
         
            +
                      raise_if_missing_key: true
         
     | 
| 
      
 51 
     | 
    
         
            +
                    )
         
     | 
| 
      
 52 
     | 
    
         
            +
                    encrypted_file.write(default_content)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    puts "Created encrypted secrets.yml file"
         
     | 
| 
      
 54 
     | 
    
         
            +
                    puts "Add #{key_path} to your .gitignore file"
         
     | 
| 
      
 55 
     | 
    
         
            +
                  else
         
     | 
| 
      
 56 
     | 
    
         
            +
                    # Create plain YAML file
         
     | 
| 
      
 57 
     | 
    
         
            +
                    File.write(secrets_path, default_content)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    puts "Created plain secrets.yml file"
         
     | 
| 
      
 59 
     | 
    
         
            +
                    puts "Remember to add #{secrets_path} to your .gitignore if it contains sensitive data"
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
       46 
61 
     | 
    
         
             
                end
         
     | 
| 
       47 
62 
     | 
    
         
             
              end
         
     | 
| 
       48 
63 
     | 
    
         | 
| 
       49 
     | 
    
         
            -
              desc "Edit  
     | 
| 
      
 64 
     | 
    
         
            +
              desc "Edit secrets.yml file"
         
     | 
| 
       50 
65 
     | 
    
         
             
              task edit: :environment do
         
     | 
| 
       51 
66 
     | 
    
         
             
                secrets_path = Rails.root.join("config/secrets.yml")
         
     | 
| 
       52 
67 
     | 
    
         
             
                key_path = Rails.root.join("config/secrets.yml.key")
         
     | 
| 
         @@ -56,18 +71,28 @@ namespace :secvault do 
     | 
|
| 
       56 
71 
     | 
    
         
             
                  exit 1
         
     | 
| 
       57 
72 
     | 
    
         
             
                end
         
     | 
| 
       58 
73 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
                 
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
                  key_path: key_path,
         
     | 
| 
       62 
     | 
    
         
            -
                  env_key: "RAILS_SECRETS_KEY",
         
     | 
| 
       63 
     | 
    
         
            -
                  raise_if_missing_key: true
         
     | 
| 
       64 
     | 
    
         
            -
                )
         
     | 
| 
      
 74 
     | 
    
         
            +
                # Check if file is encrypted
         
     | 
| 
      
 75 
     | 
    
         
            +
                is_encrypted = Secvault::Secrets.encrypted?(secrets_path)
         
     | 
| 
       65 
76 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
                 
     | 
| 
       67 
     | 
    
         
            -
                   
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
      
 77 
     | 
    
         
            +
                if is_encrypted && key_path.exist?
         
     | 
| 
      
 78 
     | 
    
         
            +
                  # Handle encrypted file
         
     | 
| 
      
 79 
     | 
    
         
            +
                  encrypted_file = ActiveSupport::EncryptedFile.new(
         
     | 
| 
      
 80 
     | 
    
         
            +
                    content_path: secrets_path,
         
     | 
| 
      
 81 
     | 
    
         
            +
                    key_path: key_path,
         
     | 
| 
      
 82 
     | 
    
         
            +
                    env_key: "RAILS_SECRETS_KEY",
         
     | 
| 
      
 83 
     | 
    
         
            +
                    raise_if_missing_key: true
         
     | 
| 
      
 84 
     | 
    
         
            +
                  )
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  encrypted_file.change do |tmp_path|
         
     | 
| 
      
 87 
     | 
    
         
            +
                    system("#{ENV["EDITOR"] || "vi"} #{tmp_path}")
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
       69 
89 
     | 
    
         | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
      
 90 
     | 
    
         
            +
                  puts "Updated encrypted #{secrets_path}"
         
     | 
| 
      
 91 
     | 
    
         
            +
                else
         
     | 
| 
      
 92 
     | 
    
         
            +
                  # Handle plain YAML file
         
     | 
| 
      
 93 
     | 
    
         
            +
                  system("#{ENV["EDITOR"] || "vi"} #{secrets_path}")
         
     | 
| 
      
 94 
     | 
    
         
            +
                  puts "Updated plain #{secrets_path}"
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
       71 
96 
     | 
    
         
             
              rescue ActiveSupport::EncryptedFile::MissingKeyError
         
     | 
| 
       72 
97 
     | 
    
         
             
                puts "Missing encryption key to decrypt secrets.yml."
         
     | 
| 
       73 
98 
     | 
    
         
             
                puts "Ask your team for your secrets key and put it in #{key_path}"
         
     | 
| 
         @@ -75,7 +100,7 @@ namespace :secvault do 
     | 
|
| 
       75 
100 
     | 
    
         
             
                puts "Invalid encryption key for secrets.yml."
         
     | 
| 
       76 
101 
     | 
    
         
             
              end
         
     | 
| 
       77 
102 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
              desc "Show  
     | 
| 
      
 103 
     | 
    
         
            +
              desc "Show secrets.yml content"
         
     | 
| 
       79 
104 
     | 
    
         
             
              task show: :environment do
         
     | 
| 
       80 
105 
     | 
    
         
             
                secrets_path = Rails.root.join("config/secrets.yml")
         
     | 
| 
       81 
106 
     | 
    
         
             
                key_path = Rails.root.join("config/secrets.yml.key")
         
     | 
| 
         @@ -85,14 +110,22 @@ namespace :secvault do 
     | 
|
| 
       85 
110 
     | 
    
         
             
                  exit 1
         
     | 
| 
       86 
111 
     | 
    
         
             
                end
         
     | 
| 
       87 
112 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
                 
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
                  key_path: key_path,
         
     | 
| 
       91 
     | 
    
         
            -
                  env_key: "RAILS_SECRETS_KEY",
         
     | 
| 
       92 
     | 
    
         
            -
                  raise_if_missing_key: true
         
     | 
| 
       93 
     | 
    
         
            -
                )
         
     | 
| 
      
 113 
     | 
    
         
            +
                # Check if file is encrypted
         
     | 
| 
      
 114 
     | 
    
         
            +
                is_encrypted = Secvault::Secrets.encrypted?(secrets_path)
         
     | 
| 
       94 
115 
     | 
    
         | 
| 
       95 
     | 
    
         
            -
                 
     | 
| 
      
 116 
     | 
    
         
            +
                if is_encrypted && key_path.exist?
         
     | 
| 
      
 117 
     | 
    
         
            +
                  # Handle encrypted file
         
     | 
| 
      
 118 
     | 
    
         
            +
                  encrypted_file = ActiveSupport::EncryptedFile.new(
         
     | 
| 
      
 119 
     | 
    
         
            +
                    content_path: secrets_path,
         
     | 
| 
      
 120 
     | 
    
         
            +
                    key_path: key_path,
         
     | 
| 
      
 121 
     | 
    
         
            +
                    env_key: "RAILS_SECRETS_KEY",
         
     | 
| 
      
 122 
     | 
    
         
            +
                    raise_if_missing_key: true
         
     | 
| 
      
 123 
     | 
    
         
            +
                  )
         
     | 
| 
      
 124 
     | 
    
         
            +
                  puts encrypted_file.read
         
     | 
| 
      
 125 
     | 
    
         
            +
                else
         
     | 
| 
      
 126 
     | 
    
         
            +
                  # Handle plain YAML file
         
     | 
| 
      
 127 
     | 
    
         
            +
                  puts File.read(secrets_path)
         
     | 
| 
      
 128 
     | 
    
         
            +
                end
         
     | 
| 
       96 
129 
     | 
    
         
             
              rescue ActiveSupport::EncryptedFile::MissingKeyError
         
     | 
| 
       97 
130 
     | 
    
         
             
                puts "Missing encryption key to decrypt secrets.yml."
         
     | 
| 
       98 
131 
     | 
    
         
             
                puts "Ask your team for your secrets key and put it in #{key_path}"
         
     | 
    
        data/lib/secvault/version.rb
    CHANGED
    
    
    
        data/lib/secvault.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: secvault
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1.0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.0.1
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Unnikrishnan KP
         
     | 
| 
         @@ -40,7 +40,7 @@ dependencies: 
     | 
|
| 
       40 
40 
     | 
    
         
             
                    version: '2.6'
         
     | 
| 
       41 
41 
     | 
    
         
             
            description: Secvault restores the classic Rails secrets.yml functionality that was
         
     | 
| 
       42 
42 
     | 
    
         
             
              removed in Rails 7.2, allowing you to manage encrypted secrets using the familiar
         
     | 
| 
       43 
     | 
    
         
            -
              YAML-based approach.
         
     | 
| 
      
 43 
     | 
    
         
            +
              YAML-based approach. Compatible with Rails 8.0+.
         
     | 
| 
       44 
44 
     | 
    
         
             
            email:
         
     | 
| 
       45 
45 
     | 
    
         
             
            - unnikrishnan.kp@bigbinary.com
         
     | 
| 
       46 
46 
     | 
    
         
             
            executables: []
         
     | 
| 
         @@ -56,6 +56,7 @@ files: 
     | 
|
| 
       56 
56 
     | 
    
         
             
            - Rakefile
         
     | 
| 
       57 
57 
     | 
    
         
             
            - lib/secvault.rb
         
     | 
| 
       58 
58 
     | 
    
         
             
            - lib/secvault/generators/secrets_generator.rb
         
     | 
| 
      
 59 
     | 
    
         
            +
            - lib/secvault/rails_secrets.rb
         
     | 
| 
       59 
60 
     | 
    
         
             
            - lib/secvault/railtie.rb
         
     | 
| 
       60 
61 
     | 
    
         
             
            - lib/secvault/secrets.rb
         
     | 
| 
       61 
62 
     | 
    
         
             
            - lib/secvault/secrets_helper.rb
         
     | 
| 
         @@ -88,5 +89,5 @@ requirements: [] 
     | 
|
| 
       88 
89 
     | 
    
         
             
            rubygems_version: 3.5.10
         
     | 
| 
       89 
90 
     | 
    
         
             
            signing_key:
         
     | 
| 
       90 
91 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       91 
     | 
    
         
            -
            summary: Rails secrets.yml functionality for Rails 7.2+
         
     | 
| 
      
 92 
     | 
    
         
            +
            summary: Rails secrets.yml functionality for Rails 7.2+ and Rails 8.0+
         
     | 
| 
       92 
93 
     | 
    
         
             
            test_files: []
         
     |