Compare commits

...

9 Commits

Author SHA1 Message Date
Jared Beck ccf0183088 Doc: fix link per past convention 2022-10-16 02:01:37 -04:00
Jared Beck bce8b193c5 Ensure YAML safe loading in Rails 6.1, part 2 2022-10-16 01:54:50 -04:00
Tim Connor 172ac1d747 Ensure YAML safe loading in Rails 6.1
As part of the fix for CVE-2022-32224 Rails intruduced safe YAML loading
and the `ActiveRecord.yaml_column_permitted_classes` config.

PaperTrail added support for respecting the new configuration here
https://github.com/paper-trail-gem/paper_trail/pull/1397

The CVE-2022-32224 fix was also backported to Rails versions 5.2.8.1,
6.0.5.1, and, 6.1.6.1, however the name of the confiuration is slightly
different from that in Rails 7.x.

    7.0.3.1 ActiveRecord.yaml_column_permitted_classes
    6.1.6.1 ActiveRecord::Base.yaml_column_permitted_classes
    6.0.5.1 ActiveRecord::Base.yaml_column_permitted_classes
    5.2.8.1 ActiveRecord::Base.yaml_column_permitted_classes

PaperTrail currently doesn't support this alternative configuration
naming, which means it will silent fall back to unsafe YAML loading.

This commit updates `PaperTrail::Serializers::YAML` to be compatible
with safe YAML loading for the Rails 5.2 / 6.0 / 6.1 branches.
2022-10-16 01:41:53 -04:00
Jared Beck e71c65604f
Merge pull request #1403 from paper-trail-gem/drop_eol_dependencies
Drop EoL dependencies
2022-10-16 01:13:45 -04:00
Jared Beck fd35de6eb5 Drop support for Ruby 2.6 (reached EoL on 2022-03-31) 2022-10-16 01:02:29 -04:00
Jared Beck 3f0e3aba2e Drop support for Rails 5.2 (reached EoL on 2022-06-01) 2022-10-16 00:54:14 -04:00
Jared Beck 6eb5c39e7e
Merge pull request #1393 from danbernier/patch-1
Update README.md: clarify :ignore vs :skip usage
2022-08-15 22:30:02 -04:00
Jared Beck b82256d5ef Doc: fix link in changelog
[ci skip]
2022-08-15 22:16:39 -04:00
Daniel Bernier a14a0e9e12
Update README.md: clarify :ignore vs :skip usage
The SSN example was the motivation: I thought ignoring it would be enough, and was surprised to find values for an ignored field in the versions table. Hopefully, this saves others the time!
2022-07-13 13:11:34 -04:00
15 changed files with 106 additions and 103 deletions

View File

@ -48,29 +48,18 @@ Testing is a little awkward because the test suite:
1. Contains a "dummy" rails app with three databases (test, foo, and bar)
1. Supports three different RDBMS': sqlite, mysql, and postgres
### Test sqlite, AR 6
### Test
For most development, testing with sqlite only is easiest and sufficient. CI
will run the rest.
```
DB=sqlite bundle exec appraisal rails-6.0 rake
```
### Test sqlite, AR 5
```
DB=sqlite bundle exec appraisal rails-5.2 rake
```
### Test mysql, AR 5
```
DB=mysql bundle exec appraisal rails-5.2 rake
```
### Test postgres, AR 5
```
DB=sqlite bundle exec appraisal rails-6.1 rake
DB=sqlite bundle exec appraisal rails-7.0 rake
DB=mysql bundle exec appraisal rails-7.0 rake
createuser --superuser postgres
DB=postgres bundle exec appraisal rails-5.2 rake
DB=postgres bundle exec appraisal rails-7.0 rake
```
## The dummy_app
@ -80,7 +69,7 @@ In the rare event you need a `console` in the `dummy_app`:
```
cd spec/dummy_app
cp config/database.mysql.yml config/database.yml
BUNDLE_GEMFILE='../../gemfiles/rails_5.2.gemfile' bin/rails console -e test
BUNDLE_GEMFILE='../../gemfiles/rails_7.0.gemfile' bin/rails console -e test
```
## Adding new schema

View File

@ -17,7 +17,7 @@ jobs:
uses: ruby/setup-ruby@v1
with:
# See "Lowest supported ruby version" in CONTRIBUTING.md
ruby-version: '2.6'
ruby-version: '2.7'
- name: Bundle
run: |
gem install bundler
@ -59,25 +59,14 @@ jobs:
# have set this up with each database as a separate job, but then we'd be
# duplicating the matrix configuration three times.
matrix:
gemfile: [ 'rails_5.2', 'rails_6.0', 'rails_6.1', 'rails_7.0' ]
gemfile: [ 'rails_6.0', 'rails_6.1', 'rails_7.0' ]
# To keep matrix size down, only test highest and lowest rubies.
# Ruby 3.0 is an exception. For now, let's continue to test against 2.7
# in case it still produces any deprecation warnings.
#
# See "Lowest supported ruby version" in CONTRIBUTING.md
ruby: [ '2.6', '2.7', '3.0', '3.1' ]
exclude:
# rails 5.2 requires ruby < 3.0
# https://github.com/rails/rails/issues/40938
- ruby: '3.0'
gemfile: 'rails_5.2'
- ruby: '3.1'
gemfile: 'rails_5.2'
# rails 7 requires ruby > 2.7
- ruby: '2.6'
gemfile: 'rails_7.0'
ruby: [ '2.7', '3.0', '3.1' ]
steps:
- name: Checkout source
uses: actions/checkout@v2

View File

@ -23,7 +23,7 @@ AllCops:
NewCops: enable
# See "Lowest supported ruby version" in CONTRIBUTING.md
TargetRubyVersion: 2.6
TargetRubyVersion: 2.7
Layout/ArgumentAlignment:
EnforcedStyle: with_fixed_indentation

View File

@ -8,12 +8,6 @@
# > appraisal. If something is specified in both the Gemfile and an appraisal,
# > the version from the appraisal takes precedence.
# > https://github.com/thoughtbot/appraisal
#
#
appraise "rails-5.2" do
gem "rails", "~> 5.2.4"
gem "rails-controller-testing", "~> 1.0.2"
end
appraise "rails-6.0" do
gem "rails", "~> 6.0.3"

View File

@ -7,7 +7,13 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
### Breaking Changes
- None
- [#1399](https://github.com/paper-trail-gem/paper_trail/pull/1399) - Same
change re: `YAML.safe_load` as in 13.0.0, but this time for Rails 6.0 and 6.1.
### Dependencies
- Drop support for Rails 5.2, which reached EoL on 2022-06-01
- Drop support for Ruby 2.6, which reached EoL on 2022-03-31
### Added
@ -21,12 +27,12 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
### Breaking Changes
- The default serializer will now use `YAML.safe_load` unless
- For Rails >= 7.0, the default serializer will now use `YAML.safe_load` unless
`ActiveRecord.use_yaml_unsafe_load`. This change only affects users whose
`versions` table has `object` or `object_changes` columns of type `text`, and
who use the YAML serializer. People who use the JSON serializer, or those with
`json(b)` columns, are unaffected. Please see [doc/pt_13_yaml_safe_load.md] for
details.
`json(b)` columns, are unaffected. Please see
[doc/pt_13_yaml_safe_load.md](doc/pt_13_yaml_safe_load.md) for details.
### Added

View File

@ -90,7 +90,7 @@ Choose version:
| paper_trail | branch | ruby | activerecord |
|-------------|------------|----------|---------------|
| unreleased | master | >= 2.6.0 | >= 5.2, < 7.1 |
| unreleased | master | >= 2.7.0 | >= 6.0, < 7.1 |
| 13 | 13-stable | >= 2.6.0 | >= 5.2, < 7.1 |
| 12 | 12-stable | >= 2.6.0 | >= 5.2, < 7.1 |
| 11 | 11-stable | >= 2.4.0 | >= 5.2, < 6.1 |
@ -415,7 +415,7 @@ my_model.paper_trail.save_with_version
#### Ignore
You can `ignore` changes to certain attributes:
If you don't want a version created when only a certain attribute changes, you can `ignore` that attribute:
```ruby
class Article < ActiveRecord::Base
@ -436,6 +436,8 @@ a.versions.length # 2
a.paper_trail.previous_version.title # 'My Title'
```
Note: ignored fields will be stored in the version records. If you want to keep a field out of the versions table, use [`:skip`](#skip) instead of `:ignore`; skipped fields are also implicitly ignored.
The `:ignore` option can also accept `Hash` arguments that we are considering deprecating.
```ruby
@ -499,17 +501,31 @@ article being saved if a changed attribute is included in `:only` but not in
#### Skip
You can skip attributes completely with the `:skip` option. As with `:ignore`,
If you never want a field's values in the versions table, you can `:skip` the attribute. As with `:ignore`,
updates to these attributes will not create a version record. In addition, if a
version record is created for some other reason, these attributes will not be
persisted.
```ruby
class Article < ActiveRecord::Base
has_paper_trail skip: [:file_upload]
class Author < ActiveRecord::Base
has_paper_trail skip: [:social_security_number]
end
```
Author's social security numbers will never appear in the versions log, and if an author updates only their social security number, it won't create a version record.
#### Comparing `:ignore`, `:only`, and `:skip`
- `:only` is basically the same as `:ignore`, but its inverse.
- `:ignore` controls whether paper_trail will create a version record or not.
- `:skip` controls whether paper_trail will save that field with the version record.
- Skipped fields are also implicitly ignored. paper_trail does this internally.
- Ignored fields are not implicitly skipped.
So:
- Ignore a field if you don't want a version record created when it's the only field to change.
- Skip a field if you don't want it to be saved with any version records.
### 2.d. Turning PaperTrail Off
PaperTrail is on by default, but sometimes you don't want to record versions.

View File

@ -1,8 +0,0 @@
# This file was generated by Appraisal
source "https://rubygems.org"
gem "rails", "~> 5.2.4"
gem "rails-controller-testing", "~> 1.0.2"
gemspec path: "../"

View File

@ -17,7 +17,7 @@ module PaperTrail
# newer rails versions. Most PT users should avoid incompatible rails
# versions.
module Compatibility
ACTIVERECORD_GTE = ">= 5.2" # enforced in gemspec
ACTIVERECORD_GTE = ">= 6.0" # enforced in gemspec
ACTIVERECORD_LT = "< 7.1" # not enforced in gemspec
E_INCOMPATIBLE_AR = <<-EOS

View File

@ -12,7 +12,7 @@ module PaperTrail
if use_safe_load?
::YAML.safe_load(
string,
permitted_classes: ::ActiveRecord.yaml_column_permitted_classes,
permitted_classes: yaml_column_permitted_classes,
aliases: true
)
elsif ::YAML.respond_to?(:unsafe_load)
@ -39,10 +39,29 @@ module PaperTrail
private
# `use_yaml_unsafe_load` was added in 7.0.3.1, will be removed in 7.1.0?
def use_safe_load?
defined?(ActiveRecord.use_yaml_unsafe_load) &&
!ActiveRecord.use_yaml_unsafe_load
if ::ActiveRecord.gem_version >= Gem::Version.new("7.0.3.1")
# `use_yaml_unsafe_load` may be removed in the future, at which point
# safe loading will be the default.
!defined?(ActiveRecord.use_yaml_unsafe_load) || !ActiveRecord.use_yaml_unsafe_load
elsif defined?(ActiveRecord::Base.use_yaml_unsafe_load)
# Rails 5.2.8.1, 6.0.5.1, 6.1.6.1
!ActiveRecord::Base.use_yaml_unsafe_load
else
false
end
end
def yaml_column_permitted_classes
if defined?(ActiveRecord.yaml_column_permitted_classes)
# Rails >= 7.0.3.1
ActiveRecord.yaml_column_permitted_classes
elsif defined?(ActiveRecord::Base.yaml_column_permitted_classes)
# Rails 5.2.8.1, 6.0.5.1, 6.1.6.1
ActiveRecord::Base.yaml_column_permitted_classes
else
[]
end
end
end
end

View File

@ -43,7 +43,7 @@ has been destroyed.
# about 3 years, per https://www.ruby-lang.org/en/downloads/branches/
#
# See "Lowest supported ruby version" in CONTRIBUTING.md
s.required_ruby_version = ">= 2.6.0"
s.required_ruby_version = ">= 2.7.0"
# We no longer specify a maximum activerecord version.
# See discussion in paper_trail/compatibility.rb

View File

@ -13,7 +13,17 @@ require File.expand_path("boot", __dir__)
module Dummy
class Application < Rails::Application
config.load_defaults(::Rails.gem_version.segments.take(2).join("."))
YAML_COLUMN_PERMITTED_CLASSES = [
::ActiveRecord::Type::Time::Value,
::ActiveSupport::TimeWithZone,
::ActiveSupport::TimeZone,
::BigDecimal,
::Date,
::Symbol,
::Time
].freeze
config.load_defaults(::ActiveRecord.gem_version.segments.take(2).join("."))
config.encoding = "utf-8"
config.filter_parameters += [:password]
@ -21,25 +31,14 @@ module Dummy
config.active_support.test_order = :sorted
config.secret_key_base = "A fox regularly kicked the screaming pile of biscuits."
# In rails >= 6.0, "`.represent_boolean_as_integer=` is now always true,
# so setting this is deprecated and will be removed in Rails 6.1."
if ::ENV["DB"] == "sqlite" &&
::Gem::Requirement.new("~> 5.2").satisfied_by?(::Rails.gem_version)
config.active_record.sqlite3.represent_boolean_as_integer = true
end
# `use_yaml_unsafe_load` was added in 7.0.3.1, will be removed in 7.1.0?
if ::ActiveRecord.respond_to?(:use_yaml_unsafe_load)
# `use_yaml_unsafe_load` was added in 5.2.8.1, 6.0.5.1, 6.1.6.1, and 7.0.3.1.
# Will be removed in 7.1.0?
if ::ActiveRecord.respond_to?(:use_yaml_unsafe_load) # 7.0.3.1
::ActiveRecord.use_yaml_unsafe_load = false
::ActiveRecord.yaml_column_permitted_classes = [
::ActiveRecord::Type::Time::Value,
::ActiveSupport::TimeWithZone,
::ActiveSupport::TimeZone,
::BigDecimal,
::Date,
::Symbol,
::Time
]
::ActiveRecord.yaml_column_permitted_classes = YAML_COLUMN_PERMITTED_CLASSES
elsif ::ActiveRecord::Base.respond_to?(:use_yaml_unsafe_load) # 5.2.8.1, 6.0.5.1, 6.1.6.1
::ActiveRecord::Base.use_yaml_unsafe_load = false
::ActiveRecord::Base.yaml_column_permitted_classes = YAML_COLUMN_PERMITTED_CLASSES
end
end
end

View File

@ -138,7 +138,7 @@ RSpec.describe Widget, type: :model, versioning: true do
it "have versions that are not live" do
widget = described_class.create(name: "Henry")
widget.update(name: "Harry")
widget.versions.map(&:reify).compact.each do |v|
widget.versions.filter_map(&:reify).each do |v|
expect(v.paper_trail).not_to be_live
end
end

View File

@ -24,12 +24,12 @@ module PaperTrail
end
it "calls the expected load method based on Psych version" do
# `use_yaml_unsafe_load` was added in 7.0.3.1, will be removed in 7.1.0?
if defined?(ActiveRecord.use_yaml_unsafe_load) && !ActiveRecord.use_yaml_unsafe_load
# `use_yaml_unsafe_load` was added in 5.2.8.1, 6.0.5.1, 6.1.6.1, and 7.0.3.1
if rails_supports_safe_load?
allow(::YAML).to receive(:safe_load)
described_class.load("string")
expect(::YAML).to have_received(:safe_load)
# Psych 4+ implements .unsafe_load
# Psych 4+ implements .unsafe_load
elsif ::YAML.respond_to?(:unsafe_load)
allow(::YAML).to receive(:unsafe_load)
described_class.load("string")
@ -60,6 +60,16 @@ module PaperTrail
expect(arel_value(matches.right)).to eq("%\narg1: Val 1\n%")
end
end
private
def rails_supports_safe_load?
# Rails 7.0.3.1 onwards will always support YAML safe loading
return true if ::ActiveRecord.gem_version >= Gem::Version.new("7.0.3.1")
# Older Rails versions may or may not, depending on whether they have been patched.
defined?(ActiveRecord::Base.use_yaml_unsafe_load)
end
end
end
end

View File

@ -7,7 +7,7 @@ require "simplecov"
SimpleCov.start do
add_filter %w[Appraisals Gemfile Rakefile doc gemfiles spec]
end
SimpleCov.minimum_coverage(ENV["DB"] == "postgres" ? 97.3 : 92.4)
SimpleCov.minimum_coverage(ENV["DB"] == "postgres" ? 96.8 : 92.4)
require "byebug"
require_relative "support/pt_arel_helpers"

View File

@ -18,22 +18,11 @@ class PaperTrailSpecMigrator
@migrations_path = dummy_app_migrations_dir
end
# Looks like the API for programmatically running migrations will change
# in rails 5.2. This is an undocumented change, AFAICT. Then again,
# how many people use the programmatic interface? Most people probably
# just use rake. Maybe we're doing it wrong.
#
# See also discussion in https://github.com/rails/rails/pull/40806, when
# MigrationContext#migrate became public.
def migrate
if ::ActiveRecord.gem_version >= ::Gem::Version.new("6.0.0.rc2")
::ActiveRecord::MigrationContext.new(
@migrations_path,
::ActiveRecord::Base.connection.schema_migration
).migrate
else
::ActiveRecord::MigrationContext.new(@migrations_path).migrate
end
::ActiveRecord::MigrationContext.new(
@migrations_path,
::ActiveRecord::Base.connection.schema_migration
).migrate
end
# Generate a migration, run it, and delete it. We use this for testing the