enjoy Railsway!! 第4回 静的コード解析

Railsアプリケーションのプログラム品質を高めるために有用な手段の一つとして、静的コード解析が挙げられます。

静的コード解析 (せいてきコードかいせき、static code analysis) または静的プログラム解析 (static program analysis) とは、コンピュータのソフトウェアの解析手法の一種であり、実行ファイルを実行することなく解析を行うこと。

静的コード解析 – Wikipedia

静的コード解析をおこなうことで、人手によるレビューを介さずに(または軽減し)不効率なコード、規約違反のコード、脆弱なコードなどを発見することができます。

静的コード解析のためのツールは様々なものが提供されていますが、今回は無料で導入できるツールを3つご紹介します。

※このコラムのプログラム等は以下の環境で動作確認しています
(2023/08/31最終確認)
 ruby: ruby 3.2.2 [arm64-darwin22]
 rails: rails (7.0.7.2)
 rubocop-rails (2.20.2)
 rails_best_practices (1.23.2)
 brakeman (6.0.1)

目次

RuboCop Rails

Ruby用の静的コード解析ツールであるRuboCopに、Railsアプリケーション特有のルール(Cop)を追加するものです。

bundlerでインストールする場合、Gemfileの適当な場所に以下のように追記してbundle installします。

Gemfile

group :development, :test do
  gem 'rubocop-rails'
end

続いて、RuboCopの設定ファイル.rubocop.ymlをアプリケーションのルードディレクトリに作成し、以下のように記述します。

.rubocop.yml

require:
  - rubocop-rails

bundlerでインストールした場合、以下のコマンドで解析を実行できます。

bundle exec rubocop

これまでRuboCopを導入していなかったRailsアプリケーションでこのコマンドを実行すると、おそらく大量の検出結果が表示されます。
Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.という指摘が目立ちますが、これはRuboCopの標準では「文字列の表現には必要出ない限りシングルクォーテーションを使う」というようなルールを適用するためです。
Railsのgenerateコマンドはダブルクォーテーションのファイルを出力するため、これにより大量の検出結果が表示されている状態です。

これらはRailsには関連しないものですが、適用するルールのカスタマイズの流れは同様ですので対応してみましょう。

適用するルールのカスタマイズ

選択肢としては、「このルールを無効化する」「ダブルクォーテーションを強制するようにルールを設定する」「一括で置き換える」などがあります。
RuboCopの設定は、.rubocop.ymlファイルに記述できます。
どのような設定ができるか、についてはドキュメントで確認できます。

.rubocop.yml

Style/StringLiterals: # 設定対象のルール(Cop)名
  Enabled: false # 無効にする場合
  EnforcedStyle: double_quotes # ダブルクォーテーションを強制する

これらを設定してもう一度解析を実行すると、検出数が大幅に減少します。
が、それでも多くの検出結果が残っているはずです。
初めて導入する場合は手間となってしまいますが、検出された違反について一通り確認し、対応を検討してください。
一度.rubocop.ymlを書き上げてしまえば、後はチームや他のアプリケーションで共有できる財産になりますので、頑張りましょう。

検出された違反を一括で置き換える

RuboCopを実行する際に-Aオプションを指定すると、置き換え可能なものについては一括で置き換えることができます。

bundle exec rubocop -A

実行する前にはGitで元に戻せるようにしておく、などを忘れないようにしてください。

Rails Best Practices

Railsアプリケーション開発のベストプラクティスを集めたRails Best Practicesに準拠しているか、を確認することができます。
積極的に更新されてはいませんが、まだまだ有用なプラクティスも含まれていますので導入をお勧めします。

bundlerでインストールする場合、Gemfileの適当な場所に以下のように追記してbundle installします。

Gemfile

group :development, :test do
  gem 'rails_best_practices'
end

bundlerでインストールした場合、以下のコマンドで解析を実行できます。

bundle exec rails_best_practices

よく検出されるものとしては、remove empty helpersがあります。
これはRailsのgenerateコマンドでhelperが生成されたものの、そのまま使っていない、という状態が起こりがちなためです。

適用するプラクティスのカスタマイズ

選択肢としては、「このプラクティスを適用しない」「警告に従って対応する」などがあります。

以下のように-gオプションを指定してコマンドを実行すると、設定ファイルconfig/rails_best_practices.ymlが生成されます。

bundle exec rails_best_practices -g 

生成されたファイルを編集して設定することができます。

config/rails_best_practices.yml

# コメントアウトすることで適用除外できる
#RemoveEmptyHelpersCheck: { }

たとえば上記のように設定して解析を実行すると、remove empty helpersが検出されなくなります。
RuboCop同様、設定を吟味してチームやアプリケーションに合った設定ファイルを作り上げましょう。

Brakeman

Railsアプリケーションの脆弱性を確認することができます。

通常脆弱性診断は多大なコストが掛かりますが、Brakemanを使用すると簡単に確認することができます。
導入も簡単なため、強くお勧めします。

bundlerでインストールする場合、Gemfileの適当な場所に以下のように追記してbundle installします。

Gemfile

group :development, :test do
  gem 'brakeman'
end

bundlerでインストールした場合、以下のコマンドで解析を実行できます。

bundle exec brakeman

RuboCopやRails Best Practicesとは異なり、何も検出されない状況がほとんどだと思います。

脆弱性への対応

実際に検出されるとどうなるか、をご紹介します。
敢えて危険なコードを実装してみました。検証目的以外で絶対に真似しないでください。

def search_user
  # emailでユーザーを探す(脆弱な例)
  User.where("email=#{params[:email]}")
end

解析を実行すると、SQL Injectionが検出されます。

RuboCopやRails Best Practicesで検出される違反や警告については、対応しなくても直ちに大きな問題にはなりません。
一方、Brakemanで検出される脆弱性は重大な結果につながる可能性があります。
必ず対応するようにしましょう。
誤検知と思われる場合などは設定ファイルにより検出を抑止できますが、ここではご紹介しません。

先ほどの危険なコードを修正し、もう一度解析してみます。

def search_user
  # emailでユーザーを探す(脆弱ではない一例)
  User.where(email: params[:email])
end

警告が表示されなくなることを確認できます。

まとめ

Railsアプリケーション向けにおすすめする静的コード解析ツールを3つご紹介しました。
Railsアプリケーションのプログラム品質を高めるため、是非導入して継続的な解析、改善をおこなってみてください。

著者/文責: 泉 隼人
・Rails技術者認定試験運営委員会 テクニカルアドバイザー
・神奈川工科大学 情報工学科 客員研究員
・鹿児島県 喜界島出身。10歳の頃N88-BASICに触り、コンピューティングにのめり込む
・興味の赴くまま様々なプラットフォーム、言語を楽しみつつ10数年来に渡りRuby on Railsでの開発業務に従事する
・Webサイト https://9uelle.jp/

お知らせ

当委員会ではRails試験を全国300か所で一年中実施をしています。興味がある方は以下をご覧の上、是非受験ください。https://railsce.com/exam

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次