db-evolve 0.1.7 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 021f7f7fa230d96348c7531d71ea4f8cc6a14af0
4
- data.tar.gz: 64e7d50a940325d5fc7669c2ed39ea51f90be8eb
3
+ metadata.gz: 8abf7748fc2f2f9425e4d63c7656593de7fb889b
4
+ data.tar.gz: 4a30a774c669bcc6493213269ec75b770ab1b579
5
5
  SHA512:
6
- metadata.gz: 63e145aa1e7166fa52648376359a8832e624c44a91af12409ed8c25cd065932e42725e15bfd746b15ff280be645e863e22f1db6bb735e7c2543725403c720661
7
- data.tar.gz: 69e299cbbf73075d9773b81971cea6dbc9a8dc4eac9095dcb26bda57da95f7222cd93463f9f8dd89e5f29c0e2b148508c6de842531ac3311793b73d4e3b37751
6
+ metadata.gz: 833c3994a6603bf1cb55f78d9432d67459c54274017dc33ea4c19ed1e48dd67772f3c036ff0f9e951a188896c93c2f890491c703fe6d6b5a91b22ca2a25e41e0
7
+ data.tar.gz: a2725c132f67375b5c7e955f4da020dd4efb31c14ef5dff07a91f928f4f28aaae176f189252e1a5c7dfc08d8ae43ceceb391ab94ee9b2b5a535aaccc99463e86
data/lib/tasks/db.rb CHANGED
@@ -47,6 +47,34 @@ namespace :db do
47
47
 
48
48
  end
49
49
 
50
+ $i_nagged = false
51
+
52
+ def build_real_connection_config to_exec: false, noop: false
53
+ require 'pg'
54
+ if to_exec
55
+ config_name = "#{Rails.env}_dbevolve"
56
+ if Rails.configuration.database_configuration[config_name].present?
57
+ config = Rails.configuration.database_configuration[config_name].clone
58
+ else
59
+ config = ActiveRecord::Base.connection_config.clone
60
+ unless $i_nagged || noop || Rails.env=='development'
61
+ puts "Your database.yml file does not contain an entry for '#{config_name}', so we're using '#{Rails.env}'. This works if your database user has permission to edit your schema, but this is not recommended outside of development. For more information visit: https://github.com/keredson/ruby-db-evolve/blob/master/README.md#schema-change-permissions"
62
+ $i_nagged = true
63
+ end
64
+ end
65
+ else
66
+ config = ActiveRecord::Base.connection_config.clone
67
+ end
68
+ config.delete(:adapter)
69
+ config.delete(:pool)
70
+ config[:dbname] = config.delete(:database)
71
+ config[:user] = config.delete(:username) || ENV['USER'] || ENV['USERNAME']
72
+ return config
73
+ end
74
+
75
+ def build_real_connection to_exec: false, noop: false
76
+ return PG::Connection.open(build_real_connection_config to_exec: to_exec, noop: noop)
77
+ end
50
78
 
51
79
  def do_evolve(noop, yes, nowait)
52
80
  existing_tables, existing_indexes = load_existing_tables()
@@ -74,6 +102,8 @@ def do_evolve(noop, yes, nowait)
74
102
 
75
103
  to_run += calc_index_changes(existing_indexes, $schema_indexes, renames, rename_cols_by_table)
76
104
 
105
+ to_run += calc_perms_changes($schema_tables, noop) unless $check_perms_for.empty?
106
+
77
107
  to_run += sql_drops(deletes)
78
108
 
79
109
  # prompt and execute
@@ -97,7 +127,7 @@ def do_evolve(noop, yes, nowait)
97
127
  return
98
128
  end
99
129
 
100
- config = ActiveRecord::Base.connection_config
130
+ config = build_real_connection_config to_exec: true
101
131
  puts "Connecting to database:"
102
132
  config.each do |k,v|
103
133
  next if k==:password
@@ -108,11 +138,6 @@ def do_evolve(noop, yes, nowait)
108
138
  print "Run this SQL? (type yes or no) "
109
139
  end
110
140
  if yes || STDIN.gets.strip=='yes'
111
- require 'pg'
112
- config = ActiveRecord::Base.connection_config
113
- config.delete(:adapter)
114
- config[:dbname] = config.delete(:database)
115
- config[:user] = config.delete(:username)
116
141
  if !nowait
117
142
  print "\nExecuting in "
118
143
  [3,2,1].each do |c|
@@ -121,7 +146,7 @@ def do_evolve(noop, yes, nowait)
121
146
  end
122
147
  end
123
148
  puts
124
- conn = PG::Connection.open(config)
149
+ conn = build_real_connection to_exec: true
125
150
  to_run.each do |sql|
126
151
  puts SQLColor.colorize(sql)
127
152
  conn.exec(sql)
@@ -172,6 +197,43 @@ def calc_index_changes(existing_indexes, schema_indexes, table_renames, rename_c
172
197
  return to_run
173
198
  end
174
199
 
200
+ def get_db_username
201
+ username = ActiveRecord::Base.connection_config[:username] || ENV['USER'] || ENV['USERNAME']
202
+ return username
203
+ end
204
+
205
+ def calc_perms_changes schema_tables, noop
206
+ username = get_db_username
207
+ users = ($check_perms_for.map { |user| ActiveRecord::Base::sanitize(user) }).join ","
208
+ database = ActiveRecord::Base.connection_config[:database]
209
+ sql = %{
210
+ select grantee, table_name, privilege_type
211
+ from information_schema.role_table_grants
212
+ where table_catalog=#{ActiveRecord::Base::sanitize(database)}
213
+ and grantee in (#{users})
214
+ and table_schema='public';
215
+ }
216
+ results = build_real_connection(noop: noop).exec(sql)
217
+ existing_perms = Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = Set.new } }
218
+ results.each do |row|
219
+ existing_perms[row['grantee']][row['table_name']].add(row['privilege_type'])
220
+ end
221
+ to_run = []
222
+ schema_tables.each do |table_name, tbl|
223
+ $check_perms_for.each do |user|
224
+ to_grant = (tbl.perms_for_user[user] - existing_perms[user][table_name]).to_a
225
+ to_revoke = (existing_perms[user][table_name] - tbl.perms_for_user[user]).to_a
226
+ to_run.push("GRANT "+ to_grant.join(',') +" ON #{escape_table(table_name)} TO #{user}") unless to_grant.empty?
227
+ to_run.push("REVOKE "+ to_revoke.join(',') +" ON #{escape_table(table_name)} FROM #{user}") unless to_revoke.empty?
228
+ end
229
+ end
230
+
231
+ if !to_run.empty?
232
+ to_run.unshift("\n-- update permissions")
233
+ end
234
+
235
+ return to_run
236
+ end
175
237
 
176
238
 
177
239
  IgnoreTables = Set.new ["schema_migrations"]
@@ -196,12 +258,28 @@ end
196
258
 
197
259
 
198
260
  class Table
199
- attr_accessor :name, :opts, :id, :columns
261
+ attr_accessor :name, :opts, :id, :columns, :perms_for_user
200
262
 
201
263
  def initialize()
202
264
  @columns = []
203
265
  end
204
266
 
267
+ def grant *args, to: nil
268
+ to = get_db_username if to.nil?
269
+ $check_perms_for.add(to)
270
+ args.each do |arg|
271
+ @perms_for_user[to] |= check_perm(arg)
272
+ end
273
+ end
274
+
275
+ def revoke *args, from: nil
276
+ from = get_db_username if from.nil?
277
+ $check_perms_for.add(from)
278
+ args.each do |arg|
279
+ @perms_for_user[from] -= check_perm(arg)
280
+ end
281
+ end
282
+
205
283
  def method_missing(method_sym, *arguments, &block)
206
284
  c = Column.new
207
285
  c.type = method_sym.to_s
@@ -233,11 +311,16 @@ end
233
311
 
234
312
  $schema_tables = {}
235
313
  $akas_tables = Hash.new { |h, k| h[k] = Set.new }
314
+ $check_perms_for = Set.new
236
315
 
237
316
  def create_table(name, opts={})
238
317
  tbl = Table.new
239
318
  tbl.name = name
240
319
  tbl.opts = opts
320
+ tbl.perms_for_user = Hash.new { |h, k| h[k] = Set.new }
321
+ $default_perms_for.each do |k,v|
322
+ tbl.perms_for_user[k] += v
323
+ end
241
324
  if opts
242
325
  if opts.has_key? 'id'
243
326
  tbl.id = opts['id']
@@ -275,6 +358,32 @@ def add_index(table, columns, opts)
275
358
  $schema_indexes.append(opts)
276
359
  end
277
360
 
361
+ $allowed_perms = Set.new ["INSERT", "SELECT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER"]
362
+ $default_perms_for = Hash.new { |h, k| h[k] = Set.new }
363
+
364
+ def check_perm perm
365
+ perm = perm.to_s.upcase
366
+ return Set.new($allowed_perms) if perm=="ALL"
367
+ raise ArgumentError.new("permission #{perm} is not one of #{$allowed_perms.to_a}") unless $allowed_perms.include? perm
368
+ return Set.new [perm]
369
+ end
370
+
371
+ def grant(*perms, to: nil)
372
+ to = get_db_username if to.nil?
373
+ $check_perms_for.add(to)
374
+ perms.each do |perm|
375
+ $default_perms_for[to] |= check_perm(perm)
376
+ end
377
+ end
378
+
379
+ def revoke(*perms, from: nil)
380
+ from = get_db_username if from.nil?
381
+ $check_perms_for.add(from)
382
+ perms.each do |perm|
383
+ $default_perms_for[from] -= check_perm(perm)
384
+ end
385
+ end
386
+
278
387
  module DB
279
388
  module Evolve
280
389
  class Schema
@@ -355,6 +464,9 @@ def sql_adds(tables)
355
464
  end
356
465
  if !$tmp_to_run.empty?
357
466
  $tmp_to_run.unshift("\n-- add tables")
467
+ if !$check_perms_for.empty?
468
+ $tmp_to_run << "REVOKE ALL ON #{(tables.map {|t| escape_table(t)}).join(',')} FROM #{$check_perms_for.to_a.join(',')}"
469
+ end
358
470
  end
359
471
  return $tmp_to_run
360
472
  end
@@ -15,7 +15,7 @@ class SQLColor
15
15
  if sql.strip.start_with?('--')
16
16
  return apply(CYAN, sql)
17
17
  end
18
- sql = sql.gsub(/(CREATE|ALTER|TABLE|COLUMN|ADD|TYPE|BEGIN|TRANSACTION|COMMIT| ON |INDEX|UPDATE|SET|WHERE)/){|s|apply(GREEN, s)}
18
+ sql = sql.gsub(/(CREATE|ALTER|TABLE|COLUMN|ADD|TYPE|BEGIN|TRANSACTION|COMMIT|GRANT|REVOKE| ON |INDEX|UPDATE|SET|WHERE)/){|s|apply(GREEN, s)}
19
19
  sql = sql.gsub(/(DROP)/){|s|apply(RED, s)}
20
20
  sql = sql.gsub(/("[^"]*")/){|s|apply(WHITE, s, bold=true)}
21
21
  return sql
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: db-evolve
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derek Anderson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-11 00:00:00.000000000 Z
11
+ date: 2016-02-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A diff/patch-esque tool to replace schema migrations in Ruby. See https://github.com/keredson/ruby-db-evolve
14
14
  for details.