Docs/APIとWebhook/SARIF統合

SARIF統合

任意のコードスキャンツール (CodeQL、Semgrep、Snyk、Checkmarx、Trivy、Bandit、GitLab SAST、OWASP ZAP) のSARIF出力をSecureCodingHubに送信します。実行内の一意の各CWEは、コミット作成者のアカウントの課題となります — 通常マージから数秒以内に。

CIが適切なトリガーである理由

汎用的な「すべての開発者が同じOWASP Top 10コースを受講する」展開は、完了率が低く、定着率はさらに低くなります。CI統合はモデルを反転します: トレーニングは問題を導入した開発者にピンポイントで、必要な脆弱性クラスにピンポイントで、それを露呈したマージに紐づいた14日間の期限とともに割り当てられます。これは監査人がジャストインタイムなセキュアコーディングトレーニングと呼ぶものです。

エンドツーエンドの仕組み

1

SASTツールがCIジョブの一部としてSARIF 2.1.0ファイルを生成します。

2

CIステップがコミットメタデータをリクエストヘッダーとしてファイルを/api/public/v1/sarifPOSTします。

3

SecureCodingHubは各resultを解析し、そのCWEタグを抽出し、内部CWE-to-topicマップでそれぞれを検索します。

4

マップされた各一意のトピックについて、X-Commit-Author-Emailと一致するメールアドレスのユーザーに14日間の期限で課題が作成されます。

5

同期レスポンスが返すのと同じペイロードでsarif.ingested Webhookが発火します。

エンドポイント

POST /api/public/v1/sarif
Authorization: Bearer scs_live_…
Content-Type: application/json
X-Source: github-codeql
X-Repo: acme/payments-api
X-Branch: main
X-Commit-Sha: 9c2f4b8e0c1d…
X-Commit-Author-Email: jane.smith@acme.com

<SARIF 2.1.0 JSON body, up to 10 MB>

必要なスコープ: sarif:ingest

リクエストヘッダー

ヘッダー必須意味
X-Source自由形式のツール識別子 — 例: github-codeqlsnyksemgrep-ci。監査のために記録されます。
X-Repoリポジトリスラッグ (owner/name)。監査のために記録されます。
X-Branchブランチ名。監査のために記録されます。
X-Commit-Sha推奨コミットハッシュ。X-Repoと組み合わせて24時間冪等性に使用されます。
X-Commit-Author-Email推奨コミット作成者のメールアドレス。SecureCodingHubユーザーに解決され、課題がそのユーザーに紐づけられます。メールがユーザーと一致しない場合、実行は取り込まれますが課題は作成されません。

レスポンス

{
  "ingestionId": "7e4c9d09-86ca-4125-bbd8-7fae54c8f654",
  "findingsCount": 2,
  "uniqueCwes": ["CWE-79", "CWE-89"],
  "unmappedCwes": [],
  "assignmentsCreated": 12,
  "notes": []
}
  • findingsCount — 解析されたresultエントリの総数。
  • uniqueCwes — すべての検出結果にわたって言及されたCWEのセット。
  • unmappedCwes — トピックにマップできなかったCWE。カバレッジ追加をご希望の場合はサポートまでお送りください。
  • assignmentsCreated — 新規課題レコードの数 (既存の重複はスキップされます)。
  • notes — 致命的でない警告 (例: 無効なコミット作成者メール形式)。

冪等性

同じSARIFファイルの再取り込みは安全です。タプル(organization, repo, commit_sha)が冪等性キーです — 24時間ウィンドウ内の重複は、元のingestionIdassignmentsCreated: 0を含む200を返します。これは、同じコミット (リベース、手動再実行、PRへのプッシュ) で再実行されるCIワークフローが重複する課題を積み重ねないことを意味します。

GitHub Actionsの例

CodeQLまたはSemgrepジョブがresults.sarifを生成した後、このステップをワークフローに配置します:

- name: Send SARIF to SecureCodingHub
  if: always()
  run: |
    curl -sS -f -X POST \
      -H "Authorization: Bearer $SCH_API_KEY" \
      -H "Content-Type: application/json" \
      -H "X-Source: github-codeql" \
      -H "X-Repo: ${{ github.repository }}" \
      -H "X-Branch: ${{ github.ref_name }}" \
      -H "X-Commit-Sha: ${{ github.sha }}" \
      -H "X-Commit-Author-Email: ${{ github.event.head_commit.author.email }}" \
      --data-binary @results.sarif \
      https://api.limeplate.com/api/public/v1/sarif
  env:
    SCH_API_KEY: ${{ secrets.SCH_API_KEY }}

リポジトリまたは組織シークレットにキーを保存します。if: always()ガードは、セキュリティジョブがビルドを失敗とマークした場合でも検出結果が送信されるようにします — これはトレーニング課題を最も発火させたい場合です。

GitLab CIの例

send_sarif_to_sch:
  stage: post-security
  image: curlimages/curl:latest
  needs: ["sast"]
  script:
    - >
      curl -sS -f -X POST
      -H "Authorization: Bearer $SCH_API_KEY"
      -H "Content-Type: application/json"
      -H "X-Source: gitlab-sast"
      -H "X-Repo: $CI_PROJECT_PATH"
      -H "X-Branch: $CI_COMMIT_BRANCH"
      -H "X-Commit-Sha: $CI_COMMIT_SHA"
      -H "X-Commit-Author-Email: $GITLAB_USER_EMAIL"
      --data-binary @gl-sast-report.json
      https://api.limeplate.com/api/public/v1/sarif
  rules:
    - if: $CI_COMMIT_BRANCH

GitLab SASTレポートはSARIF互換です — 変換は不要です。

Semgrepの例

semgrep ci --sarif --output results.sarif
curl -sS -f -X POST \
  -H "Authorization: Bearer $SCH_API_KEY" \
  -H "X-Source: semgrep" \
  -H "X-Repo: $REPO" \
  -H "X-Commit-Sha: $COMMIT" \
  -H "X-Commit-Author-Email: $AUTHOR_EMAIL" \
  --data-binary @results.sarif \
  https://api.limeplate.com/api/public/v1/sarif

CWEカバレッジ

SecureCodingHubは現在、OWASP Top 10、OWASP API Security Top 10、OWASP Mobile Top 10、CWE Top 25をトレーニングトピックにマップしています。そのセット外のCWE IDでタグ付けされた検出結果は、レスポンスのunmappedCwesリストに表示されます。SARIFタグ側で受け入れる一般的な形式:

  • external/cwe/cwe-89 (CodeQL標準)
  • cwe-89
  • CWE-89
  • cwe:89

タグはresult.properties.tagsと対応するtool.driver.rules[].properties.tagsの両方から読み取られます。

ボディサイズの上限

SARIFエンドポイントは非圧縮で最大10 MBのペイロードを受け入れます。実世界のほとんどの単一リポジトリのSASTレポートは、これを十分下回ります。上限を超えるエンタープライズ規模のモノレポレポートがある場合は、ツールドライバごとに分割し (ドライバごとに1つのSARIF実行)、それぞれをPOSTしてください — 同じコミットSHAの下で冪等になります。

失敗モード

症状可能性の高い原因
200assignmentsCreated: 0コミット作成者のメールが組織のユーザーではないか、すべてのCWEがすでに割り当て済みです。
200に空でないunmappedCwes検出結果がまだトレーニングトピックを持たないCWEを参照しています。リストをサポートに転送してください。
400 empty_bodycurlに--data-binary @file.sarifがありませんでした。
413 body_too_largeSARIFが10 MBを超えています。ドライバごとに分割してください。
idempotency:で始まるnotesエントリを持つ200同じ(repo, commit)がすでに24時間以内に取り込まれています。レスポンスはそれ以外、assignmentsCreated: 0を含む新規取り込みと同一です — 無視して安全です。