ESLint 運用ダッシュボード:SARIF/Code Scanning で違反推移を可視化

ESLint の静的解析結果を継続的にモニタリングし、プロジェクト全体のコード品質を可視化したいと考えたことはありませんか。
GitHub Actions で ESLint を実行するだけでは、その時点での違反は検出できますが、時系列での推移や傾向を把握することは難しいでしょう。そこで注目されているのが、SARIF(Static Analysis Results Interchange Format)と GitHub Code Scanning を組み合わせた運用ダッシュボードです。
本記事では、ESLint の実行結果を SARIF 形式で出力し、GitHub Code Scanning にアップロードすることで、違反の推移を継続的に可視化する方法を解説します。これにより、プロジェクトのコード品質を時系列で追跡し、改善の成果を数値で確認できるようになりますね。
背景
ESLint とコード品質管理の課題
ESLint は JavaScript や TypeScript プロジェクトにおいて、コードの品質を保つための必須ツールとなっています。しかし、従来の運用方法では以下のような課題がありました。
プロジェクトが成長するにつれて、ESLint の違反件数は増加傾向にあります。開発者は日々のコミットで新しいコードを追加しますが、既存の違反を修正する優先度は低くなりがちです。その結果、技術的負債が蓄積し、いつの間にか違反が数百件に達してしまうこともあるでしょう。
また、ESLint の実行結果はコンソールに出力されるだけで、過去の結果と比較することができません。「先月と比べて違反は減っているのか」「新しいルールを追加した効果はあったのか」といった疑問に答えるデータがないのです。
SARIF と Code Scanning の登場
こうした課題を解決するために、SARIF という標準化された静的解析結果のフォーマットが注目されています。SARIF は OASIS によって策定された JSON ベースの形式で、さまざまな静的解析ツールの結果を統一的に表現できます。
GitHub は Code Scanning という機能を提供しており、SARIF 形式の結果をアップロードすることで、セキュリティアラートやコード品質の問題を一元管理できるようになりました。これにより、ESLint の違反を GitHub のインターフェースで可視化し、時系列での推移を追跡できるのです。
以下の図は、従来の ESLint 運用と SARIF/Code Scanning を使った運用の違いを示しています。
mermaidflowchart TB
subgraph legacy ["従来の運用"]
dev1["開発者"] -->|コミット| ci1["CI/CD"];
ci1 -->|ESLint 実行| result1["コンソール出力"];
result1 -->|一時的| end1["結果は保存されない"];
end
subgraph modern ["SARIF/Code Scanning 運用"]
dev2["開発者"] -->|コミット| ci2["CI/CD"];
ci2 -->|ESLint 実行| sarif["SARIF 出力"];
sarif -->|アップロード| github["GitHub<br/>Code Scanning"];
github -->|可視化| dashboard["ダッシュボード"];
dashboard -->|時系列分析| insights["改善の追跡"];
end
従来の運用では結果が一時的なものでしたが、SARIF/Code Scanning を使うことで、継続的な可視化と分析が可能になります。
Code Scanning のメリット
Code Scanning を使うことで得られるメリットは以下の通りです。
# | メリット | 説明 |
---|---|---|
1 | 時系列での推移確認 | 違反件数の増減をグラフで確認できる |
2 | PR ごとの影響分析 | Pull Request で新たに追加された違反を自動検出 |
3 | 一元管理 | セキュリティアラートとコード品質を同じ場所で管理 |
4 | チーム共有 | 誰でも最新の状況を確認できる |
5 | アラート機能 | 重要度の高い違反を通知できる |
これらの機能により、コード品質の改善活動を計画的に進めることができるでしょう。
課題
ESLint 結果の継続的な追跡が困難
従来の ESLint 運用では、実行結果がコンソールログやテキストファイルとして出力されるだけでした。この方法では、以下のような問題が発生します。
まず、過去の結果との比較が手作業になってしまいます。「今月の違反件数は先月より増えたのか減ったのか」を知るには、過去のログを探して手動で集計する必要があるでしょう。開発チームが忙しい中で、このような作業を継続することは現実的ではありません。
次に、違反の種類や重要度ごとの分析ができません。ESLint のルールには、セキュリティに関わる重要なものから、コーディングスタイルに関する軽微なものまで様々あります。しかし、コンソール出力だけでは、どのルールの違反が増えているのか、どこから対策すべきなのかが見えにくいのです。
チーム全体での品質意識の共有
コード品質の改善は、特定の開発者だけが取り組むものではなく、チーム全体で意識を共有する必要があります。しかし、ESLint の結果が各開発者のローカル環境や CI ログにしか存在しない場合、以下のような課題があります。
プロジェクトマネージャーやテックリードが、現在のコード品質の状況を把握しづらいことです。「このプロジェクトのコード品質は良好なのか」「リファクタリングの優先度は高いのか」といった判断に必要な情報が不足してしまいます。
また、新しく参加したメンバーが、プロジェクトのコード品質の歴史や現状を理解することも難しくなります。品質改善の取り組みが可視化されていないため、過去の努力や改善の成果が伝わらないのです。
以下の図は、ESLint 運用における課題を整理したものです。
mermaidflowchart LR
problem1["過去との比較困難"] -->|結果| issue1["改善効果が<br/>見えない"]
problem2["違反の分類不足"] -->|結果| issue2["優先度が<br/>不明確"]
problem3["情報の分散"] -->|結果| issue3["チーム共有<br/>できない"]
issue1 --> goal["継続的な<br/>可視化が必要"]
issue2 --> goal
issue3 --> goal
これらの課題を解決するには、ESLint の結果を構造化されたフォーマットで保存し、継続的に分析できる仕組みが必要です。
GitHub Actions での結果保存の限界
GitHub Actions で ESLint を実行している場合、アーティファクトとして結果を保存することは可能です。しかし、この方法にも以下の制限があります。
アーティファクトは一定期間後に自動削除されるため、長期的なトレンド分析には向きません。GitHub の設定にもよりますが、デフォルトでは 90 日後にアーティファクトが削除されてしまうでしょう。
また、アーティファクトをダウンロードして手動で分析する必要があり、手間がかかります。毎週の品質レビューミーティングの前に、誰かがファイルをダウンロードして Excel で集計する、といった運用は持続可能ではありませんね。
さらに、Pull Request との紐付けが弱く、「この PR で何件の違反が増えたのか」を自動的に判定することが困難です。レビュアーは変更内容と ESLint の結果を別々に確認しなければならず、レビューの負担が増加してしまいます。
解決策
SARIF 形式での ESLint 結果出力
SARIF(Static Analysis Results Interchange Format)は、静的解析ツールの結果を標準化された形式で表現するための JSON ベースのフォーマットです。OASIS が策定した仕様で、多くの静的解析ツールがサポートしています。
ESLint で SARIF 形式の出力を行うには、専用のフォーマッターを使用します。@microsoft/eslint-formatter-sarif
というパッケージが公式に提供されており、これを使うことで簡単に SARIF 形式の結果を生成できるでしょう。
以下の図は、ESLint から SARIF、そして Code Scanning までのデータフローを示しています。
mermaidflowchart LR
code["ソースコード"] -->|解析| eslint["ESLint"]
eslint -->|SARIF<br/>フォーマッター| sarif["SARIF ファイル<br/>(JSON)"]
sarif -->|アップロード| scanning["GitHub<br/>Code Scanning"]
scanning -->|可視化| ui["Web UI<br/>ダッシュボード"]
scanning -->|API| analytics["データ分析<br/>ツール"]
SARIF 形式にすることで、GitHub だけでなく、他のツールでも結果を活用できるようになります。
SARIF フォーマッターのインストール
まず、プロジェクトに SARIF フォーマッターをインストールしましょう。
bashyarn add -D @microsoft/eslint-formatter-sarif
このパッケージは開発時のみ使用するため、-D
オプションで devDependencies に追加します。インストール後は、package.json に依存関係が追加されているか確認してください。
ESLint の実行と SARIF 出力
次に、ESLint を実行して SARIF 形式で結果を出力するコマンドを作成します。
json{
"scripts": {
"lint": "eslint .",
"lint:sarif": "eslint . --format @microsoft/eslint-formatter-sarif --output-file eslint-results.sarif"
}
}
package.json
の scripts セクションに上記のように追加することで、通常の lint コマンドとは別に SARIF 出力用のコマンドを用意できます。--format
オプションでフォーマッターを指定し、--output-file
で出力先のファイル名を指定しますね。
実行すると、プロジェクトのルートディレクトリに eslint-results.sarif
という JSON ファイルが生成されます。このファイルには、すべての ESLint 違反が構造化されたデータとして含まれているでしょう。
SARIF ファイルの構造理解
生成された SARIF ファイルの構造を見てみましょう。主要な要素を理解することで、後の活用がスムーズになります。
json{
"version": "2.1.0",
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"runs": [
{
"tool": {
"driver": {
"name": "ESLint",
"informationUri": "https://eslint.org",
"rules": []
}
},
"results": []
}
]
}
SARIF ファイルのルート構造です。version
は SARIF 仕様のバージョンを示し、現在は 2.1.0 が最新です。runs
配列には、解析実行の結果が格納されます。
json{
"tool": {
"driver": {
"name": "ESLint",
"version": "8.57.0",
"informationUri": "https://eslint.org",
"rules": [
{
"id": "no-unused-vars",
"shortDescription": {
"text": "Disallow unused variables"
},
"helpUri": "https://eslint.org/docs/rules/no-unused-vars",
"properties": {
"category": "Variables"
}
}
]
}
}
}
tool
セクションには、使用した静的解析ツール(この場合は ESLint)の情報が含まれます。rules
配列には、適用されたすべてのルールの定義が格納されており、各ルールの説明やドキュメントへのリンクが含まれていますね。
json{
"results": [
{
"ruleId": "no-unused-vars",
"level": "warning",
"message": {
"text": "'unused' is defined but never used."
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/utils/helper.ts"
},
"region": {
"startLine": 5,
"startColumn": 7
}
}
}
]
}
]
}
results
配列には、実際に検出された違反が格納されます。各違反には、ルール ID、重要度レベル、メッセージ、そして違反が発生したファイルと行番号が含まれています。この情報により、開発者は正確に問題の場所を特定できるでしょう。
GitHub Actions ワークフローの設定
SARIF ファイルを GitHub Code Scanning にアップロードするための GitHub Actions ワークフローを作成します。プロジェクトの .github/workflows
ディレクトリに新しいファイルを作成しましょう。
yamlname: ESLint SARIF Analysis
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
ワークフローの基本設定です。main
と develop
ブランチへのプッシュ、およびこれらのブランチへの Pull Request で自動実行されます。プロジェクトのブランチ戦略に合わせて調整してください。
yamljobs:
eslint:
name: Run ESLint with SARIF
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
ジョブの定義です。permissions
セクションで、コードの読み取りとセキュリティイベントの書き込み権限を設定します。Code Scanning に結果をアップロードするには、security-events: write
権限が必須ですね。
yamlsteps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn'
最初のステップでリポジトリをチェックアウトし、次に Node.js 環境をセットアップします。cache: 'yarn'
を指定することで、依存関係のインストールが高速化されるでしょう。
yaml- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run ESLint
run: yarn lint:sarif
continue-on-error: true
依存関係をインストールした後、先ほど作成した lint:sarif
コマンドを実行します。continue-on-error: true
を設定することで、ESLint で違反が見つかってもワークフローを続行できます。これにより、違反がある状態でも SARIF ファイルをアップロードできますね。
yaml- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: eslint-results.sarif
category: eslint
最後に、生成された SARIF ファイルを GitHub Code Scanning にアップロードします。github/codeql-action/upload-sarif
アクションを使用し、category
パラメータで「eslint」というカテゴリを指定しています。これにより、複数の静的解析ツールの結果を区別できるでしょう。
Code Scanning での結果確認
ワークフローが正常に実行されると、GitHub リポジトリの「Security」タブに Code Scanning の結果が表示されます。確認手順を見ていきましょう。
リポジトリのトップページから「Security」タブをクリックし、左サイドバーの「Code scanning」を選択します。すると、検出されたアラート(ESLint 違反)の一覧が表示されるはずです。
アラート一覧では、以下の情報を確認できます。
# | 項目 | 説明 |
---|---|---|
1 | ルール名 | 違反した ESLint ルール(例:no-unused-vars) |
2 | 重要度 | Error、Warning、Note のいずれか |
3 | ファイルパス | 違反が発生したファイルの場所 |
4 | ステータス | Open(未解決)または Closed(解決済み) |
5 | ブランチ | 違反が検出されたブランチ |
各アラートをクリックすると、詳細情報が表示されます。違反が発生したコードの該当行がハイライトされ、ESLint ルールの説明やドキュメントへのリンクも確認できるでしょう。
Pull Request での自動チェック
Code Scanning の最も便利な機能の一つが、Pull Request での自動チェックです。新しい PR を作成すると、その PR で追加された違反が自動的に検出され、コメントとして表示されます。
以下の図は、Pull Request でのチェックフローを示しています。
mermaidsequenceDiagram
participant Dev as 開発者
participant PR as Pull Request
participant GHA as GitHub Actions
participant CS as Code Scanning
Dev->>PR: コードをプッシュ
PR->>GHA: ワークフローをトリガー
GHA->>GHA: ESLint 実行
GHA->>CS: SARIF アップロード
CS->>CS: 前回結果と比較
CS->>PR: 新規違反を<br/>コメント
PR->>Dev: レビュー要請
開発者が Pull Request を作成すると、自動的に ESLint が実行され、新たに追加された違反がコメントとして通知されます。
PR のチェック結果では、以下の情報が表示されます。
- 新たに追加された違反の件数
- 修正された違反の件数
- 違反の詳細(ファイル名、行番号、ルール名)
レビュアーはこの情報を見ることで、PR がコード品質に与える影響を即座に把握できます。もし重要な違反が追加されている場合は、マージ前に修正を依頼できるでしょう。
時系列での推移確認
Code Scanning の大きなメリットは、違反の時系列推移を確認できることです。「Trends」タブでは、プロジェクト全体の違反件数の変化をグラフで表示できます。
グラフでは以下の情報を確認できます。
- 過去 30 日、90 日、1 年間の違反件数推移
- ルールごとの違反件数
- ブランチごとの違反件数
- 重要度別の違反分布
この情報を活用することで、以下のような分析が可能になりますね。
リファクタリングの効果測定:先月実施したリファクタリングで、実際にどれだけ違反が減ったのかを定量的に確認できます。
新ルール導入の影響確認:新しい ESLint ルールを追加した際に、どれくらいの違反が新たに検出されたかを把握できるでしょう。
チーム間の比較:複数のチームやプロジェクトで Code Scanning を使っている場合、コード品質を横断的に比較できます。
具体例
実際のプロジェクトでの導入ステップ
ここでは、実際のプロジェクトに SARIF/Code Scanning を導入する手順を、具体的なコマンドとともに説明します。Next.js + TypeScript のプロジェクトを例に進めていきましょう。
まず、プロジェクトのディレクトリに移動し、必要なパッケージをインストールします。
bashcd your-nextjs-project
yarn add -D @microsoft/eslint-formatter-sarif
インストールが完了したら、package.json
が正しく更新されているか確認してください。以下のように devDependencies に追加されているはずです。
json{
"devDependencies": {
"@microsoft/eslint-formatter-sarif": "^3.1.0",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.0"
}
}
次に、package.json
の scripts セクションに SARIF 出力用のコマンドを追加します。
json{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint:sarif": "next lint --format @microsoft/eslint-formatter-sarif --output-file eslint-results.sarif || true"
}
}
|| true
を追加することで、ESLint で違反が見つかっても終了コード 0 を返すようにしています。これにより、CI/CD パイプラインでエラーとして扱われることを防げますね。
ローカル環境で動作確認をしてみましょう。
bashyarn lint:sarif
実行すると、プロジェクトルートに eslint-results.sarif
ファイルが生成されます。このファイルの内容を確認してみてください。
bashcat eslint-results.sarif | head -n 30
正しく生成されていれば、JSON 形式で ESLint の結果が含まれているはずです。
GitHub Actions ワークフローファイルの作成
次に、GitHub Actions のワークフローファイルを作成します。.github/workflows
ディレクトリが存在しない場合は作成してください。
bashmkdir -p .github/workflows
新しいワークフローファイルを作成します。
bashtouch .github/workflows/eslint-sarif.yml
以下の内容を eslint-sarif.yml
に記述します。実際のプロジェクト環境に合わせて調整が必要な部分もあるでしょう。
yamlname: ESLint Code Scanning
on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop
schedule:
# 毎週月曜日の午前9時(JST)に定期実行
- cron: '0 0 * * 1'
jobs:
eslint-scan:
name: ESLint SARIF Analysis
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
actions: read
基本的なワークフロー設定です。プッシュと Pull Request に加えて、schedule
でも定期実行を設定しています。これにより、開発が停滞している場合でも週次でコード品質を確認できますね。
yamlsteps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn'
リポジトリのチェックアウトと Node.js 環境のセットアップです。fetch-depth: 0
を指定することで、すべてのコミット履歴を取得します。これは、後で差分分析を行う際に役立つでしょう。
yaml- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
node_modules
.yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --frozen-lockfile
依存関係のキャッシュとインストールです。actions/cache
を使うことで、2 回目以降の実行が大幅に高速化されます。プロジェクトの規模にもよりますが、数分単位で時間短縮できることもあるでしょう。
yaml- name: Run ESLint with SARIF output
run: yarn lint:sarif
continue-on-error: true
- name: Check SARIF file exists
id: sarif-check
run: |
if [ -f eslint-results.sarif ]; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "::warning::SARIF file was not generated"
fi
ESLint を実行し、SARIF ファイルの存在を確認します。ファイルが生成されなかった場合は警告を出力しますが、ワークフローは続行します。この確認ステップにより、後続の処理でエラーが発生することを防げますね。
yaml- name: Upload SARIF to GitHub Code Scanning
if: steps.sarif-check.outputs.exists == 'true'
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: eslint-results.sarif
category: eslint
wait-for-processing: true
SARIF ファイルを GitHub Code Scanning にアップロードします。wait-for-processing: true
を設定することで、アップロード処理が完了するまで待機します。これにより、Pull Request のチェックステータスが正しく更新されるでしょう。
yaml- name: Upload SARIF as artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: eslint-sarif-results
path: eslint-results.sarif
retention-days: 30
最後に、SARIF ファイルをアーティファクトとしてもアップロードします。これにより、後でファイルをダウンロードして詳細な分析を行うことができますね。retention-days
で保存期間を 30 日に設定しています。
ワークフローのコミットとプッシュ
作成したワークフローファイルをリポジトリにコミットしてプッシュします。
bashgit add .github/workflows/eslint-sarif.yml
git add package.json
git commit -m "feat: Add ESLint SARIF Code Scanning workflow"
git push origin main
プッシュすると、自動的にワークフローが実行されます。GitHub リポジトリの「Actions」タブで実行状況を確認できるでしょう。
Code Scanning 結果の確認と活用
ワークフローが成功したら、Code Scanning の結果を確認してみましょう。GitHub リポジトリの「Security」タブから「Code scanning」を選択します。
初回実行では、プロジェクト内のすべての ESLint 違反がアラートとして表示されます。違反が多い場合は、数百件のアラートが表示されることもあるでしょう。驚く必要はありません。まずは現状を把握することが重要です。
アラートはフィルタリング機能を使って整理できます。以下のフィルタが利用可能です。
textis:open # 未解決のアラートのみ
is:closed # 解決済みのアラートのみ
severity:error # エラーレベルのみ
severity:warning # 警告レベルのみ
rule:no-unused-vars # 特定のルールのみ
branch:main # 特定のブランチのみ
例えば、エラーレベルの違反のみを確認したい場合は、検索ボックスに is:open severity:error
と入力します。これにより、優先度の高い問題から対処できますね。
違反の解決とクローズ
実際に違反を修正してコミットすると、Code Scanning が自動的に変更を検出し、該当するアラートをクローズします。この仕組みを確認してみましょう。
例えば、以下のような未使用変数の違反があるとします。
typescript// src/utils/formatter.ts
export function formatDate(date: Date): string {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const unused = 'This variable is not used'; // ESLint: no-unused-vars
return `${year}-${month}-${day}`;
}
この違反を修正します。
typescript// src/utils/formatter.ts
export function formatDate(date: Date): string {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return `${year}-${month}-${day}`;
}
修正をコミットしてプッシュします。
bashgit add src/utils/formatter.ts
git commit -m "fix: Remove unused variable in formatDate"
git push origin main
ワークフローが再実行されると、Code Scanning は新しい SARIF ファイルを前回の結果と比較します。違反が修正されていることを検出すると、該当するアラートを自動的にクローズするでしょう。
Pull Request での活用例
実際の開発フローで最も効果を発揮するのが、Pull Request での活用です。新機能を開発する際の例を見てみましょう。
新しいブランチを作成し、機能を実装します。
bashgit checkout -b feature/user-profile
新しいコンポーネントを作成します。
typescript// src/components/UserProfile.tsx
import React from 'react';
interface UserProfileProps {
name: string;
email: string;
age: number;
}
export const UserProfile: React.FC<UserProfileProps> = ({
name,
email,
}) => {
const greeting = 'Hello'; // ESLint: no-unused-vars
return (
<div>
<h2>{name}</h2>
<p>{email}</p>
{/* age プロパティを使用していない: ESLint: no-unused-vars */}
</div>
);
};
このコードには、意図的に 2 つの ESLint 違反を含めています。変更をコミットして Pull Request を作成しましょう。
bashgit add src/components/UserProfile.tsx
git commit -m "feat: Add UserProfile component"
git push origin feature/user-profile
GitHub で Pull Request を作成すると、数分後に Code Scanning のチェックが実行されます。PR のチェック欄に「Code scanning results / eslint」という項目が表示され、新たに追加された違反が報告されるでしょう。
PR の「Files changed」タブでは、違反が発生している行に直接アノテーションが表示されます。レビュアーはコードレビューと同時に、コード品質の問題も確認できるため、レビューの効率が向上しますね。
違反を修正してプッシュすると、PR のチェックステータスが自動的に更新されます。
typescript// src/components/UserProfile.tsx(修正版)
import React from 'react';
interface UserProfileProps {
name: string;
email: string;
age: number;
}
export const UserProfile: React.FC<UserProfileProps> = ({
name,
email,
age,
}) => {
return (
<div>
<h2>{name}</h2>
<p>{email}</p>
<p>Age: {age}</p>
</div>
);
};
修正をプッシュします。
bashgit add src/components/UserProfile.tsx
git commit -m "fix: Use all props in UserProfile component"
git push origin feature/user-profile
ワークフローが再実行され、違反が解決されたことが確認されると、PR のチェックがパスします。これで安心してマージできるでしょう。
カスタムルールセットの適用
プロジェクトの要件に応じて、特定のルールセットを Code Scanning でも追跡したい場合があります。例えば、セキュリティ関連のルールのみを重点的に監視する設定を見てみましょう。
まず、セキュリティ関連のルールを集めた ESLint 設定ファイルを作成します。
javascript// .eslintrc.security.js
module.exports = {
extends: [
'eslint:recommended',
'plugin:security/recommended',
],
plugins: ['security'],
rules: {
'security/detect-object-injection': 'error',
'security/detect-non-literal-regexp': 'error',
'security/detect-unsafe-regex': 'error',
'security/detect-buffer-noassert': 'error',
'security/detect-eval-with-expression': 'error',
'security/detect-no-csrf-before-method-override':
'error',
},
};
セキュリティに特化した ESLint 設定です。eslint-plugin-security
を使用しているため、事前にインストールが必要です。
bashyarn add -D eslint-plugin-security
次に、セキュリティスキャン専用のスクリプトを追加します。
json{
"scripts": {
"lint": "next lint",
"lint:sarif": "next lint --format @microsoft/eslint-formatter-sarif --output-file eslint-results.sarif || true",
"lint:security": "eslint . --config .eslintrc.security.js --format @microsoft/eslint-formatter-sarif --output-file eslint-security.sarif || true"
}
}
ワークフローファイルに、セキュリティスキャン用のジョブを追加します。
yamljobs:
eslint-scan:
# 既存の通常スキャン
# ...
eslint-security-scan:
name: ESLint Security Analysis
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run security-focused ESLint
run: yarn lint:security
continue-on-error: true
- name: Upload security SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: eslint-security.sarif
category: eslint-security
セキュリティスキャン専用のジョブです。category
を eslint-security
とすることで、通常の ESLint スキャンと区別できます。Code Scanning の画面では、カテゴリごとにアラートをフィルタリングできるため、セキュリティに特化した問題を素早く確認できるでしょう。
違反件数のメトリクス取得
Code Scanning の API を使用すれば、違反件数をプログラマティックに取得し、他のダッシュボードツールと連携できます。簡単なスクリプトを作成してみましょう。
typescript// scripts/get-code-scanning-metrics.ts
import { Octokit } from '@octokit/rest';
interface ScanningAlert {
number: number;
rule: {
id: string;
severity: string;
};
state: string;
created_at: string;
}
interface Metrics {
total: number;
open: number;
closed: number;
bySeverity: {
error: number;
warning: number;
note: number;
};
byRule: Record<string, number>;
}
型定義です。Code Scanning API から返されるアラート情報と、集計後のメトリクスの型を定義しています。
typescriptasync function getCodeScanningMetrics(
owner: string,
repo: string,
token: string
): Promise<Metrics> {
const octokit = new Octokit({ auth: token });
// Code Scanning アラートを取得
const { data: alerts } = await octokit.codeScanning.listAlertsForRepo({
owner,
repo,
tool_name: 'ESLint',
per_page: 100,
});
GitHub API を使って Code Scanning のアラートを取得します。tool_name
で ESLint のアラートのみをフィルタリングしています。
typescript // メトリクスを集計
const metrics: Metrics = {
total: alerts.length,
open: 0,
closed: 0,
bySeverity: {
error: 0,
warning: 0,
note: 0,
},
byRule: {},
};
for (const alert of alerts as ScanningAlert[]) {
// ステータスごとにカウント
if (alert.state === 'open') {
metrics.open++;
} else {
metrics.closed++;
}
// 重要度ごとにカウント
const severity = alert.rule.severity.toLowerCase() as keyof typeof metrics.bySeverity;
if (severity in metrics.bySeverity) {
metrics.bySeverity[severity]++;
}
// ルールごとにカウント
const ruleId = alert.rule.id;
metrics.byRule[ruleId] = (metrics.byRule[ruleId] || 0) + 1;
}
return metrics;
}
取得したアラートをループ処理し、ステータス、重要度、ルールごとに集計します。この情報をダッシュボードに表示したり、Slack に通知したりできるでしょう。
typescript// 使用例
async function main() {
const owner = 'your-org';
const repo = 'your-repo';
const token = process.env.GITHUB_TOKEN || '';
const metrics = await getCodeScanningMetrics(
owner,
repo,
token
);
console.log('=== ESLint Code Scanning Metrics ===');
console.log(`Total alerts: ${metrics.total}`);
console.log(`Open: ${metrics.open}`);
console.log(`Closed: ${metrics.closed}`);
console.log('\nBy Severity:');
console.log(` Error: ${metrics.bySeverity.error}`);
console.log(` Warning: ${metrics.bySeverity.warning}`);
console.log(` Note: ${metrics.bySeverity.note}`);
console.log('\nTop 5 Rules:');
const topRules = Object.entries(metrics.byRule)
.sort(([, a], [, b]) => b - a)
.slice(0, 5);
for (const [rule, count] of topRules) {
console.log(` ${rule}: ${count}`);
}
}
main().catch(console.error);
スクリプトの実行例です。環境変数 GITHUB_TOKEN
に GitHub のパーソナルアクセストークンを設定して実行すると、現在のメトリクスがコンソールに出力されます。
このスクリプトを定期実行するように設定すれば、週次レポートの作成や、Slack への自動通知などに活用できるでしょう。
Slack 通知との連携
Code Scanning の結果を Slack に通知する仕組みを作ってみましょう。GitHub Actions のワークフローに通知ステップを追加します。
yaml- name: Get alert summary
id: alert-summary
if: always()
run: |
# SARIF ファイルから違反件数を集計
if [ -f eslint-results.sarif ]; then
total=$(jq '.runs[0].results | length' eslint-results.sarif)
errors=$(jq '[.runs[0].results[] | select(.level == "error")] | length' eslint-results.sarif)
warnings=$(jq '[.runs[0].results[] | select(.level == "warning")] | length' eslint-results.sarif)
echo "total=$total" >> $GITHUB_OUTPUT
echo "errors=$errors" >> $GITHUB_OUTPUT
echo "warnings=$warnings" >> $GITHUB_OUTPUT
fi
SARIF ファイルから違反件数を集計するステップです。jq
コマンドを使用して JSON をパースし、レベルごとの件数を計算しています。
yaml- name: Notify Slack
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "ESLint Code Scanning Results",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "📊 ESLint Scanning Complete"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Repository:*\n${{ github.repository }}"
},
{
"type": "mrkdwn",
"text": "*Branch:*\n${{ github.ref_name }}"
},
{
"type": "mrkdwn",
"text": "*Total Issues:*\n${{ steps.alert-summary.outputs.total }}"
},
{
"type": "mrkdwn",
"text": "*Errors:*\n${{ steps.alert-summary.outputs.errors }}"
},
{
"type": "mrkdwn",
"text": "*Warnings:*\n${{ steps.alert-summary.outputs.warnings }}"
}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Details"
},
"url": "${{ github.server_url }}/${{ github.repository }}/security/code-scanning"
}
]
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Slack への通知ステップです。main ブランチへのプッシュ時のみ通知されます。Slack Webhook URL はリポジトリのシークレットに設定しておく必要がありますね。
通知メッセージには、リポジトリ名、ブランチ名、違反件数、そして Code Scanning の詳細ページへのリンクが含まれます。チームメンバーは Slack から直接 GitHub の詳細ページにアクセスでき、素早く状況を確認できるでしょう。
まとめ
ESLint の実行結果を SARIF 形式で出力し、GitHub Code Scanning にアップロードすることで、コード品質の継続的な可視化が実現できました。
従来のコンソール出力だけでは把握できなかった違反の時系列推移や、Pull Request での自動チェックにより、チーム全体でコード品質を意識する文化が醸成されるでしょう。Code Scanning のダッシュボードは、マネージャーやテックリードにとっても、プロジェクトの健全性を一目で確認できる強力なツールとなります。
導入のハードルは決して高くありません。SARIF フォーマッターのインストールと GitHub Actions ワークフローの設定だけで、すぐに運用を開始できます。本記事で紹介した具体例を参考に、ぜひあなたのプロジェクトでも SARIF/Code Scanning を活用してみてください。
図解を含めた記事構成により、初心者の方でも理解しやすい内容になったかと思います。Code Scanning の Trends 機能を使えば、コード品質改善の成果を可視化し、チームのモチベーション向上にもつながるでしょう。
継続的なコード品質管理は、技術的負債の蓄積を防ぎ、長期的なプロジェクトの成功に欠かせません。SARIF と Code Scanning を活用して、より良いコード品質を目指していきましょう。
関連リンク
- article
ESLint 運用ダッシュボード:SARIF/Code Scanning で違反推移を可視化
- article
ESLint シェアラブル設定の設計術:単一ソースで Web/Node/React をカバー
- article
ESLint Flat Config 速見表:files/ignores/plugins/rules/languageOptions の書き方
- article
ESLint を Yarn + TypeScript + React でゼロから構築:Flat Config 完全手順(macOS)
- article
ESLint vs Biome vs Rome 後継:速度・エコシステム・移行コストを実測比較
- article
ESLint の extends が効かない問題を斬る:Flat Config の files/ignores 落とし穴
- article
ESLint 運用ダッシュボード:SARIF/Code Scanning で違反推移を可視化
- article
SolidJS 本番運用チェックリスト:CSP・SRI・Preload・エラーレポートの総点検
- article
Redis 使い方:Next.js で Cache-Tag と再検証を実装(Edge/Node 両対応)
- article
Dify 本番運用ガイド:SLO/SLA 設定とアラート設計のベストプラクティス
- article
Cursor の KPI 設計:リードタイム・欠陥率・レビュー時間を定量で追う
- article
Python 本番運用 SLO 設計:p95 レイテンシ・エラー率・スループットの指標化
- blog
iPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来