Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add readonly mode to production console
- Loading branch information
Showing
3 changed files
with
59 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# frozen_string_literal: true | ||
# loaded by marco-polo, cannot be in console.rb | ||
if Rails.env.production? | ||
puts "Running in readonly mode. Use Samson::ReadonlyDb.disable to switch to writable." | ||
Samson::ReadonlyDb.enable | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,11 @@ | ||
# frozen_string_literal: true | ||
Rails.application.console do | ||
Rails::ConsoleMethods.send(:prepend, Samson::ConsoleExtensions) | ||
|
||
puts "Samson version: #{SAMSON_VERSION.first(7)}" if SAMSON_VERSION | ||
|
||
ActiveRecord::Base.logger = Rails.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT)) | ||
Rails.logger.level = :info if ENV['PROFILE'] | ||
|
||
Audited.store[:audited_user] = "rails console #{ENV.fetch("USER")}" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# frozen_string_literal: true | ||
|
||
# Make Activerecord readonly by blocking write requests | ||
# NOTE: not perfect and can be circumvented with multiline sql statements or `;` | ||
module Samson | ||
module ReadonlyDb | ||
ALLOWED = ["SELECT ", "SHOW ", "SET @@SESSION.", "EXPLAIN "].freeze | ||
PROMPT_CHANGE = ["(", "(readonly "].freeze | ||
PROMPTS = [:PROMPT_I, :PROMPT_N].freeze | ||
|
||
class << self | ||
def enable | ||
return if @subscriber | ||
@subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |*, payload| | ||
sql = payload.fetch(:sql) | ||
next if sql.start_with?(*ALLOWED) | ||
raise ActiveRecord::ReadOnlyRecord, <<~MSG | ||
Database is in readonly mode, cannot execute query | ||
Switch off readonly with #{self}.#{method(:disable).name} | ||
#{sql} | ||
MSG | ||
end | ||
update_prompt | ||
end | ||
|
||
def disable | ||
return unless @subscriber | ||
ActiveSupport::Notifications.unsubscribe @subscriber | ||
@subscriber = nil | ||
update_prompt | ||
end | ||
|
||
private | ||
|
||
# TODO: modify normal prompt when marco-polo is not enabled | ||
# TODO: pry support | ||
def update_prompt | ||
return unless defined?(IRB) # uncovered | ||
return unless prompt = IRB.conf.dig(:PROMPT, :RAILS_ENV) | ||
|
||
PROMPTS.each do |prompt_key| | ||
value = prompt.fetch(prompt_key) # change marco-polo prompt | ||
change = (@subscriber ? PROMPT_CHANGE : PROMPT_CHANGE.reverse) | ||
value.sub!(*change) || raise("Unable to change prompt #{prompt_key} #{value.inspect}") | ||
end | ||
nil | ||
end | ||
end | ||
end | ||
end |