rls_multi_tenant 0.2.2 → 0.2.3

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.
@@ -7,132 +7,68 @@ module RlsMultiTenant
7
7
  module Generators
8
8
  class SetupGenerator < Rails::Generators::Base
9
9
  include Shared::TemplateHelper
10
-
11
- source_root File.expand_path("templates", __dir__)
12
10
 
13
- desc "Setup RLS Multi-tenant gem with tenant model and migrations"
11
+ source_root File.expand_path('templates', __dir__)
12
+
13
+ desc 'Setup RLS Multi-tenant gem with tenant model and migrations'
14
14
 
15
15
  def create_tenant_model
16
16
  tenant_class_name = RlsMultiTenant.tenant_class_name
17
17
  tenant_file_path = "app/models/#{tenant_class_name.underscore}.rb"
18
-
19
- unless File.exist?(File.join(destination_root, tenant_file_path))
20
- template "tenant_model.rb", tenant_file_path
21
- else
18
+
19
+ if File.exist?(File.join(destination_root, tenant_file_path))
22
20
  say "#{tenant_class_name} model already exists, skipping creation", :yellow
21
+ else
22
+ template 'tenant_model.rb', tenant_file_path
23
23
  end
24
24
  end
25
25
 
26
26
  def create_uuid_migration
27
- unless Dir.glob(File.join(destination_root, "db/migrate/*_enable_uuid_extension.rb")).any?
28
- create_migration_with_timestamp("enable_uuid", 1)
27
+ if Dir.glob(File.join(destination_root, 'db/migrate/*_enable_uuid_extension.rb')).any?
28
+ say 'UUID extension migration already exists, skipping creation', :yellow
29
29
  else
30
- say "UUID extension migration already exists, skipping creation", :yellow
30
+ create_migration_with_timestamp('enable_uuid', 1)
31
31
  end
32
32
  end
33
33
 
34
- def create_app_user_migration
35
- create_app_user_migrations_for_all_databases
36
- end
37
-
38
34
  def create_tenant_migration
39
35
  tenant_class_name = RlsMultiTenant.tenant_class_name
40
36
  migration_pattern = "*_create_#{tenant_class_name.underscore.pluralize}.rb"
41
-
42
- unless Dir.glob(File.join(destination_root, "db/migrate/#{migration_pattern}")).any?
43
- create_migration_with_timestamp("create_tenant", 3)
44
- else
37
+
38
+ if Dir.glob(File.join(destination_root, "db/migrate/#{migration_pattern}")).any?
45
39
  say "#{tenant_class_name} migration already exists, skipping creation", :yellow
40
+ else
41
+ create_migration_with_timestamp('create_tenant', 3)
46
42
  end
47
43
  end
48
44
 
49
45
  def show_instructions
50
46
  tenant_class_name = RlsMultiTenant.tenant_class_name
51
- say "\n" + "="*60, :green
52
- say "RLS Multi-tenant setup completed successfully!", :green
53
- say "="*60, :green
47
+ say "\n#{'=' * 60}", :green
48
+ say 'RLS Multi-tenant setup completed successfully!', :green
49
+ say '=' * 60, :green
54
50
  say "\nCreated:", :yellow
55
51
  say "• #{tenant_class_name} model", :green
56
- say "• UUID extension migration", :green
57
- say "• App user migration(s)", :green
52
+ say '• UUID extension migration', :green
58
53
  say "• #{tenant_class_name} migration", :green
59
54
  say "\nNext steps:", :yellow
60
- say "1. Make sure to use the POSTGRES_APP_USER in your database.yml.", :yellow
61
- say "\n2. Run the migrations with admin privileges:\n", :yellow
62
- say " rails db_as:admin[migrate]", :yellow
63
- say " Note: We must use the admin user because the app user doesn't have migration privileges", :yellow
64
- say "\n3. Use 'rails generate rls_multi_tenant:model' for new multi-tenant models", :yellow
65
- say "="*60, :green
55
+ say "\n1. Use 'rails generate rls_multi_tenant:model <model_name>' for new multi-tenant models", :yellow
56
+ say '=' * 60, :green
66
57
  end
67
58
 
68
59
  private
69
60
 
70
- def create_app_user_migrations_for_all_databases
71
- # Get database configuration for current environment
72
- db_config = Rails.application.config.database_configuration[Rails.env]
73
-
74
- # Handle both single database and multiple databases configuration
75
- databases_to_process = if db_config.is_a?(Hash) && db_config.key?('primary')
76
- # Multiple databases configuration
77
- db_config
78
- else
79
- # Single database configuration - treat as primary
80
- { 'primary' => db_config }
81
- end
82
-
83
- databases_to_process.each do |db_name, config|
84
- next if db_name == 'primary' # Skip primary database, handle it separately
85
-
86
- # Check if migrations_paths is defined for this database
87
- if config['migrations_paths']
88
- migration_paths = Array(config['migrations_paths'])
89
- migration_paths.each do |migration_path|
90
- migration_dir = File.join(destination_root, migration_path)
91
-
92
- # Check if migration already exists in this path
93
- unless Dir.glob(File.join(migration_dir, "*_create_app_user.rb")).any?
94
- FileUtils.mkdir_p(migration_dir) unless File.directory?(migration_dir)
95
- create_migration_with_timestamp_for_path("create_app_user", 2, migration_path)
96
- say "Created app user migration for #{db_name} in #{migration_path}", :green
97
- else
98
- say "App user migration already exists for #{db_name} in #{migration_path}, skipping creation", :yellow
99
- end
100
- end
101
- else
102
- say "No migrations_paths defined for database '#{db_name}', skipping app user migration", :yellow
103
- end
104
- end
105
-
106
- # Handle primary database (default behavior)
107
- unless Dir.glob(File.join(destination_root, "db/migrate/*_create_app_user.rb")).any?
108
- create_migration_with_timestamp("create_app_user", 2)
109
- else
110
- say "App user migration already exists for primary database, skipping creation", :yellow
111
- end
112
- end
113
-
114
61
  def create_migration_with_timestamp(migration_type, order)
115
- base_timestamp = Time.current.strftime("%Y%m%d%H%M")
116
- timestamp = "#{base_timestamp}#{sprintf('%02d', order)}"
117
-
118
- case migration_type
119
- when "enable_uuid"
120
- render_shared_template "enable_uuid_extension.rb", "db/migrate/#{timestamp}_enable_uuid_extension.rb"
121
- when "create_app_user"
122
- render_shared_template "create_app_user.rb", "db/migrate/#{timestamp}_create_app_user.rb"
123
- when "create_tenant"
124
- tenant_class_name = RlsMultiTenant.tenant_class_name
125
- render_shared_template "create_tenant.rb", "db/migrate/#{timestamp}_create_#{tenant_class_name.underscore.pluralize}.rb"
126
- end
127
- end
62
+ base_timestamp = Time.current.strftime('%Y%m%d%H%M')
63
+ timestamp = "#{base_timestamp}#{format('%02d', order)}"
128
64
 
129
- def create_migration_with_timestamp_for_path(migration_type, order, migration_path)
130
- base_timestamp = Time.current.strftime("%Y%m%d%H%M")
131
- timestamp = "#{base_timestamp}#{sprintf('%02d', order)}"
132
-
133
65
  case migration_type
134
- when "create_app_user"
135
- render_shared_template "create_app_user.rb", "#{migration_path}/#{timestamp}_create_app_user.rb"
66
+ when 'enable_uuid'
67
+ render_shared_template 'enable_uuid_extension.rb', "db/migrate/#{timestamp}_enable_uuid_extension.rb"
68
+ when 'create_tenant'
69
+ tenant_class_name = RlsMultiTenant.tenant_class_name
70
+ render_shared_template 'create_tenant.rb',
71
+ "db/migrate/#{timestamp}_create_#{tenant_class_name.underscore.pluralize}.rb"
136
72
  end
137
73
  end
138
74
  end
@@ -9,7 +9,7 @@ module RlsMultiTenant
9
9
  private
10
10
 
11
11
  def shared_template_path
12
- File.expand_path("templates", File.dirname(__FILE__))
12
+ File.expand_path('templates', File.dirname(__FILE__))
13
13
  end
14
14
 
15
15
  def copy_shared_template(template_name, destination_path)
@@ -10,10 +10,12 @@ module RlsMultiTenant
10
10
  def call(env)
11
11
  request = ActionDispatch::Request.new(env)
12
12
  tenant = resolve_tenant_from_subdomain(request)
13
-
13
+
14
14
  if tenant
15
15
  # Switch tenant context for the duration of the request
16
- Rails.logger.info "[RLS Multi-Tenant] #{request.method} #{request.path} -> Tenant: #{tenant.name} (#{tenant.id})" if defined?(Rails)
16
+ if defined?(Rails)
17
+ Rails.logger.info "[RLS Multi-Tenant] #{request.method} #{request.path} -> Tenant: #{tenant.name} (#{tenant.id})"
18
+ end
17
19
  RlsMultiTenant.tenant_class.switch(tenant) do
18
20
  @app.call(env)
19
21
  end
@@ -22,12 +24,17 @@ module RlsMultiTenant
22
24
  subdomain = extract_subdomain(request.host)
23
25
  if subdomain.present? && subdomain != 'www'
24
26
  # Subdomain exists but no tenant found - this is an error
25
- Rails.logger.warn "[RLS Multi-Tenant] #{request.method} #{request.path} -> No tenant found for subdomain '#{subdomain}'" if defined?(Rails)
26
- raise RlsMultiTenant::Error, "No tenant found for subdomain '#{subdomain}'. Please ensure the tenant exists with the correct subdomain."
27
+ if defined?(Rails)
28
+ Rails.logger.warn "[RLS Multi-Tenant] #{request.method} #{request.path} -> No tenant found for subdomain '#{subdomain}'"
29
+ end
30
+ raise RlsMultiTenant::Error,
31
+ "No tenant found for subdomain '#{subdomain}'. Please ensure the tenant exists with the correct subdomain."
27
32
  end
28
33
  # If no subdomain, allow access to public models (models without TenantContext)
29
34
  # Models that include TenantContext will automatically be constrained by RLS
30
- Rails.logger.info "[RLS Multi-Tenant] #{request.method} #{request.path} -> Public access (no subdomain)" if defined?(Rails)
35
+ if defined?(Rails)
36
+ Rails.logger.info "[RLS Multi-Tenant] #{request.method} #{request.path} -> Public access (no subdomain)"
37
+ end
31
38
  @app.call(env)
32
39
  end
33
40
  end
@@ -41,37 +48,35 @@ module RlsMultiTenant
41
48
  # Look up tenant by subdomain only
42
49
  tenant_class = RlsMultiTenant.tenant_class
43
50
  subdomain_field = RlsMultiTenant.subdomain_field
44
-
51
+
45
52
  # Only allow subdomain-based lookup
46
53
  unless tenant_class.column_names.include?(subdomain_field.to_s)
47
- raise RlsMultiTenant::ConfigurationError,
54
+ raise RlsMultiTenant::ConfigurationError,
48
55
  "Subdomain field '#{subdomain_field}' not found on #{tenant_class.name}. " \
49
56
  "Please add a '#{subdomain_field}' column to your tenant model or configure a different subdomain_field."
50
57
  end
51
-
58
+
52
59
  tenant_class.find_by(subdomain_field => subdomain)
53
- rescue => e
60
+ rescue StandardError => e
54
61
  Rails.logger.error "Failed to resolve tenant from subdomain '#{subdomain}': #{e.message}" if defined?(Rails)
55
62
  nil
56
63
  end
57
64
 
58
65
  def extract_subdomain(host)
59
66
  return nil if host.blank?
60
-
67
+
61
68
  # Remove port if present
62
69
  host = host.split(':').first
63
-
70
+
64
71
  # Split by dots and get the first part (subdomain)
65
72
  parts = host.split('.')
66
-
73
+
67
74
  # Handle localhost development (e.g., foo.localhost:3000)
68
75
  if parts.length == 2 && parts.last == 'localhost'
69
76
  parts.first
70
77
  # Handle standard domains (e.g., foo.example.com)
71
78
  elsif parts.length >= 3
72
79
  parts.first
73
- else
74
- nil
75
80
  end
76
81
  end
77
82
  end
@@ -3,39 +3,34 @@
3
3
  module RlsMultiTenant
4
4
  class Railtie < Rails::Railtie
5
5
  # Load generators after Rails is fully initialized
6
- initializer "rls_multi_tenant.load_generators", after: :set_routes_reloader do |app|
7
- require "rls_multi_tenant/generators/install/install_generator"
8
- require "rls_multi_tenant/generators/setup/setup_generator"
9
- require "rls_multi_tenant/generators/migration/migration_generator"
10
- require "rls_multi_tenant/generators/model/model_generator"
11
- require "rls_multi_tenant/generators/task/task_generator"
6
+ initializer 'rls_multi_tenant.load_generators', after: :set_routes_reloader do |_app|
7
+ require 'rls_multi_tenant/generators/install/install_generator'
8
+ require 'rls_multi_tenant/generators/setup/setup_generator'
9
+ require 'rls_multi_tenant/generators/migration/migration_generator'
10
+ require 'rls_multi_tenant/generators/model/model_generator'
12
11
  end
13
12
 
14
- initializer "rls_multi_tenant.configure" do |app|
13
+ initializer 'rls_multi_tenant.configure' do |_app|
15
14
  # Configure the gem
16
15
  RlsMultiTenant.configure do |config|
17
- config.tenant_class_name = "Tenant"
16
+ config.tenant_class_name = 'Tenant'
18
17
  config.tenant_id_column = :tenant_id
19
- config.app_user_env_var = "POSTGRES_APP_USER"
20
18
  config.enable_security_validation = true
21
19
  end
22
20
  end
23
21
 
24
- initializer "rls_multi_tenant.security_validation", after: :load_config_initializers do |app|
22
+ initializer 'rls_multi_tenant.security_validation', after: :load_config_initializers do |app|
25
23
  if RlsMultiTenant.enable_security_validation
26
24
  app.config.after_initialize do
27
- begin
28
- RlsMultiTenant::SecurityValidator.validate_environment!
29
- RlsMultiTenant::SecurityValidator.validate_database_user!
30
- rescue => e
31
- Rails.logger.error "RLS Multi-tenant initialization failed: #{e.message}"
32
- raise e
33
- end
25
+ RlsMultiTenant::SecurityValidator.validate_database_user!
26
+ rescue StandardError => e
27
+ Rails.logger.error "RLS Multi-tenant initialization failed: #{e.message}"
28
+ raise e
34
29
  end
35
30
  end
36
31
  end
37
32
 
38
- initializer "rls_multi_tenant.middleware", after: :load_config_initializers do |app|
33
+ initializer 'rls_multi_tenant.middleware', after: :load_config_initializers do |app|
39
34
  if RlsMultiTenant.enable_subdomain_middleware
40
35
  app.config.middleware.use RlsMultiTenant::Middleware::SubdomainTenantSelector
41
36
  end
@@ -4,46 +4,32 @@ module RlsMultiTenant
4
4
  module RlsHelper
5
5
  class << self
6
6
  # Enable RLS on a table with a policy
7
- def enable_rls_for_table(table_name, tenant_column: RlsMultiTenant.tenant_id_column, app_user: nil)
8
- app_user ||= ENV[RlsMultiTenant.app_user_env_var]
9
-
10
- raise ConfigurationError, "App user not configured" if app_user.blank?
11
-
7
+ def enable_rls_for_table(table_name, tenant_column: RlsMultiTenant.tenant_id_column)
12
8
  # Enable RLS
13
- ActiveRecord::Base.connection.execute("ALTER TABLE #{table_name} ENABLE ROW LEVEL SECURITY")
14
-
9
+ ActiveRecord::Base.connection.execute("ALTER TABLE #{table_name} ENABLE ROW LEVEL SECURITY, FORCE ROW LEVEL SECURITY")
10
+
15
11
  # Create policy (drop if exists first)
16
12
  policy_name = "#{table_name}_app_user"
17
13
  ActiveRecord::Base.connection.execute("DROP POLICY IF EXISTS #{policy_name} ON #{table_name}")
18
-
14
+
19
15
  tenant_session_var = "rls.#{RlsMultiTenant.tenant_id_column}"
20
- policy_sql = "CREATE POLICY #{policy_name} ON #{table_name} TO #{app_user} " \
21
- "USING (#{tenant_column} = NULLIF(current_setting('#{tenant_session_var}', TRUE), '')::uuid)"
22
-
16
+ policy_sql = "CREATE POLICY #{policy_name} ON #{table_name} " \
17
+ "USING (#{tenant_column} = NULLIF(current_setting('#{tenant_session_var}', TRUE), '')::uuid)"
18
+
23
19
  ActiveRecord::Base.connection.execute(policy_sql)
24
-
25
- # Grant permissions
26
- ActiveRecord::Base.connection.execute("GRANT SELECT, INSERT, UPDATE, DELETE ON #{table_name} TO #{app_user}")
27
-
20
+
28
21
  Rails.logger&.info "✅ RLS enabled for table #{table_name} with policy #{policy_name}"
29
22
  end
30
23
 
31
24
  # Disable RLS on a table
32
- def disable_rls_for_table(table_name, app_user: nil)
33
- app_user ||= ENV[RlsMultiTenant.app_user_env_var]
34
-
35
- raise ConfigurationError, "App user not configured" if app_user.blank?
36
-
37
- # Revoke permissions
38
- ActiveRecord::Base.connection.execute("REVOKE SELECT, INSERT, UPDATE, DELETE ON #{table_name} FROM #{app_user}")
39
-
25
+ def disable_rls_for_table(table_name)
40
26
  # Drop policy
41
27
  policy_name = "#{table_name}_app_user"
42
28
  ActiveRecord::Base.connection.execute("DROP POLICY IF EXISTS #{policy_name} ON #{table_name}")
43
-
29
+
44
30
  # Disable RLS
45
- ActiveRecord::Base.connection.execute("ALTER TABLE #{table_name} DISABLE ROW LEVEL SECURITY")
46
-
31
+ ActiveRecord::Base.connection.execute("ALTER TABLE #{table_name} DISABLE ROW LEVEL SECURITY, NO FORCE ROW LEVEL SECURITY")
32
+
47
33
  Rails.logger&.info "✅ RLS disabled for table #{table_name}"
48
34
  end
49
35
 
@@ -52,8 +38,8 @@ module RlsMultiTenant
52
38
  result = ActiveRecord::Base.connection.execute(
53
39
  "SELECT relrowsecurity FROM pg_class WHERE relname = '#{table_name}'"
54
40
  ).first
55
-
56
- result&.dig('relrowsecurity') == true
41
+
42
+ result&.dig('relrowsecurity') == true && result&.dig('relforcerowsecurity') == true
57
43
  end
58
44
 
59
45
  # Get all RLS policies for a table
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rls_multi_tenant/version"
4
- require "rls_multi_tenant/concerns/multi_tenant"
5
- require "rls_multi_tenant/concerns/tenant_context"
6
- require "rls_multi_tenant/security_validator"
7
- require "rls_multi_tenant/rls_helper"
8
- require "rls_multi_tenant/railtie" if defined?(Rails)
3
+ require 'rls_multi_tenant/version'
4
+ require 'rls_multi_tenant/concerns/multi_tenant'
5
+ require 'rls_multi_tenant/concerns/tenant_context'
6
+ require 'rls_multi_tenant/security_validator'
7
+ require 'rls_multi_tenant/rls_helper'
8
+ require 'rls_multi_tenant/railtie' if defined?(Rails)
9
9
 
10
10
  module RlsMultiTenant
11
11
  class Error < StandardError; end
@@ -14,7 +14,8 @@ module RlsMultiTenant
14
14
 
15
15
  # Configuration options
16
16
  class << self
17
- attr_accessor :tenant_class_name, :tenant_id_column, :app_user_env_var, :enable_security_validation
17
+ attr_accessor :tenant_class_name, :tenant_id_column, :enable_security_validation, :enable_subdomain_middleware,
18
+ :subdomain_field
18
19
 
19
20
  def configure
20
21
  yield self
@@ -28,18 +29,23 @@ module RlsMultiTenant
28
29
  @tenant_id_column ||= :tenant_id
29
30
  end
30
31
 
31
- def app_user_env_var
32
- @app_user_env_var ||= "POSTGRES_APP_USER"
32
+ def enable_security_validation
33
+ @enable_security_validation.nil? || @enable_security_validation
33
34
  end
34
35
 
35
- def enable_security_validation
36
- @enable_security_validation.nil? ? true : @enable_security_validation
36
+ def enable_subdomain_middleware
37
+ @enable_subdomain_middleware.nil? ? false : @enable_subdomain_middleware
38
+ end
39
+
40
+ def subdomain_field
41
+ @subdomain_field ||= :subdomain
37
42
  end
38
43
  end
39
44
 
40
45
  # Default configuration
41
- self.tenant_class_name = "Tenant"
46
+ self.tenant_class_name = 'Tenant'
42
47
  self.tenant_id_column = :tenant_id
43
- self.app_user_env_var = "POSTGRES_APP_USER"
44
48
  self.enable_security_validation = true
49
+ self.enable_subdomain_middleware = true
50
+ self.subdomain_field = :subdomain
45
51
  end
@@ -5,59 +5,29 @@ module RlsMultiTenant
5
5
  class << self
6
6
  def validate_database_user!
7
7
  return unless RlsMultiTenant.enable_security_validation
8
- return if skip_validation?
9
8
 
10
9
  begin
11
10
  # Get the current database configuration
12
11
  db_config = ActiveRecord::Base.connection_db_config
13
12
  username = db_config.configuration_hash[:username]
14
13
 
15
- # Check if the current user has SUPERUSER privileges
16
- superuser_check = ActiveRecord::Base.connection.execute(
17
- "SELECT rolname, rolsuper FROM pg_roles WHERE rolname = current_user"
14
+ # Check if the user has bypassrls privilege
15
+ bypassrls_check = ActiveRecord::Base.connection.execute(
16
+ "SELECT rolbypassrls FROM pg_roles WHERE rolname = '#{username}'"
18
17
  ).first
19
18
 
20
- if superuser_check && superuser_check['rolsuper']
21
- raise SecurityError, "Database user '#{username}' has SUPERUSER privileges. " \
22
- "In order to use RLS Multi-tenant, you must use a non-privileged user without SUPERUSER rights." \
23
- "Did you remember to edit database.yml in order to use the POSTGRES_APP_USER and POSTGRES_APP_PASSWORD?"
19
+ if bypassrls_check && bypassrls_check['rolbypassrls']
20
+ raise SecurityError, "Database user '#{username}' has BYPASSRLS privilege. " \
21
+ 'In order to use RLS Multi-tenant, you must use a non-privileged user without BYPASSRLS privilege.'
24
22
  end
25
23
 
26
24
  # Log the security check result
27
- Rails.logger&.info "✅ RLS Multi-tenant security check passed: Using user '#{username}' without SUPERUSER privileges"
28
-
29
- rescue => e
25
+ Rails.logger&.info "✅ RLS Multi-tenant security check passed: Using user '#{username}' without BYPASSRLS privilege"
26
+ rescue StandardError => e
30
27
  Rails.logger&.error "❌ RLS Multi-tenant security check failed: #{e.message}"
31
28
  raise e
32
29
  end
33
30
  end
34
-
35
- def validate_environment!
36
- return if skip_validation?
37
- return unless RlsMultiTenant.enable_security_validation
38
-
39
- app_user = ENV[RlsMultiTenant.app_user_env_var]
40
-
41
- if app_user.blank?
42
- raise ConfigurationError, "#{RlsMultiTenant.app_user_env_var} environment variable must be set"
43
- elsif ["postgres", "root"].include?(app_user)
44
- raise SecurityError, "Cannot use privileged PostgreSQL user '#{app_user}'. " \
45
- "In order to use RLS Multi-tenant, you must use a non-privileged user without SUPERUSER rights." \
46
- "Did you remember to edit database.yml in order to use the POSTGRES_APP_USER and POSTGRES_APP_PASSWORD?"
47
- end
48
- end
49
-
50
- private
51
-
52
- def skip_validation?
53
- # Skip validation if we're running an install or setup generator
54
- return true if ARGV.any? { |arg| arg.include?('rls_multi_tenant:install') || arg.include?('rls_multi_tenant:setup') }
55
-
56
- # Skip validation if we're in admin mode (set by db_as:admin task)
57
- return true if ENV['RLS_MULTI_TENANT_ADMIN_MODE'] == 'true'
58
-
59
- false
60
- end
61
31
  end
62
32
  end
63
33
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RlsMultiTenant
4
- VERSION = "0.2.2"
4
+ VERSION = '0.2.3'
5
5
  end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rls_multi_tenant/version"
4
- require "rls_multi_tenant/concerns/multi_tenant"
5
- require "rls_multi_tenant/concerns/tenant_context"
6
- require "rls_multi_tenant/security_validator"
7
- require "rls_multi_tenant/rls_helper"
8
- require "rls_multi_tenant/middleware/subdomain_tenant_selector"
9
- require "rls_multi_tenant/generators/shared/template_helper"
10
- require "rls_multi_tenant/railtie" if defined?(Rails)
3
+ require 'rls_multi_tenant/version'
4
+ require 'rls_multi_tenant/concerns/multi_tenant'
5
+ require 'rls_multi_tenant/concerns/tenant_context'
6
+ require 'rls_multi_tenant/security_validator'
7
+ require 'rls_multi_tenant/rls_helper'
8
+ require 'rls_multi_tenant/middleware/subdomain_tenant_selector'
9
+ require 'rls_multi_tenant/generators/shared/template_helper'
10
+ require 'rls_multi_tenant/railtie' if defined?(Rails)
11
11
 
12
12
  module RlsMultiTenant
13
13
  class Error < StandardError; end
@@ -16,7 +16,8 @@ module RlsMultiTenant
16
16
 
17
17
  # Configuration options
18
18
  class << self
19
- attr_accessor :tenant_class_name, :tenant_id_column, :app_user_env_var, :enable_security_validation, :enable_subdomain_middleware, :subdomain_field
19
+ attr_accessor :tenant_class_name, :tenant_id_column, :enable_security_validation, :enable_subdomain_middleware,
20
+ :subdomain_field
20
21
 
21
22
  def configure
22
23
  yield self
@@ -30,12 +31,8 @@ module RlsMultiTenant
30
31
  @tenant_id_column ||= :tenant_id
31
32
  end
32
33
 
33
- def app_user_env_var
34
- @app_user_env_var ||= "POSTGRES_APP_USER"
35
- end
36
-
37
34
  def enable_security_validation
38
- @enable_security_validation.nil? ? true : @enable_security_validation
35
+ @enable_security_validation.nil? || @enable_security_validation
39
36
  end
40
37
 
41
38
  def enable_subdomain_middleware
@@ -48,9 +45,8 @@ module RlsMultiTenant
48
45
  end
49
46
 
50
47
  # Default configuration
51
- self.tenant_class_name = "Tenant"
48
+ self.tenant_class_name = 'Tenant'
52
49
  self.tenant_id_column = :tenant_id
53
- self.app_user_env_var = "POSTGRES_APP_USER"
54
50
  self.enable_security_validation = true
55
51
  self.enable_subdomain_middleware = true
56
52
  self.subdomain_field = :subdomain
@@ -1,24 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/rls_multi_tenant/version"
3
+ require_relative 'lib/rls_multi_tenant/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "rls_multi_tenant"
6
+ spec.name = 'rls_multi_tenant'
7
7
  spec.version = RlsMultiTenant::VERSION
8
- spec.authors = ["Coding Ways"]
9
- spec.email = ["info@codingways.com"]
8
+ spec.authors = ['Coding Ways']
9
+ spec.email = ['info@codingways.com']
10
10
 
11
- spec.summary = "Rails gem for PostgreSQL Row Level Security (RLS) multi-tenant applications"
12
- spec.description = "A comprehensive gem that provides RLS-based multi-tenancy for Rails applications using PostgreSQL, including automatic tenant context switching, security validations, and migration helpers."
13
- spec.homepage = "https://github.com/codingways/rls_multi_tenant"
14
- spec.license = "MIT"
15
- spec.required_ruby_version = ">= 3.0.0"
11
+ spec.summary = 'Rails gem for PostgreSQL Row Level Security (RLS) multi-tenant applications'
12
+ spec.description = 'A comprehensive gem that provides RLS-based multi-tenancy for Rails applications using PostgreSQL, including automatic tenant context switching, security validations, and migration helpers.'
13
+ spec.homepage = 'https://github.com/codingways/rls_multi_tenant'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = '>= 3.0.0'
16
16
 
17
- spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = "https://github.com/codingways/rls_multi_tenant"
19
- spec.metadata["changelog_uri"] = "https://github.com/codingways/rls_multi_tenant/blob/main/CHANGELOG.md"
20
- spec.metadata["bug_tracker_uri"] = "https://github.com/codingways/rls_multi_tenant/issues"
21
- spec.metadata["documentation_uri"] = "https://github.com/codingways/rls_multi_tenant#readme"
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/codingways/rls_multi_tenant'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/codingways/rls_multi_tenant/blob/main/CHANGELOG.md'
20
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/codingways/rls_multi_tenant/issues'
21
+ spec.metadata['documentation_uri'] = 'https://github.com/codingways/rls_multi_tenant#readme'
22
+ spec.metadata['rubygems_mfa_required'] = 'true'
22
23
 
23
24
  # Specify which files should be added to the gem when it is released.
24
25
  spec.files = Dir.chdir(__dir__) do
@@ -27,20 +28,20 @@ Gem::Specification.new do |spec|
27
28
  f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
28
29
  end
29
30
  end
30
- spec.bindir = "exe"
31
+ spec.bindir = 'exe'
31
32
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
- spec.require_paths = ["lib"]
33
+ spec.require_paths = ['lib']
33
34
 
34
35
  # Dependencies
35
- spec.add_dependency "rails", ">= 6.0", "< 9.0"
36
- spec.add_dependency "pg", ">= 1.0", "< 3.0"
36
+ spec.add_dependency 'pg', '>= 1.0', '< 3.0'
37
+ spec.add_dependency 'rails', '>= 6.0', '< 9.0'
37
38
 
38
39
  # Development dependencies
39
- spec.add_development_dependency "rspec-rails", "~> 6.0"
40
- spec.add_development_dependency "rubocop", "~> 1.50"
41
- spec.add_development_dependency "rubocop-rails", "~> 2.20"
42
- spec.add_development_dependency "rubocop-rspec", "~> 2.20"
43
- spec.add_development_dependency "simplecov", "~> 0.22"
44
- spec.add_development_dependency "generator_spec", "~> 0.9"
45
- spec.add_development_dependency "bundler-audit", "~> 0.9"
40
+ spec.add_development_dependency 'bundler-audit', '~> 0.9'
41
+ spec.add_development_dependency 'generator_spec', '~> 0.9'
42
+ spec.add_development_dependency 'rspec-rails', '~> 6.1.0'
43
+ spec.add_development_dependency 'rubocop', '~> 1.80.0'
44
+ spec.add_development_dependency 'rubocop-rails', '~> 2.33'
45
+ spec.add_development_dependency 'rubocop-rspec', '~> 3.7'
46
+ spec.add_development_dependency 'simplecov', '~> 0.22'
46
47
  end