audited-hp 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +32 -0
  4. data/.yardopts +3 -0
  5. data/Appraisals +22 -0
  6. data/CHANGELOG +153 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +19 -0
  9. data/README.md +299 -0
  10. data/Rakefile +18 -0
  11. data/gemfiles/rails40.gemfile +9 -0
  12. data/gemfiles/rails41.gemfile +8 -0
  13. data/gemfiles/rails42.gemfile +8 -0
  14. data/gemfiles/rails50.gemfile +8 -0
  15. data/lib/audited-rspec.rb +4 -0
  16. data/lib/audited.rb +29 -0
  17. data/lib/audited/audit.rb +149 -0
  18. data/lib/audited/auditor.rb +309 -0
  19. data/lib/audited/rspec_matchers.rb +177 -0
  20. data/lib/audited/sweeper.rb +60 -0
  21. data/lib/audited/version.rb +3 -0
  22. data/lib/generators/audited/install_generator.rb +20 -0
  23. data/lib/generators/audited/migration.rb +15 -0
  24. data/lib/generators/audited/templates/add_association_to_audits.rb +11 -0
  25. data/lib/generators/audited/templates/add_comment_to_audits.rb +9 -0
  26. data/lib/generators/audited/templates/add_remote_address_to_audits.rb +10 -0
  27. data/lib/generators/audited/templates/add_request_uuid_to_audits.rb +10 -0
  28. data/lib/generators/audited/templates/install.rb +30 -0
  29. data/lib/generators/audited/templates/rename_association_to_associated.rb +23 -0
  30. data/lib/generators/audited/templates/rename_changes_to_audited_changes.rb +9 -0
  31. data/lib/generators/audited/templates/rename_parent_to_association.rb +11 -0
  32. data/lib/generators/audited/upgrade_generator.rb +57 -0
  33. data/spec/audited/audit_spec.rb +199 -0
  34. data/spec/audited/auditor_spec.rb +607 -0
  35. data/spec/audited/sweeper_spec.rb +106 -0
  36. data/spec/audited_spec_helpers.rb +20 -0
  37. data/spec/rails_app/config/application.rb +8 -0
  38. data/spec/rails_app/config/database.yml +24 -0
  39. data/spec/rails_app/config/environment.rb +5 -0
  40. data/spec/rails_app/config/environments/development.rb +21 -0
  41. data/spec/rails_app/config/environments/production.rb +35 -0
  42. data/spec/rails_app/config/environments/test.rb +47 -0
  43. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  44. data/spec/rails_app/config/initializers/inflections.rb +2 -0
  45. data/spec/rails_app/config/initializers/secret_token.rb +3 -0
  46. data/spec/rails_app/config/routes.rb +3 -0
  47. data/spec/spec_helper.rb +21 -0
  48. data/spec/support/active_record/models.rb +99 -0
  49. data/spec/support/active_record/schema.rb +81 -0
  50. data/test/db/version_1.rb +17 -0
  51. data/test/db/version_2.rb +18 -0
  52. data/test/db/version_3.rb +19 -0
  53. data/test/db/version_4.rb +20 -0
  54. data/test/db/version_5.rb +18 -0
  55. data/test/db/version_6.rb +17 -0
  56. data/test/install_generator_test.rb +17 -0
  57. data/test/test_helper.rb +19 -0
  58. data/test/upgrade_generator_test.rb +77 -0
  59. metadata +229 -0
@@ -0,0 +1,106 @@
1
+ require "spec_helper"
2
+
3
+ class AuditsController < ActionController::Base
4
+ attr_reader :company
5
+
6
+ def create
7
+ @company = Models::ActiveRecord::Company.create
8
+ head :ok
9
+ end
10
+
11
+ def update
12
+ current_user.update_attributes(password: 'foo')
13
+ head :ok
14
+ end
15
+
16
+ private
17
+
18
+ attr_accessor :current_user
19
+ attr_accessor :custom_user
20
+ end
21
+
22
+ describe AuditsController do
23
+ include RSpec::Rails::ControllerExampleGroup
24
+ render_views
25
+
26
+ before(:each) do
27
+ Audited.current_user_method = :current_user
28
+ end
29
+
30
+ let(:user) { create_user }
31
+
32
+ describe "POST audit" do
33
+
34
+ it "should audit user" do
35
+ controller.send(:current_user=, user)
36
+ expect {
37
+ post :create
38
+ }.to change( Audited::Audit, :count )
39
+
40
+ expect(controller.company.audits.last.user).to eq(user)
41
+ end
42
+
43
+ it "should support custom users for sweepers" do
44
+ controller.send(:custom_user=, user)
45
+ Audited.current_user_method = :custom_user
46
+
47
+ expect {
48
+ post :create
49
+ }.to change( Audited::Audit, :count )
50
+
51
+ expect(controller.company.audits.last.user).to eq(user)
52
+ end
53
+
54
+ it "should record the remote address responsible for the change" do
55
+ request.env['REMOTE_ADDR'] = "1.2.3.4"
56
+ controller.send(:current_user=, user)
57
+
58
+ post :create
59
+
60
+ expect(controller.company.audits.last.remote_address).to eq('1.2.3.4')
61
+ end
62
+
63
+ it "should record a UUID for the web request responsible for the change" do
64
+ allow_any_instance_of(ActionDispatch::Request).to receive(:uuid).and_return("abc123")
65
+ controller.send(:current_user=, user)
66
+
67
+ post :create
68
+
69
+ expect(controller.company.audits.last.request_uuid).to eq("abc123")
70
+ end
71
+
72
+ end
73
+
74
+ describe "PUT update" do
75
+ it "should not save blank audits" do
76
+ controller.send(:current_user=, user)
77
+
78
+ expect {
79
+ put :update, id: 123
80
+ }.to_not change( Audited::Audit, :count )
81
+ end
82
+ end
83
+ end
84
+
85
+
86
+ describe Audited::Sweeper do
87
+
88
+ it "should be thread-safe" do
89
+ t1 = Thread.new do
90
+ sleep 0.5
91
+ Audited::Sweeper.instance.controller = 'thread1 controller instance'
92
+ expect(Audited::Sweeper.instance.controller).to eq('thread1 controller instance')
93
+ end
94
+
95
+ t2 = Thread.new do
96
+ Audited::Sweeper.instance.controller = 'thread2 controller instance'
97
+ sleep 1
98
+ expect(Audited::Sweeper.instance.controller).to eq('thread2 controller instance')
99
+ end
100
+
101
+ t1.join; t2.join
102
+
103
+ expect(Audited::Sweeper.instance.controller).to be_nil
104
+ end
105
+
106
+ end
@@ -0,0 +1,20 @@
1
+ module AuditedSpecHelpers
2
+
3
+ def create_user(attrs = {})
4
+ Models::ActiveRecord::User.create({name: 'Brandon', username: 'brandon', password: 'password'}.merge(attrs))
5
+ end
6
+
7
+ def build_user(attrs = {})
8
+ Models::ActiveRecord::User.new({name: 'darth', username: 'darth', password: 'noooooooo'}.merge(attrs))
9
+ end
10
+
11
+ def create_versions(n = 2)
12
+ Models::ActiveRecord::User.create(name: 'Foobar 1').tap do |u|
13
+ (n - 1).times do |i|
14
+ u.update_attribute :name, "Foobar #{i + 2}"
15
+ end
16
+ u.reload
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,8 @@
1
+ require 'rails/all'
2
+
3
+ module RailsApp
4
+ class Application < Rails::Application
5
+ config.root = File.expand_path('../../', __FILE__)
6
+ config.i18n.enforce_available_locales = true
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ sqlite3mem: &SQLITE3MEM
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+
5
+ sqlite3: &SQLITE
6
+ adapter: sqlite3
7
+ database: audited_test.sqlite3.db
8
+
9
+ postgresql: &POSTGRES
10
+ adapter: postgresql
11
+ username: postgres
12
+ password:
13
+ database: audited_test
14
+ min_messages: ERROR
15
+
16
+ mysql: &MYSQL
17
+ adapter: mysql2
18
+ host: localhost
19
+ username: root
20
+ password:
21
+ database: audited_test
22
+
23
+ test:
24
+ <<: *<%= ENV['DB'] || 'SQLITE3MEM' %>
@@ -0,0 +1,5 @@
1
+ # Load the rails application
2
+ require File.expand_path('../application', __FILE__)
3
+
4
+ # Initialize the rails application
5
+ RailsApp::Application.initialize!
@@ -0,0 +1,21 @@
1
+ RailsApp::Application.configure do
2
+ # Settings specified here will take precedence over those in config/environment.rb
3
+
4
+ # In the development environment your application's code is reloaded on
5
+ # every request. This slows down response time but is perfect for development
6
+ # since you don't have to restart the webserver when you make code changes.
7
+ config.cache_classes = false
8
+
9
+ # Log error messages when you accidentally call methods on nil.
10
+ # config.whiny_nils = true
11
+
12
+ # Show full error reports and disable caching
13
+ config.consider_all_requests_local = true
14
+ config.action_view.debug_rjs = true
15
+ config.action_controller.perform_caching = false
16
+
17
+ # Don't care if the mailer can't send
18
+ config.action_mailer.raise_delivery_errors = false
19
+
20
+ config.eager_load = false
21
+ end
@@ -0,0 +1,35 @@
1
+ RailsApp::Application.configure do
2
+ # Settings specified here will take precedence over those in config/environment.rb
3
+
4
+ # The production environment is meant for finished, "live" apps.
5
+ # Code is not reloaded between requests
6
+ config.cache_classes = true
7
+
8
+ # Full error reports are disabled and caching is turned on
9
+ config.consider_all_requests_local = false
10
+ config.action_controller.perform_caching = true
11
+
12
+ # See everything in the log (default is :info)
13
+ # config.log_level = :debug
14
+
15
+ # Use a different logger for distributed setups
16
+ # config.logger = SyslogLogger.new
17
+
18
+ # Use a different cache store in production
19
+ # config.cache_store = :mem_cache_store
20
+
21
+ # Disable Rails's static asset server
22
+ # In production, Apache or nginx will already do this
23
+ config.serve_static_assets = false
24
+
25
+ # Enable serving of images, stylesheets, and javascripts from an asset server
26
+ # config.action_controller.asset_host = "http://assets.example.com"
27
+
28
+ # Disable delivery errors, bad email addresses will be ignored
29
+ # config.action_mailer.raise_delivery_errors = false
30
+
31
+ # Enable threaded mode
32
+ # config.threadsafe!
33
+
34
+ config.eager_load = true
35
+ end
@@ -0,0 +1,47 @@
1
+ RailsApp::Application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
+
4
+ # The test environment is used exclusively to run your application's
5
+ # test suite. You never need to work with it otherwise. Remember that
6
+ # your test database is "scratch space" for the test suite and is wiped
7
+ # and recreated between test runs. Don't rely on the data there!
8
+ config.cache_classes = true
9
+
10
+ # Do not eager load code on boot. This avoids loading your whole application
11
+ # just for the purpose of running a single test. If you are using a tool that
12
+ # preloads Rails for running tests, you may have to set it to true.
13
+ config.eager_load = false
14
+
15
+ # Configure static file server for tests with Cache-Control for performance.
16
+ if config.respond_to?(:public_file_server)
17
+ config.public_file_server.enabled = true
18
+ config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
19
+ else
20
+ config.static_cache_control = 'public, max-age=3600'
21
+ config.serve_static_files = true
22
+ end
23
+
24
+ # Show full error reports and disable caching.
25
+ config.consider_all_requests_local = true
26
+ # config.action_controller.perform_caching = false
27
+
28
+ # Raise exceptions instead of rendering exception templates.
29
+ config.action_dispatch.show_exceptions = false
30
+
31
+ # Disable request forgery protection in test environment.
32
+ # config.action_controller.allow_forgery_protection = false
33
+
34
+ # Tell Action Mailer not to deliver emails to the real world.
35
+ # The :test delivery method accumulates sent emails in the
36
+ # ActionMailer::Base.deliveries array.
37
+ config.action_mailer.delivery_method = :test
38
+
39
+ # Randomize the order test cases are executed.
40
+ config.active_support.test_order = :random
41
+
42
+ # Print deprecation notices to the stderr.
43
+ config.active_support.deprecation = :stderr
44
+
45
+ # Raises error for missing translations
46
+ # config.action_view.raise_on_missing_translations = true
47
+ end
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4
+ # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5
+
6
+ # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7
+ Rails.backtrace_cleaner.remove_silencers!
@@ -0,0 +1,2 @@
1
+ ActiveSupport::Inflector.inflections do |inflect|
2
+ end
@@ -0,0 +1,3 @@
1
+ Rails.application.config.secret_token = 'ea942c41850d502f2c8283e26bdc57829f471bb18224ddff0a192c4f32cdf6cb5aa0d82b3a7a7adbeb640c4b06f3aa1cd5f098162d8240f669b39d6b49680571'
2
+ Rails.application.config.session_store :cookie_store, key: "_my_app"
3
+ Rails.application.config.secret_key_base = 'secret value'
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ resources :audits
3
+ end
@@ -0,0 +1,21 @@
1
+ ENV['RAILS_ENV'] = 'test'
2
+
3
+ if Bundler.definition.dependencies.map(&:name).include?('protected_attributes')
4
+ require 'protected_attributes'
5
+ end
6
+ require 'rails_app/config/environment'
7
+ require 'rspec/rails'
8
+ require 'audited'
9
+ require 'audited_spec_helpers'
10
+ require 'support/active_record/models'
11
+ load "audited/sweeper.rb" # force to reload sweeper
12
+
13
+ SPEC_ROOT = Pathname.new(File.expand_path('../', __FILE__))
14
+
15
+ Dir[SPEC_ROOT.join('support/*.rb')].each{|f| require f }
16
+
17
+ RSpec.configure do |config|
18
+ config.include AuditedSpecHelpers
19
+ config.use_transactional_fixtures = false if Rails.version.start_with?('4.')
20
+ config.use_transactional_tests = false if config.respond_to?(:use_transactional_tests=)
21
+ end
@@ -0,0 +1,99 @@
1
+ require 'cgi'
2
+ require File.expand_path('../schema', __FILE__)
3
+
4
+ module Models
5
+ module ActiveRecord
6
+ class User < ::ActiveRecord::Base
7
+ audited allow_mass_assignment: true, except: :password
8
+
9
+ attr_protected :logins if respond_to?(:attr_protected)
10
+
11
+ def name=(val)
12
+ write_attribute(:name, CGI.escapeHTML(val))
13
+ end
14
+ end
15
+
16
+ class UserOnlyPassword < ::ActiveRecord::Base
17
+ self.table_name = :users
18
+ audited allow_mass_assignment: true, only: :password
19
+ end
20
+
21
+ class CommentRequiredUser < ::ActiveRecord::Base
22
+ self.table_name = :users
23
+ audited comment_required: true
24
+ end
25
+
26
+ class AccessibleAfterDeclarationUser < ::ActiveRecord::Base
27
+ self.table_name = :users
28
+ audited
29
+ attr_accessible :name, :username, :password if respond_to?(:attr_accessible)
30
+ end
31
+
32
+ class AccessibleBeforeDeclarationUser < ::ActiveRecord::Base
33
+ self.table_name = :users
34
+ attr_accessible :name, :username, :password if respond_to?(:attr_accessible) # declare attr_accessible before calling aaa
35
+ audited
36
+ end
37
+
38
+ class NoAttributeProtectionUser < ::ActiveRecord::Base
39
+ self.table_name = :users
40
+ audited allow_mass_assignment: true
41
+ end
42
+
43
+ class UserWithAfterAudit < ::ActiveRecord::Base
44
+ self.table_name = :users
45
+ audited
46
+ attr_accessor :bogus_attr, :around_attr
47
+
48
+ private
49
+
50
+ def after_audit
51
+ self.bogus_attr = "do something"
52
+ end
53
+
54
+ def around_audit
55
+ self.around_attr = yield
56
+ end
57
+ end
58
+
59
+ class Company < ::ActiveRecord::Base
60
+ audited
61
+ end
62
+
63
+ class Company::STICompany < Company
64
+ end
65
+
66
+ class Owner < ::ActiveRecord::Base
67
+ self.table_name = 'users'
68
+ has_associated_audits
69
+ has_many :companies, class_name: "OwnedCompany", dependent: :destroy
70
+ end
71
+
72
+ class OwnedCompany < ::ActiveRecord::Base
73
+ self.table_name = 'companies'
74
+ belongs_to :owner, class_name: "Owner"
75
+ attr_accessible :name, :owner if respond_to?(:attr_accessible) # declare attr_accessible before calling aaa
76
+ audited associated_with: :owner
77
+ end
78
+
79
+ class OnUpdateDestroy < ::ActiveRecord::Base
80
+ self.table_name = 'companies'
81
+ audited on: [:update, :destroy]
82
+ end
83
+
84
+ class OnCreateDestroy < ::ActiveRecord::Base
85
+ self.table_name = 'companies'
86
+ audited on: [:create, :destroy]
87
+ end
88
+
89
+ class OnCreateDestroyExceptName < ::ActiveRecord::Base
90
+ self.table_name = 'companies'
91
+ audited except: :name, on: [:create, :destroy]
92
+ end
93
+
94
+ class OnCreateUpdate < ::ActiveRecord::Base
95
+ self.table_name = 'companies'
96
+ audited on: [:create, :update]
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,81 @@
1
+ require 'active_record'
2
+ require 'logger'
3
+
4
+ begin
5
+ db_config = ActiveRecord::Base.configurations[Rails.env].clone
6
+ db_type = db_config['adapter']
7
+ db_name = db_config.delete('database')
8
+ raise Exception.new('No database name specified.') if db_name.blank?
9
+ if db_type == 'sqlite3'
10
+ db_file = Pathname.new(__FILE__).dirname.join(db_name)
11
+ db_file.unlink if db_file.file?
12
+ else
13
+ if defined?(JRUBY_VERSION)
14
+ db_config.symbolize_keys!
15
+ db_config[:configure_connection] = false
16
+ end
17
+ adapter = ActiveRecord::Base.send("#{db_type}_connection", db_config)
18
+ adapter.recreate_database db_name
19
+ adapter.disconnect!
20
+ end
21
+ rescue Exception => e
22
+ Kernel.warn e
23
+ end
24
+
25
+ logfile = Pathname.new(__FILE__).dirname.join('debug.log')
26
+ logfile.unlink if logfile.file?
27
+ ActiveRecord::Base.logger = Logger.new(logfile)
28
+
29
+ ActiveRecord::Migration.verbose = false
30
+ ActiveRecord::Base.establish_connection
31
+
32
+ ActiveRecord::Schema.define do
33
+ create_table :users do |t|
34
+ t.column :name, :string
35
+ t.column :username, :string
36
+ t.column :password, :string
37
+ t.column :activated, :boolean
38
+ t.column :suspended_at, :datetime
39
+ t.column :logins, :integer, default: 0
40
+ t.column :created_at, :datetime
41
+ t.column :updated_at, :datetime
42
+ end
43
+
44
+ create_table :companies do |t|
45
+ t.column :name, :string
46
+ t.column :owner_id, :integer
47
+ t.column :type, :string
48
+ end
49
+
50
+ create_table :authors do |t|
51
+ t.column :name, :string
52
+ end
53
+
54
+ create_table :books do |t|
55
+ t.column :authord_id, :integer
56
+ t.column :title, :string
57
+ end
58
+
59
+ create_table :audits do |t|
60
+ t.column :auditable_id, :integer
61
+ t.column :auditable_type, :string
62
+ t.column :associated_id, :integer
63
+ t.column :associated_type, :string
64
+ t.column :user_id, :integer
65
+ t.column :user_type, :string
66
+ t.column :username, :string
67
+ t.column :action, :string
68
+ t.column :audited_changes, :text
69
+ t.column :version, :integer, default: 0
70
+ t.column :comment, :string
71
+ t.column :remote_address, :string
72
+ t.column :request_uuid, :string
73
+ t.column :created_at, :datetime
74
+ end
75
+
76
+ add_index :audits, [:auditable_id, :auditable_type], name: 'auditable_index'
77
+ add_index :audits, [:associated_id, :associated_type], name: 'associated_index'
78
+ add_index :audits, [:user_id, :user_type], name: 'user_index'
79
+ add_index :audits, :request_uuid
80
+ add_index :audits, :created_at
81
+ end