masking 1.1.0 → 1.1.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +9 -4
  3. data/.github/workflows/acceptance_test_mariadb.yml +57 -1
  4. data/.github/workflows/acceptance_test_mysql.yml +1 -1
  5. data/.rubocop.yml +7 -1
  6. data/.rubocop_todo.yml +105 -0
  7. data/.ruby-version +1 -1
  8. data/CHANGELOG.md +10 -0
  9. data/Dockerfile +3 -1
  10. data/Gemfile +20 -0
  11. data/Gemfile.lock +67 -51
  12. data/README.md +18 -8
  13. data/acceptance/expected_query_result.txt +36 -30
  14. data/acceptance/import_dumpfile.sql +3 -1
  15. data/acceptance/masking.yml +2 -0
  16. data/acceptance/run_test.sh +1 -1
  17. data/docker-compose/mariadb1010.yml +17 -0
  18. data/docker-compose/mariadb1011.yml +17 -0
  19. data/docker-compose/mariadb105.yml +17 -0
  20. data/docker-compose/mariadb106.yml +17 -0
  21. data/docker-compose/mariadb107.yml +17 -0
  22. data/docker-compose/mariadb108.yml +17 -0
  23. data/docker-compose/mariadb109.yml +17 -0
  24. data/lib/masking/cli/error_message.rb +1 -1
  25. data/lib/masking/config/target_columns/column.rb +19 -5
  26. data/lib/masking/config/target_columns/method/string_binary_distinctor.rb +3 -3
  27. data/lib/masking/config/target_columns/method/type/base.rb +25 -0
  28. data/lib/masking/config/target_columns/method/type/binary.rb +19 -0
  29. data/lib/masking/config/target_columns/method/type/boolean.rb +27 -0
  30. data/lib/masking/config/target_columns/method/type/date.rb +28 -0
  31. data/lib/masking/config/target_columns/method/type/extension/ignore_null.rb +24 -0
  32. data/lib/masking/config/target_columns/method/type/float.rb +19 -0
  33. data/lib/masking/config/target_columns/method/type/integer.rb +19 -0
  34. data/lib/masking/config/target_columns/method/{null.rb → type/null.rb} +5 -5
  35. data/lib/masking/config/target_columns/method/type/string.rb +37 -0
  36. data/lib/masking/config/target_columns/method/type/time.rb +26 -0
  37. data/lib/masking/config/target_columns/method.rb +14 -10
  38. data/lib/masking/insert_statement/sql_builder.rb +2 -2
  39. data/lib/masking/insert_statement.rb +1 -1
  40. data/lib/masking/sql_dump_line.rb +1 -0
  41. data/lib/masking/version.rb +1 -1
  42. data/masking.gemspec +1 -18
  43. metadata +24 -181
  44. data/lib/masking/config/target_columns/method/binary.rb +0 -23
  45. data/lib/masking/config/target_columns/method/boolean.rb +0 -29
  46. data/lib/masking/config/target_columns/method/date.rb +0 -30
  47. data/lib/masking/config/target_columns/method/float.rb +0 -23
  48. data/lib/masking/config/target_columns/method/integer.rb +0 -23
  49. data/lib/masking/config/target_columns/method/string.rb +0 -33
  50. data/lib/masking/config/target_columns/method/time.rb +0 -28
@@ -0,0 +1,17 @@
1
+ version: '3.7'
2
+
3
+ services:
4
+ app:
5
+ build:
6
+ target: with-mysql-client
7
+ depends_on:
8
+ - mariadb1011
9
+ entrypoint: docker-compose/wait-for-mysql.sh mariadb1011
10
+
11
+ mariadb1011:
12
+ image: mariadb:10.11
13
+ environment:
14
+ MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
15
+ MYSQL_USER: mysqluser
16
+ MYSQL_PASSWORD: password
17
+ MYSQL_DATABASE: mydb
@@ -0,0 +1,17 @@
1
+ version: '3.7'
2
+
3
+ services:
4
+ app:
5
+ build:
6
+ target: with-mysql-client
7
+ depends_on:
8
+ - mariadb105
9
+ entrypoint: docker-compose/wait-for-mysql.sh mariadb105
10
+
11
+ mariadb105:
12
+ image: mariadb:10.5
13
+ environment:
14
+ MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
15
+ MYSQL_USER: mysqluser
16
+ MYSQL_PASSWORD: password
17
+ MYSQL_DATABASE: mydb
@@ -0,0 +1,17 @@
1
+ version: '3.7'
2
+
3
+ services:
4
+ app:
5
+ build:
6
+ target: with-mysql-client
7
+ depends_on:
8
+ - mariadb106
9
+ entrypoint: docker-compose/wait-for-mysql.sh mariadb106
10
+
11
+ mariadb106:
12
+ image: mariadb:10.6
13
+ environment:
14
+ MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
15
+ MYSQL_USER: mysqluser
16
+ MYSQL_PASSWORD: password
17
+ MYSQL_DATABASE: mydb
@@ -0,0 +1,17 @@
1
+ version: '3.7'
2
+
3
+ services:
4
+ app:
5
+ build:
6
+ target: with-mysql-client
7
+ depends_on:
8
+ - mariadb107
9
+ entrypoint: docker-compose/wait-for-mysql.sh mariadb107
10
+
11
+ mariadb107:
12
+ image: mariadb:10.7
13
+ environment:
14
+ MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
15
+ MYSQL_USER: mysqluser
16
+ MYSQL_PASSWORD: password
17
+ MYSQL_DATABASE: mydb
@@ -0,0 +1,17 @@
1
+ version: '3.7'
2
+
3
+ services:
4
+ app:
5
+ build:
6
+ target: with-mysql-client
7
+ depends_on:
8
+ - mariadb108
9
+ entrypoint: docker-compose/wait-for-mysql.sh mariadb108
10
+
11
+ mariadb108:
12
+ image: mariadb:10.8
13
+ environment:
14
+ MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
15
+ MYSQL_USER: mysqluser
16
+ MYSQL_PASSWORD: password
17
+ MYSQL_DATABASE: mydb
@@ -0,0 +1,17 @@
1
+ version: '3.7'
2
+
3
+ services:
4
+ app:
5
+ build:
6
+ target: with-mysql-client
7
+ depends_on:
8
+ - mariadb109
9
+ entrypoint: docker-compose/wait-for-mysql.sh mariadb109
10
+
11
+ mariadb109:
12
+ image: mariadb:10.9
13
+ environment:
14
+ MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
15
+ MYSQL_USER: mysqluser
16
+ MYSQL_PASSWORD: password
17
+ MYSQL_DATABASE: mydb
@@ -29,7 +29,7 @@ module Masking
29
29
  ERB.new(
30
30
  error_messages.fetch(error_class.to_s)
31
31
  ).result(
32
- OpenStruct.new(keyword_args).instance_eval { binding }
32
+ OpenStruct.new(keyword_args).instance_eval { binding } # rubocop:disable Style/OpenStructUse
33
33
  )
34
34
  end
35
35
  end
@@ -6,22 +6,36 @@ module Masking
6
6
  class Config
7
7
  class TargetColumns
8
8
  class Column
9
- attr_reader :name, :table_name, :method_value, :method
9
+ attr_reader :table_name, :method_value, :method
10
10
 
11
11
  def initialize(name, table_name:, method_value:)
12
12
  raise ColumnNameIsNil if name.nil?
13
13
 
14
- @name = name.to_sym
15
- @table_name = table_name.to_sym
16
- @method_value = method_value
17
- @method = Method.new(method_value)
14
+ @original_name = name.to_sym
15
+ @table_name = table_name.to_sym
16
+ @method_value = method_value
17
+ @method = Method.new(method_value, ignore_null: ignore_null?)
18
18
  end
19
19
 
20
20
  def ==(other)
21
21
  name == other.name && table_name == other.table_name && method_value == other.method_value
22
22
  end
23
23
 
24
+ def name
25
+ @name ||= ignore_null? ? original_name.to_s.chomp(IGNORE_NULL_SUFFIX).to_sym : original_name
26
+ end
27
+
28
+ def ignore_null?
29
+ @ignore_null ||= original_name.to_s.end_with?(IGNORE_NULL_SUFFIX)
30
+ end
31
+
24
32
  class ColumnNameIsNil < StandardError; end
33
+
34
+ private
35
+
36
+ attr_reader :original_name
37
+
38
+ IGNORE_NULL_SUFFIX = '?'
25
39
  end
26
40
  end
27
41
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'masking/config/target_columns/method/binary'
4
- require 'masking/config/target_columns/method/string'
3
+ require 'masking/config/target_columns/method/type/binary'
4
+ require 'masking/config/target_columns/method/type/string'
5
5
 
6
6
  module Masking
7
7
  class Config
@@ -10,7 +10,7 @@ module Masking
10
10
  module StringBinaryDistinctor
11
11
  class << self
12
12
  def new(value)
13
- binary?(value) ? Binary.new(value) : String.new(value)
13
+ binary?(value) ? Type::Binary.new(value) : Type::String.new(value)
14
14
  end
15
15
 
16
16
  private
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Masking
4
+ class Config
5
+ class TargetColumns
6
+ class Method
7
+ module Type
8
+ class Base
9
+ def initialize(value)
10
+ @value = value
11
+ end
12
+
13
+ def call(_sql_value)
14
+ raise NotImplementedError
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :value
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'masking/config/target_columns/method/type/base'
4
+
5
+ module Masking
6
+ class Config
7
+ class TargetColumns
8
+ class Method
9
+ module Type
10
+ class Binary < Base
11
+ def call(_sql_value)
12
+ "_binary '#{value}'".b
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'masking/config/target_columns/method/type/base'
4
+
5
+ module Masking
6
+ class Config
7
+ class TargetColumns
8
+ class Method
9
+ module Type
10
+ class Boolean < Base
11
+ def call(_sql_value)
12
+ boolean_format.to_s
13
+ end
14
+
15
+ private
16
+
17
+ # NOTE: 11.1.1 Numeric Type Overview, chapter BOOL, BOOLEAN
18
+ # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html
19
+ def boolean_format
20
+ value ? 1 : 0
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'masking/config/target_columns/method/type/base'
4
+ require 'date'
5
+
6
+ module Masking
7
+ class Config
8
+ class TargetColumns
9
+ class Method
10
+ module Type
11
+ class Date < Base
12
+ def call(_sql_value)
13
+ "'#{date_format}'"
14
+ end
15
+
16
+ private
17
+
18
+ FORMAT = '%Y-%m-%d'
19
+
20
+ def date_format
21
+ value.strftime(FORMAT)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Masking
4
+ class Config
5
+ class TargetColumns
6
+ class Method
7
+ module Type
8
+ module Extension
9
+ module IgnoreNull
10
+ def call(sql_value)
11
+ if sql_value == 'NULL'
12
+ sequence! if respond_to?(:sequence!, true)
13
+ return 'NULL'
14
+ end
15
+
16
+ super
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'masking/config/target_columns/method/type/base'
4
+
5
+ module Masking
6
+ class Config
7
+ class TargetColumns
8
+ class Method
9
+ module Type
10
+ class Float < Base
11
+ def call(_sql_value)
12
+ value.to_s
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'masking/config/target_columns/method/type/base'
4
+
5
+ module Masking
6
+ class Config
7
+ class TargetColumns
8
+ class Method
9
+ module Type
10
+ class Integer < Base
11
+ def call(_sql_value)
12
+ value.to_s
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -4,11 +4,11 @@ module Masking
4
4
  class Config
5
5
  class TargetColumns
6
6
  class Method
7
- class Null
8
- def initialize(*); end
9
-
10
- def call
11
- 'NULL'
7
+ module Type
8
+ class Null < Base
9
+ def call(_sql_value)
10
+ 'NULL'
11
+ end
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'masking/config/target_columns/method/type/base'
4
+
5
+ module Masking
6
+ class Config
7
+ class TargetColumns
8
+ class Method
9
+ module Type
10
+ class String < Base
11
+ def initialize(value)
12
+ super(value)
13
+ @sequence = 0
14
+ end
15
+
16
+ def call(_sql_value)
17
+ sequence!
18
+ "'#{output}'".b
19
+ end
20
+
21
+ private
22
+
23
+ SEQUENTIAL_NUMBER_PLACEHOLDER = '%{n}' # rubocop:disable Style/FormatStringToken
24
+
25
+ def output
26
+ value.sub(SEQUENTIAL_NUMBER_PLACEHOLDER, @sequence.to_s)
27
+ end
28
+
29
+ def sequence!
30
+ @sequence += 1
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'masking/config/target_columns/method/type/base'
4
+
5
+ module Masking
6
+ class Config
7
+ class TargetColumns
8
+ class Method
9
+ module Type
10
+ class Time < Base
11
+ def call(_sql_value)
12
+ "'#{time_format}'"
13
+ end
14
+
15
+ private
16
+
17
+ FORMAT = '%Y-%m-%d %H:%M:%S'
18
+ def time_format
19
+ value.strftime(FORMAT)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'forwardable'
5
- Dir[Pathname(__FILE__).dirname.join('method/*.rb').to_s].each(&method(:require))
5
+ require 'masking/config/target_columns/method/type/extension/ignore_null'
6
+ require 'masking/config/target_columns/method/string_binary_distinctor'
7
+ Dir[Pathname(__FILE__).dirname.join('method/type/*.rb').to_s].sort.each(&method(:require))
6
8
 
7
9
  module Masking
8
10
  class Config
@@ -10,8 +12,10 @@ module Masking
10
12
  class Method
11
13
  extend Forwardable
12
14
 
13
- def initialize(method)
14
- @method_type = mapping(method.class).new(method)
15
+ def initialize(method, ignore_null: false)
16
+ @method_type = mapping(method.class).new(method).tap do |obj|
17
+ obj.singleton_class.prepend(Type::Extension::IgnoreNull) if ignore_null
18
+ end
15
19
  end
16
20
 
17
21
  def_delegator :@method_type, :call
@@ -21,13 +25,13 @@ module Masking
21
25
  # rubocop:disable Layout/HashAlignment
22
26
  MAPPING = {
23
27
  ::String => StringBinaryDistinctor,
24
- ::Integer => Integer,
25
- ::Float => Float,
26
- ::Date => Date,
27
- ::Time => Time,
28
- ::TrueClass => Boolean,
29
- ::FalseClass => Boolean,
30
- ::NilClass => Null
28
+ ::Integer => Type::Integer,
29
+ ::Float => Type::Float,
30
+ ::Date => Type::Date,
31
+ ::Time => Type::Time,
32
+ ::TrueClass => Type::Boolean,
33
+ ::FalseClass => Type::Boolean,
34
+ ::NilClass => Type::Null
31
35
  }.freeze
32
36
  # rubocop:enable Layout/HashAlignment
33
37
 
@@ -18,11 +18,11 @@ module Masking
18
18
  attr_reader :table, :columns, :values
19
19
 
20
20
  def columns_section
21
- '(' + columns.map { |column| "`#{column}`" }.join(', ') + ')'
21
+ '(' + columns.map { |column| "`#{column}`" }.join(', ') + ')' # rubocop:disable Style/StringConcatenation
22
22
  end
23
23
 
24
24
  def values_section
25
- values.map { |value| '(' + value.join(',') + ')' }.join(',')
25
+ values.map { |value| "(#{value.join(',')})" }.join(',')
26
26
  end
27
27
  end
28
28
  end
@@ -36,7 +36,7 @@ module Masking
36
36
 
37
37
  def mask_value(column_index:, mask_method:)
38
38
  values.each do |value|
39
- value[column_index] = mask_method.call
39
+ value[column_index] = mask_method.call(value[column_index])
40
40
  end
41
41
  end
42
42
 
@@ -20,6 +20,7 @@ module Masking
20
20
  private
21
21
 
22
22
  attr_reader :line, :mask_processor
23
+
23
24
  INSERT_STATEMENT_REGEXP = /^INSERT/.freeze
24
25
 
25
26
  def processor
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Masking
4
- VERSION = '1.1.0'
4
+ VERSION = '1.1.1'
5
5
  end
data/masking.gemspec CHANGED
@@ -25,22 +25,5 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.required_ruby_version = '>= 2.6'
27
27
 
28
- spec.add_development_dependency 'bundler'
29
- spec.add_development_dependency 'rake'
30
- spec.add_development_dependency 'rake-notes'
31
- spec.add_development_dependency 'ruby-prof'
32
-
33
- # linter/static analyzer
34
- spec.add_development_dependency 'mdl'
35
- spec.add_development_dependency 'rubocop'
36
-
37
- # test
38
- spec.add_development_dependency 'codecov'
39
- spec.add_development_dependency 'rspec'
40
- spec.add_development_dependency 'simplecov'
41
-
42
- # debug
43
- spec.add_development_dependency 'pry'
44
- spec.add_development_dependency 'pry-byebug'
45
- spec.add_development_dependency 'tapp'
28
+ spec.metadata['rubygems_mfa_required'] = 'true'
46
29
  end