integrating-sast-into-github-actions-pipeline について
GitHub ActionsにSASTを組み込むための、開発チームとセキュリティチーム向けスキルです。CodeQLとSemgrepによるスキャンに加え、独自ルール、マージゲート、検出結果の集約を扱います。
主な機能
- 01CodeQLとSemgrepのスキャン設定
- 02組織向けSemgrepルールの作成
- 03ブランチ保護による品質ゲート
- 04誤検知の調整と検出結果の集約
活用シーン
- 01プルリクエストでの自動スキャン
- 02多言語コードベースのSAST統一
- 03セキュリティ検査に失敗した変更のマージ防止
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill integrating-sast-into-github-actions-pipelineインストール後、Claude Code で/integrating-sast-into-github-actions-pipelineを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEassets/template.mdreferences/api-reference.mdstandards.mdworkflows.mdscripts/agent.pyprocess.py詳細
GitHub Actions パイプラインへの SAST の統合
使用する場面
- 開発チームが、すべてのプルリクエストでコードレベルの脆弱性を自動検出する必要がある場合
- セキュリティチームが、組織内のすべてのリポジトリで一貫した SAST の適用を必要とする場合
- 手動または定期的なセキュリティレビューから、継続的なセキュリティテストへ移行する場合
- コンプライアンスフレームワーク(SOC 2、PCI DSS、NIST SSDF)で、自動コード分析の証跡が求められる場合
- モノレポに複数の言語が混在し、1 つのワークフローで統一的なスキャンが必要な場合
次の場合は使用しないでください:ランタイムの脆弱性検出(代わりに DAST を使用)、サードパーティの依存関係のスキャン(Snyk などの SCA ツールを使用)、または Infrastructure as Code のスキャン(Checkov または tfsec を使用)。
前提条件
- GitHub Actions が有効な GitHub リポジトリ
- GitHub Advanced Security ライセンス(プライベートリポジトリで CodeQL を使用するには必須。パブリックリポジトリでは無料)
- マネージドルールと Semgrep App ダッシュボードを利用するための Semgrep アカウント(無料プランあり)
- サポート対象言語(Python、JavaScript/TypeScript、Java、C/C++、C#、Go、Ruby、Swift、Kotlin)で書かれたリポジトリのコード
ワークフロー
ステップ 1:CodeQL 分析ワークフローを設定する
プルリクエスト時と週次スケジュールで実行し、既存コードの脆弱性を検出する CodeQL ワークフローを作成します。
# .github/workflows/codeql-analysis.yml
name: "CodeQL Analysis"
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '30 2 * * 1' # Weekly Monday 2:30 AM
jobs:
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ['javascript', 'python']
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: security-extended,security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{ matrix.language }}"
ステップ 2:Semgrep スキャンを追加する
Semgrep は、より高速なスキャンとカスタムパターンベースのルールへの対応により、CodeQL を補完します。同じ GitHub Security タブに SARIF の結果をアップロードするよう設定します。
# .github/workflows/semgrep.yml
name: "Semgrep SAST Scan"
on:
pull_request:
branches: [main, develop]
push:
branches: [main]
jobs:
semgrep:
name: Semgrep Scan
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
container:
image: semgrep/semgrep:latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run Semgrep
run: |
semgrep ci \
--config auto \
--config p/owasp-top-ten \
--config p/cwe-top-25 \
--sarif --output semgrep-results.sarif \
--severity ERROR \
--error
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: semgrep-results.sarif
category: semgrep
ステップ 3:組織固有のパターンに対応する Semgrep のカスタムルールを作成する
非推奨の社内 API や安全でない設定パターンなど、コードベース固有のパターンを検出するための組織固有のルールを作成します。
# .semgrep/custom-rules.yml
rules:
- id: hardcoded-database-url
patterns:
- pattern: |
$DB_URL = "...$PROTO://...:...$PASS@..."
message: |
Hardcoded database connection string with credentials detected.
Use environment variables or a secrets manager instead.
languages: [python, javascript, typescript]
severity: ERROR
metadata:
cwe: "CWE-798: Use of Hard-coded Credentials"
owasp: "A07:2021 - Identification and Authentication Failures"
- id: unsafe-deserialization
patterns:
- pattern-either:
- pattern: pickle.loads(...)
- pattern: yaml.load(..., Loader=yaml.Loader)
- pattern: yaml.load(..., Loader=yaml.FullLoader)
message: |
Unsafe deserialization detected. Use safe alternatives to prevent
remote code execution vulnerabilities.
languages: [python]
severity: ERROR
metadata:
cwe: "CWE-502: Deserialization of Untrusted Data"
- id: missing-csrf-protection
patterns:
- pattern: |
@app.route("...", methods=["POST"])
def $FUNC(...):
...
- pattern-not-inside: |
@csrf.exempt
...
message: "POST endpoint may lack CSRF protection."
languages: [python]
severity: WARNING
ステップ 4:ブランチ保護で品質ゲートを確立する
マージ前に SAST チェックの合格を必須とするブランチ保護ルールを設定し、脆弱なコードが本番ブランチに到達しないようにします。
# Use GitHub CLI to set branch protection requiring SAST checks
gh api repos/{owner}/{repo}/branches/main/protection \
--method PUT \
--field required_status_checks='{"strict":true,"contexts":["Analyze (javascript)","Analyze (python)","Semgrep Scan"]}' \
--field enforce_admins=true \
--field required_pull_request_reviews='{"required_approving_review_count":1}'
ステップ 5:誤検知を調整し、抑制する
CodeQL のクエリフィルターと Semgrep の nosemgrep アノテーションを使って誤検知を管理し、スキャン結果に対する開発者の信頼を維持します。
# codeql-config.yml - Custom CodeQL configuration
name: "Custom CodeQL Config"
queries:
- uses: security-extended
- uses: security-and-quality
- excludes:
id: js/unused-local-variable
paths-ignore:
- '**/test/**'
- '**/tests/**'
- '**/vendor/**'
- '**/node_modules/**'
- '**/*.test.js'
- '**/*.spec.py'
# Example: Suppressing a known false positive in Semgrep
import subprocess
def run_safe_command(cmd_list):
# nosemgrep: python.lang.security.audit.dangerous-subprocess-use
result = subprocess.run(cmd_list, capture_output=True, text=True, shell=False)
return result.stdout
ステップ 6:検出結果を集約して報告する
GitHub Security Overview ダッシュボードを使用し、リポジトリ全体のセキュリティアラートに関する通知を設定します。
# Query SARIF results via GitHub API for reporting
gh api repos/{owner}/{repo}/code-scanning/alerts \
--jq '.[] | select(.state=="open") | {rule: .rule.id, severity: .rule.security_severity_level, file: .most_recent_instance.location.path, line: .most_recent_instance.location.start_line}'
# Count open alerts by severity
gh api repos/{owner}/{repo}/code-scanning/alerts \
--jq '[.[] | select(.state=="open")] | group_by(.rule.security_severity_level) | map({severity: .[0].rule.security_severity_level, count: length})'
主な概念
| 用語 | 定義 |
|---|---|
| SAST | 静的アプリケーションセキュリティテスト。ソースコードを実行せずに分析し、セキュリティ脆弱性を検出します |
| SARIF | 静的解析結果交換形式。静的解析ツールの結果を表現するための標準化された JSON 形式です |
| CodeQL | コードをデータとして扱い、脆弱性パターンをクエリする GitHub のセマンティックコード分析エンジンです |
| Semgrep | パターンマッチングを使用し、多くの言語でバグやセキュリティ上の問題を検出する軽量な静的解析ツールです |
| Security Extended | より詳細な分析のため、デフォルトのクエリセットに追加のセキュリティクエリを含む CodeQL クエリスイートです |
| 品質ゲート | セキュリティ基準を満たさない限り、コードのパイプライン内での進行をブロックする自動チェックポイントです |
| 誤検知 | スキャンで安全なコードが誤って脆弱だと判定された結果です。抑制または調整が必要です |
ツールとシステム
- CodeQL:詳細なデータフロー分析と汚染追跡分析を備えた GitHub のセマンティックコード分析エンジン
- Semgrep:3000 以上のコミュニティルールとカスタムルールに対応する、高速で軽量なパターンマッチング型 SAST ツール
- GitHub Advanced Security:GitHub でコードスキャン、シークレットスキャン、依存関係レビューを提供するプラットフォーム
- SARIF Viewer:開発中に SARIF の結果をローカルで確認するための VS Code 拡張機能
- GitHub Security Overview:すべてのリポジトリのセキュリティアラートを集約する組織レベルのダッシュボード
よくあるシナリオ
シナリオ:複数の言語を使用するモノレポで統一的な SAST が必要な場合
コンテキスト:プラットフォームチームが、Python マイクロサービス、TypeScript フロントエンド、Go インフラストラクチャツールを含むモノレポを管理しています。セキュリティレビューは四半期ごとに手動で行われるため、レビューの合間に発生した脆弱性を見逃しています。
アプローチ:
- Python、JavaScript、Go の各言語を対象とするマトリックス戦略で CodeQL を設定します
--config autoを指定して Semgrep を追加し、言語を自動検出して該当するルールセットを適用します- パスベースのトリガーを作成し、変更された言語のディレクトリに応じて、該当するスキャンのみを実行します
- ツールと言語ごとに一意のカテゴリを設定し、すべての SARIF 結果を GitHub の Security タブにアップロードします
- すべての SAST ジョブの成功をマージの必須条件とするよう、ブランチ保護を設定します
- 変更のないコードでも新たに公開された CVE パターンの問題を検出できるよう、リポジトリ全体のスキャンを週次でスケジュールします
落とし穴:CodeQL ですべての言語を毎回の PR で解析すると、CI の所要時間が大幅に増加します。パスフィルターを使って、関連する言語のスキャンのみを実行してください。Semgrep の --config auto によって CodeQL の検出結果と競合するルールが有効になり、重複したアラートが発生する場合があります。
シナリオ:誤検知率の高さによるアラート疲れを軽減する
コンテキスト:SAST を有効にした後、検出結果の 40% が誤検知であるため、開発者が検出結果を無視するようになり、セキュリティプログラムの効果が損なわれています。
アプローチ:
- 現在のアラートをすべてエクスポートし、真陽性、誤検知、情報提供に分類します
- 誤検知が最も多いノイズの多いクエリ ID を除外するカスタム CodeQL 設定を作成します
- テストファイル、生成コード、ベンダー依存関係に対するパターンを
.semgrepignoreに記述します - セキュリティ責任者と開発責任者が新しいルールの追加を確認する、週次のトリアージミーティングを設けます
- 誤検知率を指標として追跡し、開発者の信頼を得るために 15% 未満を目標とします
落とし穴:ノイズを減らすためにルールを過剰に抑制すると、見落としが発生するおそれがあります。重大な脆弱性の種類を引き続き検出できることを確認するため、抑制内容は必ず OWASP Top 10 と CWE Top 25 に照らして検証してください。
出力形式
SAST Pipeline Scan Report
==========================
Repository: org/web-application
Branch: feature/user-auth-refactor
Scan Date: 2026-02-23
Commit: a1b2c3d4
CodeQL Results:
Language Queries Run Findings Critical High Medium
javascript 312 4 1 2 1
python 287 2 0 1 1
Semgrep Results:
Ruleset Rules Matched Findings Errors Warnings
auto 1,847 3 1 2
owasp-top-ten 186 2 1 1
custom-rules 12 1 0 1
QUALITY GATE: FAILED
Blocking findings: 2 Critical/High severity issues
- [CRITICAL] CWE-89: SQL Injection in src/api/users.py:47
- [HIGH] CWE-79: Cross-site Scripting in src/components/Search.tsx:123
Action Required: Fix blocking findings before merge is permitted.