strike 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -24,6 +24,12 @@ To generate a new dump, use the following command:
24
24
 
25
25
  $ strike dump mysql://root@localhost/db_production --profile=tables.rb > obfuscated_dump.sql
26
26
 
27
+ To obfuscate an existing sql dump, use the following command:
28
+
29
+ $ cat original_dump.sql | strike obfuscate --profile=tables.rb > obfuscated_dump.sql
30
+
31
+ It is very important to generate the mysql dump with the `-c` option.
32
+
27
33
  This command dumps the `database_url` following the tables defined in the `profile`
28
34
  file (defaults to `Strikefile`). The default dump output is STDOUT.
29
35
 
@@ -69,7 +75,6 @@ end
69
75
 
70
76
  * `mysqldump`: to create the dump to manipulate.
71
77
  * [my_obfuscate][my_obfuscate]: the core of this utility.
72
- * [Sequel][sequel]: extracts the info for the non defined tables.
73
78
  * [Thor][thor]: cli utilities.
74
79
 
75
80
  ## Notes
data/Rakefile CHANGED
@@ -3,5 +3,9 @@ require "bundler/gem_tasks"
3
3
  require "rake/testtask"
4
4
 
5
5
  Rake::TestTask.new do |t|
6
- t.pattern = "test/**/*_test.rb"
6
+ t.pattern = "spec/**/*_spec.rb"
7
7
  end
8
+
9
+ task spec: :test
10
+
11
+ task default: :test
data/TODO.md CHANGED
@@ -3,4 +3,3 @@
3
3
  * Log info in /var/log/strike/`database`-`timestamp`.log
4
4
  * Options
5
5
  - log: alternative log file
6
- * BETTER TESTS!
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.6
1
+ 0.4.0
@@ -4,16 +4,29 @@ require 'thor'
4
4
 
5
5
  class Strike < Thor
6
6
  require 'strike/interpreter'
7
- require 'strike/agent'
7
+ require 'strike/obfuscator'
8
+ require 'strike/dumper'
8
9
 
9
10
  include Thor::Actions
10
11
 
12
+ class_option :profile,
13
+ aliases: '-p',
14
+ type: :string,
15
+ default: 'Strikefile',
16
+ required: false,
17
+ desc: 'Profile with the table definitions.'
18
+ class_option :output,
19
+ aliases: '-o',
20
+ type: :string,
21
+ required: false,
22
+ desc: 'Output file. If none is given, outputs to STDOUT.'
23
+
11
24
  desc 'version', 'Show version'
12
25
  def version
13
26
  $stdout.puts "v#{IO.read(File.expand_path('../../VERSION', __FILE__))}"
14
27
  end
15
28
 
16
- desc 'dump <database_url>', 'Dump the <database_url> to STDOUT.'
29
+ desc 'dump <database_url>', 'Dump the obfuscated <database_url> to --output.'
17
30
  long_desc <<-DESC
18
31
  Dump the <database_url> following the table definitions defined in the <profile>
19
32
  (defaults to `Strikefile`). The default dump output is STDOUT.
@@ -40,34 +53,95 @@ class Strike < Thor
40
53
  \x5\t t.email :email
41
54
  \x5\tend
42
55
  DESC
43
- method_option :profile,
44
- aliases: '-p',
45
- type: :string,
46
- default: 'Strikefile',
47
- required: true,
48
- desc: 'Profile with the table definitions.'
49
- method_option :output,
50
- aliases: '-o',
51
- type: :string,
52
- required: false,
53
- desc: 'Output file. If none is given, outputs to STDOUT.'
54
56
  def dump(database_url)
55
- file = options[:profile]
57
+ with_profile do |profile|
58
+ with_output do |output|
59
+ Dumper.new.call(self, database_url) do |dump_file|
60
+ _obfuscate(profile, dump_file, output)
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ desc 'obfuscate', 'Obfuscate a mysqldump (with -c option) from --input to --output.'
67
+ long_desc <<-DESC
68
+ Obfuscate the database dump following the table definitions defined in the <profile>
69
+ (defaults to `Strikefile`). The default obfuscate output is STDOUT and the input
70
+ is STDIN.
71
+
72
+ IMPORTANT! The mysqldump must has been generated with the `-c` option.
56
73
 
57
- if options[:output]
58
- modes = File::CREAT|File::TRUNC|File::RDWR
59
- output = File.new(options[:output], modes, 0644)
74
+ Usage example:
75
+
76
+ $ strike obfuscate < dump.sql > obfuscated-dump.sql
77
+
78
+ $ cat dump.sql | strike obfuscate > obfuscated-dump.sql --profile=tables.rb
79
+
80
+ $ strike obfuscate --input=dump.sql --output=obfuscated-dump.sql
81
+
82
+ The tables are defined with a DSL, which is a wrapper
83
+ arround the obfuscation types defined in the MyObfuscate gem.
84
+
85
+ Example:
86
+ \x5\t# tables.rb
87
+ \x5\ttable :users do |t|
88
+ \x5\t # t.column_name :obfuscation_type
89
+ \x5\t t.name :first_name
90
+ \x5\t t.email :email
91
+ \x5\tend
92
+ DESC
93
+ method_option :input,
94
+ aliases: '-i',
95
+ type: :string,
96
+ required: false,
97
+ desc: 'Input file. If none is given, is read from STDIN.'
98
+ def obfuscate
99
+ with_profile do |profile|
100
+ with_input do |input|
101
+ with_output do |output|
102
+ _obfuscate(profile, input, output)
103
+ end
104
+ end
60
105
  end
106
+ end
107
+
108
+ private
109
+
110
+ def _obfuscate(profile, input, output)
111
+ tables = Interpreter.new.parse(profile.read)
112
+ Obfuscator.new.call(tables, input, output)
113
+ end
114
+
115
+ def with_input
116
+ input = options[:input] ? File.open(options[:input]) : $stdin
117
+
118
+ yield input
119
+ ensure
120
+ input.close if input != $stdin
121
+ end
122
+
123
+ def with_output
124
+ output = if options[:output]
125
+ modes = File::CREAT|File::TRUNC|File::RDWR
126
+ File.new(options[:output], modes, 0644)
127
+ else
128
+ $stdout
129
+ end
130
+
131
+ yield output
132
+ ensure
133
+ output.close if output != $stdout
134
+ end
135
+
136
+ def with_profile
137
+ file = options[:profile]
61
138
 
62
139
  if file && File.exist?(file)
63
140
  File.open(file) do |profile|
64
- tables = Interpreter.new.parse(profile.read)
65
- Agent.new.call(self, database_url, tables, output || $stdout)
141
+ yield profile
66
142
  end
67
143
  else
68
144
  $stderr.puts "Profile Error: No such file #{file}"
69
145
  end
70
- ensure
71
- output.close if output
72
146
  end
73
147
  end
@@ -0,0 +1,123 @@
1
+ # encoding: utf-8
2
+
3
+ require 'tempfile'
4
+ require 'uri'
5
+
6
+ class Strike
7
+ class Dumper
8
+ def initialize(config = {})
9
+ @dumpfile_source = config[:dumpfile_source]
10
+ end
11
+
12
+ # Dumps the data from the given database to a tmp file.
13
+ #
14
+ # @param [#run] cli the cli program that responds to `#run`.
15
+ # @param [String] database_url the connection info. @see `#parse_url`.
16
+ # @param [Proc] optional block in which the tmp file will be used.
17
+ #
18
+ # @return [nil]
19
+ def call(cli, database_url)
20
+ tempfile do |file|
21
+ begin
22
+ dump_data(cli, parse_url(database_url), file)
23
+ yield(file) if block_given?
24
+ ensure
25
+ file.unlink
26
+ end
27
+ end
28
+ end
29
+
30
+ # Converts a database_url to Hash with all the db data.
31
+ #
32
+ # Example:
33
+ # parse_url('mysql://user:pass@localhost:100/test_db')
34
+ #
35
+ # @param [String] database_url the connection info.
36
+ #
37
+ # @return [Hash] the database configuration with the following fields.
38
+ # {
39
+ # db_type: String || nil,
40
+ # host: String || nil,
41
+ # port: String || nil,
42
+ # user: String || nil,
43
+ # password: String || nil,
44
+ # database: String || nil,
45
+ # }
46
+ def parse_url(database_url)
47
+ uri = URI.parse(database_url)
48
+
49
+ {
50
+ db_type: uri.scheme.gsub(/^mysql2/, 'mysql'),
51
+ host: uri.host,
52
+ port: uri.port.to_s,
53
+ user: uri.user,
54
+ password: uri.password,
55
+ database: uri.path.gsub(/^\//, ''),
56
+ }
57
+ end
58
+
59
+ # Create a tmp file
60
+ #
61
+ # @param [Proc] yields the file.
62
+ #
63
+ # @return [nil, Tempfile]
64
+ def tempfile
65
+ tmp = dumpfile_source.call(['original_dump', 'sql'])
66
+ block_given? ? yield(tmp) : tmp
67
+ end
68
+ protected :tempfile
69
+
70
+ # Tmp file generator
71
+ #
72
+ # @return [Proc] a lambda that generates the file.
73
+ def dumpfile_source
74
+ @dumpfile_source ||= Tempfile.public_method(:new)
75
+ end
76
+ protected :dumpfile_source
77
+
78
+ # Dump the data from the database configuration and
79
+ # outputs it to the given file.
80
+ #
81
+ # @param [#run] cli the cli program that responds to `#run`.
82
+ # @param [Hash] db_config database configuration from `#parse_url`.
83
+ # @param [Tempfile, IO, File] file the file to write the dump.
84
+ #
85
+ # @return [nil]
86
+ def dump_data(cli, db_config, file)
87
+ dump_options = %w(-c
88
+ --add-drop-table
89
+ --add-locks
90
+ --single-transaction
91
+ --set-charset
92
+ --create-options
93
+ --disable-keys
94
+ --quick).join(' ')
95
+ dump_options << " -u #{db_config[:user]}" if db_config[:user]
96
+ dump_options << " -h #{db_config[:host]}" if db_config[:host]
97
+ if db_config[:port] && !db_config[:port].empty?
98
+ dump_options << " -P #{db_config[:port]}"
99
+ end
100
+ dump_options << " -p#{db_config[:password]}" if db_config[:password]
101
+ dump_options << " #{db_config[:database]}"
102
+
103
+ run cli, dump_cmd(dump_options, file)
104
+ end
105
+
106
+ # Dump cli command
107
+ def dump_cmd(options, file)
108
+ "mysqldump #{options} > #{file.path}"
109
+ end
110
+ protected :dump_cmd
111
+
112
+ # Run the command with the cli
113
+ #
114
+ # @param [#run] cli the cli program that responds to `#run`.
115
+ # @param [String] cmd the command to run.
116
+ #
117
+ # @return [nil]
118
+ def run(cli, cmd)
119
+ cli.run cmd, verbose: false, capture: true
120
+ end
121
+ protected :run
122
+ end
123
+ end
@@ -8,7 +8,7 @@ class Strike
8
8
 
9
9
  def initialize(table_source = nil)
10
10
  @table_source = table_source
11
- @tables ||= Hash.new { |h, k| h[k] = -> { :keep } }
11
+ @tables ||= Hash.new { |h, k| h[k] = :keep }
12
12
  end
13
13
 
14
14
  # Parse the given profile and generate the tables defined in it.
@@ -27,7 +27,7 @@ class Strike
27
27
  def table(name, &block)
28
28
  table = table_source.call(&block)
29
29
 
30
- @tables[name.to_sym] = table
30
+ @tables[name.to_sym] = table.call
31
31
  end
32
32
 
33
33
  def table_source
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ require 'my_obfuscate'
4
+
5
+ class Strike
6
+ class Obfuscator
7
+ def initialize(config = {})
8
+ @adapter_source = config[:adapter_source]
9
+ end
10
+
11
+ # Obfuscates the data from input to output with the given information.
12
+ #
13
+ # @param [Hash] tables the tables definitions
14
+ # @param [IO] input the input source to read from.
15
+ # @param [IO] output the output source to write to.
16
+ #
17
+ # @return [nil]
18
+ def call(tables, input, output)
19
+ adapter = adapter_source.call(tables)
20
+ adapter.globally_kept_columns = %w(id created_at updated_at)
21
+
22
+ adapter.obfuscate(input, output)
23
+ end
24
+
25
+ # Adapter generator.
26
+ def adapter_source
27
+ @adapter_source ||= MyObfuscate.public_method(:new)
28
+ end
29
+ protected :adapter_source
30
+ end
31
+ end
@@ -0,0 +1,53 @@
1
+ -- MySQL dump 10.13 Distrib 5.5.29, for osx10.8 (i386)
2
+ --
3
+ -- Host: localhost Database: example
4
+ -- ------------------------------------------------------
5
+ -- Server version 5.5.29
6
+
7
+ /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
8
+ /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
9
+ /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
10
+ /*!40101 SET NAMES utf8 */;
11
+ /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
12
+ /*!40103 SET TIME_ZONE='+00:00' */;
13
+ /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
14
+ /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
15
+ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
16
+ /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
17
+
18
+ --
19
+ -- Table structure for table `devices`
20
+ --
21
+
22
+ DROP TABLE IF EXISTS `devices`;
23
+ /*!40101 SET @saved_cs_client = @@character_set_client */;
24
+ /*!40101 SET character_set_client = utf8 */;
25
+ CREATE TABLE `devices` (
26
+ `id` int(11) NOT NULL AUTO_INCREMENT,
27
+ `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
28
+ `created_at` datetime DEFAULT NULL,
29
+ `updated_at` datetime DEFAULT NULL,
30
+ PRIMARY KEY (`id`),
31
+ ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
32
+ /*!40101 SET character_set_client = @saved_cs_client */;
33
+
34
+ --
35
+ -- Dumping data for table `devices`
36
+ --
37
+
38
+ LOCK TABLES `devices` WRITE;
39
+ /*!40000 ALTER TABLE `devices` DISABLE KEYS */;
40
+ INSERT INTO `devices` (`id`, `name`, `created_at`, `updated_at`) VALUES (1,'Original name','2010-10-20 13:40:20','2012-08-24 06:32:31'),(2,'Original name','2010-10-20 13:40:32','2012-10-24 07:39:02'),(3,'Original name','2010-10-20 13:40:46','2012-09-13 10:17:37');
41
+ /*!40000 ALTER TABLE `devices` ENABLE KEYS */;
42
+ UNLOCK TABLES;
43
+ /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
44
+
45
+ /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
46
+ /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
47
+ /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
48
+ /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
49
+ /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
50
+ /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
51
+ /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
52
+
53
+ -- Dump completed on 2013-01-11 15:47:10
@@ -0,0 +1,3 @@
1
+ table :devices do |t|
2
+ t.name type: :fixed, string: proc { 'Obfuscated name' }
3
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../minitest_helper'
4
+ require 'strike'
5
+
6
+ describe Strike, 'Use of Strike in the cli' do
7
+ describe '#obfuscate' do
8
+ let(:assets_path) { File.join(File.dirname(__FILE__), '..', 'assets') }
9
+ let(:input) { "#{assets_path}/dump.sql" }
10
+ let(:profile) { "#{assets_path}/dump_profile.rb" }
11
+ let(:params) { %W(obfuscate --input=#{input} --profile=#{profile}) }
12
+
13
+ it 'should obfuscate the sql dump' do
14
+ out = capture_io { Strike.start(params) }.join('')
15
+
16
+ out.wont_match /Original name/
17
+ # dump_profile.rb sets this string in each name
18
+ out.must_match /Obfuscated name/
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,94 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../../minitest_helper'
4
+ require 'strike/dumper'
5
+
6
+ describe Strike::Dumper do
7
+ let(:database_url) { 'mysql://test:pass@localhost:3005/test' }
8
+ let(:database_config) do
9
+ {
10
+ db_type: 'mysql',
11
+ host: 'localhost',
12
+ port: '3005',
13
+ user: 'test',
14
+ password: 'pass',
15
+ database: 'test',
16
+ }
17
+ end
18
+
19
+ let(:options) do
20
+ dump_options = %w(-c
21
+ --add-drop-table
22
+ --add-locks
23
+ --single-transaction
24
+ --set-charset
25
+ --create-options
26
+ --disable-keys
27
+ --quick).join(' ')
28
+ dump_options << " -u #{database_config[:user]}"
29
+ dump_options << " -h #{database_config[:host]}"
30
+ dump_options << " -P #{database_config[:port]}"
31
+ dump_options << " -p#{database_config[:password]}"
32
+ dump_options << " #{database_config[:database]}"
33
+
34
+ dump_options
35
+ end
36
+
37
+ let(:cli) do
38
+ MiniTest::Mock.new.expect(
39
+ :run,
40
+ true,
41
+ ["mysqldump #{options} > path", { verbose: false, capture: true }]
42
+ )
43
+ end
44
+
45
+ let(:dumper) { Strike::Dumper.new }
46
+
47
+ subject { dumper }
48
+
49
+ describe '#parse_url' do
50
+ it 'should parse the given connection as a url' do
51
+ subject.parse_url(database_url).must_equal database_config
52
+ end
53
+ end
54
+
55
+ describe '#dump_data' do
56
+ let(:output) { MiniTest::Mock.new.expect(:path, 'path') }
57
+
58
+ it 'should dump data with the default options' do
59
+ subject.dump_data(cli, database_config, output).must_equal true
60
+ end
61
+
62
+ after do
63
+ output.verify
64
+ cli.verify
65
+ end
66
+ end
67
+
68
+ describe '#call' do
69
+ let(:output) do
70
+ MiniTest::Mock.new.
71
+ expect(:path, 'path').
72
+ expect(:unlink, true).
73
+ expect(:must_equal, true, [MiniTest::Mock])
74
+ end
75
+
76
+ let(:dumpfile_source) do
77
+ MiniTest::Mock.new.expect(:call, output, [['original_dump', 'sql']])
78
+ end
79
+
80
+ let(:dumper) { Strike::Dumper.new(dumpfile_source: dumpfile_source) }
81
+
82
+ it 'should generate dump file with default options and a database_url' do
83
+ subject.call(cli, database_url) do |file|
84
+ file.must_equal output
85
+ end
86
+ end
87
+
88
+ after do
89
+ dumpfile_source.verify
90
+ output.verify
91
+ cli.verify
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../../minitest_helper'
4
+ require 'strike/interpreter'
5
+
6
+ describe Strike::Interpreter do
7
+
8
+ let(:table_users) { { name: :keep } }
9
+ let(:table_movies) { :keep }
10
+
11
+ let(:table_source) do
12
+ ->(&block) { block ? block.call(table_mock) : -> { table_movies } }
13
+ end
14
+
15
+ let(:table_users) { {name: :keep } }
16
+
17
+ let(:table_mock) do
18
+ tb = MiniTest::Mock.new.expect(:call, table_users)
19
+
20
+ MiniTest::Mock.new.expect(:name, tb, [:first_name])
21
+ end
22
+
23
+ let(:profile) do
24
+ <<-PROFILE
25
+ table :users do |t|
26
+ t.name :first_name
27
+ end
28
+
29
+ table :movies
30
+ PROFILE
31
+ end
32
+
33
+ subject { Strike::Interpreter.new(table_source) }
34
+
35
+ describe '#parse' do
36
+ let(:tables) { subject.parse(profile) }
37
+
38
+ it 'should parse all profile tables' do
39
+ tables.count.must_equal 2
40
+ end
41
+
42
+ it 'should parse tables with a block' do
43
+ tables[:users].must_equal table_users
44
+ table_mock.verify
45
+ end
46
+
47
+ it 'should parse tables without a block' do
48
+ tables[:movies].must_equal table_movies
49
+ end
50
+ end
51
+
52
+ describe '#tables' do
53
+ let(:tables) { subject.tables }
54
+
55
+ it 'should have default tables' do
56
+ tables[:test].must_equal :keep
57
+ tables[:test2].must_equal :keep
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../../minitest_helper'
4
+ require 'strike/obfuscator'
5
+
6
+ describe Strike::Obfuscator do
7
+ let(:input) { Object.new }
8
+ let(:output) { Object.new }
9
+ let(:tables) { { users: :keep, movies: :keep } }
10
+ let(:adapter_mock) do
11
+ MiniTest::Mock.new.
12
+ expect(:globally_kept_columns=, true, [%w(id created_at updated_at)]).
13
+ expect(:obfuscate, true, [input, output])
14
+ end
15
+ let(:adapter_source) do
16
+ MiniTest::Mock.new.expect(:call, adapter_mock, [tables])
17
+ end
18
+
19
+ let(:obfuscator) { Strike::Obfuscator.new(adapter_source: adapter_source) }
20
+
21
+ subject { obfuscator }
22
+
23
+ describe '#call' do
24
+ it 'should prepare the adapter and call it' do
25
+ subject.call(tables, input, output).must_equal true
26
+ end
27
+
28
+ after do
29
+ adapter_source.verify
30
+ adapter_mock.verify
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../../minitest_helper'
4
+ require 'strike/table'
5
+
6
+ describe Strike::Table do
7
+ let(:hash) { { name: :test } }
8
+ let(:table) { Strike::Table.new }
9
+
10
+ subject { table }
11
+
12
+ describe '#method_missing' do
13
+ it 'should respond to missing methods' do
14
+ subject.name(:test).wont_be_nil
15
+ subject.test.wont_be_nil
16
+ end
17
+ end
18
+
19
+ describe '#to_hash' do
20
+ before { subject.name(:test) }
21
+
22
+ it 'should save method calls as hash' do
23
+ subject.to_hash.must_equal hash
24
+ end
25
+ end
26
+
27
+ describe '#initialize' do
28
+ let(:table) do
29
+ Strike::Table.new do |t|
30
+ t.name :test
31
+ end
32
+ end
33
+
34
+ it 'should accept a block' do
35
+ subject.to_hash.must_equal hash
36
+ end
37
+ end
38
+
39
+ describe '#call' do
40
+ it 'should respond with a Hash' do
41
+ subject.call.must_equal Hash.new
42
+ end
43
+ end
44
+ end
File without changes
@@ -3,8 +3,8 @@
3
3
  Gem::Specification.new do |gem|
4
4
  gem.authors = ['Juan Hernández']
5
5
  gem.email = ['juan.hernandez@wuaki.tv']
6
- gem.description = %q{Dump a mysql database with sensitive data encrypted}
7
- gem.summary = %q{Dump a mysql database with sensitive data encrypted}
6
+ gem.description = %q{Obfuscate a mysql dump database with sensitive data}
7
+ gem.summary = %q{Dump and obfuscate a mysql database with sensitive data}
8
8
  gem.homepage = 'https://github.com/wuakitv/strike'
9
9
 
10
10
  gem.files = `git ls-files`.split($\)
@@ -16,8 +16,5 @@ Gem::Specification.new do |gem|
16
16
 
17
17
  gem.add_runtime_dependency 'rake', '~> 0.9'
18
18
  gem.add_runtime_dependency 'my_obfuscate', '~> 0.3.7'
19
- gem.add_runtime_dependency 'sequel', '~> 3.39'
20
- gem.add_runtime_dependency 'mysql2', '~> 0.3.11'
21
- gem.add_runtime_dependency 'sqlite3', '~> 1.3.6'
22
19
  gem.add_runtime_dependency 'thor', '~> 0.16.0'
23
20
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strike
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-27 00:00:00.000000000 Z
12
+ date: 2013-01-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -43,54 +43,6 @@ dependencies:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
45
  version: 0.3.7
46
- - !ruby/object:Gem::Dependency
47
- name: sequel
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ~>
52
- - !ruby/object:Gem::Version
53
- version: '3.39'
54
- type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ~>
60
- - !ruby/object:Gem::Version
61
- version: '3.39'
62
- - !ruby/object:Gem::Dependency
63
- name: mysql2
64
- requirement: !ruby/object:Gem::Requirement
65
- none: false
66
- requirements:
67
- - - ~>
68
- - !ruby/object:Gem::Version
69
- version: 0.3.11
70
- type: :runtime
71
- prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ~>
76
- - !ruby/object:Gem::Version
77
- version: 0.3.11
78
- - !ruby/object:Gem::Dependency
79
- name: sqlite3
80
- requirement: !ruby/object:Gem::Requirement
81
- none: false
82
- requirements:
83
- - - ~>
84
- - !ruby/object:Gem::Version
85
- version: 1.3.6
86
- type: :runtime
87
- prerelease: false
88
- version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
- requirements:
91
- - - ~>
92
- - !ruby/object:Gem::Version
93
- version: 1.3.6
94
46
  - !ruby/object:Gem::Dependency
95
47
  name: thor
96
48
  requirement: !ruby/object:Gem::Requirement
@@ -107,7 +59,7 @@ dependencies:
107
59
  - - ~>
108
60
  - !ruby/object:Gem::Version
109
61
  version: 0.16.0
110
- description: Dump a mysql database with sensitive data encrypted
62
+ description: Obfuscate a mysql dump database with sensitive data
111
63
  email:
112
64
  - juan.hernandez@wuaki.tv
113
65
  executables:
@@ -125,13 +77,19 @@ files:
125
77
  - VERSION
126
78
  - bin/strike
127
79
  - lib/strike.rb
128
- - lib/strike/agent.rb
80
+ - lib/strike/dumper.rb
129
81
  - lib/strike/interpreter.rb
82
+ - lib/strike/obfuscator.rb
130
83
  - lib/strike/table.rb
84
+ - spec/assets/dump.sql
85
+ - spec/assets/dump_profile.rb
86
+ - spec/bin/strike_spec.rb
87
+ - spec/lib/strike/dumper_spec.rb
88
+ - spec/lib/strike/interpreter_spec.rb
89
+ - spec/lib/strike/obfuscator_spec.rb
90
+ - spec/lib/strike/table_spec.rb
91
+ - spec/minitest_helper.rb
131
92
  - strike.gemspec
132
- - test/lib/strike/interpreter_test.rb
133
- - test/lib/strike/table_test.rb
134
- - test/minitest_helper.rb
135
93
  homepage: https://github.com/wuakitv/strike
136
94
  licenses: []
137
95
  post_install_message:
@@ -155,8 +113,13 @@ rubyforge_project:
155
113
  rubygems_version: 1.8.23
156
114
  signing_key:
157
115
  specification_version: 3
158
- summary: Dump a mysql database with sensitive data encrypted
116
+ summary: Dump and obfuscate a mysql database with sensitive data
159
117
  test_files:
160
- - test/lib/strike/interpreter_test.rb
161
- - test/lib/strike/table_test.rb
162
- - test/minitest_helper.rb
118
+ - spec/assets/dump.sql
119
+ - spec/assets/dump_profile.rb
120
+ - spec/bin/strike_spec.rb
121
+ - spec/lib/strike/dumper_spec.rb
122
+ - spec/lib/strike/interpreter_spec.rb
123
+ - spec/lib/strike/obfuscator_spec.rb
124
+ - spec/lib/strike/table_spec.rb
125
+ - spec/minitest_helper.rb
@@ -1,106 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'tempfile'
4
- require 'mysql2'
5
- require 'sequel'
6
- require 'my_obfuscate'
7
-
8
- class Strike
9
- class Agent
10
- def initialize(config = {})
11
- @db_connector = config[:db_connector]
12
- @dumpfile_source = config[:dumpfile_source]
13
- @obfuscator_source = config[:obfuscator_source]
14
- end
15
-
16
- def connect_to_db(database_url)
17
- db_connector.call(database_url.gsub(/^mysql:/, 'mysql2:'))
18
- end
19
- protected :connect_to_db
20
-
21
- def db_connector
22
- @db_connector ||= Sequel.public_method(:connect)
23
- end
24
- protected :db_connector
25
-
26
- def call(cli, database_url, tables, output = $stdout)
27
- @cli = cli
28
- @db = connect_to_db(database_url)
29
- @tables = tables
30
-
31
- tempfile do |file|
32
- dump_data(@db.opts, file)
33
- obfuscate_data(file, output)
34
- end
35
- end
36
-
37
- def tempfile(&block)
38
- tmp = dumpfile_source.call(['original_dump', 'sql']) do |file|
39
- block.call(file)
40
- file
41
- end
42
- ensure
43
- tmp.unlink if tmp
44
- end
45
- protected :tempfile
46
-
47
- def dumpfile_source
48
- @dumpfile_source ||= Tempfile.public_method(:open)
49
- end
50
- protected :dumpfile_source
51
-
52
- # TODO: support more databases
53
- def dump_data(db_config, file)
54
- dump_options = %w(-c
55
- --add-drop-table
56
- --add-locks
57
- --single-transaction
58
- --set-charset
59
- --create-options
60
- --disable-keys
61
- --quick).join(' ')
62
- dump_options << " -u #{db_config[:user]}" if db_config[:user]
63
- dump_options << " -h #{db_config[:host]}" if db_config[:host]
64
- dump_options << " -P #{db_config[:port]}" if db_config[:port]
65
- dump_options << " -p#{db_config[:password]}" if db_config[:password]
66
- dump_options << " #{db_config[:database]}"
67
-
68
- run dump_cmd(dump_options, file)
69
- end
70
-
71
- def dump_cmd(options, file)
72
- "mysqldump #{options} > #{file.path}"
73
- end
74
- protected :dump_cmd
75
-
76
- def run(cmd)
77
- @cli.run cmd, verbose: false, capture: true
78
- end
79
- protected :run
80
-
81
- def obfuscate_data(input, output)
82
- obfuscator = obfuscator_source.call(table_definitions)
83
- obfuscator.globally_kept_columns = %w(id created_at updated_at)
84
-
85
- obfuscator.obfuscate(input, output)
86
- end
87
-
88
- def obfuscator_source
89
- @obfuscator_source ||= MyObfuscate.public_method(:new)
90
- end
91
- protected :obfuscator_source
92
-
93
- def table_definitions
94
- db_tables.reduce({}) do |acc, table|
95
- acc[table] = @tables[table].call
96
- acc
97
- end
98
- end
99
- protected :table_definitions
100
-
101
- def db_tables
102
- @db.tables
103
- end
104
- protected :db_tables
105
- end
106
- end
@@ -1,44 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require_relative '../../minitest_helper'
4
- require 'strike/interpreter'
5
-
6
- class Strike::InterpreterTest < MiniTest::Unit::TestCase
7
- def setup
8
- @interpreter = Strike::Interpreter.new(table_source)
9
- @profile = <<-PROFILE
10
- table :users do |t|
11
- t.name :first_name
12
- end
13
-
14
- table :movies
15
- PROFILE
16
- end
17
-
18
- def test_should_parse_a_profile_into_tables
19
- tables = @interpreter.parse(@profile)
20
-
21
- assert_equal 2, tables.count
22
- assert tables[:users]
23
- assert tables[:movies]
24
-
25
- table_mock.verify
26
- end
27
-
28
- def test_should_have_default_tables
29
- tables = @interpreter.tables
30
-
31
- assert_equal :keep, tables[:test].call
32
- assert_equal :keep, tables[:test2].call
33
- end
34
-
35
- private
36
-
37
- def table_source
38
- ->(&block) { block ? block.call(table_mock) : table_mock }
39
- end
40
-
41
- def table_mock
42
- @table_mock ||= MiniTest::Mock.new.expect(:name, true, [:first_name])
43
- end
44
- end
@@ -1,35 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require_relative '../../minitest_helper'
4
- require 'strike/table'
5
-
6
- class Strike::TableTest < MiniTest::Unit::TestCase
7
- def setup
8
- @table = Strike::Table.new
9
- end
10
-
11
- def test_should_respond_to_missing_methods
12
- assert @table.name(:test)
13
- assert @table.test
14
- end
15
-
16
- def test_should_save_method_calls_as_hash
17
- expected = { name: :test }
18
- @table.name(:test)
19
-
20
- assert_equal expected, @table.to_hash
21
- end
22
-
23
- def test_should_respond_to_call
24
- assert_equal Hash.new, @table.call
25
- end
26
-
27
- def test_should_accept_a_block_when_its_initialized
28
- table = Strike::Table.new do |t|
29
- t.name :test
30
- end
31
- expected = { name: :test }
32
-
33
- assert_equal expected, table.to_hash
34
- end
35
- end