strike 0.3.6 → 0.4.0

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.
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