Gitのフック(pre-commit)とGithubActionsでSnyk Codeによる継続的なコードスキャンを試してみた

2022.08.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、AWS事業本部コンサルティング部に所属している今泉(@bun76235104)です。

先日 Snyk Code とVSCodeの拡張機能でローカル環境で開発中コードのスキャンをやってみました。

実際のところ開発の時点で自分が書いているコードのどこが危険かというフィードバックをもらえることはありがたく、各種IDEで手軽に導入できるので非常に素晴らしいと思います。

今回はチーム開発をする上で、個々人が利用しているIDEに依存せず、SnykCodeを継続的に利用できないか考えて、以下2種類を試してみました!

  • git hooksの機能を使ってコミット前にSnyk Code実行
    • pre-commit によってコミット前のSnyk Codeによるチェック
  • GithubActionsによりコードプッシュ時のSnyk Code実行

なお、今回前準備として以下の設定が終わっていることを前提に話を進めますのでご了承ください。

  • gitコマンドのインストール
  • Snyk CLIのインストールと設定
    • snyk code test コマンドが利用できる状態

git hooksによるコミット前のSnyk Codeによるスキャン

Git - Git フックの機能を活用して、Snyk Codeのチェック非通過の場合はコミットすらできないように設定してみます。

プロジェクトのルートで以下コマンドを実行します。

mkdir .githooks
touch .githooks/pre-commit
chmod 766 .githhoks/pre-commit

.githooks/pre-commitに以下の内容を書き込みます。

.githooks/pre-commit

#!/bin/sh
snyk code test

snyk code test のコマンドでは危険なコードが検出されるとステータスコードが1で終了します。

pre-commitでは、ステータスコードが1で終了した場合、変更をコミットすることができなくなりますので、開発者にとってもコミット履歴が綺麗に保てるというメリットがあると思います。

今回は危険度の低いコードでも検出された場合コミットできないので、コマンドにオプションをつけて危険度が高いものだけを対象にしても良いかもしれません。

# オプション
--severity-threshold=<low|medium|high|critical>
  Report only vulnerabilities at the specified level or higher. Note that the Snyk Code
  configuration issues do not currently use the critical severity level.

例えばhigh以上のレベルだけを対象にする場合はpre-commitで実行させるコマンドを以下の様に書き換えると良いと思います。

snyk code test --severity-threshold=high

次に各開発メンバーが本プロジェクトのルートディレクトリにて、以下コマンドを実施して .githooks/pre-commit の内容をコミット前に実施する様に設定します。

git config --local core.hooksPath .githooks/

試しに脆弱なコードを追加してコミットしようとすると以下の様に表示され、コミットできないことを確認しました。

ng.js

function dangerCode1() {
  const url = new URL(window.location.href);
  const params = url.searchParams;
  eval(params);
}

function dangerCode2() {
  location.href = "/danger/1/show?param=" + param;
}
Testing  ...

 ✗ [High] Code Injection
   Path: ng.js, line 4
   Info: Unsanitized input from the document location flows into eval, where it is executed as JavaScript code. This may result in a Code Injection vulnerability.


✔ Test completed

Organization:      hoge
Test type:         Static code analysis
Project path:      hoge
Summary;

  1 Code issues found
  1 [High]

Github Actionsでpush時にSnyk Codeのスキャンを実施する

ワークフローの追加

pre-commitによるSnyk Code実行で検出されたコードがコミットされることは予防できているはずですが、各開発者の設定の不備や、意図的にpre-commitを無効化される可能性があります。

そのため、GithubActionsを利用してsnyk code test が通らなければ、マージできない様に設定していきます。(今回はコードのプッシュ時に発火するように設定しています)

次にGithubActions用のワークフローを記載します。

.github/workflows/snyk-code.yml

# 参考; https://github.com/snyk-labs/nodejs-goof/blob/f985f27f48b00b38c0d2d86f87280bee06fddb0c/.github/workflows/snyk-code.yml#L1
name: "snyk code test"
on: [push]
jobs:
  snyk_code_test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: snyk/actions/setup@master
      - name: Snyk Test
        run: snyk code test --org=${{ secrets.SNYK_ORG }}
        continue-on-error: true
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

本変更をリポジトリにプッシュする前に、事前にSnyk Tokenの内容をGithubリポジトリのSecretsに設定する必要があります。

Tokenの取得方法については、こちらの記事が参考になります。

GithubリポジトリへのSecretsの設定方法については、暗号化されたシークレット - GitHub Docsをご参照ください。

SNYK_TOKEN と共に SNYK_ORG にOrganizationの識別子も設定してください。

識別子(orgslugname)についてはHow to select the organization to use in the CLI – Support Portal | Snykをご参照ください。

ブランチ保護の設定

以下記事を参考に、ブランチの保護を行います。

Require branches to be up to date before merging の設定で snyk_code_test を設定しておきましょう。

repo_branch_setting

GithubActionsを動かしてみた

一時的に pre-commitをコメントアウトして、危険なコード(ng.js)をコミットしてリポジトリにプッシュしてみました。

snyk code testが終了コード1で終了するため、ワークフローが失敗し、マージできない状態になっています。

Actions Failed

Actionsの内容をみてみると、以下の様に検知してくれていることがわかります。

Run snyk code test --org=***

Testing /home/runner/work/snyk-code-pre-commit/snyk-code-pre-commit ...

 ✗ [High] Code Injection 
   Path: ng.js, line 4 
   Info: Unsanitized input from the document location flows into eval, where it is executed as JavaScript code. This may result in a Code Injection vulnerability.


✔ Test completed

Organization:      ***
Test type:         Static code analysis
Project path:      /home/runner/work/snyk-code-pre-commit/snyk-code-pre-commit

Summary:

  1 Code issues found
  1 [High] 


Error: Process completed with exit code 1.

まとめ

今回はgitのフック機能とGithubActionsを利用して、Snyk Codeを実行してみました。

Snykはさまざまなツールとの統合を出してくれているので、これらを使いこなすことでソフトウェア開発の様々なライフサイクルで活躍してくれそうです。

なお、今回は pre-commit によるタイミングでチェックを行なっていますが、コミット毎にチェックが走るのが辛い場合は pre-push のタイミングにするなど工夫をすると開発者体験が変わってくると思います。

この記事がどなたかの参考になりますと幸いです。