audited-hp 4.3.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.
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