activerecord-cipherstash-pg-adapter 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 434fd7249bd70c44846fa14a0d1ece70776c0ef79ee4632ca39f15b6036e49dd
4
- data.tar.gz: b54aa489eb0053e8a065dc7d938cc35f7ced39b3c0cd06d41b13a55b7494c080
3
+ metadata.gz: f49b439e9bfe2874fc67bf0f4064ba66a3659a9e67b207e156ddb2b3cf8c5bb2
4
+ data.tar.gz: 02347f9e3efe1f15da8dd6c11e8745c424d7dd9f65b493640ea57f41370dd7b3
5
5
  SHA512:
6
- metadata.gz: 7ad1fb8b78eb0ca2bf4796c1096dfbc58ab2efa4b435d9f5f70db0dbe0a7fbcf5399944ea969a75da2754d04116930061fbadb2e95afa61b014c622b26214e25
7
- data.tar.gz: b8b577f348e757cb2c0da27096d3475f14dbe9d9a555d80d8e1e8e25fdd7238713509167abbeaaff4129d5b939dfc7df4d3f49cd5ab992a92975eea54e387646
6
+ metadata.gz: 703fb309bb186e2350856b0f5fabae1e373685e13552afb53cfb04fb2630866f271cbbf2efebe305e9a06bc5f62dbc3808379d2037286e4af42a9052bae8185a
7
+ data.tar.gz: 5885728f591239c6f6893dbd9f2b19bb75976bd01237fedb24a9fcf42804ce78315b5da1831af0cf35961ea6210c072fc28c520bfbc703157cd163dc369a9c60
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.6.0] - 2023-04-20
4
+
5
+ ### Changed
6
+
7
+ - Updated the adapter name constant to be the same as the ActiveRecord PostgreSQL adapter.
8
+
9
+ ### Fixed
10
+
11
+ - Logic around Rails credentials taking precedence over local env vars.
12
+
13
+ ## [0.5.0] - 2023-04-19
14
+
15
+ ### Added
16
+
17
+ - Support for Rails credentials to set the required driver environment variables.
18
+
19
+ ### Fixed
20
+
21
+ - Hide internal CipherStash columns.
22
+
3
23
  ## [0.4.0] - 2023-04-06
4
24
 
5
25
  ### Changed
@@ -3,6 +3,7 @@
3
3
  require "active_support/core_ext/object/try"
4
4
  require "active_record/connection_adapters/abstract_adapter"
5
5
  require "active_record/connection_adapters/statement_pool"
6
+ require "active_record/connection_adapters/cipherstash_column_mapper"
6
7
 
7
8
  require_relative "./cipherstash_pg/column"
8
9
  require_relative "./cipherstash_pg/database_statements"
@@ -52,7 +53,7 @@ module ActiveRecord
52
53
 
53
54
  module ConnectionAdapters
54
55
  class CipherStashPGAdapter < AbstractAdapter
55
- ADAPTER_NAME = "CipherStash PostgreSQL"
56
+ ADAPTER_NAME = "PostgreSQL"
56
57
 
57
58
  class << self
58
59
  def new_client(conn_params)
@@ -805,19 +806,31 @@ module ActiveRecord
805
806
  # Query implementation notes:
806
807
  # - format_type includes the column size constraint, e.g. varchar(50)
807
808
  # - ::regclass is a function that gives the id for a table name
809
+ #
810
+ # NOTE: this method has been modified from the original version that was lifted
811
+ # from ActiveRecord's PostgreSQL adapter. The query is untouched, but
812
+ # `CipherStashColumnMapper` is custom. See the docs in `CipherStashColumnMapper`
813
+ # for details.
814
+ #
815
+ # Original source:
816
+ # https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L1009-L1041
808
817
  def column_definitions(table_name)
809
- query(<<~SQL, "SCHEMA")
810
- SELECT a.attname, format_type(a.atttypid, a.atttypmod),
811
- pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
812
- c.collname, col_description(a.attrelid, a.attnum) AS comment
813
- FROM pg_attribute a
814
- LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
815
- LEFT JOIN pg_type t ON a.atttypid = t.oid
816
- LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
817
- WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
818
- AND a.attnum > 0 AND NOT a.attisdropped
819
- ORDER BY a.attnum
820
- SQL
818
+ column_definitions =
819
+ query(<<~SQL, "SCHEMA")
820
+ SELECT a.attname, format_type(a.atttypid, a.atttypmod),
821
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
822
+ c.collname, col_description(a.attrelid, a.attnum) AS comment,
823
+ #{supports_virtual_columns? ? 'attgenerated' : quote('')} as attgenerated
824
+ FROM pg_attribute a
825
+ LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
826
+ LEFT JOIN pg_type t ON a.atttypid = t.oid
827
+ LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
828
+ WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
829
+ AND a.attnum > 0 AND NOT a.attisdropped
830
+ ORDER BY a.attnum
831
+ SQL
832
+
833
+ CipherStashColumnMapper.map_column_definitions(column_definitions)
821
834
  end
822
835
 
823
836
  def extract_table_ref_from_insert_sql(sql)
@@ -3,6 +3,7 @@
3
3
  require "active_support/core_ext/object/try"
4
4
  require "active_record/connection_adapters/abstract_adapter"
5
5
  require "active_record/connection_adapters/statement_pool"
6
+ require "active_record/connection_adapters/cipherstash_column_mapper"
6
7
 
7
8
  require_relative "./cipherstash_pg/column"
8
9
  require_relative "./cipherstash_pg/database_statements"
@@ -53,7 +54,7 @@ module ActiveRecord
53
54
 
54
55
  module ConnectionAdapters
55
56
  class CipherStashPGAdapter < AbstractAdapter
56
- ADAPTER_NAME = "CipherStash PostgreSQL"
57
+ ADAPTER_NAME = "PostgreSQL"
57
58
 
58
59
  class << self
59
60
  def new_client(conn_params)
@@ -911,20 +912,31 @@ module ActiveRecord
911
912
  # Query implementation notes:
912
913
  # - format_type includes the column size constraint, e.g. varchar(50)
913
914
  # - ::regclass is a function that gives the id for a table name
915
+ #
916
+ # NOTE: this method has been modified from the original version that was lifted
917
+ # from ActiveRecord's PostgreSQL adapter. The query is untouched, but
918
+ # `CipherStashColumnMapper` is custom. See the docs in `CipherStashColumnMapper`
919
+ # for details.
920
+ #
921
+ # Original source:
922
+ # https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L1009-L1041
914
923
  def column_definitions(table_name)
915
- query(<<~SQL, "SCHEMA")
916
- SELECT a.attname, format_type(a.atttypid, a.atttypmod),
917
- pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
918
- c.collname, col_description(a.attrelid, a.attnum) AS comment,
919
- #{supports_virtual_columns? ? 'attgenerated' : quote('')} as attgenerated
920
- FROM pg_attribute a
921
- LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
922
- LEFT JOIN pg_type t ON a.atttypid = t.oid
923
- LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
924
- WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
925
- AND a.attnum > 0 AND NOT a.attisdropped
926
- ORDER BY a.attnum
927
- SQL
924
+ column_definitions =
925
+ query(<<~SQL, "SCHEMA")
926
+ SELECT a.attname, format_type(a.atttypid, a.atttypmod),
927
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
928
+ c.collname, col_description(a.attrelid, a.attnum) AS comment,
929
+ #{supports_virtual_columns? ? 'attgenerated' : quote('')} as attgenerated
930
+ FROM pg_attribute a
931
+ LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
932
+ LEFT JOIN pg_type t ON a.atttypid = t.oid
933
+ LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
934
+ WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
935
+ AND a.attnum > 0 AND NOT a.attisdropped
936
+ ORDER BY a.attnum
937
+ SQL
938
+
939
+ CipherStashColumnMapper.map_column_definitions(column_definitions)
928
940
  end
929
941
 
930
942
  def extract_table_ref_from_insert_sql(sql)
@@ -0,0 +1,52 @@
1
+ require "set"
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ # A module for mapping CipherStash internal columns to columns that ActiveRecord can work with.
6
+ #
7
+ # @private
8
+ class CipherStashColumnMapper
9
+ ENCRYPTED_INDEX_COLUMN_REGEX = /^__.+_(match|ore|unique)$/
10
+ ENCRYPTED_SOURCE_COLUMN_REGEX = /^__(.+)_encrypted$/
11
+
12
+ class << self
13
+ # Maps the given column definitions by filtering out CipherStash internal columns. This method
14
+ # also adds in plaintext columns if necessary (for example, when using the driver in "encrypted"
15
+ # mode after the original plaintext columns have been dropped).
16
+ def map_column_definitions(column_definitions)
17
+ all_column_names = column_definitions.map(&:first).to_set
18
+
19
+ column_definitions
20
+ .reject { |column_definition| encrypted_index_column?(column_definition) }
21
+ .map { |column_definition| maybe_rename_source_column(column_definition, all_column_names) }
22
+ .reject { |column_definition| encrypted_source_column?(column_definition) }
23
+ end
24
+
25
+ private
26
+
27
+ def encrypted_index_column?(column_definition)
28
+ ENCRYPTED_INDEX_COLUMN_REGEX =~ column_name(column_definition)
29
+ end
30
+
31
+ def encrypted_source_column?(column_definition)
32
+ ENCRYPTED_SOURCE_COLUMN_REGEX =~ column_name(column_definition)
33
+ end
34
+
35
+ def column_name(column_definition)
36
+ column_definition.first
37
+ end
38
+
39
+ def maybe_rename_source_column(column_definition, all_column_names)
40
+ column_name, *rest = column_definition
41
+ match = column_name.match(ENCRYPTED_SOURCE_COLUMN_REGEX)
42
+
43
+ if match && !all_column_names.include?(match.captures.first)
44
+ [match.captures.first, *rest]
45
+ else
46
+ column_definition
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  #
3
3
  # Why the funky filename
4
- # (lib/active_record/connection_adapters/cipherstash_pg_adapter.rb)
4
+ # (lib/active_record/connection_adapters/postgres_cipherstash_adapter.rb)
5
5
  # that doesn't match the gem structure? It's to hook into Rails.
6
6
  #
7
7
  # See this chunk from:
@@ -11,6 +11,33 @@ module ActiveRecord
11
11
  rake_tasks do
12
12
  load "cipherstash_tasks.rake"
13
13
  end
14
+
15
+ initializer "postgres_cipherstash_adapter.configure" do
16
+ if defined?(Rails.application.credentials)
17
+ cs_credentials = Rails.application.credentials.try(:cipherstash)
18
+
19
+ client_id = cs_credentials&.fetch(:client_id, nil)
20
+ client_key = cs_credentials&.fetch(:client_key, nil)
21
+ workspace_id = cs_credentials&.fetch(:workspace_id, nil)
22
+ client_access_key = cs_credentials&.fetch(:client_access_key, nil)
23
+
24
+ unless client_id.nil?
25
+ ENV["CS_CLIENT_ID"] = client_id
26
+ end
27
+
28
+ unless client_key.nil?
29
+ ENV["CS_CLIENT_KEY"] = client_key
30
+ end
31
+
32
+ unless workspace_id.nil?
33
+ ENV["CS_WORKSPACE_ID"] = workspace_id
34
+ end
35
+
36
+ unless client_access_key.nil?
37
+ ENV["CS_CLIENT_ACCESS_KEY"] = client_access_key
38
+ end
39
+ end
40
+ end
14
41
  end
15
42
 
16
43
  # Method to install CipherStash custom ORE types
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ActiveRecord
2
- CIPHERSTASH_PG_ADAPTER_VERSION = "0.4.0"
2
+ CIPHERSTASH_PG_ADAPTER_VERSION = "0.6.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-cipherstash-pg-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robin Howard
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-06 00:00:00.000000000 Z
11
+ date: 2023-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -135,6 +135,7 @@ files:
135
135
  - lib/active_record/connection_adapters/7.0/cipherstash_pg/type_metadata.rb
136
136
  - lib/active_record/connection_adapters/7.0/cipherstash_pg/utils.rb
137
137
  - lib/active_record/connection_adapters/7.0/postgres_cipherstash_adapter.rb
138
+ - lib/active_record/connection_adapters/cipherstash_column_mapper.rb
138
139
  - lib/active_record/connection_adapters/cipherstash_pg/database_extensions.rb
139
140
  - lib/active_record/connection_adapters/cipherstash_pg/database_tasks.rb
140
141
  - lib/active_record/connection_adapters/postgres_cipherstash_adapter.rb
@@ -148,7 +149,7 @@ metadata:
148
149
  homepage_uri: https://github.com/cipherstash/activerecord-cipherstash-pg-adapter
149
150
  source_code_uri: https://github.com/cipherstash/activerecord-cipherstash-pg-adapter.git
150
151
  changelog_uri: https://github.com/cipherstash/activerecord-cipherstash-pg-adapter/blob/main/CHANGELOG.md
151
- post_install_message:
152
+ post_install_message:
152
153
  rdoc_options: []
153
154
  require_paths:
154
155
  - lib
@@ -164,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
165
  version: '0'
165
166
  requirements: []
166
167
  rubygems_version: 3.3.7
167
- signing_key:
168
+ signing_key:
168
169
  specification_version: 4
169
170
  summary: CipherStash PostgreSQL adapter for ActiveRecord.
170
171
  test_files: []