mtwtfss_yaml_db_anonymizer 0.7

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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Njg2MWU3ZjNhY2RmYTJhZThiMTBhNTkyYzA0YjYzMDUxNjM3MzE0Ng==
5
+ data.tar.gz: !binary |-
6
+ YTE0OThlOWM2Yjg0ZDJiMGQ0ZGZhMDAwODk5Mjk3NzQzOGQ5NGEyMg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZGFkMTUyOTk0Y2NiMDU4M2ExZWU0ZjFkOWE1YzRkNzg1YjZiOWYwNWFiZWNi
10
+ NzJhOTVjMmM2M2Q1ZGUxYzAxY2ZkNDFjZTE1Y2NmYjU1MzBmZGQ3ODU4YTAx
11
+ N2VmZTM2MDNlNTBlNDMwY2YzYmQ3OWUwNjkwOGQ2N2Q5ZTY0ODg=
12
+ data.tar.gz: !binary |-
13
+ MjIyMzQ5ZGJjZGU5YTk5Nzg4ODk3NDA2YmY3MjNkMWQ0YzlkZGFlY2RmOGQ4
14
+ Yjc1NTY1ZTliYTVjZDcxOTcxYWQ2OGE4ZGE5MTlkM2I5NGI4MzJmNTcxYTA5
15
+ YmY5ZmQ4NzUxYThkZDI5OTMwYTg3OTNjNjAyMjYwYTFkMmJkOTM=
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color -f documentation --drb
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - ruby-head
6
+ - jruby-19mode # JRuby in 1.9 mode
7
+ - jruby-head
8
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mtwtfss_yaml_db_anonymizer.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,13 @@
1
+ guard 'spork' do
2
+ watch('Gemfile')
3
+ watch('Gemfile.lock')
4
+ watch('spec/spec_helper.rb') { :rspec }
5
+ end
6
+
7
+ guard 'rspec', :version => 2 do
8
+ watch(%r{^spec/.+_spec\.rb$})
9
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
10
+ watch('spec/spec_helper.rb') { "spec" }
11
+ end
12
+
13
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # MtwtfssYamlDb::Anonymizer
2
+
3
+ Dumps anonymized database contents to a YAML file. This is useful if you want to develop Rails applications with near-live data from your server. Based on [yaml_db](https://github.com/ludicast/yaml_db).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'mtwtfss_yaml_db_anonymizer'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install mtwtfss_yaml_db_anonymizer
18
+
19
+ ## Usage
20
+
21
+ * Specify the database fields to anonymize, e.g. in
22
+ `config/initializers/mtwtfss_yaml_db_anonymizer.rb`:
23
+
24
+ ```ruby
25
+ MtwtfssYamlDb::Anonymizer.define do
26
+ table :users do
27
+ remove :encrypted_password
28
+ replace :name, with: 'John Doe'
29
+ replace :phone, with: ->(phone) { phone.to_s[0..-3] + '***' }
30
+ end
31
+
32
+ table :logs do
33
+ truncate
34
+ end
35
+ end
36
+ ```
37
+
38
+ * Run `rake db:data:dump_anonymized` on your server. This creates an anonymized dump in `db/data.yml`
39
+
40
+ * Copy `db/data.yml` to your local machine
41
+
42
+ * Run `rake db:data:load` on your local machine.
43
+
44
+ ## Todo
45
+
46
+ * Provide capistrano integration
47
+
48
+ ## Contributing
49
+
50
+ 1. Fork it
51
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
52
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
53
+ 4. Push to the branch (`git push origin my-new-feature`)
54
+ 5. Create new Pull Request
55
+
56
+ ## License
57
+
58
+ MIT License.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,51 @@
1
+ require 'yaml_db'
2
+ require 'mtwtfss_yaml_db/anonymizer/railtie'
3
+
4
+ module MtwtfssYamlDb
5
+ module Anonymizer
6
+ autoload :Dump, 'mtwtfss_yaml_db/anonymizer/dump'
7
+ autoload :Helper, 'mtwtfss_yaml_db/anonymizer/helper'
8
+ autoload :VERSION, 'mtwtfss_yaml_db/anonymizer/version'
9
+
10
+ class << self
11
+ attr_accessor :definition
12
+
13
+ def define(*args, &block)
14
+ self.definition = {}
15
+ class_eval &block
16
+ end
17
+
18
+ def table(table_name, &block)
19
+ @table_name = table_name.to_s
20
+ self.definition[@table_name] = {}
21
+ class_eval &block
22
+ end
23
+
24
+ def truncate
25
+ self.definition[@table_name] = :truncate
26
+ end
27
+
28
+ def remove(column_name)
29
+ self.definition[@table_name][column_name.to_s] = nil
30
+ end
31
+
32
+ def remove_row_if(column_name, opts={})
33
+ self.definition[@table_name][column_name.to_s] = opts[:condition]
34
+ end
35
+
36
+ def replace(column_name, opts={})
37
+ self.definition[@table_name][column_name.to_s] = opts[:with]
38
+ end
39
+
40
+ def anonymize(table, column, value)
41
+ return value unless self.definition.key?(table.to_s) and self.definition[table.to_s].key?(column.to_s)
42
+ block_or_value = self.definition[table.to_s][column.to_s]
43
+ if block_or_value.is_a?(Proc)
44
+ block_or_value.arity == 1 ? block_or_value.call(value) : block_or_value.call
45
+ else
46
+ block_or_value
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,45 @@
1
+ module MtwtfssYamlDb
2
+ module Anonymizer
3
+ class Dump < ::YamlDb::Dump
4
+
5
+ def self.dump_table_records(io, table)
6
+ return super(io, table) unless Anonymizer.definition.is_a? Hash
7
+ return if Anonymizer.definition[table.to_s] == :truncate
8
+
9
+ table_record_header(io)
10
+
11
+ column_names = table_column_names(table)
12
+
13
+ each_table_page(table) do |records|
14
+ rows = SerializationHelper::Utils.unhash_records(records, column_names)
15
+ records_anonymized = records.map do |record|
16
+ # FIXME Why isn't there a map_with_index?
17
+ record_anonymized = []
18
+ record.each_with_index do |value, i|
19
+ if Anonymizer.anonymize(table, column_names[i], value) == 'REMOVE_ROW'
20
+ record_anonymized = 'REMOVE_ROW'
21
+ break
22
+ else
23
+ record_anonymized << Anonymizer.anonymize(table, column_names[i], value)
24
+ end
25
+ end
26
+ record_anonymized
27
+ end
28
+ records_anonymized.delete_if { |record| record == 'REMOVE_ROW' }
29
+ io.write(YamlDb::Utils.chunk_records(records_anonymized))
30
+ end
31
+ end
32
+
33
+ def self.dump_table_columns(io, table)
34
+ super(io, table) unless Anonymizer.definition.is_a?(Hash) && Anonymizer.definition[table.to_s] == :truncate
35
+ end
36
+
37
+ def self.tables
38
+ ActiveRecord::Base.connection.tables
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
45
+
@@ -0,0 +1,19 @@
1
+ module MtwtfssYamlDb
2
+ module Anonymizer
3
+ module Helper
4
+ class << self
5
+ def dumper
6
+ MtwtfssYamlDb::Anonymizer::Dump
7
+ end
8
+
9
+ def loader
10
+ YamlDb::Load
11
+ end
12
+
13
+ def extension
14
+ "yml"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module MtwtfssYamlDb
2
+ module Anonymizer
3
+ class Railtie < ::Rails::Railtie
4
+ rake_tasks do
5
+ load File.join(File.dirname(__FILE__), '..', '..', 'tasks', 'mtwtfss_yaml_db_anonymizer.rake')
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module MtwtfssYamlDb
2
+ module Anonymizer
3
+ VERSION = "0.7"
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ require 'mtwtfss_yaml_db/anonymizer'
@@ -0,0 +1,19 @@
1
+ namespace :db do
2
+ namespace :data do
3
+ desc 'Dump anonymized database contents to db/data.yml'
4
+ task :dump_anonymized => :environment do
5
+ format_class = ENV['class'] || "MtwtfssYamlDb::Helper"
6
+ filter = ENV['filter_tables']
7
+
8
+ SerializationHelper::Base.new(MtwtfssYamlDb::Anonymizer::Helper, filter).dump File.join(Rails.root, 'db', 'data.yml')
9
+ end
10
+
11
+ task :dump_anonymized_dir => :environment do
12
+ format_class = ENV['class'] || "MtwtfssYamlDb::Helper"
13
+ dir = ENV['dir'] || "#{Time.now.to_s.gsub(/ /, '_')}"
14
+ filter = ENV['filter_tables']
15
+
16
+ SerializationHelper::Base.new(MtwtfssYamlDb::Anonymizer::Helper, filter).dump_to_dir "#{Rails.root}/db/#{dir}"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/mtwtfss_yaml_db/anonymizer/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Thomas Hollstegge"]
6
+ gem.description = %q{Dumps anonymized database contents to .yml files}
7
+ gem.summary = %q{A database dumper with anonymization}
8
+ gem.homepage = "https://github.com/mtwtfss/yaml_db_anonymizer"
9
+
10
+ gem.files = `git ls-files`.split($\)
11
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
12
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
+ gem.name = "mtwtfss_yaml_db_anonymizer"
14
+ gem.require_paths = ["lib"]
15
+ gem.version = MtwtfssYamlDb::Anonymizer::VERSION
16
+
17
+ gem.add_dependency 'mtwtfss_yaml_db'
18
+
19
+ gem.add_development_dependency 'rspec', '~> 2.11.0'
20
+ gem.add_development_dependency 'rails', '~> 3.2'
21
+ gem.add_development_dependency 'guard-rspec', '~> 1.1.0'
22
+ gem.add_development_dependency 'guard-spork', '~> 1.1.0'
23
+ end
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'spork'
3
+
4
+ Spork.prefork do
5
+ require 'rspec'
6
+ require 'bundler/setup'
7
+
8
+ end
9
+
10
+ Spork.each_run do
11
+ require 'mtwtfss_yaml_db_anonymizer'
12
+
13
+ end
14
+
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ describe MtwtfssYamlDb::Anonymizer do
4
+ context 'definition' do
5
+ before do
6
+ MtwtfssYamlDb::Anonymizer.define do
7
+ table :mytable do
8
+ remove :a
9
+ replace :b, with: 0
10
+ replace :c, with: lambda { |val| "Anonymized #{val}" }
11
+ replace :d, with: lambda { "Anonymized value" }
12
+ end
13
+ end
14
+ end
15
+
16
+ it "should anonymize" do
17
+ MtwtfssYamlDb::Anonymizer.anonymize(:mytable, :a, "foo").should == nil
18
+ end
19
+
20
+ it "should anonymize with simple values" do
21
+ MtwtfssYamlDb::Anonymizer.anonymize(:mytable, :b, "foo").should == 0
22
+ end
23
+
24
+ it "should anonymize with blocks" do
25
+ MtwtfssYamlDb::Anonymizer.anonymize(:mytable, :c, "bar").should == "Anonymized bar"
26
+ end
27
+
28
+ it "should anonymize with blocks" do
29
+ MtwtfssYamlDb::Anonymizer.anonymize(:mytable, :d, "bar").should == "Anonymized value"
30
+ end
31
+ end
32
+
33
+ context 'export' do
34
+ before do
35
+ # Taken from yaml_db specs
36
+ silence_warnings { ActiveRecord::Base = mock('ActiveRecord::Base').as_null_object }
37
+ ActiveRecord::Base.stub(:connection).and_return(stub('connection').as_null_object)
38
+ ActiveRecord::Base.connection.stub!(:tables).and_return([ 'mytable', 'schema_info', 'schema_migrations' ])
39
+ ActiveRecord::Base.connection.stub!(:columns).with('mytable').and_return([ mock('a',:name => 'a', :type => :string), mock('b', :name => 'b', :type => :string) ])
40
+ ActiveRecord::Base.connection.stub!(:select_one).and_return({"count"=>"2"})
41
+ ActiveRecord::Base.connection.stub!(:select_all).and_return([ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ])
42
+ MtwtfssYamlDb::Utils.stub!(:quote_table).with('mytable').and_return('mytable')
43
+ end
44
+
45
+ before(:each) do
46
+ # Taken from yaml_db specs
47
+ File.stub!(:new).with('dump.yml', 'w').and_return(StringIO.new)
48
+ @io = StringIO.new
49
+ end
50
+
51
+ context 'tables' do
52
+ it 'dumps rails schema tables' do
53
+ MtwtfssYamlDb::Anonymizer::Dump.tables.should == %w(mytable schema_info schema_migrations)
54
+ end
55
+ end
56
+
57
+ context 'truncated' do
58
+ before do
59
+ MtwtfssYamlDb::Anonymizer.define do
60
+ table :mytable do
61
+ truncate
62
+ end
63
+ end
64
+ end
65
+
66
+ it 'should not export headers for truncated tables' do
67
+ MtwtfssYamlDb::Anonymizer::Dump.dump_table_columns(@io, 'mytable')
68
+ @io.rewind
69
+ @io.read.should == ""
70
+ end
71
+
72
+ it 'should not export records for truncated tables' do
73
+ MtwtfssYamlDb::Anonymizer::Dump.dump_table_records(@io, 'mytable')
74
+ @io.rewind
75
+ @io.read.should == ""
76
+ end
77
+ end
78
+
79
+ context 'anonymized' do
80
+ before do
81
+ MtwtfssYamlDb::Anonymizer.define do
82
+ table :mytable do
83
+ replace 'a', with: 0
84
+ end
85
+ end
86
+ end
87
+
88
+ it 'should anonymize the dump with the given schema' do
89
+ MtwtfssYamlDb::Anonymizer::Dump.dump_table_records(@io, 'mytable')
90
+ @io.rewind
91
+ @io.read.should == <<EOYAML
92
+ records:
93
+ - - 0
94
+ - 2
95
+ - - 0
96
+ - 4
97
+ EOYAML
98
+ end
99
+ end
100
+ end
101
+
102
+ context 'fallback' do
103
+ let(:io) { double('io') }
104
+ let(:table) { double('table') }
105
+
106
+ before do
107
+ MtwtfssYamlDb::Anonymizer.definition = nil
108
+ end
109
+
110
+ it 'falls back to MtwtfssYamlDb::Dump.dump_table_records if definition is missing' do
111
+ MtwtfssYamlDb::Dump.should_receive(:dump_table_records).with(io, table)
112
+ MtwtfssYamlDb::Anonymizer::Dump.dump_table_records(io, table)
113
+ end
114
+
115
+ it 'falls back to MtwtfssYamlDb::Dump.dump_table_columns if definition is missing' do
116
+ MtwtfssYamlDb::Dump.should_receive(:dump_table_columns).with(io, table)
117
+ MtwtfssYamlDb::Anonymizer::Dump.dump_table_columns(io, table)
118
+ end
119
+ end
120
+ end
121
+
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mtwtfss_yaml_db_anonymizer
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.7'
5
+ platform: ruby
6
+ authors:
7
+ - Thomas Hollstegge
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mtwtfss_yaml_db
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.11.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 2.11.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard-rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.1.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-spork
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 1.1.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 1.1.0
83
+ description: Dumps anonymized database contents to .yml files
84
+ email:
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - .gitignore
90
+ - .rspec
91
+ - .travis.yml
92
+ - Gemfile
93
+ - Guardfile
94
+ - LICENSE
95
+ - README.md
96
+ - Rakefile
97
+ - lib/mtwtfss_yaml_db/anonymizer.rb
98
+ - lib/mtwtfss_yaml_db/anonymizer/dump.rb
99
+ - lib/mtwtfss_yaml_db/anonymizer/helper.rb
100
+ - lib/mtwtfss_yaml_db/anonymizer/railtie.rb
101
+ - lib/mtwtfss_yaml_db/anonymizer/version.rb
102
+ - lib/mtwtfss_yaml_db_anonymizer.rb
103
+ - lib/tasks/mtwtfss_yaml_db_anonymizer.rake
104
+ - mtwtfss_yaml_db_anonymizer.gemspec
105
+ - spec/spec_helper.rb
106
+ - spec/yaml_db/anonymizer_spec.rb
107
+ homepage: https://github.com/mtwtfss/yaml_db_anonymizer
108
+ licenses: []
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.0.3
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: A database dumper with anonymization
130
+ test_files:
131
+ - spec/spec_helper.rb
132
+ - spec/yaml_db/anonymizer_spec.rb
133
+ has_rdoc: