data_taster 0.2.2

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.
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DataTaster
4
+ class Sanitizer
5
+ # Ensures the given tables are cleaned of
6
+ # information deemed sensitive
7
+ def initialize(table_name, custom_selections)
8
+ @table_name = table_name
9
+ @custom_selections = custom_selections || {}
10
+ @include_insert = DataTaster.config.include_insert
11
+ end
12
+
13
+ def clean!
14
+ return if skippable_table?
15
+
16
+ # custom selections should ALWAYS override defaults
17
+ default_selections.merge(custom_selections).filter_map do |column_name, sanitized_value|
18
+ sql = DataTaster::Detergent.new(
19
+ table_name, column_name, sanitized_value
20
+ ).deliver
21
+
22
+ process(sql)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :table_name, :custom_selections, :include_insert
29
+
30
+ def process(sql)
31
+ return if sql == DataTaster::SKIP_CODE
32
+ return sql unless include_insert
33
+
34
+ DataTaster.safe_execute(sql)
35
+ rescue => e
36
+ e.message << context_warning
37
+
38
+ raise e
39
+ end
40
+
41
+ def context_warning
42
+ <<~WARNING
43
+
44
+ *****
45
+
46
+ DATA TASTER WARNING: Many columns are sanitized by default for safety. Please check DataTaster documentation for more details.
47
+
48
+ *****
49
+
50
+ WARNING
51
+ end
52
+
53
+ def skippable_table?
54
+ DataTaster.confection[table_name].blank? ||
55
+ DataTaster.confection[table_name] == DataTaster::SKIP_CODE
56
+ end
57
+
58
+ def default_selections
59
+ table_columns.each_with_object({}) do |table_col, selections|
60
+ sanitized_value = defaults.select do |default_col|
61
+ table_col.match(default_col)
62
+ end&.first&.last
63
+
64
+ next unless sanitized_value
65
+
66
+ selections[table_col] = sanitized_value
67
+ end
68
+ end
69
+
70
+ def table_columns
71
+ @table_columns ||= ActiveRecord::Base
72
+ .connection
73
+ .schema_cache
74
+ .columns(table_name.to_s)
75
+ .map(&:name)
76
+ end
77
+
78
+ def defaults # rubocop:disable Metrics/MethodLength
79
+ {
80
+ # `encrypted` should be removed if it is not custom-sanitized
81
+ /encrypted/ => "",
82
+ /#{exceptions}.*(ssn|passport|license)/ => "111111111",
83
+ /#{exceptions}.*(dob|birth)/ => Date.current - 29.years,
84
+ /#{exceptions}.*(note|body)/ => "Redacted for privacy",
85
+ /#{exceptions}.*(compensation|income)/ => 999_999,
86
+ /#{exceptions(extra: ['2'])}.*email.*/ => "CONCAT('#{table_name}_', id, '@nitrophrg.com')",
87
+ /email.*2$/ => "CONCAT('#{table_name}_', id, '_2', '@nitrophrg.com')",
88
+ /#{exceptions(extra: %w[2 email])}.*address.*/ => "CONCAT(id, ' Disneyland Dr')",
89
+ /#{exceptions(extra: ['email'])}.*address.*2/ => "Unit M",
90
+ }.freeze
91
+ end
92
+
93
+ def exceptions(extra: [])
94
+ default = %w[_id _at type subject ip mac remote count encrypted voice count]
95
+ all_exceptions = default + extra
96
+
97
+ "^(?!.*(?:#{all_exceptions.join('|')}))"
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DataTaster
4
+ VERSION = "0.2.2"
5
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ module DataTaster
6
+ autoload :Collection, "data_taster/collection"
7
+ autoload :Confection, "data_taster/confection"
8
+ autoload :Detergent, "data_taster/detergent"
9
+ autoload :Helper, "data_taster/helper"
10
+ autoload :Sample, "data_taster/sample"
11
+ autoload :Sanitizer, "data_taster/sanitizer"
12
+
13
+ SKIP_CODE = "skip_processing"
14
+
15
+ def self.logger=(logger)
16
+ @logger = logger
17
+ end
18
+
19
+ def self.logger
20
+ @logger ||= Logger.new($stdout)
21
+ end
22
+
23
+ def self.config(**args)
24
+ @config ||= Config.new(
25
+ args[:months],
26
+ Array.wrap(args[:list] || Rails.root.glob("**/data_taster_export_tables.yml")),
27
+ args[:source_client] || raise(ArgumentError, "DataTaster.config missing source_client"),
28
+ args[:working_client] || raise(ArgumentError, "DataTaster.config missing working_client"),
29
+ args[:include_insert] || false
30
+ )
31
+ end
32
+
33
+ def self.confection
34
+ @confection ||= DataTaster::Confection.new.assemble
35
+ end
36
+
37
+ def self.sample!
38
+ DataTaster
39
+ .config
40
+ .source_client
41
+ .query("SHOW tables").collect { |t| t[t.keys.first] }
42
+ .each do |table_name|
43
+ DataTaster::Sample.new(table_name).serve!
44
+ end
45
+ end
46
+
47
+ def self.safe_execute(sql, client = DataTaster.config.working_client)
48
+ foreign_key_check = client.query("SELECT @@FOREIGN_KEY_CHECKS").first["@@FOREIGN_KEY_CHECKS"]
49
+
50
+ begin
51
+ client.query("SET FOREIGN_KEY_CHECKS=0")
52
+ client.query(sql)
53
+ ensure
54
+ client.query("SET FOREIGN_KEY_CHECKS=#{foreign_key_check};")
55
+ end
56
+ end
57
+
58
+ Config = Struct.new(:months, :list, :source_client, :working_client, :include_insert)
59
+ end
data/mkdocs.yml ADDED
@@ -0,0 +1,7 @@
1
+ site_name: Data Taster
2
+
3
+ nav:
4
+ - "Home": "README.md"
5
+ - "Changelog": "CHANGELOG.md"
6
+ plugins:
7
+ - techdocs-core
@@ -0,0 +1,4 @@
1
+ module DataTaster
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,236 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: data_taster
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Jill Klang
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-01-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: license_finder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '7.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '7.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: appraisal
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 2.5.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.5.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: parser
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '2.5'
76
+ - - "!="
77
+ - !ruby/object:Gem::Version
78
+ version: 2.5.1.1
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '2.5'
86
+ - - "!="
87
+ - !ruby/object:Gem::Version
88
+ version: 2.5.1.1
89
+ - !ruby/object:Gem::Dependency
90
+ name: rainbow
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '='
94
+ - !ruby/object:Gem::Version
95
+ version: 2.2.2
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '='
101
+ - !ruby/object:Gem::Version
102
+ version: 2.2.2
103
+ - !ruby/object:Gem::Dependency
104
+ name: rake
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '13.0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '13.0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: rspec
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '3.0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '3.0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: simplecov
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - '='
136
+ - !ruby/object:Gem::Version
137
+ version: 0.15.1
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - '='
143
+ - !ruby/object:Gem::Version
144
+ version: 0.15.1
145
+ - !ruby/object:Gem::Dependency
146
+ name: test-unit
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - '='
150
+ - !ruby/object:Gem::Version
151
+ version: 3.1.5
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - '='
157
+ - !ruby/object:Gem::Version
158
+ version: 3.1.5
159
+ - !ruby/object:Gem::Dependency
160
+ name: yard
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - '='
164
+ - !ruby/object:Gem::Version
165
+ version: 0.9.34
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - '='
171
+ - !ruby/object:Gem::Version
172
+ version: 0.9.34
173
+ description: Export, sanitize, and import data to help develop better apps.
174
+ email:
175
+ - jillian.emilie@gmail.com
176
+ executables: []
177
+ extensions: []
178
+ extra_rdoc_files: []
179
+ files:
180
+ - ".rubocop.yml"
181
+ - Appraisals
182
+ - CODE_OF_CONDUCT.md
183
+ - Gemfile
184
+ - Gemfile.lock
185
+ - LICENSE.txt
186
+ - README.md
187
+ - Rakefile
188
+ - doc/dependency_decisions.yml
189
+ - docs/CHANGELOG.md
190
+ - docs/README.md
191
+ - gemfiles/.bundle/config
192
+ - gemfiles/rails_6_0.gemfile
193
+ - gemfiles/rails_6_0.gemfile.lock
194
+ - gemfiles/rails_6_1.gemfile
195
+ - gemfiles/rails_6_1.gemfile.lock
196
+ - gemfiles/rails_7_0.gemfile
197
+ - gemfiles/rails_7_0.gemfile.lock
198
+ - lib/data_taster.rb
199
+ - lib/data_taster/collection.rb
200
+ - lib/data_taster/confection.rb
201
+ - lib/data_taster/detergent.rb
202
+ - lib/data_taster/flavors.rb
203
+ - lib/data_taster/helper.rb
204
+ - lib/data_taster/sample.rb
205
+ - lib/data_taster/sanitizer.rb
206
+ - lib/data_taster/version.rb
207
+ - mkdocs.yml
208
+ - sig/data_taster.rbs
209
+ homepage: https://github.com/powerhome/power-tools
210
+ licenses:
211
+ - MIT
212
+ metadata:
213
+ rubygems_mfa_required: 'true'
214
+ homepage_uri: https://github.com/powerhome/power-tools
215
+ source_code_uri: https://github.com/powerhome/power-tools
216
+ changelog_uri: https://github.com/powerhome/power-tools/blob/main/packages/data_taster/docs/CHANGELOG.md
217
+ post_install_message:
218
+ rdoc_options: []
219
+ require_paths:
220
+ - lib
221
+ required_ruby_version: !ruby/object:Gem::Requirement
222
+ requirements:
223
+ - - ">="
224
+ - !ruby/object:Gem::Version
225
+ version: '2.7'
226
+ required_rubygems_version: !ruby/object:Gem::Requirement
227
+ requirements:
228
+ - - ">="
229
+ - !ruby/object:Gem::Version
230
+ version: '0'
231
+ requirements: []
232
+ rubygems_version: 3.5.4
233
+ signing_key:
234
+ specification_version: 4
235
+ summary: Delicious and sanitized data samples for development and testing.
236
+ test_files: []