2020.04.08

Microsoft Application Inspector でレガシーコードを解析する

D.M. です。
今回は、コード解析ツール Microsoft Application Inspector でレガシーのコードを解析してみたら、わかっていなかった機能が見つかったよという話です。

microsoft_application_inspector_logo

モチベーション

コードレビューの効率化に関心があってツールを調べていたとき、コード解析ツールの Microsoft Application Inspector を見つけたので検証してみました。
このツールは2020年1月にリリースされたもので、結論としてはコードレビュー的な役割はなかったのですが、機能調査用ツールとしてはそこそこ役に立ちそうなので、記事にしてみます。

この記事の対象者

・Microsoft Application Inspector で何ができるのか知りたい人
何の役に立つのか、具体例を挙げながら紹介します。

・他の人が書いた膨大なコードの機能を把握するためのツールを探している人
Microsoft Application Inspector のユースケースとしては、保守系の案件で引き継いだプロジェクトやサードパーティライブラリがどんな機能を持っているのかを調査するときが考えられます。これに当てはまる人は是非ご一読ください。

この記事の流れ

1.基本編
このツールで何ができるのかを説明します。

2.実践編
インストールしてレガシーコードを解析します。
結果の読み方を解説します。
独自ルールを設定できるようにします。

1.基本編

Microsoft Application Inspector で何ができるのか

無料で利用できるコマンドラインツールで、できることは対象プロジェクトの機能要素の識別と一覧化です。
ソースコード解析コマンド analyze を実行すると、対象フォルダのコードにどんな機能が実装されているかを判定してくれます。具体的には、あらかじめ用意されたパターンにマッチしたコードの行に Tag 付けを行い、結果として出力します。Tag は機能のラベルのようなもので、結果レポートは Tag の一覧が HTML で出力されます。( json, text 形式もある)

Tag List は何の役に立つのか

Tag で検知された機能の一覧は、何の役に立つのでしょうか。

デフォルトで設定された Tag
tag

Tag はプロジェクトの機能の要素を網羅的に把握することに非常に役に立ちます。
Tag には例えば DB アクセス、ファイル IO 、 暗号化 、 Flash 、 Bluetooth 、Amazon S3 、ソーシャルメディア連携などが含まれています。これらは該当のアプリケーションの担当者、特にテックリードやマネジメントに関わる人間は充分に把握しておかなければならない項目になるかと思います。

把握するって一体何の意味があるの?

DB アクセスがあるなんて言われなくてもわかってるって?確かに DB はほとんどのシステムで頻繁に利用されているので把握していないなんて状況はありえないかもしれません。
ただ他の機能はどうでしょうか。例えばファイル IO がログ以外で使われているかについて、各プロジェクトで完全に把握しているでしょうか。例えば、保守系の案件で引き継いだ管理ツールなどでは調査しなければわからなかったりします。サーバの移転作業などで、アプリがファイル IO をしている箇所がある場合は特定のフォルダを作成して書き込み権限を付与する必要があったりするので、事前に把握しておかなければ設定の不備を招いてしまいます。
また MD5 や SHA-1 などの古いアルゴリズムがいまだに残っているか調査済みでしょうか。もしあればセキュリティホールになる可能性が高いのですぐに修正をかける必要がありますが、引き継いだばかりのタイミングではそこまで気が回らないことが多いと思います。
この analyze コマンドはそんな問題の解決を手助けします。機能要素を一覧化することで、アプリケーションのアップデートや移管、引継ぎに必要な作業や、セキュリティ上のリスクを把握するためのヒントを得ることができるというわけです。

サポートされている言語

Java 、 C 、 C++ 、C# 、 Python 、 PHP 、 JavaScript (Node.js) 、 Ruby など主要な言語は概ね網羅しています。
アップデートされる可能性があるので公式での確認をオススメします。
https://github.com/microsoft/ApplicationInspector/wiki/2.1-Field:-applies_to-(languages-support)

2.実践編

さてここから実際にツールを利用していきます。
やることは以下の3点です。
・インストール
・analyze コマンドによるレガシーコード解析
・Tag のカスタマイズ

インストール

Microsoft 製なので Windows でのインストールは公式を参照に従えば楽勝だと思っています。詳細は以下を参照してもらうと良いかと。
https://github.com/microsoft/ApplicationInspector/blob/master/JustRunIt.md

今回は CentOS 7 にインストールしてみようと思います。
(他でほとんどやってる人がいなかったのですが意外と簡単でした)

まず依存関係のあるソフトウェアを先にいれておく必要があります。
具体的には dotnet のライブラリを入れます。
MS 公式の説明があるのでそのとおりに rpm と yum を実行します。
https://docs.microsoft.com/ja-jp/dotnet/core/install/linux-package-manager-centos7

実際のコマンドはこちらです。

$ sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm
$ sudo yum install dotnet-sdk-3.1

次に Application Inspector 本体をインストールします。
Github にあるのでそこから最新の zip を落としてきます。

$ wget  https://github.com/microsoft/ApplicationInspector/releases/download/v1.1.28/ApplicationInspector_linux_1.1.28.zip
$ unzip ApplicationInspector_linux_1.1.28.zip

これだけで完了です。
正常にインストールできたか1回コマンドを実行して確認してみます。
以下が返って来れば OK です。

$ cd ApplicationInspector_1.1.28/
$ dotnet ApplicationInspector.CLI.dll
ApplicationInspector.CLI 1.1.28+534a000be2
© Microsoft Corporation. All rights reserved.

ERROR(S):
  No verb selected.

  analyze        Inspect source directory/file/compressed file (.tgz|zip) against defined                 characteristics

  tagdiff        Compares unique tag values between two source paths

  tagtest        Test (T/F) for presence of custom rule set in source

  exporttags     Export unique rule tags to view what code features may be detected

  verifyrules    Verify custom rules syntax is valid

  packrules      Combine multiple rule files into one file for ease in distribution

  help           Display more information on a specific command.

  version        Display version information.

analyze コマンドによるレガシーコード解析

いよいよ本題。
analyze コマンドを実行しちゃいますよ~!

今回はユースケースとしてレガシーコードの解析を扱ってみます。
ちょうど私の担当していたプロジェクトに10年以上使っている Java のコードがあります。前任者からあまりまともな引き継ぎができておらず、コードが膨大でどんな機能があるのか充分に理解できていません。共通コンポーネントと管理ツール、 API 、エンドユーザ向け画面、バッチなどあらゆる機能があり、統廃合を繰り返しながら現在でも一部の機能が現役で運用されています。ざっくりカウントしただけでも java のソースが2700以上ありました。説明を書いているだけでウンザリしてきます(笑)

analyze コマンドは以下のように実行します。
オプション -s でファイルパス /data/git/gmo/ 以下にある java のプロジェクトを解析します。プロジェクトの都合上、外部ライブラリの src をそっくり保持している zip ファイルがあったのでそれは –file-path-exclusions で解析の対象外にしました。また sh も不要なものの整理ができていないので対象外にします。

$ dotnet ApplicationInspector.CLI.dll analyze -s /data/git/gmo/ –file-path-exclusions .zip,.sh
analyze command running
0% source files processedDecompressing files…
Decompressing files…
Decompressing files…

100% source files processed
Preparing report
Unable to launch output.html automatically. Set the BROWSER environment variable to your desired browser and try again or launch your browser and navigate to the file to view the report file manually.
analyze command completed
See output file at output.html

analyze コマンドでは識別パターンを使用してフォルダ内のソースを検証し、こういうキーワードが見つかったからこういう機能があるよねという感じでアプリ内で発見された機能を Tag という形でラベリングして、 html で出力してくれます。

今回処理時間は数分で出力完了しました。

解析結果の output.html を理解する

結果の output.html は ApplicationInspector.CLI.dll と同じ階層に出力されました。ファイルはひとつですが、中はいくつかのセクションに分かれますのでそれぞれを読んでいきます。

まず1枚目は Project Info 「プロジェクト基本情報」です。
こちらにはパッケージ名、バージョン、説明、フォルダパス、作者、解析日時が表示されています。Skipped がすごい大量にありますが大丈夫なんでしょうか。。作者 Stephen Ostermiller となっていますが恐らくライブラリの中に書かれた Auther の記述を検知して表示しています(どこに記載されているか発見できなかったので除外できませんでした)。ファイルの種類の分類も java が6600っておかしい数字です。
精度の不安は残りますが、ここにこだわってもあまり重要な情報はないので、一旦次に進みます。
output

2つ目は Metadata 「メタデータ」です。
1つ目の基本情報以外の技術要素が検出されています。アプリケーションタイプ = web.application は恐らくフレームワークから推測しているのでしょう。パッケージタイプは実際中身に zip や jar があるので圧縮・非圧縮の2つが記載されています。ファイルタイプの箇所は拡張子を全部拾ってきてるものと思われます。(ものすごい長かったのでの切れている)
output_metadata

3つ目 Tags List 「タグ一覧」は、この解析結果の本丸ともいうべきパートです。
上述のとおり Tag はこのアプリケーションが持っている機能コンポーネントなので、どういう機能を持っているかがここで網羅的にわかるわけですね。
今回の解析で何がわかったのかはこの次のセクションで取り上げます。
output_taglist

4つ目は Tag Counters 「タグカウンター」という統計情報です。
このレポートは Class や Function をカウントして表示しています。
このレポートで何をカウントするかは preferences フォルダ内の json で定義されるようです。

output_tagcounters
※実際解析したコードは Java で数千ファイルあるはずなのに Class が16個しかカウントされておらず、明らかにおかしいですがいったんは気にしないで進めます。後述する rules のような明確なフォーマットの説明が Wiki に出ていないので現状カスタマイズは難しいかなという印象です。
https://github.com/microsoft/ApplicationInspector/wiki/6.-Customized-Reports

analyze で気がついたことと最大のメリット

ついに来ました。今日1番言いたいことはここです。

この解析によって、認識していなかった機能と未使用コードの発見ができました。

例えばこれ。
Cloud Service: Hosting (Amazon Web Services)


どうやら AWS に連携してる機能があるようです。よく調べてみるとバッチで外部の会社さんと S3 でデータのやり取りをしています。ずっとエラーも起こさず元気に動いているのでぜんぜん気がつきませんでした。

次はこちら。
Social Media: Facebook
facebook
Facebook の URL という変数が定義されています(文字化けしていますが。。)。おそらく以前 Facebook 連携を実装したのでしょう。現在はその機能を持ったページは残っていません。いわゆるゴミが残っている状態ですので、消してよさそうです。

もちろんもっといろいろありますが、結局何が言いたいかというと、こういう網羅的な気づきがこのツールの価値だということです。
把握できていなかった機能で、仮にまだ生きている機能であれば、それを発見できるということはサービス運営上絶対に役に立ちます。特に外部サービス連携は仕様がコロコロ変わるので、放置していたらいつか問題になる可能性大。この解析での気づきでこれからはウォッチ対象にするべきという判断ができます。逆にいらないものを認識して消すことで複雑さを解消し、シンプルで運用しやすいものにシェイプアップすることができます。

analyze のコツ

実際実行する上で気がついた小ネタを書きます。

依存する外部のライブラリの解析は分けて実行したほうが良いです。
理由はライブラリの使ってない機能まで Tag でリスト化されてしまうためです。

例えばこれ。
CloudServices.Finance.eCommerce
payment
このタグが引っかかったのは古いライブラリの src が対象フォルダ内に含まれていたためです。実際この payment 関連の機能は実装されていないので過剰な検知なのですが、この解析ツールはソースコード内をキーワード payment で引っ掛けているだけなのでこういうことが起こりえます。(検知の信頼度を表す Confidence は Medium なので、筋は通っている)

analyze でときおり読めないファイルがあって停止したりします。
その場合は –file-path-exclusions で指定すると除外できます。今回は zip と sh を除外しています。
あるプロジェクトのソースではバイナリーのファイルが読めずに analyze が停止してしまったのでこちらを指定して除外しました。読む必要がないライブラリのファイル名も .zip .jar のように拡張子を指定すると除外できます。

繰り返し出てくる Tag の全ソースはデフォルト設定では解析されません。
ある Tag の機能がはじめに見つかったコードだけを指摘して、2回目以降は省略されます。全部表示した場合は –allow-dup-tags を指定すると可能です。パフォーマンス上結構時間が掛かるようになるのと、HTMLフォーマットのレポートが使えず json または text 形式になります。(1回やってみましたが途中で止まってしまいましたので結果どうなるかわかっていません)

出力された output.html は CSS や JS に依存しているのですが、それらファイルはダウンロードした zip を解凍したフォルダ直下にある html フォルダ内にあります。正常に表示するには output.html と html フォルダは同じフォルダの同列におく必要があります。output.html を単体で開こうとしてもデザイン崩れが発生するので注意してください。

Tag のカスタマイズ

最後に Tag をパターンマッチする rule をカスタマイズする例を説明します。

rule は、 analyze コマンドが Tag を認識するパターンを定義したものです。
例としてデフォルトで備わっている DB アクセス有無を判定する rule の json を見てみましょう。patterns の箇所で定義されてるのですが、 DB アクセスの有無は (select|insert|delete|update) の文字列があるかどうかを正規表現で判定しています。他のオプションが何をしようとしてるかわかるようにコメントを記載しました。( # が私の書いたコメント)

[
{
    “name”: “Data: DBMS (SQL)”, # チェック対象の名前
    “id”: “AI011600”, # 管理用のID
    “description”: “Data: DBMS (SQL)”, # 説明
    “applies_to”: [], # 適用するプログラミング言語。この例では空なので全言語
    “tags”: [ # タグ。このツールで機能を表す指標です。
      “Data.DBMS.SQL”
    ],
    “severity”: “moderate”, # 深刻さ
    “patterns”: [ # ソースコードをどう検知するかのパターンマッチルールです
      {
        “pattern”: “[‘\\\”](select|insert|delete|update)\\s.*”, # 検知する文字列
        “type”: “regex”, # regex, regex-word, string, substring の4種類から選べる。正規表現、正規表現における完全一致、完全一致、部分一致
        “scopes”: [ “code” ], # 適用範囲。code, html, comment, all の4種類
        “modifiers”: [ “i” ], # サーチ方法 i: case insensitive search 大文字小文字区別しない d: dot match all ドット=全てにマッチ m: multiline search 複数行
        “confidence”: “high” # 自信!まあ検知精度の高さと思います。Wikiに説明がない。。
      }
          ],
    “conditions”: [ # 追加条件。誤検知を減らす方法で、追加の条件が満たされているか満たされていない場合にのみ有効と見なす。
      {
        “pattern”: { # 追加条件の実体。上記と同じパラメータで設定します
          “pattern”: “from|where”,
          “type”: “regex-word”,
          “scopes”: [
            “code”
          ],
          “modifiers”: [ “i” ],
          “_comment”: “” # 文字通りただのコメント行です
        },
        “search_in”: “finding-region(-5,5)”, # 追加条件の適用条件。前後5行に追加条件パターンを適用して判定する
        “negate_finding”: false, # false に設定した場合、condition のパターンが一致した場合、結果を有効にする
        “_comment”: “”
      }
    ]
  }
]

ごちゃっとしてしまいましたが、この形式を守っていけば自分で新しい rule をカスタマイズできます。記載方法の詳細については公式ページを確認してください。
https://github.com/microsoft/ApplicationInspector/wiki/3.-Pattern-Object-Schema

デフォルトのルールが定義されているのは、 Github リポジトリの AppInspector / rules / default にある json ファイルです。ダウンロードしてきて中を見てみると json にパターンマッチルールが大量に記載されていることがわかります。 analyze というのは、つまるところ、ソースコードをこれら rule に沿って grep して機能の有り無しを判定するという非常にシンプルな仕組みのようです。

Tag をもっと活用するためのコマンド

他の Tag 系コマンドは以下があります。

tagdiff
2つのバージョンの機能の差分をタグで比較してくれるコマンドです。リリースの前に何かクリティカルな変更が入っていないかを確認する作業で使えると思います。

tagtest
指定した機能があるかを検証します。 analyze はどんな機能があるか表示するので、その逆をやる感じです。例えば DBアクセスがあるかどうかを調べるための rule を作って実行すると failed か succeeded で有り無し結果がわかります。検証対象のタグは rule と同じ書き方で json で定義します。

例えば DB アクセス Tag だけを検証したい場合、上記の rule だけを1つの custom_rule.json ファイルに切り出して以下のようにコマンドを実行します。

$ dotnet ApplicationInspector.CLI.dll  tagtest -s  /data/git/gmo/common/ -r ./custom_rule.json
tagtest command running
Tagtest for [RulesPresent]: succeeded
Tagtest command completed

対象ソース内に1つでも DB アクセス Tag が見つかった場合は succeeded が出てきます。
custom_rule.json ファイル内に複数の rule が定義されていた場合は全ての条件を満たさないと failed になります。

exporttags
解析結果として表示される全 Tag を確認するコマンドです。
実行してみるとすぐにわかりますが執筆段階でデフォルトタグが441個あることがわかりました。

$ dotnet ApplicationInspector.CLI.dll exporttags
Exporttags command running
Authentication.General
Authentication.Google
Authentication.HTMLForm
Authentication.JWT
Authentication.LDAP
Authentication.Microsoft.Online
Authentication.Microsoft.Windows.ActiveDirectory
Authentication.Microsoft.Windows.Kerberos

OS.SystemRegistry.Read
OS.SystemRegistry.Write
OS.UserAccount.Write
Exporttags command completed

余談

3月9日ごろは v.1.1.10 でしたが 3月31日 v.1.1.28 になっていました。アップデート速度が速すぎませんか(苦笑) そして README もちょこちょこ変わっていましたので、ツールとしてはまだまだ発展途上といった印象があります。
ただ充分な可能性を持っているので今後もウォッチしていきたいと思います。

次世代システム研究室では、 GMO インターネットグループ全体のサービス開発に携わるアーキテクトを募集しています。ご興味のある方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。

皆さんのご応募をお待ちしています。

  • Twitter
  • Facebook
  • はてなブックマークに追加

グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。

 
  • AI研究開発室
  • 大阪研究開発グループ