いかに危険なコマンド実行間違いを防ぐか。そのためにExeCopを書いてみた

追記: Bashにも対応しました

皆さんもpeco/percol/fzf/anyfinderなどのフィルタリングツールを便利に使っていると思います。

ちなみに私はpeco派です。

コマンド実行間違い

ところで、*sh_historyを使ったコマンド補完をpecoにまかせていて ( こういうの )、「コマンド実行間違い」をしてしまうことありませんか?

例えば、

  • bundle exec cap staging deploy のつもりが bundle exec cap production deploy を選択して本番環境へデプロイしまったり
  • docker container start xxx のつもりが docker container stop $(docker container ls -aq) を選択して全てのコンテナをストップさせてしまったり

pecoを経由した「フィルタリングして実行」があまりに便利なので、ついつい「フィルタリング -> 選択」をカジュアルに実施してしまい、結果、コマンド実行間違いが多くなってしまいました。

ちなみに、最近私がやらかしたコマンド実行間違いは、Roadworkerのテストを AWS_PROFILE=my-awstest bundle exec rake で実行するつもりが、AWS_PROFILE=k1low bundle exec rake で実行してしまい、プライベートのRoute53のHostedZone設定を全て消してしまったことです ( これ で簡単にテスト環境をつくれるようになったから。。。 )。

いつか、もっと危険なコマンド実行間違いをやらかしそうです。

ExeCopで危険なコマンド実行間違いを防ぐ

というわけで、コマンド実行間違いを防ぐためにExeCopという名前でzshスクリプトを書いてみました。

github.com

ExeCopは、.execop ファイルを設置しておくことで、そのディレクトリ以下で実行するコマンドを監視してくれます。

そして .execop ファイルに書いてある設定に沿ってコマンドをキャンセルしたり yes/no の確認フェーズをはさんだりします。

demo

インストール

execop.zsh を任意の場所にダウンロードし、 .zshrc に以下のように記述します。

. /path/to/execop.zsh

Bashの場合は、execop.bash を任意の場所にダウンロードし、 .bashrc に以下のように記述します。

. /path/to/execop.bash

.execop ファイルの設置

.execop ファイルは例えば以下のように書きます。

deny when command_match destroy
confirm when command_match rm
deny when command_eq rm -rf /
confirm when env_eq AWS_PROFILE=production

上記の設定だと、

  • コマンドに destroy という文字列が入っていた時、コマンド実行をキャンセルする
  • コマンドに rm という文字列が入っていた時、yes/no の確認フェーズをはさむ
  • コマンドが rm -rf / だった時、コマンド実行をキャンセルする
  • 環境環境 AWS_PROFILEproduction だった時、yes/no の確認フェーズをはさむ

という監視がはいるようになります。

例えば、TerraformのファイルがあるディレクトリでAWS_PROFILEに制限をかけたり、Capistranoのデプロイディレクトリでデプロイコマンドに確認フェーズを差し込むなどすると良さそうです。

.execop ファイルの監視設定のフォーマットは以下のような感じです。

[action] when [matcher] [command or environment value]

actionは denyconfirm の2つ。

matcherは今のところ command_match command_not_match command_eq command_not_eq env_eq env_not_eq を実装しています。

懸念点

ExeCopを導入するとコマンド実行のたびに監視処理が走ります( preexec )。

若干挙動が遅くなるかもですが、危険なコマンド実行間違いをするよりはマシなのでこのまま運用してみようと思います。

というわけで

危険なコマンド実行間違いにビクビクしている方は、 自己責任で ご利用ください。

ちなみに、皆さんはどのようにしてコマンド実行間違いを防いでいるんでしょうか。