VulnCheck Action は、VulnCheck が提供するターンキーの CI 統合です。VulnCheck CLI を内包し、プルリクエストごとにリポジトリをスキャンし、検出結果があれば実行を失敗させたうえで、その結果をプルリクエストのコメントとして投稿します。レビュー担当者はレビュー画面を離れることなく内容を確認できます。
VulnCheck API トークンをリポジトリまたは Organization のシークレットとして保存します(以下の例では VC_TOKEN)。その上でワークフローを追加します。
name: Scan with VulnCheck
on:
pull_request:
branches:
- main
permissions: write-all
jobs:
scan:
name: Scan with VulnCheck
runs-on: ubuntu-latest
steps:
- uses: vulncheck-oss/action@v1
with:
command: scan
token: ${{ secrets.VC_TOKEN }}
これで統合は完了です。この Action 自体はチェックアウトを行わないため、ワークフローの他のステップで作業ツリーが必要な場合は先に actions/checkout を追加してください。
token は VulnCheck API トークンです。API トークン から作成し、シークレットとして保存してください。ワークフローファイルに直接記述しないでください。必須の入力は token のみです。
| 入力 | 説明 | 既定値 |
|---|---|---|
token | VulnCheck API トークン | — |
command | 実行するコマンド | scan |
scan-path | スキャン対象のパス | ./ |
scan-cvss-base-threshold | CVSS 基本値のしきい値 | — |
scan-cvss-temporal-threshold | CVSS Temporal 値のしきい値 | — |
scan-cve-details | 検出結果ごとにパッケージ種別、カタロガー、検出箇所をアノテーションとして出力する | false |
scan-cve-npm-rel | npm を使用して CVE のパッケージから所有者を辿る | false |
disable-pr-comment | スキャン結果をプルリクエストのコメントとして投稿しない | false |
github-token | 認証済み GitHub クライアントの作成に使用するトークン | ${{ github.token }} |
scan-cve-details を有効にすると、各検出結果はワークフローのアノテーションとしても出力されます。
Notice: CVE-2021-23337 found in npm package lodash in /package-lock.json using javascript-lock-cataloger
Notice: CVE-2021-44906 found in npm package minimist in /package-lock.json using javascript-lock-cataloger
CLI とは異なり、Action は成否の判定まで行います。
| 設定 | Action が実行を失敗させる条件 |
|---|---|
| しきい値を設定しない | 深刻度を問わず、脆弱性が 1 件でも見つかった場合 |
scan-cvss-base-threshold または scan-cvss-temporal-threshold を設定 | いずれかのしきい値以上の検出結果があった場合 |
既定の動作は厳格です。深刻度の低い検出結果が 1 件あるだけで実行が失敗します。実際にポリシーに違反するものだけに絞り込むには、しきい値を設定してください。
- uses: vulncheck-oss/action@v1
with:
command: scan
token: ${{ secrets.VC_TOKEN }}
scan-cvss-base-threshold: '7.0'
また、いずれかのしきい値を設定すると、プルリクエストのコメントの形式も変わります。検出結果が 1 つの一覧ではなく、しきい値以上のものとしきい値未満のものに分かれて表示されます。
vulncheck scan 単体は常に終了コード 0 を返すため、CLI を使うレシピでは明示的な jq ゲートを追加しています。Action は自身の JavaScript でポリシー判定を行うので、その上にさらにゲートを追加しないでください。| 出力 | 説明 |
|---|---|
scan-output | スキャンの結果 |
scan-count | 検出された脆弱性の件数 |
scan-signature | 結果の SHA256 ハッシュ。実行間の変化の検出に使用 |
これらは結果を取得するためのものであり、ゲートに使うものではありません。後続のステップが値を読み取れる時点で Action はすでに実行を失敗させているため、出力を使うステップには if: always() が必要です。
- uses: vulncheck-oss/action@v1
id: vulncheck
with:
command: scan
token: ${{ secrets.VC_TOKEN }}
scan-cvss-base-threshold: '7.0'
- name: Save the scan results
if: always()
env:
SCAN_COUNT: ${{ steps.vulncheck.outputs.scan-count }}
SCAN_OUTPUT: ${{ steps.vulncheck.outputs.scan-output }}
run: |
echo "$SCAN_COUNT vulnerabilities found"
printf '%s' "$SCAN_OUTPUT" > scan.json
- uses: actions/upload-artifact@v4
if: always()
with:
name: vulncheck-scan
path: scan.json
出力を run: スクリプトに直接展開せず env: 経由で読み取ることで、スキャン結果に由来する値がシェルとして解釈されるのを防げます。
プルリクエストへのコメント投稿には書き込み権限が必要です。
permissions: write-all
権限を付与したくない場合は disable-pr-comment: true を設定してください。コメントは結果の表示手段であってゲートそのものではないため、検出結果があれば実行は変わらず失敗します。失われるのはレビュー画面上のサマリーだけです。
フォークからのプルリクエストはスキャンできません。GitHub はフォークから作成された pull_request の実行にリポジトリのシークレットを渡さないため、secrets.VC_TOKEN は空のまま渡され、Action は認証エラーで失敗します。ジョブに if: github.event.pull_request.head.repo.full_name == github.repository を指定してこれらの実行をスキップし、マージ後のコードはデフォルトブランチでのスキャンでカバーしてください。
同じプルリクエストで再実行した場合、Action は新しい scan-signature を以前のコメントと比較します。結果が変わっていなければ再度コメントせず、変わっていればその変化を投稿します。
@v1 は v1 系の最新リリースを追跡します。厳密に固定する場合は vulncheck-oss/action@v1.1.5 のようなリリースタグ、あるいは組織のポリシーで不変な参照が求められる場合はコミット SHA を指定してください。
この Action は node24 上で動作し、ランナー側に追加のツールを必要としません。ポリシーによりサードパーティ製 Action が禁止されている場合や、パブリックな Marketplace にアクセスできない GitHub Enterprise Server では、CLI を直接実行してください。結果は同じで、Marketplace への依存もありません。
name: Scan with VulnCheck CLI
on:
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
env:
VC_TOKEN: ${{ secrets.VC_TOKEN }}
VC_CLI_VERSION: 1.1.0
VC_CVSS_THRESHOLD: '7.0'
steps:
- uses: actions/checkout@v6
- name: Install the VulnCheck CLI
run: |
ARCH="$(uname -m)"
case "$ARCH" in x86_64) ARCH=amd64 ;; aarch64) ARCH=arm64 ;; esac
curl -sSL "https://github.com/vulncheck-oss/cli/releases/download/v${VC_CLI_VERSION}/vulncheck_${VC_CLI_VERSION}_linux_${ARCH}.tar.gz" | tar -xz -C /tmp
sudo install -m 0755 "/tmp/vulncheck_${VC_CLI_VERSION}_linux_${ARCH}/bin/vulncheck" /usr/local/bin/vulncheck
vulncheck version
- name: Scan
run: |
vulncheck scan . --json > scan.json
jq -r '"\((.vulnerabilities // []) | length) vulnerabilities found"' scan.json
- name: Gate on findings
run: |
jq -e --argjson max "$VC_CVSS_THRESHOLD" '
[ (.vulnerabilities // [])[]
| select((.cvss_base_score // 0 | tonumber? // 0) >= $max or .in_kev) ] | length == 0
' scan.json > /dev/null || {
echo "::error::Findings at or above CVSS ${VC_CVSS_THRESHOLD}, or in VulnCheck KEV"
jq -r --argjson max "$VC_CVSS_THRESHOLD" '
(.vulnerabilities // [])[]
| select((.cvss_base_score // 0 | tonumber? // 0) >= $max or .in_kev)
| " \(.cve) \(.name)@\(.version) CVSS \(.cvss_base_score) KEV \(.in_kev) fixed in \(.fixed_versions // "n/a")"
' scan.json
exit 1
}
- uses: actions/upload-artifact@v4
if: always()
with:
name: vulncheck-scan
path: scan.json
各ステップの意味と、ゲートを別ステップにしている理由については CI/CD での VulnCheck を参照してください。