Performance: Added mysql helper to do strategy: reset manually for mysql.
This commit is contained in:
parent
ea30bf80bf
commit
eea67c1774
5 changed files with 137 additions and 55 deletions
|
@ -460,46 +460,6 @@
|
||||||
"confidence": "Medium",
|
"confidence": "Medium",
|
||||||
"note": "Admin configured RegExp"
|
"note": "Admin configured RegExp"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"warning_type": "SQL Injection",
|
|
||||||
"warning_code": 0,
|
|
||||||
"fingerprint": "a5818edfcce4a3860c36ce71d434d1d4dd91fe3cac9ac945c71e4e2932ffe6cc",
|
|
||||||
"check_name": "SQL",
|
|
||||||
"message": "Possible SQL injection",
|
|
||||||
"file": "app/models/ticket/search.rb",
|
|
||||||
"line": 203,
|
|
||||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
|
||||||
"code": "Ticket.select(\"DISTINCT(tickets.id), #{::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")}\")",
|
|
||||||
"render_path": null,
|
|
||||||
"location": {
|
|
||||||
"type": "method",
|
|
||||||
"class": "Ticket::Search",
|
|
||||||
"method": "search"
|
|
||||||
},
|
|
||||||
"user_input": "::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")",
|
|
||||||
"confidence": "Medium",
|
|
||||||
"note": "SqlHelper does properly escape table and column names."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"warning_type": "SQL Injection",
|
|
||||||
"warning_code": 0,
|
|
||||||
"fingerprint": "a5818edfcce4a3860c36ce71d434d1d4dd91fe3cac9ac945c71e4e2932ffe6cc",
|
|
||||||
"check_name": "SQL",
|
|
||||||
"message": "Possible SQL injection",
|
|
||||||
"file": "app/models/ticket/search.rb",
|
|
||||||
"line": 212,
|
|
||||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
|
||||||
"code": "Ticket.select(\"DISTINCT(tickets.id), #{::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")}\")",
|
|
||||||
"render_path": null,
|
|
||||||
"location": {
|
|
||||||
"type": "method",
|
|
||||||
"class": "Ticket::Search",
|
|
||||||
"method": "search"
|
|
||||||
},
|
|
||||||
"user_input": "::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")",
|
|
||||||
"confidence": "Medium",
|
|
||||||
"note": "SqlHelper does properly escape table and column names."
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"warning_type": "Dangerous Send",
|
"warning_type": "Dangerous Send",
|
||||||
"warning_code": 23,
|
"warning_code": 23,
|
||||||
|
@ -540,6 +500,26 @@
|
||||||
"confidence": "Medium",
|
"confidence": "Medium",
|
||||||
"note": "ObjectLookup.by_id works as designed"
|
"note": "ObjectLookup.by_id works as designed"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Command Injection",
|
||||||
|
"warning_code": 14,
|
||||||
|
"fingerprint": "be422b13e9cd280bc5ae570cd575777a4d48d8a53aed09bb59d1db85eee4927b",
|
||||||
|
"check_name": "Execute",
|
||||||
|
"message": "Possible command injection",
|
||||||
|
"file": "lib/mysql_strategy.rb",
|
||||||
|
"line": 64,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/command_injection/",
|
||||||
|
"code": "system(\"mysqldump #{mysql_arguments} > #{backup_file}\", :exception => true)",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "MysqlStrategy",
|
||||||
|
"method": "s(:self).backup"
|
||||||
|
},
|
||||||
|
"user_input": "mysql_arguments",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Mysql arguments are internal / from config."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"warning_type": "Denial of Service",
|
"warning_type": "Denial of Service",
|
||||||
"warning_code": 76,
|
"warning_code": 76,
|
||||||
|
@ -716,6 +696,26 @@
|
||||||
"confidence": "Weak",
|
"confidence": "Weak",
|
||||||
"note": "Reflections come from the models themselves and are thus safe to use."
|
"note": "Reflections come from the models themselves and are thus safe to use."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Command Injection",
|
||||||
|
"warning_code": 14,
|
||||||
|
"fingerprint": "fe15417756eed2c518c355309ee042b57df5f88a5410858dce3fa9fe9c893b84",
|
||||||
|
"check_name": "Execute",
|
||||||
|
"message": "Possible command injection",
|
||||||
|
"file": "lib/mysql_strategy.rb",
|
||||||
|
"line": 56,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/command_injection/",
|
||||||
|
"code": "system(\"mysql #{mysql_arguments} < #{backup_file}\", :exception => true)",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "MysqlStrategy",
|
||||||
|
"method": "s(:self).rollback"
|
||||||
|
},
|
||||||
|
"user_input": "mysql_arguments",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Mysql arguments are internal / from config."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"warning_type": "Denial of Service",
|
"warning_type": "Denial of Service",
|
||||||
"warning_code": 76,
|
"warning_code": 76,
|
||||||
|
@ -723,7 +723,7 @@
|
||||||
"check_name": "RegexDoS",
|
"check_name": "RegexDoS",
|
||||||
"message": "Model attribute used in regular expression",
|
"message": "Model attribute used in regular expression",
|
||||||
"file": "app/models/ticket.rb",
|
"file": "app/models/ticket.rb",
|
||||||
"line": 1612,
|
"line": 1577,
|
||||||
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
"code": "/#{Setting.get(\"send_no_auto_response_reg_exp\")}/i",
|
"code": "/#{Setting.get(\"send_no_auto_response_reg_exp\")}/i",
|
||||||
"render_path": null,
|
"render_path": null,
|
||||||
|
@ -737,6 +737,6 @@
|
||||||
"note": "Admin configured RegExp"
|
"note": "Admin configured RegExp"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"updated": "2021-07-20 13:22:48 +0200",
|
"updated": "2021-07-22 13:52:48 +0200",
|
||||||
"brakeman_version": "5.0.4"
|
"brakeman_version": "5.1.1"
|
||||||
}
|
}
|
||||||
|
|
73
lib/mysql_strategy.rb
Normal file
73
lib/mysql_strategy.rb
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
require 'fileutils'
|
||||||
|
require 'digest'
|
||||||
|
|
||||||
|
class MysqlStrategy
|
||||||
|
def self.db?
|
||||||
|
ActiveRecord::Base.connection.instance_values['config'][:adapter] == 'mysql2'
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.db_checksum
|
||||||
|
@@db_checksum ||= begin # rubocop:disable Style/ClassVars
|
||||||
|
files = Dir[ Rails.root.join('db/**/*') ].reject { |f| File.directory?(f) }
|
||||||
|
content = files.map { |f| File.read(f) }.join
|
||||||
|
Digest::MD5.hexdigest(content).to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.basepath
|
||||||
|
Rails.root.join("tmp/mysql_reset/#{db_checksum}/")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.backup_file
|
||||||
|
"#{basepath}db.sql"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.backup_exists?
|
||||||
|
File.exist?(backup_file)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.username
|
||||||
|
ActiveRecord::Base.connection.instance_values['config'][:username]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.password
|
||||||
|
ActiveRecord::Base.connection.instance_values['config'][:password]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.host
|
||||||
|
ActiveRecord::Base.connection.instance_values['config'][:host] || '127.0.0.1'
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.database
|
||||||
|
ActiveRecord::Base.connection.instance_values['config'][:database]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.mysql_arguments
|
||||||
|
args = " -u#{username} -h#{host}"
|
||||||
|
args += " -p#{password}" if password.present? # allow for passwordless access on dev systems
|
||||||
|
args + " #{database}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.rollback
|
||||||
|
system("mysql #{mysql_arguments} < #{backup_file}", exception: true)
|
||||||
|
Rake::Task['zammad:db:rebuild'].reenable
|
||||||
|
Rake::Task['zammad:db:rebuild'].invoke
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.backup
|
||||||
|
Rake::Task['zammad:db:reset'].reenable
|
||||||
|
Rake::Task['zammad:db:reset'].invoke
|
||||||
|
system("mysqldump #{mysql_arguments} > #{backup_file}", exception: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.reset
|
||||||
|
FileUtils.mkdir_p Rails.root.join(basepath)
|
||||||
|
if backup_exists?
|
||||||
|
rollback
|
||||||
|
else
|
||||||
|
backup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
16
lib/tasks/zammad/db/rebuild.rake
Normal file
16
lib/tasks/zammad/db/rebuild.rake
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
namespace :zammad do
|
||||||
|
|
||||||
|
namespace :db do
|
||||||
|
|
||||||
|
desc 'Clears the Cache and reloads the Settings'
|
||||||
|
task rebuild: :environment do
|
||||||
|
Package::Migration.linked
|
||||||
|
ActiveRecord::Base.connection.reconnect!
|
||||||
|
ActiveRecord::Base.descendants.each(&:reset_column_information)
|
||||||
|
Cache.clear
|
||||||
|
Setting.reload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@ namespace :zammad do
|
||||||
# we loop over each dependent task to be able to
|
# we loop over each dependent task to be able to
|
||||||
# execute them and their prerequisites multiple times (in tests)
|
# execute them and their prerequisites multiple times (in tests)
|
||||||
# there is no way in rake to achieve that
|
# there is no way in rake to achieve that
|
||||||
%w[db:drop:_unsafe db:create db:migrate db:seed].each do |task|
|
%w[db:drop:_unsafe db:create db:migrate db:seed zammad:db:rebuild].each do |task|
|
||||||
|
|
||||||
if task == 'db:drop:_unsafe'
|
if task == 'db:drop:_unsafe'
|
||||||
# ensure all DB connections are closed before dropping the DB
|
# ensure all DB connections are closed before dropping the DB
|
||||||
|
@ -26,12 +26,6 @@ namespace :zammad do
|
||||||
ensure
|
ensure
|
||||||
$stdout = STDOUT
|
$stdout = STDOUT
|
||||||
end
|
end
|
||||||
|
|
||||||
Package::Migration.linked
|
|
||||||
ActiveRecord::Base.connection.reconnect!
|
|
||||||
ActiveRecord::Base.descendants.each(&:reset_column_information)
|
|
||||||
Cache.clear
|
|
||||||
Setting.reload
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,18 +3,17 @@
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
|
|
||||||
config.around(:each, db_strategy: :reset) do |example|
|
config.around(:each, db_strategy: :reset) do |example|
|
||||||
if ActiveRecord::Base.connection.instance_values['config'][:adapter] != 'postgresql'
|
if MysqlStrategy.db?
|
||||||
self.use_transactional_tests = false
|
self.use_transactional_tests = false
|
||||||
end
|
end
|
||||||
example.run
|
example.run
|
||||||
if ActiveRecord::Base.connection.instance_values['config'][:adapter] == 'postgresql'
|
if MysqlStrategy.db?
|
||||||
|
MysqlStrategy.reset
|
||||||
|
else
|
||||||
Models.all.each_key do |model|
|
Models.all.each_key do |model|
|
||||||
model.connection.schema_cache.clear!
|
model.connection.schema_cache.clear!
|
||||||
model.reset_column_information
|
model.reset_column_information
|
||||||
end
|
end
|
||||||
else
|
|
||||||
Rake::Task['zammad:db:reset'].reenable
|
|
||||||
Rake::Task['zammad:db:reset'].invoke
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue