masking 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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