lib/database_cleaner/safeguard.rb
module DatabaseCleaner
class Safeguard
class Error < Exception
class RemoteDatabaseUrl < Error
def initialize
super("ENV['DATABASE_URL'] is set to a remote URL. Please refer to https://github.com/DatabaseCleaner/database_cleaner#safeguards")
end
end
class ProductionEnv < Error
def initialize(env)
super("ENV['#{env}'] is set to production. Please refer to https://github.com/DatabaseCleaner/database_cleaner#safeguards")
end
end
class UrlNotAllowed < Error
def initialize
super("ENV['DATABASE_URL'] is set to a URL that is not on the allowlist. Please refer to https://github.com/DatabaseCleaner/database_cleaner#safeguards")
end
end
end
class AllowedUrl
def run
return if skip?
raise Error::UrlNotAllowed if database_url_not_allowed?
end
private
def database_url_not_allowed?
!DatabaseCleaner.url_allowlist.any? {|allowed| allowed === ENV['DATABASE_URL'] }
end
def skip?
!DatabaseCleaner.url_allowlist
end
end
class RemoteDatabaseUrl
LOCAL = %w(localhost 127.0.0.1)
def run
raise Error::RemoteDatabaseUrl if !skip? && given?
end
private
def given?
remote?(ENV['DATABASE_URL'])
end
def remote?(url)
return false unless url
parsed = URI.parse(url)
return false if parsed.scheme == 'sqlite3:'
host = parsed.host
return false unless host
return false if LOCAL.include?(host)
return false if host.end_with? '.local'
true
end
def skip?
ENV['DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL'] ||
DatabaseCleaner.allow_remote_database_url ||
DatabaseCleaner.url_allowlist
end
end
class Production
KEYS = %w(ENV APP_ENV RACK_ENV RAILS_ENV)
def run
raise Error::ProductionEnv.new(key) if !skip? && given?
end
private
def given?
!!key
end
def key
@key ||= KEYS.detect { |key| ENV[key] == 'production' }
end
def skip?
ENV['DATABASE_CLEANER_ALLOW_PRODUCTION'] ||
DatabaseCleaner.allow_production
end
end
CHECKS = [
RemoteDatabaseUrl,
Production,
AllowedUrl
]
def run
CHECKS.each { |const| const.new.run }
end
end
end