🐙

CodePipelineでソース内に例外の隠蔽がないかチェックする

2023/02/26に公開

こんにちは。深緑です。

以前、CodePipelineでPHPの静的解析を実行するようにしました。
これをベースに、PHPのソースコード内に例外の隠蔽をしているコードがないかチェックするようにしてみます。
例外の隠蔽チェックはPHPStanでもできるのかも知れませんが、本記事を書いた時点ではPHPStanでのやり方はわからなかったのでシェルスクリプトを用いた独自の方法で実現しています。

例外の隠蔽チェックを書いたシェルスクリプトを用意する

ソース内にこんな例外処理が複数あるとします。
下側のソースは例外を再度throwしてないので例外の隠蔽になってしまってるコードです。

        try {
	    throw new \Exception();
        } catch (\Throwable $th) {
            throw $th;
        }
	try {
	    throw new \Exception();
	} catch (\Throwable $th) {
	    // throw $th;
	}

これらのソースコードを含むディレクトリに対し、pcre2grepでcatchから閉じカッコ(})までを検索します。

find ./app -name "*.php" | xargs pcre2grep -Mrh 'catch.*{[\s\S]*?'} | grep -v "//"

そして、検索結果に対してcatchの数とthrowの数を取得。
それぞれの数が一致していれば隠蔽はなしでOK。
合わないのならその差が想定通り=意図したものであるということをチェックしてOK・NGを判定します。

catch=$(find ./app -name "*.php" | xargs pcre2grep -Mrh 'catch.*{[\s\S]*?'} | grep -v "//" | grep "catch" | wc -l)
throw=$(find ./app -name "*.php" | xargs pcre2grep -Mrh 'catch.*{[\s\S]*?'} | grep -v "//" | grep "throw" | wc -l)

完成系がこちらです。

concealing_exceptions.sh
#!/bin/bash

cd `dirname $0`

# catchとthrowの数が一致していないコードの内、すでに把握しているものの数
known=1
catch=$(find ./app -name "*.php" | xargs pcre2grep -Mrh 'catch.*{[\s\S]*?'} | grep -v "//" | grep "catch" | wc -l)
throw=$(find ./app -name "*.php" | xargs pcre2grep -Mrh 'catch.*{[\s\S]*?'} | grep -v "//" | grep "throw" | wc -l)

echo "catch statements found : $catch"
echo "throw statements found : $throw"

if [ $((catch)) -ne $((throw)) ]; then
  echo "Number of catch and throw statements do not match"
  if [ $((known)) -ne $(($catch - $throw)) ]; then
    echo "Number of known exceptions do not match"
    exit 1
  else
    echo "Number of known exceptions match"
  fi
fi

echo "No problem found"
exit 0

CodeBuildで例外の隠蔽チェックを書いたシェルを呼び出すようにする

buildspec.ymlで例外の隠蔽チェックを書いたシェルスクリプトファイルを呼ぶように記載します。

buildspec.yml
version: 0.2
phases:
  install:
    runtime-versions:
      php: 8.1
    commands:
        - yum install -y pcre2-tools
        - composer install --working-dir=./
  pre_build:
    commands:
      - sh ./concealing_exceptions.sh 
      - composer stan --working-dir=./

CodeBuildは動作環境を特に指定してないので、Amazon Linuxベースで動作します。
Amazon Linuxでpcre2grepを使用するためにpcre2-toolsのインストールコマンドを入れています。

- yum install -y pcre2-tools

commandsでシェルスクリプトファイルを呼びます。
シェルスクリプトファイルが異常終了したら(リターンコードが0でない)ビルドはここで止まります。

- sh ./concealing_exceptions.sh 

この状態でCodePipelineを実行しCodeBuildを起動させます。
ログを見るとしっかりと例外の隠蔽チェックを呼び出されていることがわかります。

CodeBuildの実行結果

Discussion