[GitHub Actions] npm-auditで脆弱性が検出されれば実行をFailさせる

2022.04.27

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、GitHub Actionsでnpm-auditコマンドの実行で脆弱性があれば実行をFailさせるWorkflowを作ってみます。

このような仕組みを作るならDependabotSnykを使っても良さそうですが、使ってみたいactionsもあったので勉強がてら自分で仕組みを作ってみました。

npm auditとは

npm auditコマンドを使用すると、プロジェクト内のDependencyをスキャンして、レジストリに問い合わせて脆弱性が無いかをチェックしたり、自動修正したりすることができます。

またGitHub Actionsでnpm-auditを実行する上で役立ちそうなオプションとしてaudit-levelomitがあります。

audit-levelオプション

npm-auditは検出した脆弱性を緊急度に応じて次の4段階でレベル分けします。

  • low
  • moderate
  • high
  • critical

既定では、いずれのレベルの脆弱性が検出されてもnon-zero exit codeとなります。下記ではレベルmoderateの脆弱性が検出されてexit codeが1となっています。

$ npm audit
# npm audit report

log4js  <6.4.0
Severity: moderate
Incorrect Default Permissions in log4js - https://github.com/advisories/GHSA-82v2-mx6x-wq7q
No fix available
node_modules/log4js
  jest-logger  *
  Depends on vulnerable versions of log4js
  node_modules/jest-logger

2 moderate severity vulnerabilities

Some issues need review, and may require choosing
a different dependency.

$ echo $?  
1

audit-levelオプションを指定すると、指定した以上のレベルの脆弱性の検出時のみnon-zero exit codeとすることができます。先程のDependencyに対してaudit-levelオプションを指定して実行すると次のようになります。

$ npm audit --audit-level high
$ echo $?                     
0

$ npm audit --audit-level moderate
$ echo $?                     
1

このオプションを指定すれば、緊急度が高く迅速な修正が必要な脆弱性が検出された時のみWorkflow実行をFailさせて通知をする運用が可能です。

omitオプション

npm-auditでは既定ではDependencyとDevDepndencyの両方に対して脆弱性検出を行います。

omitオプションでdevを指定すると、Dependencyの方のみに対して脆弱性検出を行います。

$ npm audit --omit=dev

ちなみに--productionを指定しても同じ結果が得られますが、--omit=devの方を使うように促されます。

DevDepndencyがプロダクトに使われないことが明確であるプロジェクトであれば、このオプションを指定してDependencyのみ脆弱性検出の対象とする運用も考えられます。

やってみる

次のWorkflowをGitHub Actionsで作ってみます。

  • npm-auditを定期実行して、脆弱性があればFailさせる(通知をする)

実装時に脆弱性が検出されなかったDependencyでしばらく経ってから深刻な脆弱性が発見/発表される場合もあるので、継続的な監視が大切です。

定期実行

Workflowを定期実行させたい場合は、scheduleイベントを使用します。

次のようなWorkflowで試してみます。npm-auditの実行で--audit-level highとしています。

.github/workflows/audit-dependency.yaml

on:
  schedule:
    - cron: "0 0 * * 0" #日本時間 毎週月曜日 朝9時00分

jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Audit Dependency
        run: |
          npm audit --audit-level high --omit=dev

Workflowが実行されると、レベルmoderateの脆弱性が検出されていますが、audit-levelの指定によりzero exit codeとなりFailはしていません。

次にnpm-auditの実行を--audit-level moderateとします。

.github/workflows/audit-dependency.yaml

      - name: Audit Dependency
        run: |
          npm audit --audit-level high --omit=dev

Workflowが実行されると、先程と同じくレベルmoderateの脆弱性が検出されて、WorkflowがFailしました。

Failによるメール通知も届きました。

この通知を受けたらDependencyを修正する対応を取る運用とすれば良さそうです。

注意点

ちなみに注意点として、scheduleイベントは予定時刻から数十分近くずれることがあるそうです。私が試した際にも予定時刻になっても全然実行されなくて焦りました…。

さらなる改善をするなら

Fail時にメールだけでなくSlack通知をしたいなら下記のSlack社公式のActionを使えば実現できます。

またPull Request作成も自動化したいなら下記のActionが使えそうです。(Dependencyの修正は自分で行う必要があり)

またWorkflow内でのジョブのFailの検知はneeds.<job-id>.result == 'failure'で出来るようです。

おわりに

GitHub Actionsでnpm-auditコマンドの実行で脆弱性があれば実行をFailさせるWorkflowを作ってみました。

繰り返しになりますが、ソフトウェアではリリースからしばらく経ってから深刻な脆弱性が発見/発表される場合があるので、継続的な脆弱性監視の実施と、脆弱性を検出された際に迅速な対応ができる体制を持つことが大切です。クリティカルなシステムでは今回のような仕組み(もしくはDependabotやSnykなどの既成サービス)を必ず構築/運用するようにしましょう。

参考

以上