GitHub Actionsでライブラリの脆弱性を毎朝自動検知しSlackへ通知する設計術
目次
開閉
「またパッケージの脆弱性報告が見過ごされていた……」
Webエンジニアとして複数のプロジェクトを抱えていると、依存ライブラリのセキュリティアップデート作業は後回しになりがちです。ある日突然、深刻な脆弱性(CVE)が発表され、慌てて緊急対応に追われた経験を持つ方も少なくないでしょう。
今回は、GitHub Actionsのスケジュール実行 と、PyPA公式の監査ツール pypa/pip-audit(Node.js環境であれば npm-audit)を活用し、「毎朝定時に依存パッケージの脆弱性を全自動スキャンし、問題があればSlackへピンポイント通知する仕組み」の構築手順を解説します。
検証環境・前提情報
- GitHub Actions Runner:
ubuntu-latest- Python: 3.11 / 3.12(
pip-audit2.7系)- Node.jsの場合: Node.js 20.x / npm 10.x
- 通知先連携: Slack Incoming Webhooks
なぜ「脆弱性スキャンの自動化」が必要なのか?
手動での脆弱性チェックは、どれほど意識の高いチームであっても必ず形骸化します。「リリース時に確認する」というルールを作っても、繁忙期には「今回は軽微な修正だから」とスルーされがちです。
私がこの自動化を導入するきっかけとなったのは、過去に古い依存ライブラリのセキュリティホールを突かれ、開発環境のトークンが漏洩しかけたヒヤリハットでした。それ以来、「人間の記憶や習慣に頼るセキュリティ運用は廃止する」と心に決めました。
自動スキャンフローの全体像
毎朝の始業前に自動実行され、脆弱性が検出された場合のみSlackへ通知を送る構成です。問題がない場合は通知を飛ばさない「サイレント運用」にすることで、通知のオオカミ少年化を防ぎます。
graph TD
A["毎朝8:17 (GitHub Actions cron)"] --> B["リポジトリのチェックアウト"]
B --> C["依存ライブラリのスキャン (pip-audit / npm audit)"]
C --> D{"脆弱性は検出されたか?"}
D -- "検出された" --> E["Slack Incoming Webhook へエラー詳細を送信"]
D -- "問題なし" --> F["処理終了 (通知なし)"]
E --> G["エンジニアが朝会で確認・対応"]GitHub Actions ワークフローの実装コード
以下は、Pythonプロジェクトにおける pip-audit を用いた実際のワークフロー定義ファイル(.github/workflows/vulnerability-scan.yml)です。
name: Daily Security Vulnerability Audit
on:
schedule:
# 毎朝 UTC 23:17 (日本時間 8:17) に実行
- cron: '17 23 * * *'
workflow_dispatch: # 手動実行用ボタンも設置
jobs:
audit:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies & audit tool
run: |
python -m pip install --upgrade pip
pip install pip-audit
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Run pip-audit
id: audit
continue-on-error: true
run: |
# 脆弱性レポートをファイルに出力
pip-audit --desc on > audit_report.txt 2>&1
echo "exit_code=$?" >> $GITHUB_OUTPUT
- name: Notify Slack on failure
if: steps.audit.outputs.exit_code != '0'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
run: |
REPORT=$(cat audit_report.txt | head -n 30)
PAYLOAD=$(jq -n --arg txt "⚠️ *【セキュリティ警告】依存ライブラリに脆弱性が検出されました* \n\`\`\`\n$REPORT\n\`\`\`" '{text: $txt}')
curl -X POST -H 'Content-type: application/json' --data "$PAYLOAD" "$SLACK_WEBHOOK_URL"実際の検知ログと通知の見え方
pip-audit が脆弱性を検知すると、生成される audit_report.txt には以下のような詳細なレポートが出力されます。
$ pip-audit --desc on
Found 2 known vulnerabilities in 2 packages
Name Version ID Fix Versions Description
------- ---------- -------------- ------------- ----------------------------------------------------------------------
certifi 2022.12.07 PYSEC-2023-228 2023.7.22 Certifi before 2023.07.22 recognizes e-Tugra root certificate...
urllib3 1.26.17 PYSEC-2023-212 1.26.18 Urllib3 1.26.17 and 2.0.6 sanitize the Proxy-Authorization header...
このレポートの先頭部分が整形され、Slackの指定チャンネルへ直接カード形式で届きます。パッケージ名、現在のバージョン、修正版バージョンが一目でわかるため、朝会でのトリアージ(即座に対応するか、週末に回すか)がスムーズに進みます。
実装のこだわりポイント
continue-on-error: trueとステータス制御 スキャンエラーでステップを即時異常終了させず、終了コードを取得して後続のSlack通知処理へ引き継いでいます。jqによる安全なJSONペイロード生成 ログメッセージ内に特殊文字や改行が含まれていても、jqを経由することでSlackのAPIリクエストが壊れないように配慮しています。- 通知の絞り込み
head -n 30でログの長さを制限し、Slackの通知画面が巨大なスタックトレースで埋め尽くされないように配慮しています。
現場目線の運用ノウハウ・OS差異のフォロー
実務でこの仕組みを長期間安定して運用するために、いくつか押さえておきたい現場のポイントがあります。
1. cronの実行時刻は「毎時00分」を避ける
GitHub Actionsのスケジュール実行は、世界中のジョブが集中する「毎時00分」(例: 0 23 * * *)に設定すると、キューの滞留により実行開始が15〜30分遅延することが日常茶飯事です。
今回のコードで 17 23 * * *(JST 8:17)のように端数分を指定しているのはそのためです。数分ずらすだけで、混雑を回避してほぼ定刻通りに実行されます。
また、GitHubの仕様として、デフォルトブランチで60日間コミットなどの活動がないリポジトリでは、スケジュール実行が自動的に停止されます。あまり更新頻度の高くないメンテナンスフェーズのリポジトリでは、時折手動実行(workflow_dispatch)を走らせるなどの配慮が必要です。
2. ローカル検証時のOS差異(macOS / Windows)
CIに組み込む前に手元で pip-audit を試す場合、OS環境によって少し挙動が異なります。
- macOS / Linux環境: ターミナルで
pip install pip-auditして実行するだけで素直に動作します。 - Windows環境(PowerShell): 仮想環境(
venv)をアクティベートした状態で実行する必要があります。また、PowerShellのリダイレクト(>)はデフォルトでUTF-16やShift-JIS(CP932)になりやすく、後続処理で文字化けを起こすトラブルが現場で頻発します。CI上のubuntu-latestで統一して実行・通知させる構成にしておくのが、最も環境差異のトラブルを減らせる選択肢です。
3. Node.jsプロジェクト(npm audit)に応用する際のコツ
Node.jsプロジェクトで同様の構成を取る場合、npm audit をそのまま実行すると devDependencies(開発時のみ使用するツール群)の軽微な警告まで拾ってしまい、通知過多(アラート疲れ)に陥りがちです。
本番運用では以下のように引数を指定し、重大度や対象を絞り込むのが現場の定石です。
# 本番依存のみ、かつ重大度が High 以上の脆弱性のみを検知
npm audit --omit=dev --audit-level=high実際に導入して得られた3つのメリット
- 脆弱性の即時手当がルーチン化された 毎朝Slackに通知が来ると、朝のコーヒーを飲みながら「このライブラリならバージョンアップすれば済むな」と、その日のタスクにサクッと組み込めるようになりました。
- 開発メンバーのセキュリティ意識向上 チーム全体で「ライブラリは常に最新近くに保つもの」という認識が共有され、バージョン固定の理由をコードレビューで確認する文化が定着しました。
- 無駄な「手作業チェック会議」の撲滅 月1回のセキュリティ点検会議が不要になり、月あたり約4時間のエンジニア工数が削減されました。
まとめ:セキュリティは「仕組み」で守る
セキュリティ対策で最も重要なのは、「エンジニアの善意や注意深さに依存しない環境づくり」です。
今回紹介したGitHub Actionsの設定は、15分もあればリポジトリに導入できます。まずは手元のプロジェクトで手動起動(workflow_dispatch)から試してみてください。
自動化によって守られた安心感のもとで、本来集中すべき機能開発に力を注いでいきましょう!
GitHub Actionsを活用した依存関係の管理や自動化の仕組みをさらに広げたい方は、Dependabotと組み合わせた安全な自動マージ運用の実践ノウハウも合わせてご覧ください。