Skip to content

Commit

Permalink
Merge pull request #17 from os0x/rails71
Browse files Browse the repository at this point in the history
Support Rails 7.1
  • Loading branch information
nekketsuuu authored Sep 18, 2024
2 parents 019668b + 7bcbe52 commit ebfee15
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 100 deletions.
28 changes: 5 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,20 @@ jobs:
fail-fast: false
matrix:
ruby:
- '2.6'
- '2.7'
- '3.0'
- '3.1'
- '3.2'
- '3.3'
gemfile:
- rails_5.0
- rails_5.1
- rails_5.2
- rails_6.0
- rails_6.1
- rails_7.0
exclude:
# Ruby >= 3.0 is supported since Rails 6.0
- ruby: '3.0'
gemfile: rails_5.0
- ruby: '3.0'
gemfile: rails_5.1
- ruby: '3.0'
gemfile: rails_5.2
- ruby: '3.1'
gemfile: rails_5.0
- ruby: '3.1'
gemfile: rails_5.1
- ruby: '3.1'
gemfile: rails_5.2
# Rails 7.0 supports Ruby >= 2.7 only
- ruby: '2.6'
gemfile: rails_7.0
- rails_7.1
name: Run test with Ruby ${{ matrix.ruby }} and Gemfile ${{ matrix.gemfile }}
services:
mysql:
image: mysql:5.7
image: mysql:8.4
env:
MYSQL_ALLOW_EMPTY_PASSWORD: '1'
MYSQL_DATABASE: blouson
Expand All @@ -56,7 +38,7 @@ jobs:
env:
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
Expand Down
16 changes: 4 additions & 12 deletions Appraisals
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
appraise 'rails-5.0' do
gem 'rails', '~> 5.0.0'
end

appraise 'rails-5.1' do
gem 'rails', '~> 5.1.0'
end

appraise 'rails-5.2' do
gem 'rails', '~> 5.2.0'
end

appraise 'rails-6.0' do
gem 'rails', '~> 6.0.0'
end
Expand All @@ -22,4 +10,8 @@ appraise 'rails-7.0' do
gem 'rails', '~> 7.0.0'
end

appraise 'rails-7.1' do
gem 'rails', '~> 7.1.0'
end

# vim: set ft=ruby:
2 changes: 1 addition & 1 deletion blouson.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_dependency 'rails', '>= 4.0.0'
spec.add_dependency 'rails', '>= 6.0.0'

spec.add_development_dependency 'arproxy'
spec.add_development_dependency 'mysql2'
Expand Down
7 changes: 0 additions & 7 deletions gemfiles/rails_5.1.gemfile

This file was deleted.

7 changes: 0 additions & 7 deletions gemfiles/rails_5.2.gemfile

This file was deleted.

2 changes: 1 addition & 1 deletion gemfiles/rails_5.0.gemfile → gemfiles/rails_7.1.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

source "https://rubygems.org"

gem "rails", "~> 5.0.0"
gem "rails", "~> 7.1.0"

gemspec path: "../"
5 changes: 5 additions & 0 deletions lib/blouson/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ class Engine < Rails::Engine
ActiveRecord::StatementInvalid.class_eval do
prepend Blouson::SensitiveQueryFilter::StatementInvalidErrorFilter
end
if Rails::VERSION::MAJOR >= 7 && Rails::VERSION::MINOR >= 1 && defined?(Mysql2::Error)
ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
prepend Blouson::SensitiveQueryFilter::AbstractAdapterFilter
end
end
end
end
end
Expand Down
53 changes: 39 additions & 14 deletions lib/blouson/sensitive_query_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,43 @@ def self.filter_sensitive_words(message)
end

module StatementInvalidErrorFilter
def initialize(message = nil, original_exception = nil, sql: nil, binds: nil)
if SensitiveQueryFilter.contain_sensitive_query?(message) || (SensitiveQueryFilter.contain_sensitive_query?(sql))
def initialize(message = nil, sql: nil, binds: nil, connection_pool: nil)
if SensitiveQueryFilter.contain_sensitive_query?(message) || SensitiveQueryFilter.contain_sensitive_query?(sql)
message = SensitiveQueryFilter.filter_sensitive_words(message) if message
sql = SensitiveQueryFilter.filter_sensitive_words(sql) if sql
if defined?(Mysql2::Error)
if original_exception.is_a?(Mysql2::Error)
original_exception.extend(Mysql2Filter)
elsif $!.is_a?(Mysql2::Error)
if $!.is_a?(Mysql2::Error)
$!.extend(Mysql2Filter)
end
end
end

if original_exception
# Rails < 5.0
super(message, original_exception)
elsif sql
if connection_pool
# Rails >= 7.1
#
# - https://github.com/rails/rails/pull/48295
super(message, sql: sql, binds: binds, connection_pool: connection_pool)
else
# Rails >= 6.0
#
# - https://github.com/rails/rails/pull/34468
super(message, sql: sql, binds: binds)
end
end

def set_query(sql, binds)
if SensitiveQueryFilter.contain_sensitive_query?(sql)
super(SensitiveQueryFilter.filter_sensitive_words(sql), binds)
else
# Rails >= 5.0
#
# - https://github.com/rails/rails/pull/18774
# - https://github.com/rails/rails/pull/27503
super(message)
super(sql, binds)
end
end

def to_s
if SensitiveQueryFilter.contain_sensitive_query?(sql)
SensitiveQueryFilter.filter_sensitive_words(super)
else
super
end
end
end
Expand All @@ -51,5 +61,20 @@ def message
SensitiveQueryFilter.filter_sensitive_words(super)
end
end

module AbstractAdapterFilter
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block)
super(sql, name, binds, type_casted_binds, statement_name, async: false, &block)
rescue ActiveRecord::RecordNotUnique, Mysql2::Error => ex
if ex.cause.is_a?(Mysql2::Error)
ex.cause.extend(Mysql2Filter)
elsif $!.is_a?(Mysql2::Error)
$!.extend(Mysql2Filter)
end
raise ex
end

private :log
end
end
end
63 changes: 28 additions & 35 deletions spec/blouson/sensitive_query_filter_spec.rb
Original file line number Diff line number Diff line change
@@ -1,35 +1,38 @@
require 'spec_helper'

if ActiveRecord.version >= Gem::Version.new('7.1') && defined?(Mysql2::Error)
ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
prepend Blouson::SensitiveQueryFilter::AbstractAdapterFilter
end
end

ActiveRecord::StatementInvalid.class_eval do
prepend Blouson::SensitiveQueryFilter::StatementInvalidErrorFilter
end

RSpec.describe Blouson::SensitiveQueryFilter do
describe 'StatementInvalidErrorFilter' do
def error
model_class.where(condition).first
rescue => e
return e
end

before do
dummy_error = Class.new(ActiveRecord::StatementInvalid) do
prepend Blouson::SensitiveQueryFilter::StatementInvalidErrorFilter
end
stub_const('ActiveRecord::StatementInvalid', dummy_error)
end
def error
model_class.where(condition).first
rescue => e
return e
end

context 'with query to sensitive table' do
let(:model_class) { SecureUser }
let(:email) { '[email protected]' }
let(:condition) { { invalid_column: email } }

it 'filters SQL statement' do
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect { model_class.where(condition).first }.to raise_error(/\[FILTERED\]/)
else
expect { model_class.where(condition).first }.to raise_error(/SELECT.*\[FILTERED\]/)
end
end

it 'filters to_s message' do
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect(error.to_s).not_to include(email)
expect(error.to_s).to include('[FILTERED]')
else
Expand All @@ -40,7 +43,7 @@ def error
end

it 'filters inspect message' do
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect(error.inspect).to include('[FILTERED]')
else
expect(error.to_s).to include('SELECT')
Expand All @@ -49,7 +52,7 @@ def error
end
end

if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
it 'filters sql message' do
expect(error.sql).to include('SELECT')
expect(error.sql).not_to include(email)
Expand All @@ -64,7 +67,7 @@ def error
rescue => e
error = e
end
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect(error.to_s).not_to include(email)
expect(error.to_s).to include('[FILTERED]')

Expand All @@ -82,7 +85,7 @@ def error
let(:email) { "'alice'@example'.com''" }

it 'filters sensitive data' do
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect(error.to_s).not_to include('alice')

expect(error.sql).to include('SELECT')
Expand All @@ -101,7 +104,7 @@ def error
let(:condition) { { invalid_column: email, email2: email } }

it 'filters sensitive data' do
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect(error.to_s).not_to include('alice')

expect(error.sql).to include('SELECT')
Expand All @@ -119,11 +122,6 @@ def error

context 'with sensitive value in Mysql2::Error' do
before do
dummy_error = Class.new(ActiveRecord::RecordNotUnique) do
prepend Blouson::SensitiveQueryFilter::StatementInvalidErrorFilter
end
stub_const('ActiveRecord::RecordNotUnique', dummy_error)

model_class.create!(email: email, email2: email)
end

Expand All @@ -134,7 +132,7 @@ def error
it 'filters sensitive data' do
expect { model_class.create!(email: email, email2: email) }.to raise_error { |e|
expect(e).to be_a(ActiveRecord::RecordNotUnique)
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect(e.message).to_not include('alice')

expect(e.sql).to include('INSERT INTO `secure_users` ')
Expand Down Expand Up @@ -162,7 +160,7 @@ def error
let(:condition) { { invalid_column: name } }

it 'does not filter SQL statement' do
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect { model_class.where(condition).first }.to raise_error(/Unknown column 'users.invalid_column'/)
else
expect { model_class.where(condition).first }.to raise_error(/Unknown column 'users.invalid_column'/)
Expand All @@ -171,7 +169,7 @@ def error
end

it 'does not filter to_s' do
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect(error.to_s).not_to include('[FILTERED]')
else
expect(error.to_s).to include('SELECT')
Expand All @@ -181,7 +179,7 @@ def error
end

it 'does not filter inspect message' do
if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect(error.inspect).not_to include('[FILTERED]')
else
expect(error.to_s).to include('SELECT')
Expand All @@ -190,7 +188,7 @@ def error
end
end

if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
it 'does not filter sql message' do
expect(error.sql).to include('SELECT')
expect(error.sql).to include(name)
Expand All @@ -200,11 +198,6 @@ def error

context 'with non-sensitive value in Mysql2::Error' do
before do
dummy_error = Class.new(ActiveRecord::RecordNotUnique) do
prepend Blouson::SensitiveQueryFilter::StatementInvalidErrorFilter
end
stub_const('ActiveRecord::RecordNotUnique', dummy_error)

model_class.create!(name: name)
end

Expand All @@ -216,7 +209,7 @@ def error
expect { model_class.create!(name: name) }.to raise_error { |e|
expect(e).to be_a(ActiveRecord::RecordNotUnique)

if Rails::VERSION::MAJOR >= 6
if ActiveRecord::VERSION::MAJOR >= 6
expect(e.message).to include(name)
expect(e.message).to_not include('[FILTERED]')

Expand Down

0 comments on commit ebfee15

Please sign in to comment.