masking 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +9 -4
- data/.github/workflows/acceptance_test_mariadb.yml +57 -1
- data/.github/workflows/acceptance_test_mysql.yml +1 -1
- data/.rubocop.yml +7 -1
- data/.rubocop_todo.yml +105 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +10 -0
- data/Dockerfile +3 -1
- data/Gemfile +20 -0
- data/Gemfile.lock +67 -51
- data/README.md +18 -8
- data/acceptance/expected_query_result.txt +36 -30
- data/acceptance/import_dumpfile.sql +3 -1
- data/acceptance/masking.yml +2 -0
- data/acceptance/run_test.sh +1 -1
- data/docker-compose/mariadb1010.yml +17 -0
- data/docker-compose/mariadb1011.yml +17 -0
- data/docker-compose/mariadb105.yml +17 -0
- data/docker-compose/mariadb106.yml +17 -0
- data/docker-compose/mariadb107.yml +17 -0
- data/docker-compose/mariadb108.yml +17 -0
- data/docker-compose/mariadb109.yml +17 -0
- data/lib/masking/cli/error_message.rb +1 -1
- data/lib/masking/config/target_columns/column.rb +19 -5
- data/lib/masking/config/target_columns/method/string_binary_distinctor.rb +3 -3
- data/lib/masking/config/target_columns/method/type/base.rb +25 -0
- data/lib/masking/config/target_columns/method/type/binary.rb +19 -0
- data/lib/masking/config/target_columns/method/type/boolean.rb +27 -0
- data/lib/masking/config/target_columns/method/type/date.rb +28 -0
- data/lib/masking/config/target_columns/method/type/extension/ignore_null.rb +24 -0
- data/lib/masking/config/target_columns/method/type/float.rb +19 -0
- data/lib/masking/config/target_columns/method/type/integer.rb +19 -0
- data/lib/masking/config/target_columns/method/{null.rb → type/null.rb} +5 -5
- data/lib/masking/config/target_columns/method/type/string.rb +37 -0
- data/lib/masking/config/target_columns/method/type/time.rb +26 -0
- data/lib/masking/config/target_columns/method.rb +14 -10
- data/lib/masking/insert_statement/sql_builder.rb +2 -2
- data/lib/masking/insert_statement.rb +1 -1
- data/lib/masking/sql_dump_line.rb +1 -0
- data/lib/masking/version.rb +1 -1
- data/masking.gemspec +1 -18
- metadata +24 -181
- data/lib/masking/config/target_columns/method/binary.rb +0 -23
- data/lib/masking/config/target_columns/method/boolean.rb +0 -29
- data/lib/masking/config/target_columns/method/date.rb +0 -30
- data/lib/masking/config/target_columns/method/float.rb +0 -23
- data/lib/masking/config/target_columns/method/integer.rb +0 -23
- data/lib/masking/config/target_columns/method/string.rb +0 -33
- 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
|
@@ -6,22 +6,36 @@ module Masking
|
|
6
6
|
class Config
|
7
7
|
class TargetColumns
|
8
8
|
class Column
|
9
|
-
attr_reader :
|
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
|
-
@
|
15
|
-
@table_name
|
16
|
-
@method_value
|
17
|
-
@method
|
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
|
@@ -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
|
-
|
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|
|
25
|
+
values.map { |value| "(#{value.join(',')})" }.join(',')
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/lib/masking/version.rb
CHANGED
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.
|
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
|