多数のOrganizationやRepositoryへGitHub secret scanningのcustom patternを配布する作業は、REST APIで自動化できます。2026年7月13日から、Enterprise、Organization、Repositoryの各階層で、custom patternの取得・作成・更新・削除を行うREST APIが正式提供されています。
ただし、APIだけで運用を完結させることはできません。パターンが実際のコードにどう一致するかを確認するdry runと、パターンを有効化する最終publishは、引き続きGitHub UIで行う必要があります。そのため、実務では「REST APIでドラフトを一括同期し、GitHub UIでdry runとpublishを行う」という二段階の運用にするのが現実的です。(The GitHub Blog)
この記事では、階層別endpointの選び方、認証権限、POST・PATCH・DELETEの具体例、多数のOrganizationやRepositoryへ安全に配布する設計、dry run制約への対処方法まで解説します。
secret scanning custom patternをREST APIで管理できる範囲
custom pattern向けREST APIでは、基本的なCRUD操作を実行できます。一方、実際のRepositoryを検索するGitHubのdry runと、パターンのpublishはAPIの対象外です。
| 操作 | REST API | 補足 |
|---|---|---|
| パターン一覧の取得 | 可能 | GETを使用 |
| パターンの新規作成 | 可能 | POSTで複数件をまとめて作成可能 |
| パターンの更新 | 可能 | PATCHで1パターンずつ更新 |
| パターンの削除 | 可能 | DELETEで複数件をまとめて削除可能 |
| 定義差分の確認 | 独自実装で可能 | 現在値と管理ファイルを比較する |
| Repositoryに対するdry run | 不可 | GitHub UIで実行 |
| 最終publish | 不可 | GitHub UIで実行 |
ここで注意したいのは、「独自実装のplan」と「GitHubのdry run」は別物だという点です。
独自のplan処理では、APIから取得した現在の定義と、Gitなどで管理している期待値を比較できます。しかし、正規表現が実際のコードに何件一致するか、誤検知が発生するかまでは確認できません。実データへの一致確認は、GitHub UIのdry runが必要です。
階層別endpointと使い分け
custom pattern APIは、Enterprise、Organization、Repositoryの3階層に用意されています。
| 階層 | ベースendpoint | 適した用途 |
|---|---|---|
| Enterprise | /enterprises/{enterprise}/secret-scanning/custom-patterns | 複数Organizationへ共通ルールを適用する |
| Organization | /orgs/{org}/secret-scanning/custom-patterns | Organizationごとの社内ルールを管理する |
| Repository | /repos/{owner}/{repo}/secret-scanning/custom-patterns | 特定Repositoryだけの例外ルールを管理する |
各階層で使用するHTTPメソッドは共通です。
| 操作 | メソッド | endpoint |
|---|---|---|
| 一覧取得 | GET | ベースendpoint |
| 新規作成 | POST | ベースendpoint |
| 更新 | PATCH | ベースendpoint+/{pattern_id} |
| 削除 | DELETE | ベースendpoint |
PATCHではURLにpattern_idを含めます。一方、DELETEではURLにIDを付けず、削除対象をリクエストボディのpatterns配列で指定します。この違いは実装時に間違えやすいポイントです。(GitHub Docs)
Enterprise階層を選ぶ場合
複数のOrganizationに同じパターンを適用したい場合、Organizationごとに同じ定義を複製するより、Enterprise階層で一元管理した方が管理対象を減らせます。
ただし、Enterprise endpointには次の制約があります。
- classic personal access tokenが必要
admin:enterpriseスコープが必要- fine-grained personal access tokenは利用できない
- GitHub Appのinstallation access tokenやuser access tokenは利用できない
- Enterpriseレベルのパターンは、作成者だけが編集やdry runを実行できる
特に最後の作成者制約は重要です。自動化専用アカウントでPOSTした後、別の管理者がUIでdry runできない構成になる可能性があります。Enterprise階層で自動化する場合は、誰の認証情報で作成し、誰がUIでdry runとpublishを行うのかを先に決めてください。(GitHub Docs)
Organization階層を選ぶ場合
Organizationごとに異なる命名規則やトークン形式を検知したい場合は、Organization endpointが適しています。
たとえば、事業部ごとにOrganizationが分かれていて、内部サービスのトークン形式も異なる場合です。Organization単位なら、共通ルールを保ちつつ、対象範囲を適切に限定できます。
GitHub Appやfine-grained personal access tokenにも対応しているため、多数のOrganizationを継続的に管理する自動化では、Enterprise階層より扱いやすいケースがあります。
Repository階層を選ぶ場合
Repository固有の秘密情報を検知したい場合は、Repository endpointを使用します。
たとえば、旧システムだけで使われている独自APIキーや、特定製品のライセンスキー形式を検知する場合です。
共通パターンまでRepositoryごとに複製すると、更新漏れや削除漏れが起きやすくなります。Repository階層は、全体ルールの配布先ではなく、局所的な例外に限定するのが安全です。
APIに必要な認証と権限
必要なトークンと権限は階層ごとに異なります。
| 階層 | classic PAT | fine-grained PAT/GitHub App |
|---|---|---|
| Enterprise | admin:enterprise | 非対応 |
| Organization | GETはread:org、変更操作はwrite:org | OrganizationのAdministration権限。GETはread、POST・PATCH・DELETEはwrite |
| Repository | repoまたはsecurity_events。公開Repositoryのみならpublic_repoも利用可能 | RepositoryのSecret scanning alerts権限。GETはread、変更操作はwrite |
OrganizationやRepositoryを大量に扱う場合は、可能であればGitHub Appを使い、対象OrganizationやRepositoryだけに権限を付与する方が管理しやすくなります。
一方、Enterprise endpointではGitHub Appやfine-grained PATを利用できません。Enterprise全体をAPI管理する場合は、classic PATの保管、ローテーション、利用者監査を別途設計する必要があります。(GitHub Docs)
REST APIリクエストの基本形
GitHub REST APIでは、APIバージョンを明示して呼び出すことが推奨されます。2026年7月時点のドキュメントでは、2026-03-10が最新のAPIバージョンとして案内されています。(GitHub Docs)
Organization階層から一覧を取得する例は次のとおりです。
export GH_TOKEN='<YOUR_TOKEN>'
export ORG='example-org'
curl --fail-with-body \
--silent \
--show-error \
--location \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "X-GitHub-Api-Version: 2026-03-10" \
"https://api.github.com/orgs/${ORG}/secret-scanning/custom-patterns?per_page=100"
トークンをスクリプトやRepositoryへ直接記述してはいけません。CI/CDで実行する場合は、GitHub ActionsのSecrets、外部シークレット管理サービス、GitHub Appの短期トークンなどを利用します。
GETで利用できる主な絞り込み条件
一覧取得では、状態やpush protectionの設定状態を指定できます。
| パラメーター | 主な値 | 用途 |
|---|---|---|
state | published、unpublished | 公開済みか未公開かを絞り込む |
push_protection | enabled、disabled | push protectionの状態で絞り込む |
sort | created、updated、name | 並び替え項目 |
direction | asc、desc | 昇順・降順 |
per_page | 最大100 | 1ページの取得件数 |
page | 1以上 | 取得ページ |
管理対象が100件を超える場合は、1回のGETだけでは全件を取得できません。レスポンスのLinkヘッダーを処理し、次のページがなくなるまで取得してください。(GitHub Docs)
POSTでcustom patternを一括作成する
新しいパターンは、ベースendpointへPOSTします。リクエストボディにはpatterns配列を指定できるため、複数のパターンをまとめて作成できます。
Organization階層へ作成する例は次のとおりです。
{
"patterns": [
{
"name": "Internal service token",
"pattern": "svc_[A-Z0-9]{32}",
"start_delimiter": "\\A|[^0-9A-Za-z]",
"end_delimiter": "\\z|[^0-9A-Za-z]",
"must_match": [
"svc_"
],
"must_not_match": [
"svc_TEST_"
]
}
]
}
curl --fail-with-body \
--silent \
--show-error \
--location \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "X-GitHub-Api-Version: 2026-03-10" \
-H "Content-Type: application/json" \
"https://api.github.com/orgs/${ORG}/secret-scanning/custom-patterns" \
--data-binary @create-patterns.json
各フィールドの役割は次のとおりです。
| フィールド | 必須 | 内容 |
| —————– | -: | ——————— |
| name | 必須 | GitHub UIなどに表示するパターン名 |
| pattern | 必須 | 秘密情報本体を検出する正規表現 |
| start_delimiter | 任意 | パターン直前に許容する境界 |
| end_delimiter | 任意 | パターン直後に許容する境界 |
| must_match | 任意 | 追加で一致を必要とする条件 |
| must_not_match | 任意 | 一致対象から除外する条件 |
作成に成功するとHTTPステータス201が返ります。APIで作成した直後のパターンはunpublishedであり、push protectionも無効な状態です。その後、GitHub UIでdry runとpublishを行います。(GitHub Docs)
正規表現のJSONエスケープに注意する
正規表現中のバックスラッシュは、JSON上で二重にエスケープする必要があります。
たとえば、正規表現として\Aを渡したい場合、JSONファイルには\\Aと記述します。
{
"start_delimiter": "\\A|[^0-9A-Za-z]"
}
シェルスクリプト内でJSON文字列を直接組み立てると、シェルとJSONの両方でエスケープが必要になり、意図しない正規表現になりやすくなります。固定のJSONファイルを使用するか、jqなどのJSON生成ツールを使う方が安全です。
PATCHでcustom patternを更新する
パターンの更新は、pattern_idを含むendpointへPATCHします。
/orgs/{org}/secret-scanning/custom-patterns/{pattern_id}
リクエスト例は次のとおりです。
{
"pattern": "svc_[A-Z0-9]{40}",
"start_delimiter": "\\A|[^0-9A-Za-z]",
"end_delimiter": "\\z|[^0-9A-Za-z]",
"must_match": [
"svc_"
],
"must_not_match": [
"svc_TEST_",
"svc_EXAMPLE_"
],
"custom_pattern_version": "<CURRENT_VERSION>"
}
export PATTERN_ID='123'
curl --fail-with-body \
--silent \
--show-error \
--location \
-X PATCH \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "X-GitHub-Api-Version: 2026-03-10" \
-H "Content-Type: application/json" \
"https://api.github.com/orgs/${ORG}/secret-scanning/custom-patterns/${PATTERN_ID}" \
--data-binary @update-pattern.json
custom_pattern_versionは必須
PATCHでは、現在のcustom_pattern_versionを送信する必要があります。これは、別の管理者や自動処理によってパターンが変更された後、古い情報で上書きすることを防ぐための仕組みです。
更新前に現在の状態を取得し、差分計算に使用したバージョンをPATCHへ含めます。古いバージョンを送信すると、412 Precondition Failedになる可能性があります。
412が返った場合、同じリクエストをそのまま再送してはいけません。最新状態を取得し直し、期待値との差分を再計算してから更新します。(GitHub Docs)
APIでは名前変更を前提にしない
公開されているPATCH仕様には、更新可能フィールドとしてnameが含まれていません。したがって、自動化ではパターン名を後から変更できる前提にしない方が安全です。
名称変更が必要な場合は、次のような段階移行にします。
- 新しい名前でパターンを作成する
- GitHub UIでdry runする
- 新しいパターンをpublishする
- 動作を確認する
- 古いパターンを削除する
管理ファイルでは、表示名とは別に変更しない内部キーを持たせると、名称変更による対応関係の崩れを防げます。
patterns:
- key: internal-service-token
name: Internal service token
pattern: svc_[A-Z0-9]{32}
このkeyはGitHubへ送信する項目ではなく、自動化スクリプト内でパターンを識別するための独自項目です。
DELETEでcustom patternを一括削除する
削除では、URLにpattern_idを含めません。ベースendpointへDELETEし、リクエストボディのpatterns配列で対象を指定します。
{
"patterns": [
{
"pattern_id": 123,
"custom_pattern_version": "<CURRENT_VERSION>",
"post_delete_action": "resolve_alerts"
},
{
"pattern_id": 456,
"custom_pattern_version": "<CURRENT_VERSION>",
"post_delete_action": "resolve_alerts"
}
]
}
curl --fail-with-body \
--silent \
--show-error \
--location \
-X DELETE \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "X-GitHub-Api-Version: 2026-03-10" \
-H "Content-Type: application/json" \
"https://api.github.com/orgs/${ORG}/secret-scanning/custom-patterns" \
--data-binary @delete-patterns.json
成功時はHTTPステータス204が返ります。
post_delete_actionを必ず明示する
post_delete_actionには、次の2種類があります。
| 値 | 削除後のアラート |
|---|---|
delete_alerts | 関連するアラートを完全に削除する |
resolve_alerts | 関連するアラートを「pattern deleted」として解決済みにする |
省略時の既定値はdelete_alertsです。監査履歴を残したい環境で省略すると、意図せず既存アラートを削除するおそれがあります。
通常は、過去の検出履歴を追跡できるresolve_alertsを明示し、アラート自体を消す必要がある場合だけdelete_alertsを選ぶ方が安全です。(GitHub Docs)
関連アラートが大量にある場合、パターン削除後のアラート処理には時間がかかることがあります。APIから204が返った直後に、すべての画面表示やアラート状態が更新されているとは限りません。(GitHub)
多数のOrganizationやRepositoryへ配布する設計
大量配布では、単純にPOSTを繰り返すだけでは不十分です。途中失敗、手動変更、削除漏れ、パターンIDの違いを考慮し、期待する状態と現在の状態を比較する「desired state方式」にします。
定義ファイルを正本にする
たとえば、次のようなYAMLをGitで管理します。
patterns:
- key: internal-service-token
name: Internal service token
pattern: svc_[A-Z0-9]{32}
start_delimiter: '\A|[^0-9A-Za-z]'
end_delimiter: '\z|[^0-9A-Za-z]'
must_match:
- 'svc_'
must_not_match:
- 'svc_TEST_'
targets:
organizations:
- example-org-a
- example-org-b
repositories:
- owner: example-org-c
repo: legacy-api
この定義ファイルを正本とし、GitHub UI上の定義を直接修正する運用は例外扱いにします。
UIで緊急修正した場合も、そのまま放置せず、同じ変更を定義ファイルへ戻します。そうしないと、次回の自動同期で手動変更が元に戻る可能性があります。
一括管理処理の基本フロー
自動化処理は、次の順序にします。
| 段階 | 処理 |
|---|---|
| Inventory | GETで対象階層の全パターンを取得する |
| Normalize | JSONの並び順や省略値を正規化する |
| Match | 独自キー、名前、保存済みpattern IDを使って対応付ける |
| Plan | 作成・更新・削除予定を表示する |
| Apply create | 不足しているパターンをPOSTする |
| Apply update | 差分があるパターンをPATCHする |
| Apply delete | 明示的に許可された場合だけDELETEする |
| UI review | GitHub UIでdry runする |
| Publish | GitHub UIでpublishする |
| Verify | GETで公開状態と定義を再確認する |
処理イメージは次のようになります。
for each target:
current_patterns = fetch_all_pages(target)
desired_patterns = load_manifest(target)
plan = calculate_diff(current_patterns, desired_patterns)
print(plan)
if mode == "apply":
create_patterns(plan.creates)
for update in plan.updates:
update_pattern(update)
if allow_delete:
delete_patterns(plan.deletes)
POSTとDELETEは複数件をまとめて実行できますが、PATCHはpattern_id単位です。更新対象が多い場合は、APIのレート制限や途中失敗を考慮し、一定件数ごとに処理するか、再開可能な実装にします。(The GitHub Blog)
planとapplyを分離する
GitHubのdry runをAPIから実行できない以上、自動化側には少なくとも定義差分を確認するplanモードが必要です。
./sync-custom-patterns --plan
出力例は次のようにします。
Target: organization/example-org-a
CREATE:
- Internal service token
UPDATE:
- Legacy API key
pattern: changed
must_not_match: 1 item added
DELETE:
- Old deployment token
post_delete_action: resolve_alerts
実際に変更する場合だけapplyを指定します。
./sync-custom-patterns --apply
さらに削除は別のフラグで保護します。
./sync-custom-patterns --apply --allow-delete
これにより、定義ファイルの読み込み失敗や対象Organizationの指定ミスによって、既存パターンが一括削除される事故を防ぎやすくなります。
dry runとpublishを運用フローへ組み込む
APIで作成または更新した後は、GitHub UIでdry runを実行します。OrganizationやEnterprise階層では、dry runの対象Repositoryを選択できます。dry runによって見つかった一致は確認用であり、この時点ではsecret scanning alertは作成されません。(GitHub)
推奨する運用フローは次のとおりです。
APIでunpublished状態まで同期する
CI/CDまたは管理スクリプトで、各階層へPOST・PATCHを実行します。
この段階では、検出ルールを本番適用したとは考えません。API処理の役割は、GitHub UIで評価できるドラフトを準備するところまでです。
変更レポートを出力する
自動処理の終了時に、少なくとも次の情報を記録します。
- 対象Enterprise、Organization、Repository
- 作成・更新・削除したパターン
pattern_id- API実行結果
- dry runが必要なパターン
- publish待ちのパターン
- 削除時の
post_delete_action
GitHub Actionsで実行する場合は、Job SummaryやPull Requestコメントへ出力すると、レビュー担当者が確認しやすくなります。
GitHub UIでdry runする
まず少数の代表的なRepositoryで試します。
選定するRepositoryは、単に規模の小さいものではなく、次のようなコードを含むものが適しています。
- 実際の設定ファイルが多いRepository
- テスト用トークンやサンプル値を含むRepository
- 生成コードや圧縮済みファイルを含むRepository
- 過去のGit履歴が長いRepository
- 利用言語やフレームワークが異なるRepository
誤検知が多い場合は、must_not_matchやdelimiterを調整します。検知漏れが疑われる場合は、パターン本体だけでなく、前後の境界条件も確認してください。
GitHub UIでpublishする
dry runの結果を確認し、問題がなければpublishします。
push protectionを利用する場合も、dry runとpublishを先に完了させる必要があります。最初からpushをブロックするのではなく、通常の検知で誤検知を確認してから段階的に有効化する方が安全です。(GitHub)
APIで公開状態を再確認する
publish後にGETを実行し、state=publishedになったことを確認します。
curl --fail-with-body \
--silent \
--show-error \
--location \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "X-GitHub-Api-Version: 2026-03-10" \
"https://api.github.com/orgs/${ORG}/secret-scanning/custom-patterns?state=published&per_page=100"
APIで定義を同期しただけで処理を成功扱いにすると、UIでpublishされていないパターンを「配布済み」と誤認します。自動化の完了条件は、APIの成功とpublish後の再確認を分けて管理してください。
更新時に既存アラートへ与える影響
custom patternを変更すると、以前のバージョンで作成されたアラートが閉じられます。そのため、正規表現の微調整であっても、単なる設定変更として扱わない方が安全です。(GitHub)
更新前には、次の情報を記録しておきます。
- 現在のパターン定義
- 現在のpattern IDとversion
- 既存アラート数
- 変更理由
- dry run結果
- publish実施者
- ロールバック方針
誤検知の除外条件を1件追加するだけでも、既存アラートの状態が変化する可能性があります。セキュリティ担当者が調査中のアラートがある場合は、更新前に影響を共有してください。
よくある失敗と対処方法
| 症状 | 主な確認ポイント | 対処 |
|---|---|---|
400 Bad Request | JSON形式、正規表現のエスケープ、必須フィールド | jqなどでJSONを検証する |
403 Forbidden | トークンの種類、scope、OrganizationやRepositoryの権限 | 階層ごとの必要権限を確認する |
404 Not Found | Enterprise名、Organization名、Repository名、endpoint階層 | 対象名とAPIパスを再確認する |
412 Precondition Failed | custom_pattern_versionが古い | 最新状態を取得し、差分を再計算する |
422 Unprocessable Entity | 正規表現、delimiter、複数パターンの一部が不正 | ペイロードを分割して問題のパターンを特定する |
| POST後も検知されない | unpublishedのまま | GitHub UIでdry runとpublishを行う |
| DELETE後に履歴が消えた | post_delete_actionを省略した | 通常はresolve_alertsを明示する |
| Enterpriseで別の管理者がdry runできない | 作成者制約 | API実行者とUI担当者を事前に統一する |
1件の不正なパターンで一括作成が失敗する
POSTで複数パターンを送信すると、いずれかの定義に問題がある場合に422になることがあります。
大量配布の前に、ローカルでJSON構文を検証し、最初は少数のパターンでテストしてください。エラー時にはペイロードを半分ずつ分割すると、問題のある定義を特定しやすくなります。
APIレスポンスのサンプルだけで型を決める
ドキュメント上のサンプルレスポンスは、すべてのフィールドを常に掲載しているとは限りません。特にPATCHで必要なcustom_pattern_versionを扱う実装では、サンプルJSONの見た目だけでデータモデルを固定しないことが重要です。
実際のAPIレスポンスとOpenAPI schemaを確認し、不明なフィールドを破棄しない形でクライアントを実装します。
階層をまたいで同じパターンを複製する
同じルールをEnterprise、Organization、Repositoryへそれぞれ登録すると、どの階層の定義が正本なのか分からなくなります。
基本方針は次のようにします。
- 全体共通ルールはEnterprise
- Organization固有ルールはOrganization
- Repository固有の例外だけRepository
Enterprise endpointの認証制約や作成者制約が運用に合わない場合は、Organization階層へ展開する設計も選択肢になります。その場合も、定義ファイルは1か所に集約し、Organizationごとのコピーを手動管理しないことが重要です。
安全に導入するための実践手順
最初から全Organizationへ展開するのではなく、次の順序で導入します。
対象階層と認証方法を決める
共通ルールならEnterprise、部門別ならOrganization、例外ならRepositoryを基本にします。
Enterpriseを選ぶ場合はclassic PATと作成者制約、OrganizationやRepositoryを選ぶ場合はGitHub Appの権限設計を確認します。
既存パターンをすべて取得する
GETを使用し、ページネーションを処理して全件を取得します。既存のpattern ID、状態、定義をバックアップします。
desired stateファイルを作る
Gitで管理するYAMLまたはJSONへ、パターン、適用対象、削除後のアラート処理方針を記録します。
planモードを実行する
作成・更新・削除の予定を確認します。削除が含まれる場合は、自動適用せずレビューを必須にします。
小規模な対象へapplyする
最初は検証用OrganizationまたはRepositoryへ適用します。APIが成功したことだけでなく、GitHub UIにunpublishedのパターンが表示されることも確認します。
GitHub UIでdry runする
実データへの一致件数と誤検知を確認します。パターン本体だけでなく、delimiterや除外条件も調整します。
publish後にAPIで再確認する
state=publishedで一覧を取得し、期待した対象に公開済みパターンが存在することを確認します。
対象を段階的に拡大する
検証用Repository、単一Organization、複数Organizationの順に展開します。各段階でdry run結果とアラート件数を確認し、一括展開による大量誤検知を防ぎます。
REST APIとUIを分担することが一括管理の要点
GitHub secret scanningのcustom patternは、REST APIによって多数のEnterprise、Organization、Repositoryへ配布・更新・削除できるようになりました。特に、POSTによる複数作成、PATCHによるバージョン管理付き更新、DELETEによる複数削除を組み合わせれば、Git管理された定義を各環境へ同期できます。
一方、APIはGitHubのdry runと最終publishを代替しません。完全無人化を目指すのではなく、次の役割分担にすることが重要です。
- REST APIで定義の取得、差分確認、作成、更新、削除を自動化する
- 独自のplanモードで変更内容をレビューする
- GitHub UIで実Repositoryに対するdry runを行う
- 誤検知を確認してからUIでpublishする
- publish後にREST APIで状態を再確認する
まずは1つのOrganizationまたは検証用Repositoryで、GET、POST、UIでのdry run、publish、GETによる再確認までを一巡させてください。その流れを自動化の標準手順として固めてから、対象OrganizationやRepositoryを増やすのが安全です。

コメント