GitHub ActionsのSHAピン留めを設定で強制する。何が止まるか、lockfileならタグのまま通せるかを試す

GitHub ActionsのSHAピン留めを設定で強制する。何が止まるか、lockfileならタグのまま通せるかを試す

GitHub ActionsのSHAピン留めは設定で強制できます。タグ参照のほか、composite actionの中のタグ参照でも止まりました。GAになったworkflow lockfileならタグのまま通ることを確かめ、フルSHAへの書き換えとの使い分けを整理します。
2026.11.02

どうも!オペ部の西村祐二です!

GitHub Actionsのアクションをactions/checkout@v7のようなタグではなく、完全なcommit SHA(以下、フルSHA)で固定する運用は、サプライチェーン対策としてよく勧められます。ただ、レビューで見落とすと、タグ参照が紛れ込んだまま残ります。GitHubには、フルSHAで固定していないアクションを設定で禁止する「Require actions to be pinned to a full-length commit SHA」というポリシーがあります。

この記事では、この設定を有効にしたとき、何が止まり、何が通るかを参照の書き方ごとに確かめます。止まったものをworkflow lockfileでタグのまま通せるかも試し、フルSHAへの書き換えとlockfileの使い分けを整理します。

確認したのは2026年11月2日です。環境は、Freeプランのアカウントに作ったプライベートリポジトリと、GitHubホストのubuntu-latestランナーです。次の条件は試していないため、この記事の結果からは判断できません。

  • OrganizationやEnterpriseでまとめて有効にした場合
  • 許可リスト(Allow select actions)や、lockfileを必須にするRequire lockfileポリシーとの組み合わせ
  • 別のリポジトリにある再利用ワークフローや、サードパーティのcomposite action
  • ジョブのcontainer:やservices:で指定するイメージ
  • push以外のイベントや、セルフホストランナー

先に結論:止まるもの、通るもの

強制を有効にした状態で、参照の書き方ごとにワークフローを1本ずつ動かした結果です。

書き方 例 結果
タグ actions/checkout@v7 止まる
ブランチ actions/checkout@main 止まる
短縮SHA actions/checkout@3d3c42e 止まる(強制しなくても使えない)
フルSHA actions/checkout@3d3c42e5…(40桁) 通る
同じリポジトリのアクション ./.github/actions/hello、$/.github/actions/hello 通る(対象外)
docker://のステップ docker://alpine:3.20 通る(対象外)
再利用ワークフローの呼び出し …/reusable.yml@v1 通る(対象外)
再利用ワークフローの中のタグ参照 呼ばれる側でactions/checkout@v7 止まる
フルSHAで固定したcomposite actionの中のタグ参照 中でactions/checkout@v7 止まる
lockfileでオンボードしたワークフロー actions/checkout@v7とcomposite actionの@v1をタグのまま 通る(composite actionの中のタグ参照も含む)

$/は、ワークフローと同じリポジトリの、実行中のコミットを指す参照です。オンボードは、gh actions-lockでワークフローの依存をlockfileに記録することを指します。

注意が必要なのは、composite actionと再利用ワークフローの中のタグ参照です。自分のワークフローをフルSHAで固定していても、ここにタグ参照があると止まります。一方、lockfileでオンボードしたワークフローは、タグのままでもcomposite actionの中まで通りました。これから始めるなら、lockfileを中心にして、この強制と組み合わせる形が良さそうです。使い分けは最後の節で整理します。

次の図は自作した概念図で、公式の構成図ではありません。表の結果を、強制のチェックがかかった場所ごとに整理しています。赤の箱はフルSHAが必要だった参照、灰色の点線の箱は対象外だった参照です。lockfileでオンボードしたワークフローは、緑の点線で囲んだ範囲をlockfileに記録したコミットで取得するため、タグのままでも通ります。

自作した、SHAピン留めの強制がかかる場所の概念図。ワークフローから4本の矢印が出ている。ステップのusesと、その先のcomposite actionの中のusesはフルSHAが必要。ジョブのusesで呼ぶ再利用ワークフローはタグで呼べるが、再利用ワークフローの中のusesはフルSHAが必要。同じリポジトリのアクション(./と$/)とdocker://のステップは対象外。lockfileでオンボードしたワークフローは、ステップのusesとcomposite actionの中のusesをlockfileに記録したコミットで取得し、タグのままでも通る

画面かAPIで有効にする

画面から有効にする

リポジトリの「Settings」→「Actions」→「General」を開くと、「Actions permissions」のラジオボタンの下にチェックボックスがあります。赤枠は追記です。

リポジトリのSettingsのActions、Generalの画面。Actions permissionsのラジオボタンの下にある「Require actions to be pinned to a full-length commit SHA」のチェックボックスが赤枠で囲まれ、オンになっている

Freeプランのアカウントのリポジトリでも、このチェックボックスがありました。Changelogによると、Actionsを無効にしている場合は表示されません。ドキュメントでは、Organizationなど上位のポリシーで上書きされている場合、リポジトリ側では変更できないことがあるとされています。

APIで有効にする

REST APIではsha_pinning_requiredで切り替えます。リポジトリ単位なら次のとおりです。今回はallowed_actionsも今の値(all)のまま指定しています。

gh api -X PUT repos/<owner>/<repo>/actions/permissions \
  -F enabled=true -f allowed_actions=all -F sha_pinning_required=true

設定後に取得すると、sha_pinning_requiredがtrueになっていました。

gh api repos/<owner>/<repo>/actions/permissions
{"enabled":true,"allowed_actions":"all","sha_pinning_required":true}

ドキュメントでは、Organization単位のPUT /orgs/{org}/actions/permissionsでも同じ項目を指定できるとされています(Organization単位では試していません)。

参照の書き方を1つずつ変えたワークフローで試す

検証用のリポジトリに、参照の書き方を1つずつ変えたワークフローを14本置きました。ステップのアクションを試すワークフローは、次のタグ参照の例からuses:の行を変えています。再利用ワークフローは、ジョブのuses:で呼んでいます。

.github/workflows/t01-tag.yml
name: t01-tag
on: [push, workflow_dispatch]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7

composite actionの中のタグ参照を試すため、中でactions/checkout@v7を使うcomposite actionも用意しました。./で参照すると強制の対象外になるため、ワークフローからは、ほかのリポジトリのアクションと同じowner/repo/path@SHAの形で、フルSHAを付けて参照します。

.github/actions/composite-tag/action.yml
name: composite-tag
description: Composite action that uses another action by tag
runs:
  using: composite
  steps:
    - uses: actions/checkout@v7
    - run: echo "inner checkout done"
      shell: bash
.github/workflows/t10-composite-inner-tag.yml
name: t10-composite-inner-tag
on: [push, workflow_dispatch]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: ynishimura/blog-verify-sha-pinning/.github/actions/composite-tag@b49117c7d7390c3bcda8b7321ae7b75b85686529

まず、t01〜t11の11本を強制を無効にしたまま動かし、短縮SHA以外はすべて成功することを確かめました。そのあと強制を有効にし、空コミットをpushして同じ11本を動かしています。再利用ワークフローの中のタグ参照(t12)と、lockfileでオンボードするワークフロー(t13、t14)は、強制を有効にした後に追加しました。

強制すると何が止まり、何が通るか

タグ・ブランチ・短縮SHAはジョブの準備段階で止まる

タグ、ブランチ、短縮SHAで参照したワークフローは、ジョブの「Set up job」で失敗しました。ジョブ自体は作成されますが、アクションのダウンロード情報を取得する段階で次のエラーになります。赤枠は追記です。

強制を有効にした後のt01-tag.ymlの実行画面。StatusはFailureで、Annotationsに「The action actions/checkout@v7 is not allowed in ynishimura/blog-verify-sha-pinning because all actions must be pinned to a full-length commit SHA.」というエラーが表示され、赤枠で囲まれている

##[error]The action actions/checkout@v7 is not allowed in ynishimura/blog-verify-sha-pinning because all actions must be pinned to a full-length commit SHA.

@mainと@3d3c42eも、参照部分が違うだけで同じ文面でした。

短縮SHAは、強制を無効にしていても失敗します。強制を有効にする前の実行では、フルSHAを使うよう求める次のエラーでした。

##[error]Unable to resolve action `actions/checkout@3d3c42e`, the provided ref `3d3c42e` is the shortened version of a commit SHA, which is not supported. Please use the full commit SHA `3d3c42e5aac5ba805825da76410c181273ba90b1` instead.

同じリポジトリのアクションとdocker://のステップは対象外

./.github/actions/helloのようなローカル参照と、$/参照のワークフローは、強制を有効にしても成功しました。$/は実行中のコミットに解決されるため、ログ上もフルSHAで取得されています。

Download action repository 'ynishimura/blog-verify-sha-pinning@c886d0f25fc872848150f0b5b2fdba2175fbc1a7' (SHA:c886d0f25fc872848150f0b5b2fdba2175fbc1a7)

ローカル参照については、強制を有効にすると止まるという報告が2025年8月にGitHub Community Discussion #170337へ寄せられています。同じスレッドには2025年11月3日に、修正されたようで、自分の組織ではSHAで固定せずにローカルのアクションを使えた、という利用者の返信が付いています。公式のChangelogでの告知は見つけられていません。2026年11月2日時点の今回の環境では、ローカル参照で止まることはありませんでした。

docker://alpine:3.20のように、イメージをタグで指定したdocker://のステップも成功しました。イメージを固定したい場合は、alpine:3.20@sha256:…のようにダイジェストを自分で指定する必要がありそうです(ダイジェストの指定は試していません)。

再利用ワークフローは呼べても、中のアクションで止まる

ジョブのuses:で再利用ワークフローを@v1のようにタグで呼ぶワークフローは成功しました。ドキュメントにも「Reusable workflows can still be referenced by tag.」とあります。

ただし、呼ばれる側の再利用ワークフローの中でactions/checkout@v7を使うと、呼び出し側のワークフローが失敗しました。エラーは呼ばれる側のジョブ(call / inner)で出ており、文面はタグ参照のときと同じです。今回は、呼ばれる側の再利用ワークフローも強制を有効にした同じリポジトリに置いています。別のリポジトリにある再利用ワークフローで、呼び出し側と呼ばれる側のどちらの設定で判定されるかは切り分けていません。

composite actionは中のタグ参照で止まる

composite actionをフルSHAで参照しても、中でactions/checkout@v7を使っていると失敗しました。ログを見ると、外側のcomposite actionはダウンロードできています。そのあと、中のアクションを解決する段階で止まっています。

Download action repository 'ynishimura/blog-verify-sha-pinning@b49117c7d7390c3bcda8b7321ae7b75b85686529' (SHA:b49117c7d7390c3bcda8b7321ae7b75b85686529)
Getting action download info
##[error]The action actions/checkout@v7 is not allowed in ynishimura/blog-verify-sha-pinning because all actions must be pinned to a full-length commit SHA.

対照として、中で別のアクションを使わないcomposite action(runステップだけ)をフルSHAで参照したワークフローは成功しました。このことから、止まった原因は中のタグ参照だと分かります。今回試したのは自分のリポジトリのcomposite actionですが、Zennの記事では、サードパーティのcomposite actionで止まった例が報告されています。

lockfileでタグのまま通す

workflow lockfileは、ワークフローが使うアクションと、その中で使われるアクションのコミットを.github/workflows/actions.lockに記録する仕組みです。2026年10月28日にGAになりました。ドキュメントには「Locked dependencies satisfy Require actions to be pinned to a full-length commit SHA without changes to the workflow file.」とあります。lockfileでオンボードしたワークフローなら、フルSHAに書き換えなくても強制の要件を満たすという意味です。lockfileの仕組みは以前の記事で試しています。

タグのままcomposite actionの中まで通った

actions/checkoutを@v7で、さきほどのcomposite actionを@v1で参照するワークフローを用意しました。どちらもタグ参照です。gh actions-lock v0.4.0(gh extension install github/gh-actions-lockで入れられます)で、このワークフローだけをオンボードします。

gh actions-lock .github/workflows/t14-locked-fresh.yml
Scanning 1 workflow
Planning pins
Pinned 2 actions across 1 workflow
  actions/checkout@v7 (3d3c42e)
    └─ .github/workflows/t14-locked-fresh.yml
  ynishimura/blog-verify-sha-pinning@v1 (b49117c)
    └─ .github/workflows/t14-locked-fresh.yml
1 action pinned without a full semver tag
  actions/checkout@v7 → latest: v7.0.1
    .github/workflows/t14-locked-fresh.yml
  Update the uses: line in your workflow to the full version to lock precisely.

今回のワークフローでは、@v7は書き換えられず、そのままlockfileに記録されました。代わりに、完全なバージョンのタグ(@v7.0.1)に書き換えるよう勧める警告が出ています。

ただし、これはv0.4.0がいつも@v7のまま残すという意味ではありません。READMEによると、@v7のような部分的なバージョンは完全なタグに絞り込まれ、--no-narrowを付けると書いたまま残ります。今回残ったのは、composite actionの中でも同じactions/checkout@v7を使っているためです。gh actions-lockのソースには、composite actionが宣言している参照は書き換えずに残す処理があります。

lockfileには、composite actionのエントリのusesとして、中で使うactions/checkout@v7も記録されています。次は最終的なlockfileから、t14に関係する部分だけを抜き出したものです。actions/checkout@v7のエントリは、後述のt13を作り直したときに追加されていたもので、t14のオンボードで増えたのはworkflowsの部分です。自分のリポジトリのIDは伏せています。

.github/workflows/actions.lock(抜粋)
workflows:
    '.github/workflows/t14-locked-fresh.yml':
        - 'actions/checkout@v7'
        - 'ynishimura/blog-verify-sha-pinning@v1'
dependencies:
    'actions/checkout@v7':
        ref: 'v7'
        commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1'
        owner_id: 44036562
        repo_id: 197814629
    'ynishimura/blog-verify-sha-pinning@v1':
        ref: 'v1'
        commit: 'sha1-b49117c7d7390c3bcda8b7321ae7b75b85686529'
        owner_id: <owner_id>
        repo_id: <repo_id>
        uses:
            - 'actions/checkout@v7'

強制を有効にしたままpushすると、このワークフローは成功しました。ログでは、lockfileを使う旨のメッセージに続いて、2つのアクションがlockfileに記録したコミットで取得されています。composite actionの中のactions/checkout@v7はワークフローから直接参照するものと同じ参照で、ダウンロードの行は1回だけでした。

Using locked action versions from the workflow's lockfile
Download action repository 'actions/checkout@v7' (SHA:3d3c42e5aac5ba805825da76410c181273ba90b1)
Download action repository 'ynishimura/blog-verify-sha-pinning@v1' (SHA:b49117c7d7390c3bcda8b7321ae7b75b85686529)

同じpushで動いた、オンボードしていないワークフローは失敗のままです。タグ参照のワークフロー(t01)と、同じcomposite actionをフルSHAで参照するワークフロー(t10)がそうです。ドキュメントにも「Dependencies that aren't in the lockfile still need a full-length SHA.」とあります。

v0.2.0で作ったlockfileは作り直す

最初はgh actions-lock v0.2.0でオンボードしていました(t13)。v0.2.0は、composite actionが同じ参照を使っていてもワークフローの@v7を@v7.0.1に書き換え、composite actionの中のactions/checkout@v7までactions/checkout@v7.0.1として記録しました。このlockfileでは、ワークフローは実行時に次のエラーで失敗しました。

Using locked action versions from the workflow's lockfile
##[error]lockfile missing pin for actions/checkout@v7

composite actionの中には@v7と書かれているのに、lockfileには@v7.0.1しかないため、照合できなかったと読めます。強制のエラーとは文面が違い、オンボードしたワークフローの依存がlockfileにそろっていないことによる失敗です(強制を無効にした状態では試していません)。v0.4.0に上げてgh actions-lock --verifyを実行すると、このlockfileはincomplete-lockfileとして検出されました。引数を付けずに実行したため、オンボードしていないほかのワークフローのエラーも出ましたが、t13に関係する部分は次のとおりです。

✗ Lockfile doesn't match locked manifest actions/checkout@v7
  ynishimura/blog-verify-sha-pinning/.github/actions/composite-tag@v1 at locked commit b49117c7d739 uses actions/checkout@v7, but its lockfile entry ynishimura/blog-verify-sha-pinning@v1 does not record it
  ! restore the edge from version control, or run `gh actions-lock --relock`
  see: https://github.com/github/gh-actions-lock/blob/main/docs/troubleshooting.md#incomplete-lockfile

v0.3.0のリリースノートにも、古いlockfileは--verifyでincomplete-lockfileになることがあると書かれています。直し方はgh actions-lock --relockです。実際に作り直すと、t13も強制を有効にしたまま成功しました。v0.2.0のころに作ったlockfileは、gh extension upgrade actions-lockで最新にしてから--verifyを実行し、incomplete-lockfileが出たら--relockで作り直すことにしました。

有効にする前に確かめたいことと使い分け

この設定は、違反したワークフローを止めるだけです。フルSHAへの書き換えや、新しいリリースへの更新はしません。書き換えと更新には、pinactやRenovateなどのツールが別に必要です。

今回の結果を踏まえると、有効にする前に次の2点を確かめておく必要がありそうです。

  1. 使っているcomposite actionと再利用ワークフローの中にタグ参照がないか
    • タグ参照があるcomposite actionは、lockfileでオンボードするか、上流の修正を待つことになります
    • 再利用ワークフローの中については、Locking action dependenciesでは、呼び出し側ではなく、呼ばれる側のリポジトリのlockfileが対象になるとされています。呼ばれる側のリポジトリでオンボードして通るかは試していません
  2. Freeプランでは、違反を記録するだけの段階がないこと
    • Freeプランのリポジトリの設定画面では、チェックボックスが1つあるだけでした。有効にした時点から、該当するワークフローは失敗します

フルSHAに書き換えるか、lockfileを使うか

止まったワークフローを通す方法は、フルSHAに書き換えるか、lockfileでオンボードするかの2つです。今回の結果から、違いを自分なりに整理しました。

観点 フルSHAに書き換える lockfileでオンボードする
composite actionの中のタグ参照 自分で管理していないものは直せない lockfileに記録され、通った(試したのは自分のcomposite action)
ワークフローの見た目 SHAが並ぶ(タグはコメントで残す) タグのまま
使うツール pinactやRenovateなど gh actions-lock(まだ0.x系)
ワークフローを追加したとき 書き換えツールを通す 自分でオンボードする

Dependabotの扱いについては、Locking action dependenciesに「Dependabot only updates lockfile entries for workflows that are already onboarded.」とあります。新しいワークフローのオンボードは、自動ではされません。

lockfileは2026年10月28日にGAになり、lockfileを必須にするRequire lockfileポリシーもGAに含まれています。これから始めるなら、lockfileを中心にして、SHAピン留めの強制と組み合わせるのが良さそうです。ドキュメントでは、lockfileは推移的な依存までコミットで固定するとされていて、自分で管理していないcomposite actionの中も対象になります。強制と組み合わせれば、オンボードし忘れたタグ参照のワークフローも止まります。すべてのワークフローをオンボードし終えたら、Require lockfileポリシーに切り替える形も考えられます(今回は試していません)。

一方、gh actions-lockはまだ0.x系で、v0.3.0では動作が変わりました。すでにpinactやRenovateでフルSHAへの固定を運用しているリポジトリは、それを続けながら、ワークフロー単位でlockfileへ移していくのが無理がないと考えています。

まとめ

「Require actions to be pinned to a full-length commit SHA」を有効にすると、タグ、ブランチ、短縮SHAで参照したアクションはジョブの準備段階で止まります。composite actionや再利用ワークフローの中にタグ参照があっても、同じエラーで失敗しました。一方、同じリポジトリのアクション、再利用ワークフローの呼び出し、docker://のステップは対象外でした。

lockfileでオンボードしたワークフローは、タグのままでもcomposite actionの中まで強制の要件を満たしました。v0.2.0で作ったlockfileは作り直しが必要でしたが、lockfileがGAになった今は、lockfileを中心に強制と組み合わせる形を選ぼうと思います。

誰かの参考になれば幸いです。


参考リンク:

この記事をシェアする

関連記事