masking 1.1.0 → 1.1.2.pre.alpha
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 +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 +19 -0
- data/CODEOWNERS +1 -0
- data/Dockerfile +5 -3
- data/Dockerfile.ghcr +10 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +67 -51
- data/README.md +38 -26
- data/acceptance/expected_error_result.txt +2 -0
- 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 +18 -6
- 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 +16 -9
- 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 +29 -184
- data/lib/masking/cli/error_messages.yml +0 -10
- 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
@@ -1,33 +1,39 @@
|
|
1
1
|
*************************** 1. row ***************************
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
binary_or_blob: \x92
|
2
|
+
id: 1
|
3
|
+
string: anonymized string
|
4
|
+
email: anonymized+1@example.com
|
5
|
+
integer: 12345
|
6
|
+
float: 123.45
|
7
|
+
boolean: 1
|
8
|
+
null: NULL
|
9
|
+
date: 2018-08-24
|
10
|
+
time: 2018-08-24 15:54:06
|
11
|
+
binary_or_blob: \x92
|
12
|
+
nullable_string: string1
|
13
|
+
nullable_integer: NULL
|
12
14
|
*************************** 2. row ***************************
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
binary_or_blob: \x92\x92
|
15
|
+
id: 2
|
16
|
+
string: anonymized string
|
17
|
+
email: anonymized+2@example.com
|
18
|
+
integer: 12345
|
19
|
+
float: 123.45
|
20
|
+
boolean: 1
|
21
|
+
null: NULL
|
22
|
+
date: 2018-08-24
|
23
|
+
time: 2018-08-24 15:54:06
|
24
|
+
binary_or_blob: \x92\x92
|
25
|
+
nullable_string: NULL
|
26
|
+
nullable_integer: 33333
|
23
27
|
*************************** 3. row ***************************
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
binary_or_blob: NULL
|
28
|
+
id: 3
|
29
|
+
string: anonymized string
|
30
|
+
email: anonymized+3@example.com
|
31
|
+
integer: 12345
|
32
|
+
float: 123.45
|
33
|
+
boolean: 1
|
34
|
+
null: NULL
|
35
|
+
date: 2018-08-24
|
36
|
+
time: 2018-08-24 15:54:06
|
37
|
+
binary_or_blob: NULL
|
38
|
+
nullable_string: string3
|
39
|
+
nullable_integer: 33333
|
@@ -33,6 +33,8 @@ CREATE TABLE `users` (
|
|
33
33
|
`date` date DEFAULT NULL,
|
34
34
|
`time` timestamp NULL DEFAULT NULL,
|
35
35
|
`binary_or_blob` binary(11) DEFAULT NULL,
|
36
|
+
`nullable_string` varchar(20) DEFAULT '',
|
37
|
+
`nullable_integer` int(11) DEFAULT NULL,
|
36
38
|
PRIMARY KEY (`id`)
|
37
39
|
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
|
38
40
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
@@ -43,7 +45,7 @@ CREATE TABLE `users` (
|
|
43
45
|
|
44
46
|
LOCK TABLES `users` WRITE;
|
45
47
|
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
|
46
|
-
INSERT INTO `users` (`id`, `string`, `email`, `integer`, `float`, `boolean`, `null`, `date`, `time`, `binary_or_blob`) VALUES (1,'example@exa','test@example.com',1245,2.1,1,-321,NULL,NULL,_binary '\\x92\0\0\0\0\0\0\0'),(2,'あいうえお','invalid@email',0,-23.4422,0,321,NULL,NULL,_binary '\\x92\\x92\0\0\0'),(3,'+-l;a*&^%$','chikahiro@test.com',-1,21.2321,NULL,-231321,'2019-10-31','2019-10-31 16:27:21',NULL);
|
48
|
+
INSERT INTO `users` (`id`, `string`, `email`, `integer`, `float`, `boolean`, `null`, `date`, `time`, `binary_or_blob`, `nullable_string`, `nullable_integer`) VALUES (1,'example@exa','test@example.com',1245,2.1,1,-321,NULL,NULL,_binary '\\x92\0\0\0\0\0\0\0','abcde',NULL),(2,'あいうえお','invalid@email',0,-23.4422,0,321,NULL,NULL,_binary '\\x92\\x92\0\0\0',NULL,12),(3,'+-l;a*&^%$','chikahiro@test.com',-1,21.2321,NULL,-231321,'2019-10-31','2019-10-31 16:27:21',NULL,'abc123',-123);
|
47
49
|
/*!40000 ALTER TABLE `users` ENABLE KEYS */;
|
48
50
|
UNLOCK TABLES;
|
49
51
|
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
data/acceptance/masking.yml
CHANGED
@@ -7,6 +7,8 @@ users:
|
|
7
7
|
'null': NULL
|
8
8
|
date: 2018-08-24
|
9
9
|
time: 2018-08-24 15:54:06
|
10
|
+
nullable_string?: string%{n}
|
11
|
+
nullable_integer?: 33333
|
10
12
|
## TODO: something not working well with binary...
|
11
13
|
# binary_or_blob: !binary |
|
12
14
|
# R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
|
data/acceptance/run_test.sh
CHANGED
@@ -10,16 +10,28 @@ MYSQL_DBNAME=${MYSQL_DBNAME:-mydb}
|
|
10
10
|
|
11
11
|
FILEDIR="$( cd "$( dirname "$0" )" && pwd )"
|
12
12
|
|
13
|
-
|
13
|
+
# clear tmp file
|
14
14
|
rm "$FILEDIR"/tmp/* || echo 'no tmp file'
|
15
15
|
|
16
|
-
|
16
|
+
# import database
|
17
17
|
mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DBNAME" < "$FILEDIR/import_dumpfile.sql"
|
18
18
|
|
19
|
-
|
19
|
+
# masking & restore
|
20
20
|
mysqldump -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DBNAME" --complete-insert | exe/masking -c "$FILEDIR/masking.yml" > "$FILEDIR/tmp/masking_dumpfile.sql"
|
21
21
|
mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DBNAME" < "$FILEDIR/tmp/masking_dumpfile.sql"
|
22
|
-
|
23
|
-
## compare
|
22
|
+
## compare the result
|
24
23
|
mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DBNAME" -e 'SELECT * FROM users ORDER BY id;' --vertical > "$FILEDIR/tmp/query_result.txt"
|
25
|
-
diff "$FILEDIR/
|
24
|
+
diff "$FILEDIR/expected_query_result.txt" "$FILEDIR/tmp/query_result.txt" || (echo 'test failed' && exit 1)
|
25
|
+
|
26
|
+
# test errors
|
27
|
+
set +e
|
28
|
+
## without masking.yml
|
29
|
+
mysqldump -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DBNAME" --complete-insert | exe/masking -c "$FILEDIR/no_file.yml" 2>> "$FILEDIR/tmp/errors.txt" 1> /dev/null
|
30
|
+
## without `--complete-insert``
|
31
|
+
mysqldump -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DBNAME" | exe/masking -c "$FILEDIR/masking.yml" 2>> "$FILEDIR/tmp/errors.txt" 1> /dev/null
|
32
|
+
set -e
|
33
|
+
### compare the result
|
34
|
+
diff "$FILEDIR/expected_error_result.txt" "$FILEDIR/tmp/errors.txt" || (echo 'error output test failed' && exit 1)
|
35
|
+
|
36
|
+
echo 'test passed!'
|
37
|
+
exit 0
|
@@ -0,0 +1,17 @@
|
|
1
|
+
version: '3.7'
|
2
|
+
|
3
|
+
services:
|
4
|
+
app:
|
5
|
+
build:
|
6
|
+
target: with-mysql-client
|
7
|
+
depends_on:
|
8
|
+
- mariadb1010
|
9
|
+
entrypoint: docker-compose/wait-for-mysql.sh mariadb1010
|
10
|
+
|
11
|
+
mariadb1010:
|
12
|
+
image: mariadb:10.10
|
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
|
+
- 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
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'pathname'
|
4
3
|
require 'erb'
|
5
4
|
require 'ostruct'
|
5
|
+
require 'masking/errors'
|
6
6
|
|
7
7
|
module Masking
|
8
8
|
class Cli
|
@@ -19,19 +19,26 @@ module Masking
|
|
19
19
|
|
20
20
|
attr_reader :error_class
|
21
21
|
|
22
|
-
YAML_FILE_PATH = Pathname('lib/masking/cli/error_messages.yml')
|
23
|
-
|
24
|
-
def error_messages
|
25
|
-
@error_messages = YAML.safe_load(YAML_FILE_PATH.read)
|
26
|
-
end
|
27
|
-
|
28
22
|
def error_message(keyword_args)
|
29
23
|
ERB.new(
|
30
|
-
|
24
|
+
ERROR_MESSAGES.fetch(error_class.to_s)
|
31
25
|
).result(
|
32
|
-
OpenStruct.new(keyword_args).instance_eval { binding }
|
26
|
+
OpenStruct.new(keyword_args).instance_eval { binding } # rubocop:disable Style/OpenStructUse
|
33
27
|
)
|
34
28
|
end
|
29
|
+
|
30
|
+
ERROR_MESSAGES = {
|
31
|
+
'Masking::Error::ConfigFileDoesNotExist' =>
|
32
|
+
'ERROR: config file (<%= config_file_path %>) does not exist',
|
33
|
+
'Masking::Error::ConfigFileIsNotFile' =>
|
34
|
+
'ERROR: config file (<%= config_file_path %>) is not file',
|
35
|
+
'Masking::Error::ConfigFileIsNotValidYaml' =>
|
36
|
+
'ERROR: config file (<%= config_file_path %>) is not valid yaml format',
|
37
|
+
'Masking::Error::ConfigFileContainsNullAsColumnName' =>
|
38
|
+
'ERROR: config file (<%= config_file_path %>) is not valid, column name contains `null`',
|
39
|
+
'Masking::Error::InsertStatementParseError' =>
|
40
|
+
'ERROR: cannot parse SQL dump file. you may forget to put `--complete-insert` option in mysqldump?'
|
41
|
+
}.freeze
|
35
42
|
end
|
36
43
|
end
|
37
44
|
end
|
@@ -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
|
|