より安全にadhoqを実行したい

追記:だいたいの内容が反映された、adhoq v0.4.0がリリースされていますので、ご利用ください。

github.com

adhoqを使うと、管理画面などで任意のSQLができるようになって便利そうだ。 ただ調査をしていると、sandbox機構は、Transactionを実行してRollbackする、という方式になっているので、アプリケーション実行ユーザーがDROP TABLEできる権限で動いていたりすると、DROP TABLEなどすることができてしまうので、通常のアプリケーションユーザーとは別のユーザーで実行したかった。(アプリケーションユーザーがDROP TABLEできない方がのぞましいが。

また、本番と同じ系統で任意のSQLを実行できるようにした場合、重いSQLなどを実行されてしまったときに本番で別の部分がSlow queryになってしまうので、サービスから隔離した系統で実行させたいというのもあった。

Adhoqの設定には、 config.database_connection というものがあって、ここを置きかえればよさそうにも思えるが、

https://github.com/esminc/adhoq/blob/master/lib/adhoq.rb#L17

      config.database_connection = proc { ActiveRecord::Base.connection }

ここを置きかえただけだと、Adhoqのユーザーの入力したSQL実行終了後に、Adhoqのレコード入れるときなどのconnectionを元に戻すことができないので、うまくいかないっぽかったのでAdhoqそのものを変更した。

Comparing esminc:master...walf443:connection_switchable · esminc/adhoq · GitHub

インターフェースを変えてしまうのでPRにして通るかどうかわからないし英語で書いてうまく伝わるかなー、といった感じだったのでひとまずブログで書いてみた。

なお、手元ではreadonlyな接続を利用するのに、switch_pointとあわせて利用していて、上記のパッチに加えて、

# config/initializers/adhoq.rb
Adhoq.configure do |config|
  config.hidden_model_names = %w[SwitchPoint::Proxy::MainReadonly]
end

module AdhoqReadonlyable
  def with_connection
    result = nil
    SwitchPoint.with_readonly_all do
      result = yield(ApplicationRecord.connection)
    end
    result
  end
end
Adhoq::Executor::ConnectionWrapper.prepend(AdhoqReadonlyable)

といった感じにして、connectionまわりを差し変えている。

また、触っていて、いくつか気になったところを見つけたのでいくつか別途PRにした。