audited 5.0.1 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of audited might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f924caa522dc6d65c88066c2d28416dfcef844efa85bdef056da226db12a8984
4
- data.tar.gz: 63bdef3cd4aefea080eb36e6b7c394f5d97b465e3376027a68e3c28f1b278d5c
3
+ metadata.gz: e18ef251e91f3a66070afa58f5d9e5f12ac81777ca5389b3939a9fd349602e92
4
+ data.tar.gz: c0fbd5a136b6e43ae6e39229de6690811d24adf4f1f2f555a49752cac3bd230b
5
5
  SHA512:
6
- metadata.gz: acbc5581e27594c84ad817ac7e2f90e02d34786106689a943177552890205d4acfaa5a7ac5489b1a0fbdbc5196028d462e4540d5253ee78b2612bc8f03abfcad
7
- data.tar.gz: 532724043c0c57659a3c3f3d0eaf21c832a6c3863a8607bb802d882bf13b4579e8b051265e6c4082a51bdbc2291f7466508e03c7cb67df90bda6b8c234a6d7a4
6
+ metadata.gz: 9bbb38bc63b2cbafd43b7090ab307acde19e9ca21d22710ddc7b42a5a10fc08f0151c1b43b557a1978699005ac66ce7932eec7f8d5f3de6b3c14d7a4d77c73af
7
+ data.tar.gz: 707e5ddda189015b0475e663d7fb4faa3576a1a373dbe3f78436fce96e97cb7ed0a852fc328cec177716f95e035a45dd291f70888ba783572e4b854a84721a45
@@ -0,0 +1,128 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - master
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1]
16
+ appraisal:
17
+ - rails50
18
+ - rails51
19
+ - rails52
20
+ - rails60
21
+ - rails61
22
+ - rails70
23
+ db: [POSTGRES, MYSQL, SQLITE]
24
+ exclude:
25
+ # MySQL has issues on Ruby 2.3
26
+ # https://github.com/ruby/setup-ruby/issues/150
27
+ - ruby: 2.3
28
+ db: MYSQL
29
+
30
+ # PostgresSQL is segfaulting on 2.3
31
+ # Doesn't seem worth solving.
32
+ - ruby: 2.3
33
+ db: POSTGRES
34
+
35
+ # Rails 5.0 supports Ruby 2.2-2.4
36
+ - appraisal: rails50
37
+ ruby: 2.5
38
+ - appraisal: rails50
39
+ ruby: 2.6
40
+ - appraisal: rails50
41
+ ruby: 2.7
42
+ - appraisal: rails50
43
+ ruby: 3.0
44
+ - appraisal: rails50
45
+ ruby: 3.1
46
+
47
+ # Rails 5.1 supports Ruby 2.2-2.5
48
+ - appraisal: rails51
49
+ ruby: 2.6
50
+ - appraisal: rails51
51
+ ruby: 2.7
52
+ - appraisal: rails51
53
+ ruby: 3.0
54
+ - appraisal: rails51
55
+ ruby: 3.1
56
+
57
+ # Rails 5.2 supports Ruby 2.2-2.5
58
+ - appraisal: rails52
59
+ ruby: 2.6
60
+ - appraisal: rails52
61
+ ruby: 2.7
62
+ - appraisal: rails52
63
+ ruby: 3.0
64
+ - appraisal: rails52
65
+ ruby: 3.1
66
+
67
+ # Rails 6.0 supports Ruby 2.5-2.7
68
+ - appraisal: rails60
69
+ ruby: 2.3
70
+ - appraisal: rails60
71
+ ruby: 2.4
72
+ - appraisal: rails60
73
+ ruby: 3.0
74
+ - appraisal: rails60
75
+ ruby: 3.1
76
+
77
+ # Rails 6.1 supports Ruby 2.5+
78
+ - appraisal: rails61
79
+ ruby: 2.3
80
+ - appraisal: rails61
81
+ ruby: 2.4
82
+
83
+ # Rails 7 supports Ruby 2.7+
84
+ - appraisal: rails70
85
+ ruby: 2.3
86
+ - appraisal: rails70
87
+ ruby: 2.4
88
+ - appraisal: rails70
89
+ ruby: 2.5
90
+ - appraisal: rails70
91
+ ruby: 2.6
92
+
93
+ services:
94
+ postgres:
95
+ image: postgres
96
+ env:
97
+ POSTGRES_USER: postgres
98
+ POSTGRES_PASSWORD: postgres
99
+ POSTGRES_DB: audited_test
100
+ ports:
101
+ - 5432:5432
102
+ # needed because the postgres container does not provide a healthcheck
103
+ options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
104
+
105
+ env:
106
+ DB_DATABASE: audited_test
107
+ DB_USER: root
108
+ DB_PASSWORD: 'root'
109
+ DB_HOST: localhost
110
+
111
+ steps:
112
+ - name: Setup MySQL
113
+ run: |
114
+ sudo /etc/init.d/mysql start
115
+ mysql -e 'CREATE DATABASE audited_test;' -uroot -proot
116
+ mysql -e 'SHOW DATABASES;' -uroot -proot
117
+ - uses: actions/checkout@v3
118
+ - name: Copy Gemfile
119
+ run: sed 's/\.\././' gemfiles/${{ matrix.appraisal }}.gemfile > Gemfile
120
+ - name: Set up Ruby ${{ matrix.ruby }}
121
+ uses: ruby/setup-ruby@v1
122
+ with:
123
+ ruby-version: ${{ matrix.ruby }}
124
+ bundler-cache: true
125
+ - name: Run tests
126
+ env:
127
+ DB: ${{ matrix.db }}
128
+ run: bundle exec rake
data/Appraisals CHANGED
@@ -6,6 +6,7 @@ appraise "rails50" do
6
6
  gem "mysql2", ">= 0.3.18", "< 0.6.0"
7
7
  gem "pg", ">= 0.18", "< 2.0"
8
8
  gem "sqlite3", "~> 1.3.6"
9
+ gem "psych", "~> 3.1"
9
10
  end
10
11
 
11
12
  appraise "rails51" do
@@ -13,13 +14,15 @@ appraise "rails51" do
13
14
  gem "mysql2", ">= 0.3.18", "< 0.6.0"
14
15
  gem "pg", ">= 0.18", "< 2.0"
15
16
  gem "sqlite3", "~> 1.3.6"
17
+ gem "psych", "~> 3.1"
16
18
  end
17
19
 
18
20
  appraise "rails52" do
19
- gem "rails", ">= 5.2.0", "< 5.3"
21
+ gem "rails", ">= 5.2.8.1", "< 5.3"
20
22
  gem "mysql2", ">= 0.4.4", "< 0.6.0"
21
23
  gem "pg", ">= 0.18", "< 2.0"
22
24
  gem "sqlite3", "~> 1.3.6"
25
+ gem "psych", "~> 3.1"
23
26
  end
24
27
 
25
28
  appraise "rails60" do
@@ -35,3 +38,10 @@ appraise "rails61" do
35
38
  gem "pg", ">= 1.1", "< 2.0"
36
39
  gem "sqlite3", "~> 1.4"
37
40
  end
41
+
42
+ appraise "rails70" do
43
+ gem "rails", ">= 7.0.0", "< 7.1"
44
+ gem "mysql2", ">= 0.4.4"
45
+ gem "pg", ">= 1.1"
46
+ gem "sqlite3", ">= 1.4"
47
+ end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Audited ChangeLog
2
2
 
3
+ ## 5.1.0 (2022-12-23)
4
+
5
+ Changed
6
+
7
+ - config.audit_class takes a string - @simmerz
8
+ [#609](https://github.com/collectiveidea/audited/pull/609)
9
+ - Filter encrypted attributes automatically - @vlad-psh
10
+ [#630](https://github.com/collectiveidea/audited/pull/630)
11
+
12
+ Improved
13
+
14
+ - README improvements - @jess, @mstroming
15
+ [#605](https://github.com/collectiveidea/audited/pull/605)
16
+ [#640](https://github.com/collectiveidea/audited/issues/640)
17
+ - Ignore deadlocks in concurrent audit combinations - @Crammaman
18
+ [#621](https://github.com/collectiveidea/audited/pull/621)
19
+ - Fix timestamped_migrations deprecation warning - @shouichi
20
+ [#624](https://github.com/collectiveidea/audited/pull/624)
21
+ - Ensure audits are re-enabled after blocks - @dcorlett
22
+ [#632](https://github.com/collectiveidea/audited/pull/632)
23
+ - Replace raw string where clause with query methods - @macowie
24
+ [#642](https://github.com/collectiveidea/audited/pull/642)
25
+ - Test against more Ruby/Rails Versions - @enomotodev, @danielmorrison
26
+ [#610](https://github.com/collectiveidea/audited/pull/610)
27
+ [#643](https://github.com/collectiveidea/audited/pull/643)
28
+
29
+ ## 5.0.2 (2021-09-16)
30
+
31
+ Added
32
+
33
+ - Relax ActiveRecord version constraint to support Rails 7
34
+ [#597](https://github.com/collectiveidea/audited/pull/597)
35
+
36
+ Improved
37
+
38
+ - Improve loading - @mvastola
39
+ [#592](https://github.com/collectiveidea/audited/pull/592)
40
+ - Update README - @danirod, @clement1234
41
+ [#596](https://github.com/collectiveidea/audited/pull/596)
42
+ [#594](https://github.com/collectiveidea/audited/pull/594)
43
+
44
+
3
45
  ## 5.0.1 (2021-06-11)
4
46
 
5
47
  Improved
data/README.md CHANGED
@@ -1,23 +1,29 @@
1
- Audited [![Build Status](https://secure.travis-ci.org/collectiveidea/audited.svg)](http://travis-ci.org/collectiveidea/audited) [![Code Climate](https://codeclimate.com/github/collectiveidea/audited.svg)](https://codeclimate.com/github/collectiveidea/audited) [![Security](https://hakiri.io/github/collectiveidea/audited/master.svg)](https://hakiri.io/github/collectiveidea/audited/master)
1
+ Audited
2
+ [![Gem Version](https://img.shields.io/gem/v/audited.svg)](http://rubygems.org/gems/audited)
3
+ ![Build Status](https://github.com/collectiveidea/audited/actions/workflows/ci.yml/badge.svg)
4
+ [![Code Climate](https://codeclimate.com/github/collectiveidea/audited.svg)](https://codeclimate.com/github/collectiveidea/audited)
2
5
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
3
6
  =======
4
7
 
5
8
  **Audited** (previously acts_as_audited) is an ORM extension that logs all changes to your models. Audited can also record who made those changes, save comments and associate models related to the changes.
6
9
 
7
10
 
8
- Audited currently (5.x) works with Rails 6.1, 6.0, 5.2, 5.1, and 5.0.
11
+ Audited currently (5.x) works with Rails 7.0, 6.1, 6.0, 5.2, 5.1, and 5.0.
9
12
 
10
13
  For Rails 4, use gem version 4.x
11
14
  For Rails 3, use gem version 3.0 or see the [3.0-stable branch](https://github.com/collectiveidea/audited/tree/3.0-stable).
12
15
 
13
16
  ## Supported Rubies
14
17
 
15
- Audited supports and is [tested against](http://travis-ci.org/collectiveidea/audited) the following Ruby versions:
18
+ Audited supports and is [tested against](https://github.com/collectiveidea/audited/actions/workflows/ci.yml) the following Ruby versions:
16
19
 
17
- * 2.3.7
18
- * 2.4.4
19
- * 2.5.1
20
- * 2.6.3
20
+ * 2.3 (only tested on Sqlite due to testing issues with other DBs)
21
+ * 2.4
22
+ * 2.5
23
+ * 2.6
24
+ * 2.7
25
+ * 3.0
26
+ * 3.1
21
27
 
22
28
  Audited may work just fine with a Ruby version not listed above, but we can't guarantee that it will. If you'd like to maintain a Ruby that isn't listed, please let us know with a [pull request](https://github.com/collectiveidea/audited/pulls).
23
29
 
@@ -30,7 +36,16 @@ Audited is currently ActiveRecord-only. In a previous life, Audited worked with
30
36
  Add the gem to your Gemfile:
31
37
 
32
38
  ```ruby
33
- gem "audited", "~> 4.9"
39
+ gem "audited", "~> 5.0"
40
+ ```
41
+
42
+ And if you're using ```require: false``` you must add initializers like this:
43
+
44
+ ```ruby
45
+ #./config/initializers/audited.rb
46
+ require "audited"
47
+
48
+ Audited::Railtie.initializers.each(&:run)
34
49
  ```
35
50
 
36
51
  Then, from your Rails app directory, create the `audits` table:
@@ -204,7 +219,7 @@ Audited.current_user_method = :authenticated_user
204
219
  Outside of a request, Audited can still record the user with the `as_user` method:
205
220
 
206
221
  ```ruby
207
- Audited.audit_class.as_user(User.find(1)) do
222
+ Audited.audit_model.as_user(User.find(1)) do
208
223
  post.update!(title: "Hello, world!")
209
224
  end
210
225
  post.audits.last.user # => #<User id: 1>
@@ -231,7 +246,7 @@ end
231
246
  `as_user` also accepts a string, which can be useful for auditing updates made in a CLI environment:
232
247
 
233
248
  ```rb
234
- Audited.audit_class.as_user("console-user-#{ENV['SSH_USER']}") do
249
+ Audited.audit_model.as_user("console-user-#{ENV['SSH_USER']}") do
235
250
  post.update_attributes!(title: "Hello, world!")
236
251
  end
237
252
  post.audits.last.user # => 'console-user-username'
@@ -271,6 +286,7 @@ class User < ActiveRecord::Base
271
286
  end
272
287
 
273
288
  class Company < ActiveRecord::Base
289
+ audited
274
290
  has_many :users
275
291
  has_associated_audits
276
292
  end
@@ -298,9 +314,7 @@ If you want to audit only under specific conditions, you can provide conditional
298
314
  ```ruby
299
315
  class User < ActiveRecord::Base
300
316
  audited if: :active?
301
-
302
- private
303
-
317
+
304
318
  def active?
305
319
  last_login > 6.months.ago
306
320
  end
@@ -371,6 +385,17 @@ User.auditing_enabled = false
371
385
  end
372
386
  ```
373
387
 
388
+ ### Encrypted attributes
389
+
390
+ If you're using ActiveRecord's encryption (available from Rails 7) to encrypt some attributes, Audited will automatically filter values of these attributes. No additional configuration is required. Changes to encrypted attributes will be logged as `[FILTERED]`.
391
+
392
+ ```ruby
393
+ class User < ActiveRecord::Base
394
+ audited
395
+ encrypts :password
396
+ end
397
+ ```
398
+
374
399
  ### Custom `Audit` model
375
400
 
376
401
  If you want to extend or modify the audit model, create a new class that
@@ -387,7 +412,7 @@ Then set it in an initializer:
387
412
  # config/initializers/audited.rb
388
413
 
389
414
  Audited.config do |config|
390
- config.audit_class = CustomAudit
415
+ config.audit_class = "CustomAudit"
391
416
  end
392
417
  ```
393
418
 
@@ -6,5 +6,6 @@ gem "rails", "~> 5.0.0"
6
6
  gem "mysql2", ">= 0.3.18", "< 0.6.0"
7
7
  gem "pg", ">= 0.18", "< 2.0"
8
8
  gem "sqlite3", "~> 1.3.6"
9
+ gem "psych", "~> 3.1"
9
10
 
10
11
  gemspec name: "audited", path: "../"
@@ -6,5 +6,6 @@ gem "rails", "~> 5.1.4"
6
6
  gem "mysql2", ">= 0.3.18", "< 0.6.0"
7
7
  gem "pg", ">= 0.18", "< 2.0"
8
8
  gem "sqlite3", "~> 1.3.6"
9
+ gem "psych", "~> 3.1"
9
10
 
10
11
  gemspec name: "audited", path: "../"
@@ -2,9 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", ">= 5.2.0", "< 5.3"
5
+ gem "rails", ">= 5.2.8.1", "< 5.3"
6
6
  gem "mysql2", ">= 0.4.4", "< 0.6.0"
7
7
  gem "pg", ">= 0.18", "< 2.0"
8
8
  gem "sqlite3", "~> 1.3.6"
9
+ gem "psych", "~> 3.1"
9
10
 
10
11
  gemspec name: "audited", path: "../"
@@ -0,0 +1,10 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", ">= 7.0.0", "< 7.1"
6
+ gem "mysql2", ">= 0.4.4"
7
+ gem "pg", ">= 1.1"
8
+ gem "sqlite3", ">= 1.4"
9
+
10
+ gemspec name: "audited", path: "../"
data/lib/audited/audit.rb CHANGED
@@ -34,7 +34,7 @@ module Audited
34
34
  end
35
35
 
36
36
  def text_column?
37
- Audited.audit_class.columns_hash["audited_changes"].type.to_s == "text"
37
+ Audited.audit_model.columns_hash["audited_changes"].type.to_s == "text"
38
38
  end
39
39
  end
40
40
  end
@@ -78,14 +78,14 @@ module Audited
78
78
  # Returns a hash of the changed attributes with the new values
79
79
  def new_attributes
80
80
  (audited_changes || {}).each_with_object({}.with_indifferent_access) do |(attr, values), attrs|
81
- attrs[attr] = (action == "update" ? values.last : values)
81
+ attrs[attr] = (action == "update") ? values.last : values
82
82
  end
83
83
  end
84
84
 
85
85
  # Returns a hash of the changed attributes with the old values
86
86
  def old_attributes
87
87
  (audited_changes || {}).each_with_object({}.with_indifferent_access) do |(attr, values), attrs|
88
- attrs[attr] = (action == "update" ? values.first : values)
88
+ attrs[attr] = (action == "update") ? values.first : values
89
89
  end
90
90
  end
91
91
 
@@ -174,7 +174,7 @@ module Audited
174
174
  if action == "create"
175
175
  self.version = 1
176
176
  else
177
- collection = Rails::VERSION::MAJOR >= 6 ? self.class.unscoped : self.class
177
+ collection = (Rails::VERSION::MAJOR >= 6) ? self.class.unscoped : self.class
178
178
  max = collection.auditable_finder(auditable_id, auditable_type).maximum(:version) || 0
179
179
  self.version = max + 1
180
180
  end
@@ -13,7 +13,7 @@ module Audited
13
13
  #
14
14
  # See <tt>Audited::Auditor::ClassMethods#audited</tt>
15
15
  # for configuration options
16
- module Auditor #:nodoc:
16
+ module Auditor # :nodoc:
17
17
  extend ActiveSupport::Concern
18
18
 
19
19
  CALLBACKS = [:audit_create, :audit_update, :audit_destroy]
@@ -79,8 +79,8 @@ module Audited
79
79
  before_destroy :require_comment if audited_options[:on].include?(:destroy)
80
80
  end
81
81
 
82
- has_many :audits, -> { order(version: :asc) }, as: :auditable, class_name: Audited.audit_class.name, inverse_of: :auditable
83
- Audited.audit_class.audited_class_names << to_s
82
+ has_many :audits, -> { order(version: :asc) }, as: :auditable, class_name: Audited.audit_class, inverse_of: :auditable
83
+ Audited.audit_model.audited_class_names << to_s
84
84
 
85
85
  after_create :audit_create if audited_options[:on].include?(:create)
86
86
  before_update :audit_update if audited_options[:on].include?(:update)
@@ -97,7 +97,7 @@ module Audited
97
97
  end
98
98
 
99
99
  def has_associated_audits
100
- has_many :associated_audits, as: :associated, class_name: Audited.audit_class.name
100
+ has_many :associated_audits, as: :associated, class_name: Audited.audit_model.name
101
101
  end
102
102
  end
103
103
 
@@ -159,27 +159,28 @@ module Audited
159
159
  # Returns nil for versions greater than revisions count
160
160
  def revision(version)
161
161
  if version == :previous || audits.last.version >= version
162
- revision_with Audited.audit_class.reconstruct_attributes(audits_to(version))
162
+ revision_with Audited.audit_model.reconstruct_attributes(audits_to(version))
163
163
  end
164
164
  end
165
165
 
166
166
  # Find the oldest revision recorded prior to the date/time provided.
167
167
  def revision_at(date_or_time)
168
168
  audits = self.audits.up_until(date_or_time)
169
- revision_with Audited.audit_class.reconstruct_attributes(audits) unless audits.empty?
169
+ revision_with Audited.audit_model.reconstruct_attributes(audits) unless audits.empty?
170
170
  end
171
171
 
172
172
  # List of attributes that are audited.
173
173
  def audited_attributes
174
174
  audited_attributes = attributes.except(*self.class.non_audited_columns)
175
+ audited_attributes = redact_values(audited_attributes)
176
+ audited_attributes = filter_encrypted_attrs(audited_attributes)
175
177
  normalize_enum_changes(audited_attributes)
176
178
  end
177
179
 
178
180
  # Returns a list combined of record audits and associated audits.
179
181
  def own_and_associated_audits
180
- Audited.audit_class.unscoped
181
- .where("(auditable_type = :type AND auditable_id = :id) OR (associated_type = :type AND associated_id = :id)",
182
- type: self.class.base_class.name, id: id)
182
+ Audited.audit_model.unscoped.where(auditable: self)
183
+ .or(Audited.audit_model.unscoped.where(associated: self))
183
184
  .order(created_at: :desc)
184
185
  end
185
186
 
@@ -190,8 +191,13 @@ module Audited
190
191
  combine_target.comment = "#{combine_target.comment}\nThis audit is the result of multiple audits being combined."
191
192
 
192
193
  transaction do
193
- combine_target.save!
194
- audits_to_combine.unscope(:limit).where("version < ?", combine_target.version).delete_all
194
+ begin
195
+ combine_target.save!
196
+ audits_to_combine.unscope(:limit).where("version < ?", combine_target.version).delete_all
197
+ rescue ActiveRecord::Deadlocked
198
+ # Ignore Deadlocks, if the same record is getting its old audits combined more than once at the same time then
199
+ # both combining operations will be the same. Ignoring this error allows one of the combines to go through successfully.
200
+ end
195
201
  end
196
202
  end
197
203
 
@@ -206,7 +212,7 @@ module Audited
206
212
  revision.send :instance_variable_set, "@destroyed", false
207
213
  revision.send :instance_variable_set, "@_destroyed", false
208
214
  revision.send :instance_variable_set, "@marked_for_destruction", false
209
- Audited.audit_class.assign_revision_attributes(revision, attributes)
215
+ Audited.audit_model.assign_revision_attributes(revision, attributes)
210
216
 
211
217
  # Remove any association proxies so that they will be recreated
212
218
  # and reference the correct object for this revision. The only way
@@ -234,6 +240,7 @@ module Audited
234
240
  end
235
241
 
236
242
  filtered_changes = redact_values(filtered_changes)
243
+ filtered_changes = filter_encrypted_attrs(filtered_changes)
237
244
  filtered_changes = normalize_enum_changes(filtered_changes)
238
245
  filtered_changes.to_hash
239
246
  end
@@ -257,19 +264,36 @@ module Audited
257
264
  end
258
265
 
259
266
  def redact_values(filtered_changes)
260
- [audited_options[:redacted]].flatten.compact.each do |option|
261
- changes = filtered_changes[option.to_s]
262
- new_value = audited_options[:redaction_value] || REDACTED
263
- values = if changes.is_a? Array
264
- changes.map { new_value }
265
- else
266
- new_value
267
- end
268
- hash = {option.to_s => values}
269
- filtered_changes.merge!(hash)
267
+ filter_attr_values(
268
+ audited_changes: filtered_changes,
269
+ attrs: Array(audited_options[:redacted]).map(&:to_s),
270
+ placeholder: audited_options[:redaction_value] || REDACTED
271
+ )
272
+ end
273
+
274
+ def filter_encrypted_attrs(filtered_changes)
275
+ filter_attr_values(
276
+ audited_changes: filtered_changes,
277
+ attrs: respond_to?(:encrypted_attributes) ? Array(encrypted_attributes).map(&:to_s) : []
278
+ )
279
+ end
280
+
281
+ # Replace values for given attrs to a placeholder and return modified hash
282
+ #
283
+ # @param audited_changes [Hash] Hash of changes to be saved to audited version record
284
+ # @param attrs [Array<String>] Array of attrs, values of which will be replaced to placeholder value
285
+ # @param placeholder [String] Placeholder to replace original attr values
286
+ def filter_attr_values(audited_changes: {}, attrs: [], placeholder: "[FILTERED]")
287
+ attrs.each do |attr|
288
+ next unless audited_changes.key?(attr)
289
+
290
+ changes = audited_changes[attr]
291
+ values = changes.is_a?(Array) ? changes.map { placeholder } : placeholder
292
+
293
+ audited_changes[attr] = values
270
294
  end
271
295
 
272
- filtered_changes
296
+ audited_changes
273
297
  end
274
298
 
275
299
  def rails_below?(rails_version)
@@ -290,20 +314,20 @@ module Audited
290
314
 
291
315
  def audit_create
292
316
  write_audit(action: "create", audited_changes: audited_attributes,
293
- comment: audit_comment)
317
+ comment: audit_comment)
294
318
  end
295
319
 
296
320
  def audit_update
297
321
  unless (changes = audited_changes).empty? && (audit_comment.blank? || audited_options[:update_with_comment_only] == false)
298
322
  write_audit(action: "update", audited_changes: changes,
299
- comment: audit_comment)
323
+ comment: audit_comment)
300
324
  end
301
325
  end
302
326
 
303
327
  def audit_destroy
304
328
  unless new_record?
305
329
  write_audit(action: "destroy", audited_changes: audited_attributes,
306
- comment: audit_comment)
330
+ comment: audit_comment)
307
331
  end
308
332
  end
309
333
 
@@ -397,7 +421,7 @@ module Audited
397
421
  # end
398
422
  #
399
423
  def without_auditing
400
- auditing_was_enabled = auditing_enabled
424
+ auditing_was_enabled = class_auditing_enabled
401
425
  disable_auditing
402
426
  yield
403
427
  ensure
@@ -411,7 +435,7 @@ module Audited
411
435
  # end
412
436
  #
413
437
  def with_auditing
414
- auditing_was_enabled = auditing_enabled
438
+ auditing_was_enabled = class_auditing_enabled
415
439
  enable_auditing
416
440
  yield
417
441
  ensure
@@ -431,11 +455,11 @@ module Audited
431
455
  # convenience wrapper around
432
456
  # @see Audit#as_user.
433
457
  def audit_as(user, &block)
434
- Audited.audit_class.as_user(user, &block)
458
+ Audited.audit_model.as_user(user, &block)
435
459
  end
436
460
 
437
461
  def auditing_enabled
438
- Audited.store.fetch("#{table_name}_auditing_enabled", true) && Audited.auditing_enabled
462
+ class_auditing_enabled && Audited.auditing_enabled
439
463
  end
440
464
 
441
465
  def auditing_enabled=(val)
@@ -466,6 +490,10 @@ module Audited
466
490
  default_ignored_attributes
467
491
  end
468
492
  end
493
+
494
+ def class_auditing_enabled
495
+ Audited.store.fetch("#{table_name}_auditing_enabled", true)
496
+ end
469
497
  end
470
498
  end
471
499
  end
@@ -221,7 +221,7 @@ module Audited
221
221
  def association_exists?
222
222
  !reflection.nil? &&
223
223
  reflection.macro == :has_many &&
224
- reflection.options[:class_name] == Audited.audit_class.name
224
+ reflection.options[:class_name] == Audited.audit_model.name
225
225
  end
226
226
  end
227
227
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Audited
4
- VERSION = "5.0.1"
4
+ VERSION = "5.1.0"
5
5
  end
data/lib/audited.rb CHANGED
@@ -13,7 +13,11 @@ module Audited
13
13
  attr_writer :audit_class
14
14
 
15
15
  def audit_class
16
- @audit_class ||= Audit
16
+ @audit_class ||= "Audited::Audit"
17
+ end
18
+
19
+ def audit_model
20
+ audit_class.constantize
17
21
  end
18
22
 
19
23
  def store
@@ -39,9 +43,9 @@ module Audited
39
43
  end
40
44
 
41
45
  require "audited/auditor"
42
- require "audited/audit"
43
46
 
44
47
  ActiveSupport.on_load :active_record do
48
+ require "audited/audit"
45
49
  include Audited::Auditor
46
50
  end
47
51
 
@@ -4,14 +4,22 @@ module Audited
4
4
  module Generators
5
5
  module Migration
6
6
  # Implement the required interface for Rails::Generators::Migration.
7
- def next_migration_number(dirname) #:nodoc:
7
+ def next_migration_number(dirname) # :nodoc:
8
8
  next_migration_number = current_migration_number(dirname) + 1
9
- if ::ActiveRecord::Base.timestamped_migrations
9
+ if timestamped_migrations?
10
10
  [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
11
11
  else
12
12
  "%.3d" % next_migration_number
13
13
  end
14
14
  end
15
+
16
+ private
17
+
18
+ def timestamped_migrations?
19
+ (Rails.version >= "7.0") ?
20
+ ::ActiveRecord.timestamped_migrations :
21
+ ::ActiveRecord::Base.timestamped_migrations
22
+ end
15
23
  end
16
24
  end
17
25
  end
@@ -37,7 +37,7 @@ describe Audited::Audit do
37
37
 
38
38
  context "when a custom audit class is configured" do
39
39
  it "should be used in place of #{described_class}" do
40
- Audited.config { |config| config.audit_class = CustomAudit }
40
+ Audited.config { |config| config.audit_class = "CustomAudit" }
41
41
  TempModel1.audited
42
42
 
43
43
  record = TempModel1.create
@@ -62,7 +62,7 @@ describe Audited::Audit do
62
62
  end
63
63
 
64
64
  describe "#audited_changes" do
65
- let(:audit) { Audited.audit_class.new }
65
+ let(:audit) { Audited.audit_model.new }
66
66
 
67
67
  it "can unserialize yaml from text columns" do
68
68
  audit.audited_changes = {foo: "bar"}
@@ -234,6 +234,14 @@ describe Audited::Auditor do
234
234
  expect(user.audits.last.audited_changes["password"]).to eq(["My", "Custom", "Value", 7])
235
235
  end
236
236
 
237
+ if ::ActiveRecord::VERSION::MAJOR >= 7
238
+ it "should filter encrypted attributes" do
239
+ user = Models::ActiveRecord::UserWithEncryptedPassword.create(password: "password")
240
+ user.save
241
+ expect(user.audits.last.audited_changes["password"]).to eq("[FILTERED]")
242
+ end
243
+ end
244
+
237
245
  if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
238
246
  describe "'json' and 'jsonb' audited_changes column type" do
239
247
  let(:migrations_path) { SPEC_ROOT.join("support/active_record/postgres") }
@@ -272,11 +280,11 @@ describe Audited::Auditor do
272
280
  yesterday = 1.day.ago
273
281
 
274
282
  u = Models::ActiveRecord::NoAttributeProtectionUser.new(name: "name",
275
- username: "username",
276
- password: "password",
277
- activated: true,
278
- suspended_at: yesterday,
279
- logins: 2)
283
+ username: "username",
284
+ password: "password",
285
+ activated: true,
286
+ suspended_at: yesterday,
287
+ logins: 2)
280
288
 
281
289
  expect(u.name).to eq("name")
282
290
  expect(u.username).to eq("username")
@@ -814,6 +822,15 @@ describe Audited::Auditor do
814
822
  }.to_not change(Audited::Audit, :count)
815
823
  end
816
824
 
825
+ context "when global audits are disabled" do
826
+ it "should re-enable class audits after #without_auditing block" do
827
+ Audited.auditing_enabled = false
828
+ Models::ActiveRecord::User.without_auditing {}
829
+ Audited.auditing_enabled = true
830
+ expect(Models::ActiveRecord::User.auditing_enabled).to eql(true)
831
+ end
832
+ end
833
+
817
834
  it "should reset auditing status even it raises an exception" do
818
835
  begin
819
836
  Models::ActiveRecord::User.without_auditing { raise }
@@ -884,6 +901,15 @@ describe Audited::Auditor do
884
901
  }.to change(Audited::Audit, :count).by(1)
885
902
  end
886
903
 
904
+ context "when global audits are disabled" do
905
+ it "should re-enable class audits after #with_auditing block" do
906
+ Audited.auditing_enabled = false
907
+ Models::ActiveRecord::User.with_auditing {}
908
+ Audited.auditing_enabled = true
909
+ expect(Models::ActiveRecord::User.auditing_enabled).to eql(true)
910
+ end
911
+ end
912
+
887
913
  it "should reset auditing status even it raises an exception" do
888
914
  Models::ActiveRecord::User.disable_auditing
889
915
  begin
@@ -4,6 +4,12 @@ module RailsApp
4
4
  class Application < Rails::Application
5
5
  config.root = File.expand_path("../../", __FILE__)
6
6
  config.i18n.enforce_available_locales = true
7
+
8
+ if !Rails.version.start_with?("5.0") && !Rails.version.start_with?("5.1") && config.active_record.respond_to?(:yaml_column_permitted_classes=)
9
+ config.active_record.yaml_column_permitted_classes =
10
+ %w[String Symbol Integer NilClass Float Time Date FalseClass Hash Array DateTime TrueClass BigDecimal
11
+ ActiveSupport::TimeWithZone ActiveSupport::TimeZone ActiveSupport::HashWithIndifferentAccess]
12
+ end
7
13
  end
8
14
  end
9
15
 
@@ -9,7 +9,8 @@ sqlite3: &SQLITE
9
9
  postgresql: &POSTGRES
10
10
  adapter: postgresql
11
11
  username: postgres
12
- password:
12
+ password: postgres
13
+ host: localhost
13
14
  database: audited_test
14
15
  min_messages: ERROR
15
16
 
@@ -17,7 +18,7 @@ mysql: &MYSQL
17
18
  adapter: mysql2
18
19
  host: localhost
19
20
  username: root
20
- password:
21
+ password: root
21
22
  database: audited_test
22
23
  charset: utf8
23
24
 
@@ -44,4 +44,9 @@ RailsApp::Application.configure do
44
44
 
45
45
  # Raises error for missing translations
46
46
  # config.action_view.raise_on_missing_translations = true
47
+
48
+ if ::ActiveRecord::VERSION::MAJOR >= 7
49
+ config.active_record.encryption.key_derivation_salt = SecureRandom.hex
50
+ config.active_record.encryption.primary_key = SecureRandom.hex
51
+ end
47
52
  end
@@ -41,6 +41,14 @@ module Models
41
41
  audited redacted: :password, redaction_value: ["My", "Custom", "Value", 7]
42
42
  end
43
43
 
44
+ if ::ActiveRecord::VERSION::MAJOR >= 7
45
+ class UserWithEncryptedPassword < ::ActiveRecord::Base
46
+ self.table_name = :users
47
+ audited
48
+ encrypts :password
49
+ end
50
+ end
51
+
44
52
  class CommentRequiredUser < ::ActiveRecord::Base
45
53
  self.table_name = :users
46
54
  audited except: :password, comment_required: true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: audited
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.1
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Keepers
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2021-06-11 00:00:00.000000000 Z
16
+ date: 2022-12-23 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: activerecord
@@ -24,7 +24,7 @@ dependencies:
24
24
  version: '5.0'
25
25
  - - "<"
26
26
  - !ruby/object:Gem::Version
27
- version: '6.2'
27
+ version: '7.1'
28
28
  type: :runtime
29
29
  prerelease: false
30
30
  version_requirements: !ruby/object:Gem::Requirement
@@ -34,7 +34,7 @@ dependencies:
34
34
  version: '5.0'
35
35
  - - "<"
36
36
  - !ruby/object:Gem::Version
37
- version: '6.2'
37
+ version: '7.1'
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: appraisal
40
40
  requirement: !ruby/object:Gem::Requirement
@@ -58,7 +58,7 @@ dependencies:
58
58
  version: '5.0'
59
59
  - - "<"
60
60
  - !ruby/object:Gem::Version
61
- version: '6.2'
61
+ version: '7.1'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
@@ -68,7 +68,7 @@ dependencies:
68
68
  version: '5.0'
69
69
  - - "<"
70
70
  - !ruby/object:Gem::Version
71
- version: '6.2'
71
+ version: '7.1'
72
72
  - !ruby/object:Gem::Dependency
73
73
  name: rspec-rails
74
74
  requirement: !ruby/object:Gem::Requirement
@@ -115,16 +115,16 @@ dependencies:
115
115
  name: sqlite3
116
116
  requirement: !ruby/object:Gem::Requirement
117
117
  requirements:
118
- - - "~>"
118
+ - - ">="
119
119
  - !ruby/object:Gem::Version
120
- version: '1.3'
120
+ version: 1.3.6
121
121
  type: :development
122
122
  prerelease: false
123
123
  version_requirements: !ruby/object:Gem::Requirement
124
124
  requirements:
125
- - - "~>"
125
+ - - ">="
126
126
  - !ruby/object:Gem::Version
127
- version: '1.3'
127
+ version: 1.3.6
128
128
  - !ruby/object:Gem::Dependency
129
129
  name: mysql2
130
130
  requirement: !ruby/object:Gem::Requirement
@@ -165,9 +165,9 @@ executables: []
165
165
  extensions: []
166
166
  extra_rdoc_files: []
167
167
  files:
168
+ - ".github/workflows/ci.yml"
168
169
  - ".gitignore"
169
170
  - ".standard.yml"
170
- - ".travis.yml"
171
171
  - ".yardopts"
172
172
  - Appraisals
173
173
  - CHANGELOG.md
@@ -180,6 +180,7 @@ files:
180
180
  - gemfiles/rails52.gemfile
181
181
  - gemfiles/rails60.gemfile
182
182
  - gemfiles/rails61.gemfile
183
+ - gemfiles/rails70.gemfile
183
184
  - lib/audited-rspec.rb
184
185
  - lib/audited.rb
185
186
  - lib/audited/audit.rb
@@ -250,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
250
251
  - !ruby/object:Gem::Version
251
252
  version: '0'
252
253
  requirements: []
253
- rubygems_version: 3.1.6
254
+ rubygems_version: 3.3.7
254
255
  signing_key:
255
256
  specification_version: 4
256
257
  summary: Log all changes to your models
data/.travis.yml DELETED
@@ -1,67 +0,0 @@
1
- language: ruby
2
- cache: bundler
3
- rvm:
4
- - 2.3.8
5
- - 2.4.10
6
- - 2.5.9
7
- - 2.6.7
8
- - 2.7.3
9
- - 3.0.1
10
- - ruby-head
11
- env:
12
- - DB=SQLITE
13
- - DB=POSTGRES
14
- - DB=MYSQL
15
- addons:
16
- postgresql: "9.4"
17
- services:
18
- - mysql
19
- before_install:
20
- # https://github.com/travis-ci/travis-ci/issues/8978
21
- - "travis_retry gem update --system"
22
- gemfile:
23
- - gemfiles/rails50.gemfile
24
- - gemfiles/rails51.gemfile
25
- - gemfiles/rails52.gemfile
26
- - gemfiles/rails60.gemfile
27
- - gemfiles/rails61.gemfile
28
- matrix:
29
- include:
30
- - rvm: 2.6.7
31
- script: bundle exec standardrb
32
- env: DB=standard # make travis build display nicer
33
- exclude:
34
- - rvm: 2.3.8
35
- gemfile: gemfiles/rails61.gemfile
36
- - rvm: 2.4.10
37
- gemfile: gemfiles/rails61.gemfile
38
- - rvm: 2.3.8
39
- gemfile: gemfiles/rails60.gemfile
40
- - rvm: 2.4.10
41
- gemfile: gemfiles/rails60.gemfile
42
- - rvm: 2.6.7
43
- gemfile: gemfiles/rails42.gemfile
44
- - rvm: 2.7.3
45
- gemfile: gemfiles/rails42.gemfile
46
- - rvm: 3.0.1
47
- gemfile: gemfiles/rails42.gemfile
48
- - rvm: 3.0.1
49
- gemfile: gemfiles/rails50.gemfile
50
- - rvm: 3.0.1
51
- gemfile: gemfiles/rails51.gemfile
52
- - rvm: 3.0.1
53
- gemfile: gemfiles/rails52.gemfile
54
- - rvm: ruby-head
55
- gemfile: gemfiles/rails42.gemfile
56
- allow_failures:
57
- - rvm: ruby-head
58
- fast_finish: true
59
- branches:
60
- only:
61
- - master
62
- - /.*-stable$/
63
- notifications:
64
- webhooks:
65
- urls:
66
- - https://buildlight.collectiveidea.com/
67
- on_start: always