pg_rls 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5296cf19938df79d340f6da931acf0aee13e967720d964ec979773189634c155
4
- data.tar.gz: ebf0278848a707e692198346dc734e8da9024c3b5e1325da760c4d7f7cdc30f2
3
+ metadata.gz: 1bead0b6e11e78f3aebe2c843c8cceaa178664bad5755f4f6858893f0232979c
4
+ data.tar.gz: c91f321f93c5d79aebccf09413f98580cc64104a32e350f874dce1c170c1c6a8
5
5
  SHA512:
6
- metadata.gz: 97465ed5ea998a4c6e6ae39aae82d08ae0663733ef0f442d4716431adb607f13b96fb44139d5c5be83696cbb044cfa778a918a74aa842906ae798869f0fb3145
7
- data.tar.gz: c85948bfbcd16f610b2095f2900fee54d3abc3cd27b581eb282144e4b444341a0cfb50c2b1ef98e8cd9d395c22e6218d81fa19d2281df956bb3d8e5cf4e39204
6
+ metadata.gz: 3baca7c6f170a2ffe07538413374230163d6a907372186bfe3bbab61b5fe8f7eb32402bd4781ef6f0a35b0f8f80e6b6dd2df1115f807810955a606b899f13eb9
7
+ data.tar.gz: '00866118e32d11bacc622119a0bbd02880c1f231b59fed3f65b58b176b29b96f0a38469b4071ebc3f4d32c3261a5090153683bc48512a556f48f4edbf72d09b3'
data/.rubocop.yml CHANGED
@@ -24,3 +24,6 @@ Security/MarshalLoad:
24
24
  Metrics/ModuleLength:
25
25
  Exclude:
26
26
  - 'lib/pg_rls.rb'
27
+ Naming/AccessorMethodName:
28
+ Exclude:
29
+ - 'lib/pg_rls/tenant.rb'
data/Gemfile.lock CHANGED
@@ -1,8 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pg_rls (0.1.2)
5
- bundler (~> 2.2)
4
+ pg_rls (0.1.4)
6
5
 
7
6
  GEM
8
7
  remote: https://rubygems.org/
@@ -284,4 +283,4 @@ RUBY VERSION
284
283
  ruby 3.2.2p53
285
284
 
286
285
  BUNDLED WITH
287
- 2.3.15
286
+ 2.4.22
@@ -16,6 +16,9 @@ module PgRls
16
16
  end
17
17
  super
18
18
  end
19
+ ENVIRONMENT_LINE = 'Rails.application.initialize!'
20
+ ENVIRONMENT_PATH = 'config/environment.rb'
21
+
19
22
  APPLICATION_LINE = 'class Application < Rails::Application'
20
23
  APPLICATION_PATH = 'config/application.rb'
21
24
 
@@ -50,6 +53,14 @@ module PgRls
50
53
  template 'pg_rls.rb.tt', 'config/initializers/pg_rls.rb'
51
54
  end
52
55
 
56
+ def inject_include_to_environment
57
+ return if environment_already_included?
58
+
59
+ gsub_file(ENVIRONMENT_PATH, /(#{Regexp.escape(ENVIRONMENT_LINE)})/mio) do |match|
60
+ "require_relative 'initializers/pg_rls'\n#{match}"
61
+ end
62
+ end
63
+
53
64
  def inject_include_to_application
54
65
  return if aplication_already_included?
55
66
 
@@ -74,6 +85,10 @@ module PgRls
74
85
  File.readlines(APPLICATION_PATH).grep(/config.active_record.schema_format = :sql/).any?
75
86
  end
76
87
 
88
+ def environment_already_included?
89
+ File.readlines(ENVIRONMENT_PATH).grep(%r{require_relative 'initializers/pg_rls'}).any?
90
+ end
91
+
77
92
  def initialize_error_text
78
93
  <<~ERROR
79
94
  TO DO
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgRls
4
+ module Admin
5
+ module ActiveRecord
6
+ module Migrator
7
+ def initialize(*args)
8
+ PgRls.instance_variable_set(:@as_db_admin, true)
9
+ super
10
+ end
11
+ end
12
+
13
+ module Tasks
14
+ module DatabaseTasks
15
+ def resolve_configuration(configuration)
16
+ PgRls.instance_variable_set(:@as_db_admin, true) unless PgRls.as_db_admin?
17
+ super
18
+ end
19
+
20
+ def migration_class
21
+ PgRls.instance_variable_set(:@as_db_admin, true) unless PgRls.as_db_admin?
22
+ super
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -13,6 +13,8 @@ module ActiveRecord
13
13
  end
14
14
 
15
15
  def configuration_hash
16
+ reset_pg_rls_configuration if db_changed?
17
+
16
18
  return admin_configuration_hash if PgRls.as_db_admin?
17
19
 
18
20
  rls_configuration_hash
@@ -28,6 +30,15 @@ module ActiveRecord
28
30
  config[:password] = PgRls.password
29
31
  end.freeze
30
32
  end
33
+
34
+ def db_changed?
35
+ admin_configuration_hash[:database] != @configuration_hash[:database]
36
+ end
37
+
38
+ def reset_pg_rls_configuration
39
+ @rls_configuration_hash = nil
40
+ @admin_configuration_hash = nil
41
+ end
31
42
  end
32
43
  end
33
44
  end
@@ -23,130 +23,19 @@ namespace :db do
23
23
  include PgRls::Schema::UpStatements
24
24
 
25
25
  override_task grant_usage: :load_config do
26
- PgRls.admin_tasks_execute do
27
- create_rls_user
28
- end
29
- end
30
-
31
- override_task create: :load_config do
32
- PgRls.admin_tasks_execute do
33
- Rake::Task['db:create:original'].invoke
34
- end
35
- end
36
-
37
- override_task drop: :load_config do
38
- PgRls.admin_tasks_execute do
39
- Rake::Task['db:drop:original'].invoke
40
- end
41
- end
42
-
43
- override_task migrate: :load_config do
44
- PgRls.admin_tasks_execute do
45
- Rake::Task['db:migrate:original'].invoke
46
- end
47
- end
48
-
49
- override_task rollback: :load_config do
50
- PgRls.admin_tasks_execute do
51
- Rake::Task['db:rollback:original'].invoke
52
- end
53
- end
54
-
55
- override_task prepare: :load_config do
56
- PgRls.admin_tasks_execute do
57
- Rake::Task['db:prepare:original'].invoke
58
- end
59
- end
60
-
61
- override_task setup: :load_config do
62
- PgRls.admin_tasks_execute do
63
- Rake::Task['db:setup:original'].invoke
64
- end
65
- end
66
-
67
- override_task prepare: :load_config do
68
- PgRls.admin_tasks_execute do
69
- Rake::Task['db:reset:original'].invoke
70
- end
71
- end
72
-
73
- override_task purge: :load_config do
74
- PgRls.admin_tasks_execute do
75
- Rake::Task['db:purge:original'].invoke
76
- end
26
+ PgRls.instance_variable_set(:@as_db_admin, true)
27
+ create_rls_user
77
28
  end
78
29
 
79
30
  override_task abort_if_pending_migrations: :load_config do
80
- PgRls.admin_tasks_execute do
81
- Rake::Task['db:abort_if_pending_migrations:original'].invoke
82
- end
31
+ PgRls.instance_variable_set(:@as_db_admin, true)
32
+ Rake::Task['db:abort_if_pending_migrations:original'].invoke
83
33
  end
84
34
 
85
35
  namespace :test do
86
36
  override_task grant_usage: :load_config do
87
- PgRls.admin_tasks_execute do
88
- create_rls_user
89
- end
90
- end
91
-
92
- override_task create: :load_config do
93
- PgRls.admin_tasks_execute do
94
- Rake::Task['db:test:create:original'].invoke
95
- end
96
- end
97
-
98
- override_task drop: :load_config do
99
- PgRls.admin_tasks_execute do
100
- Rake::Task['db:test:drop:original'].invoke
101
- end
102
- end
103
-
104
- override_task prepare: :load_config do
105
- PgRls.admin_tasks_execute do
106
- Rake::Task['db:test:prepare:original'].invoke
107
- end
108
- end
109
-
110
- override_task setup: :load_config do
111
- PgRls.admin_tasks_execute do
112
- Rake::Task['db:test:setup:original'].invoke
113
- end
114
- end
115
-
116
- override_task purge: :load_config do
117
- PgRls.admin_tasks_execute do
118
- Rake::Task['db:test:purge:original'].invoke
119
- end
120
- end
121
-
122
- override_task load_schema: :load_config do
123
- PgRls.admin_tasks_execute do
124
- Rake::Task['db:test:load_schema:original'].invoke
125
- end
126
- end
127
- end
128
-
129
- namespace :environment do
130
- override_task set: :load_config do
131
- PgRls.admin_tasks_execute do
132
- Rake::Task['db:environment:set:original'].invoke
133
- end
134
- end
135
- end
136
-
137
- namespace :schema do
138
- override_task load: :load_config do
139
- PgRls.admin_tasks_execute do
140
- Rake::Task['db:schema:load:original'].invoke
141
- Rake::Task['db:grant_usage'].invoke
142
- Rake::Task['db:test:grant_usage'].invoke
143
- end
144
- end
145
-
146
- override_task dump: :load_config do
147
- PgRls.admin_tasks_execute do
148
- Rake::Task['db:schema:dump:original'].invoke
149
- end
37
+ PgRls.instance_variable_set(:@as_db_admin, true)
38
+ create_rls_user
150
39
  end
151
40
  end
152
41
  end
@@ -2,4 +2,3 @@
2
2
 
3
3
  require_relative 'rake_only_error'
4
4
  require_relative 'tenant_not_found'
5
- require_relative 'admin_username'
@@ -28,19 +28,5 @@ module PgRls
28
28
  session[:_tenant] = nil
29
29
  raise PgRls::Errors::TenantNotFound, 'No tenant was found'
30
30
  end
31
-
32
- def switch_tenant_by_resource!(resource = nil)
33
- Tenant.switch!(resource)
34
- session[:_tenant] = resource
35
- rescue PgRls::Errors::TenantNotFound
36
- Tenant.switch(session[:_tenant])
37
- rescue NoMethodError
38
- session[:tenant] = nil
39
- redirect_to '/'
40
- end
41
-
42
- def tenant_match_session_cookies?
43
- session[:_tenant] == request.subdomain
44
- end
45
31
  end
46
32
  end
data/lib/pg_rls/tenant.rb CHANGED
@@ -4,15 +4,9 @@ module PgRls
4
4
  # Tenant Controller
5
5
  module Tenant
6
6
  class << self
7
- attr_reader :tenant
8
-
9
7
  def switch(resource)
10
- tenant = switch_tenant!(resource)
11
-
12
- "RLS changed to '#{tenant.id}'"
13
- rescue StandardError => e
14
- Rails.logger.info('connection was not made')
15
- Rails.logger.info(e)
8
+ switch!(resource)
9
+ rescue PgRls::Errors::TenantNotFound
16
10
  nil
17
11
  end
18
12
 
@@ -20,17 +14,19 @@ module PgRls
20
14
  tenant = switch_tenant!(resource)
21
15
 
22
16
  "RLS changed to '#{tenant.id}'"
23
- rescue StandardError => e
17
+ rescue StandardError
24
18
  Rails.logger.info('connection was not made')
25
- raise e
19
+ raise PgRls::Errors::TenantNotFound
26
20
  end
27
21
 
28
22
  def with_tenant!(resource)
29
- tenant = switch_tenant!(resource)
23
+ PgRls.main_model.connection_pool.with_connection do
24
+ tenant = switch_tenant!(resource)
30
25
 
31
- yield(tenant) if block_given?
32
- ensure
33
- reset_rls! unless PgRls.test_inline_tenant == true
26
+ yield(tenant).presence if block_given?
27
+ ensure
28
+ reset_rls! unless PgRls.test_inline_tenant == true
29
+ end
34
30
  end
35
31
 
36
32
  def fetch
@@ -39,19 +35,15 @@ module PgRls
39
35
  nil
40
36
  end
41
37
 
42
- def tenant!
43
- @tenant ||= PgRls.main_model.find_by!(
38
+ def fetch!
39
+ PgRls.main_model.find_by!(
44
40
  tenant_id: PgRls.connection_class.connection.execute(
45
41
  "SELECT current_setting('rls.tenant_id')"
46
42
  ).getvalue(0, 0)
47
43
  )
48
44
  end
49
- alias fetch! tenant!
50
45
 
51
46
  def reset_rls!
52
- return if @tenant.blank?
53
-
54
- @tenant = nil
55
47
  PgRls.execute_rls_in_shards do |connection_class|
56
48
  connection_class.transaction do
57
49
  connection_class.connection.execute('RESET rls.tenant_id')
@@ -61,6 +53,15 @@ module PgRls
61
53
  nil
62
54
  end
63
55
 
56
+ def set_rls!(tenant_id)
57
+ PgRls.execute_rls_in_shards do |connection_class|
58
+ connection_class.transaction do
59
+ connection_class.connection.execute(format('SET rls.tenant_id = %s',
60
+ connection_class.connection.quote(tenant_id)))
61
+ end
62
+ end
63
+ end
64
+
64
65
  private
65
66
 
66
67
  def switch_tenant!(resource)
@@ -68,31 +69,29 @@ module PgRls
68
69
  PgRls.main_model.ignored_columns = []
69
70
  # rubocop: enable Rails/IgnoredColumnsAssignment
70
71
 
71
- find_tenant(resource)
72
+ tenant = find_tenant(resource)
72
73
 
73
- PgRls.execute_rls_in_shards do |connection_class|
74
- connection_class.transaction do
75
- connection_class.connection.execute(format('SET rls.tenant_id = %s',
76
- connection_class.connection.quote(tenant.tenant_id)))
77
- end
78
- end
74
+ set_rls!(tenant.tenant_id)
79
75
 
80
76
  tenant
77
+ rescue NoMethodError
78
+ raise PgRls::Errors::TenantNotFound
81
79
  end
82
80
 
83
81
  def find_tenant(resource)
84
- raise PgRls::Errors::AdminUsername if PgRls.admin_connection?
85
-
86
82
  reset_rls!
87
83
 
84
+ tenant = nil
85
+
88
86
  PgRls.search_methods.each do |method|
89
- break if @tenant.present?
87
+ break if tenant.present?
90
88
 
91
- @method = method
92
- @tenant = find_tenant_by_method(resource, method)
89
+ tenant = find_tenant_by_method(resource, method)
93
90
  end
94
91
 
95
92
  raise PgRls::Errors::TenantNotFound if tenant.blank?
93
+
94
+ tenant
96
95
  end
97
96
 
98
97
  def find_tenant_by_method(resource, method)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgRls
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.4'
5
5
  end
data/lib/pg_rls.rb CHANGED
@@ -6,27 +6,24 @@ require_relative 'pg_rls/version'
6
6
  require_relative 'pg_rls/database/prepared'
7
7
  require_relative 'pg_rls/schema/statements'
8
8
  require_relative 'pg_rls/database/configurations'
9
+ require_relative 'pg_rls/database/admin_statements'
9
10
  require_relative 'pg_rls/tenant'
10
11
  require_relative 'pg_rls/multi_tenancy'
11
12
  require_relative 'pg_rls/railtie' if defined?(Rails)
12
13
  require_relative 'pg_rls/errors/index'
13
14
 
15
+ ActiveRecord::Migrator.prepend PgRls::Admin::ActiveRecord::Migrator
16
+ ActiveRecord::Tasks::DatabaseTasks.prepend PgRls::Admin::ActiveRecord::Tasks::DatabaseTasks
17
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.include PgRls::Schema::Statements
14
18
  # PostgreSQL Row Level Security
15
19
  module PgRls
16
20
  class Error < StandardError; end
17
- SECURE_USERNAME = 'app_user'
18
-
19
21
  class << self
20
22
  extend Forwardable
21
23
 
22
24
  WRITER_METHODS = %i[table_name class_name search_methods].freeze
23
- READER_METHODS = %i[
24
- connection_class execute table_name class_name search_methods
25
- ].freeze
26
- DELEGATORS_METHODS = %i[
27
- connection_class execute table_name search_methods
28
- class_name main_model
29
- ].freeze
25
+ READER_METHODS = %i[connection_class execute table_name class_name search_methods].freeze
26
+ DELEGATORS_METHODS = %i[connection_class execute table_name search_methods class_name main_model].freeze
30
27
 
31
28
  attr_writer(*WRITER_METHODS)
32
29
  attr_reader(*READER_METHODS)
@@ -34,7 +31,6 @@ module PgRls
34
31
  def_delegators(*DELEGATORS_METHODS)
35
32
 
36
33
  def setup
37
- ActiveRecord::ConnectionAdapters::AbstractAdapter.include PgRls::Schema::Statements
38
34
  ActiveRecord::Base.ignored_columns += %w[tenant_id]
39
35
 
40
36
  yield self
@@ -44,32 +40,11 @@ module PgRls
44
40
  @connection_class ||= ActiveRecord::Base
45
41
  end
46
42
 
47
- def rake_tasks?
48
- Rake.application.top_level_tasks.present? || ARGV.any? { |arg| arg =~ /rake|dsl/ }
49
- rescue NoMethodError
50
- false
51
- end
52
-
53
- def admin_tasks_execute
54
- raise PgRls::Errors::RakeOnlyError unless rake_tasks?
55
-
56
- self.as_db_admin = true
57
-
58
- yield
59
- ensure
60
- self.as_db_admin = false
61
- end
62
-
63
43
  def admin_execute(query = nil, &)
64
- current_tenant = PgRls::Tenant.fetch
65
- establish_new_connection!(admin: true)
66
-
67
- return ensure_block_execution(&) if block_given?
68
-
69
- execute(query)
44
+ current_tenant, reset_rls_connection = establish_admin_connection
45
+ execute_query_or_block(query, &)
70
46
  ensure
71
- establish_new_connection!
72
- PgRls::Tenant.switch(current_tenant) if current_tenant.present?
47
+ reset_connection_if_needed(current_tenant, reset_rls_connection)
73
48
  end
74
49
 
75
50
  def establish_new_connection!(admin: false)
@@ -142,9 +117,37 @@ module PgRls
142
117
  establish_new_connection!(admin: true) if reset_connection
143
118
  end
144
119
 
120
+ def establish_admin_connection
121
+ reset_rls_connection = false
122
+ current_tenant = nil
123
+
124
+ unless admin_connection?
125
+ reset_rls_connection = true
126
+ current_tenant = PgRls::Tenant.fetch
127
+ establish_new_connection!(admin: true)
128
+ end
129
+
130
+ [current_tenant, reset_rls_connection]
131
+ end
132
+
145
133
  def ensure_block_execution(*, **)
146
134
  yield(*, **).presence
147
135
  end
136
+
137
+ def execute_query_or_block(query = nil, &)
138
+ if block_given?
139
+ ensure_block_execution(&)
140
+ else
141
+ execute(query)
142
+ end
143
+ end
144
+
145
+ def reset_connection_if_needed(current_tenant, reset_rls_connection)
146
+ return unless reset_rls_connection
147
+
148
+ establish_new_connection!
149
+ PgRls::Tenant.switch(current_tenant) if current_tenant.present?
150
+ end
148
151
  end
149
152
 
150
153
  mattr_accessor :table_name
metadata CHANGED
@@ -1,34 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_rls
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Laloush
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-14 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.2'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.2'
11
+ date: 2023-11-13 00:00:00.000000000 Z
12
+ dependencies: []
27
13
  description: |2
28
14
  This gem will help you to integrate PostgreSQL RLS to help you develop a great multitenancy application
29
15
  checkout the repository at https://github.com/Dandush03/pg_rls
30
16
  email:
31
- - daniel.laloush@influitive.com
17
+ - d.laloush@outlook.com
32
18
  executables: []
33
19
  extensions: []
34
20
  extra_rdoc_files: []
@@ -61,10 +47,10 @@ files:
61
47
  - lib/generators/templates/pg_rls.rb.tt
62
48
  - lib/pg_rls.rb
63
49
  - lib/pg_rls/Rakefile
50
+ - lib/pg_rls/database/admin_statements.rb
64
51
  - lib/pg_rls/database/configurations.rb
65
52
  - lib/pg_rls/database/prepared.rb
66
53
  - lib/pg_rls/database/tasks/admin_database.rake
67
- - lib/pg_rls/errors/admin_username.rb
68
54
  - lib/pg_rls/errors/index.rb
69
55
  - lib/pg_rls/errors/rake_only_error.rb
70
56
  - lib/pg_rls/errors/tenant_not_found.rb
@@ -85,7 +71,7 @@ licenses:
85
71
  - MIT
86
72
  metadata:
87
73
  rubygems_mfa_required: 'true'
88
- post_install_message:
74
+ post_install_message:
89
75
  rdoc_options: []
90
76
  require_paths:
91
77
  - lib
@@ -100,8 +86,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
86
  - !ruby/object:Gem::Version
101
87
  version: '0'
102
88
  requirements: []
103
- rubygems_version: 3.4.19
104
- signing_key:
89
+ rubygems_version: 3.4.22
90
+ signing_key:
105
91
  specification_version: 4
106
92
  summary: Write a short summary, because RubyGems requires one.
107
93
  test_files: []
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PgRls
4
- module Errors
5
- class AdminUsername < StandardError
6
- def initialize(msg = nil)
7
- msg ||= 'Cannot set or reset tenant for admin user'
8
- super(msg)
9
- end
10
- end
11
- end
12
- end