pg_audit_log 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.rdoc +3 -11
- data/lib/pg_audit_log.rb +1 -0
- data/lib/pg_audit_log/extensions/3.0/postgresql_adapter.rb +3 -62
- data/lib/pg_audit_log/extensions/3.1/postgresql_adapter.rb +3 -62
- data/lib/pg_audit_log/extensions/shared/postgresql_adapter.rb +68 -0
- data/lib/pg_audit_log/function.rb +26 -6
- data/lib/pg_audit_log/version.rb +1 -1
- data/spec/configuration_spec.rb +1 -7
- metadata +15 -14
data/README.rdoc
CHANGED
@@ -13,19 +13,11 @@ Compatible with Rails 3.0.x and 3.1.x
|
|
13
13
|
|
14
14
|
== INSTALL
|
15
15
|
|
16
|
-
=== Enable
|
16
|
+
=== Enable plpgsql langauges in your postgresql instance
|
17
17
|
|
18
|
-
|
18
|
+
As a superuser in postgres make sure your database has plpgsql enabled:
|
19
19
|
|
20
|
-
|
21
|
-
For homebrew: /usr/local/var/postgres/postgresql.conf
|
22
|
-
For linux: it varies from distro to distro.
|
23
|
-
|
24
|
-
At the bottom of the file add the following:
|
25
|
-
|
26
|
-
custom_variable_classes = 'audit'
|
27
|
-
|
28
|
-
Then restart your PostgreSQL server
|
20
|
+
CREATE OR REPLACE PROCEDURAL LANGUAGE plpgsql;
|
29
21
|
|
30
22
|
=== Rails 3
|
31
23
|
|
data/lib/pg_audit_log.rb
CHANGED
@@ -3,11 +3,9 @@ require "active_record/connection_adapters/postgresql_adapter"
|
|
3
3
|
# Did not want to reopen the class but sending an include seemingly is not working.
|
4
4
|
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
5
5
|
def execute_with_auditing(sql, name = nil)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
log_user_id = %[SET audit.user_id = #{current_user.try(:id) || "-1"}]
|
10
|
-
log_user_unique_name = %[SET audit.user_unique_name = "#{user_unique_name}"]
|
6
|
+
user_id, unique_name = user_id_and_name
|
7
|
+
log_user_id = PgAuditLog::Function.user_identifier_temporary_function(user_id)
|
8
|
+
log_user_unique_name = PgAuditLog::Function.user_unique_name_temporary_function(unique_name)
|
11
9
|
|
12
10
|
log([log_user_id, log_user_unique_name, sql].join("; "), name) do
|
13
11
|
if @async
|
@@ -23,62 +21,5 @@ class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
|
23
21
|
end
|
24
22
|
|
25
23
|
alias_method_chain :execute, :auditing
|
26
|
-
|
27
|
-
def begin_db_transaction
|
28
|
-
execute_without_auditing "BEGIN"
|
29
|
-
end
|
30
|
-
|
31
|
-
# Commits a transaction.
|
32
|
-
def commit_db_transaction
|
33
|
-
execute_without_auditing "COMMIT"
|
34
|
-
end
|
35
|
-
|
36
|
-
# Aborts a transaction.
|
37
|
-
def rollback_db_transaction
|
38
|
-
execute_without_auditing "ROLLBACK"
|
39
|
-
end
|
40
|
-
|
41
|
-
def create_savepoint
|
42
|
-
execute_without_auditing("SAVEPOINT #{current_savepoint_name}")
|
43
|
-
end
|
44
|
-
|
45
|
-
def rollback_to_savepoint
|
46
|
-
execute_without_auditing("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
|
47
|
-
end
|
48
|
-
|
49
|
-
def release_savepoint
|
50
|
-
execute_without_auditing("RELEASE SAVEPOINT #{current_savepoint_name}")
|
51
|
-
end
|
52
|
-
|
53
|
-
def drop_table_with_auditing(table_name, options = {})
|
54
|
-
if PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
|
55
|
-
PgAuditLog::Triggers.drop_for_table(table_name)
|
56
|
-
end
|
57
|
-
drop_table_without_auditing(table_name, options)
|
58
|
-
end
|
59
|
-
alias_method_chain :drop_table, :auditing
|
60
|
-
|
61
|
-
def create_table_with_auditing(table_name, options = {}, &block)
|
62
|
-
create_table_without_auditing(table_name, options, &block)
|
63
|
-
unless options[:temporary] ||
|
64
|
-
PgAuditLog::IGNORED_TABLES.include?(table_name) ||
|
65
|
-
PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
|
66
|
-
PgAuditLog::Triggers.create_for_table(table_name)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
alias_method_chain :create_table, :auditing
|
70
|
-
|
71
|
-
def rename_table_with_auditing(table_name, new_name)
|
72
|
-
rename_table_without_auditing(table_name, new_name)
|
73
|
-
if PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
|
74
|
-
PgAuditLog::Triggers.drop_for_table(table_name)
|
75
|
-
end
|
76
|
-
unless PgAuditLog::IGNORED_TABLES.include?(table_name) ||
|
77
|
-
PgAuditLog::Triggers.tables_with_triggers.include?(new_name)
|
78
|
-
PgAuditLog::Triggers.create_for_table(new_name)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
alias_method_chain :rename_table, :auditing
|
82
|
-
|
83
24
|
end
|
84
25
|
|
@@ -3,11 +3,9 @@ require "active_record/connection_adapters/postgresql_adapter"
|
|
3
3
|
# Did not want to reopen the class but sending an include seemingly is not working.
|
4
4
|
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
5
5
|
def generate_auditing_sql(sql)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
log_user_id = %[SET audit.user_id = #{current_user.try(:id) || "-1"}]
|
10
|
-
log_user_unique_name = %[SET audit.user_unique_name = "#{user_unique_name}"]
|
6
|
+
user_id, unique_name = user_id_and_name
|
7
|
+
log_user_id = PgAuditLog::Function.user_identifier_temporary_function(user_id)
|
8
|
+
log_user_unique_name = PgAuditLog::Function.user_unique_name_temporary_function(unique_name)
|
11
9
|
{ :user_id => log_user_id, :unique_name => log_user_unique_name, :sql => sql }
|
12
10
|
end
|
13
11
|
|
@@ -32,62 +30,5 @@ class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
|
32
30
|
end
|
33
31
|
end
|
34
32
|
alias_method_chain :execute, :auditing
|
35
|
-
|
36
|
-
def begin_db_transaction
|
37
|
-
execute_without_auditing "BEGIN"
|
38
|
-
end
|
39
|
-
|
40
|
-
# Commits a transaction.
|
41
|
-
def commit_db_transaction
|
42
|
-
execute_without_auditing "COMMIT"
|
43
|
-
end
|
44
|
-
|
45
|
-
# Aborts a transaction.
|
46
|
-
def rollback_db_transaction
|
47
|
-
execute_without_auditing "ROLLBACK"
|
48
|
-
end
|
49
|
-
|
50
|
-
def create_savepoint
|
51
|
-
execute_without_auditing("SAVEPOINT #{current_savepoint_name}")
|
52
|
-
end
|
53
|
-
|
54
|
-
def rollback_to_savepoint
|
55
|
-
execute_without_auditing("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
|
56
|
-
end
|
57
|
-
|
58
|
-
def release_savepoint
|
59
|
-
execute_without_auditing("RELEASE SAVEPOINT #{current_savepoint_name}")
|
60
|
-
end
|
61
|
-
|
62
|
-
def drop_table_with_auditing(table_name, options = {})
|
63
|
-
if PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
|
64
|
-
PgAuditLog::Triggers.drop_for_table(table_name)
|
65
|
-
end
|
66
|
-
drop_table_without_auditing(table_name, options)
|
67
|
-
end
|
68
|
-
alias_method_chain :drop_table, :auditing
|
69
|
-
|
70
|
-
def create_table_with_auditing(table_name, options = {}, &block)
|
71
|
-
create_table_without_auditing(table_name, options, &block)
|
72
|
-
unless options[:temporary] ||
|
73
|
-
PgAuditLog::IGNORED_TABLES.include?(table_name) ||
|
74
|
-
PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
|
75
|
-
PgAuditLog::Triggers.create_for_table(table_name)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
alias_method_chain :create_table, :auditing
|
79
|
-
|
80
|
-
def rename_table_with_auditing(table_name, new_name)
|
81
|
-
rename_table_without_auditing(table_name, new_name)
|
82
|
-
if PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
|
83
|
-
PgAuditLog::Triggers.drop_for_table(table_name)
|
84
|
-
end
|
85
|
-
unless PgAuditLog::IGNORED_TABLES.include?(table_name) ||
|
86
|
-
PgAuditLog::Triggers.tables_with_triggers.include?(new_name)
|
87
|
-
PgAuditLog::Triggers.create_for_table(new_name)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
alias_method_chain :rename_table, :auditing
|
91
|
-
|
92
33
|
end
|
93
34
|
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "active_record/connection_adapters/postgresql_adapter"
|
2
|
+
|
3
|
+
# Did not want to reopen the class but sending an include seemingly is not working.
|
4
|
+
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
5
|
+
def begin_db_transaction
|
6
|
+
execute_without_auditing "BEGIN"
|
7
|
+
end
|
8
|
+
|
9
|
+
def commit_db_transaction
|
10
|
+
execute_without_auditing "COMMIT"
|
11
|
+
end
|
12
|
+
|
13
|
+
def rollback_db_transaction
|
14
|
+
execute_without_auditing "ROLLBACK"
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_savepoint
|
18
|
+
execute_without_auditing("SAVEPOINT #{current_savepoint_name}")
|
19
|
+
end
|
20
|
+
|
21
|
+
def rollback_to_savepoint
|
22
|
+
execute_without_auditing("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
|
23
|
+
end
|
24
|
+
|
25
|
+
def release_savepoint
|
26
|
+
execute_without_auditing("RELEASE SAVEPOINT #{current_savepoint_name}")
|
27
|
+
end
|
28
|
+
|
29
|
+
def drop_table_with_auditing(table_name, options = {})
|
30
|
+
if PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
|
31
|
+
PgAuditLog::Triggers.drop_for_table(table_name)
|
32
|
+
end
|
33
|
+
drop_table_without_auditing(table_name, options)
|
34
|
+
end
|
35
|
+
alias_method_chain :drop_table, :auditing
|
36
|
+
|
37
|
+
def create_table_with_auditing(table_name, options = {}, &block)
|
38
|
+
create_table_without_auditing(table_name, options, &block)
|
39
|
+
unless options[:temporary] ||
|
40
|
+
PgAuditLog::IGNORED_TABLES.include?(table_name) ||
|
41
|
+
PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
|
42
|
+
PgAuditLog::Triggers.create_for_table(table_name)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
alias_method_chain :create_table, :auditing
|
46
|
+
|
47
|
+
def rename_table_with_auditing(table_name, new_name)
|
48
|
+
rename_table_without_auditing(table_name, new_name)
|
49
|
+
if PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
|
50
|
+
PgAuditLog::Triggers.drop_for_table(table_name)
|
51
|
+
end
|
52
|
+
unless PgAuditLog::IGNORED_TABLES.include?(table_name) ||
|
53
|
+
PgAuditLog::Triggers.tables_with_triggers.include?(new_name)
|
54
|
+
PgAuditLog::Triggers.create_for_table(new_name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
alias_method_chain :rename_table, :auditing
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def user_id_and_name
|
62
|
+
current_user = Thread.current[:current_user]
|
63
|
+
user_id = current_user.try(:id) || "-1"
|
64
|
+
user_unique_name = current_user.try(:unique_name) || "UNKNOWN"
|
65
|
+
return [user_id, user_unique_name]
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -5,10 +5,6 @@ module PgAuditLog
|
|
5
5
|
"audit_changes"
|
6
6
|
end
|
7
7
|
|
8
|
-
def custom_variable
|
9
|
-
"audit"
|
10
|
-
end
|
11
|
-
|
12
8
|
def users_table_name
|
13
9
|
"users"
|
14
10
|
end
|
@@ -25,6 +21,30 @@ module PgAuditLog
|
|
25
21
|
"last_accessed_at"
|
26
22
|
end
|
27
23
|
|
24
|
+
def user_identifier_temporary_function(user_id)
|
25
|
+
sql = <<-SQL
|
26
|
+
CREATE OR REPLACE FUNCTION pg_temp.pg_audit_log_user_identifier() RETURNS integer
|
27
|
+
LANGUAGE plpgsql
|
28
|
+
AS $_$
|
29
|
+
BEGIN
|
30
|
+
RETURN #{user_id};
|
31
|
+
END
|
32
|
+
$_$;
|
33
|
+
SQL
|
34
|
+
end
|
35
|
+
|
36
|
+
def user_unique_name_temporary_function(username)
|
37
|
+
sql = <<-SQL
|
38
|
+
CREATE OR REPLACE FUNCTION pg_temp.pg_audit_log_user_unique_name() RETURNS varchar
|
39
|
+
LANGUAGE plpgsql
|
40
|
+
AS $_$
|
41
|
+
BEGIN
|
42
|
+
RETURN '#{username}';
|
43
|
+
END
|
44
|
+
$_$;
|
45
|
+
SQL
|
46
|
+
end
|
47
|
+
|
28
48
|
def install
|
29
49
|
execute <<-SQL
|
30
50
|
CREATE OR REPLACE PROCEDURAL LANGUAGE plpgsql;
|
@@ -46,8 +66,8 @@ module PgAuditLog
|
|
46
66
|
old_value := NULL;
|
47
67
|
primary_key_column := NULL;
|
48
68
|
primary_key_value := NULL;
|
49
|
-
user_identifier :=
|
50
|
-
unique_name :=
|
69
|
+
user_identifier := pg_temp.pg_audit_log_user_identifier();
|
70
|
+
unique_name := pg_temp.pg_audit_log_user_unique_name();
|
51
71
|
column_name := col.column_name;
|
52
72
|
|
53
73
|
EXECUTE 'SELECT pg_attribute.attname
|
data/lib/pg_audit_log/version.rb
CHANGED
data/spec/configuration_spec.rb
CHANGED
@@ -5,14 +5,8 @@ describe "the PostgreSQL database" do
|
|
5
5
|
ActiveRecord::Base.connection.reconnect!
|
6
6
|
end
|
7
7
|
|
8
|
-
it "allows custom class variables for audit" do
|
9
|
-
lambda {
|
10
|
-
ActiveRecord::Base.connection.execute('SET audit.test = 1')
|
11
|
-
}.should_not raise_error(ActiveRecord::StatementInvalid), "Your postgres is not configured for auditing. See README.rdoc"
|
12
|
-
end
|
13
|
-
|
14
8
|
it "has an audit log table" do
|
15
9
|
ActiveRecord::Base.connection.table_exists?("audit_log").should be_true
|
16
10
|
end
|
17
11
|
|
18
|
-
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_audit_log
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10-
|
12
|
+
date: 2011-10-03 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement: &
|
16
|
+
requirement: &2152506680 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 3.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2152506680
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: pg
|
27
|
-
requirement: &
|
27
|
+
requirement: &2152505720 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 0.9.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2152505720
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec-rails
|
38
|
-
requirement: &
|
38
|
+
requirement: &2152505120 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2152505120
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: with_model
|
49
|
-
requirement: &
|
49
|
+
requirement: &2152503960 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 0.1.3
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2152503960
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: autotest
|
60
|
-
requirement: &
|
60
|
+
requirement: &2152503100 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2152503100
|
69
69
|
description: A completely transparent audit logging component for your application
|
70
70
|
using a stored procedure and triggers. Comes with specs for your project and a rake
|
71
71
|
task to generate the reverse SQL to undo changes logged
|
@@ -94,6 +94,7 @@ files:
|
|
94
94
|
- lib/pg_audit_log/entry.rb
|
95
95
|
- lib/pg_audit_log/extensions/3.0/postgresql_adapter.rb
|
96
96
|
- lib/pg_audit_log/extensions/3.1/postgresql_adapter.rb
|
97
|
+
- lib/pg_audit_log/extensions/shared/postgresql_adapter.rb
|
97
98
|
- lib/pg_audit_log/function.rb
|
98
99
|
- lib/pg_audit_log/triggers.rb
|
99
100
|
- lib/pg_audit_log/version.rb
|
@@ -119,7 +120,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
119
120
|
version: '0'
|
120
121
|
segments:
|
121
122
|
- 0
|
122
|
-
hash:
|
123
|
+
hash: -732310515117041189
|
123
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
125
|
none: false
|
125
126
|
requirements:
|
@@ -128,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
129
|
version: '0'
|
129
130
|
segments:
|
130
131
|
- 0
|
131
|
-
hash:
|
132
|
+
hash: -732310515117041189
|
132
133
|
requirements: []
|
133
134
|
rubyforge_project:
|
134
135
|
rubygems_version: 1.8.10
|