GitHub Actionsのworkflow lockfileを試す。actions.lockで依存をcommitに固定し、ズレたら実行前に止める

GitHub Actionsのworkflow lockfileを試す。actions.lockで依存をcommitに固定し、ズレたら実行前に止める

GitHub Actionsのworkflow lockfileを試しました。gh actions-lockでactions.lockを生成し、推移的依存の記録、未更新時の実行停止、タグが動いても固定commitで動くことを確かめます。GAとv0.4.0に合わせて更新しました。
2026.10.16

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

GitHub Actionsで使うアクションは、GitHubのドキュメントや各アクションのREADMEではactions/checkout@v5のようにタグで参照する形で書かれています。ただし、タグは後から動かせるため、レビューしたときと違うコードがCIで動く余地が残ります。この対策として「完全なcommit SHAで固定する」運用がありますが、ワークフローが読みにくくなります。さらに、アクションが内部で呼ぶ別のアクション(推移的依存)までは固定できません。

workflow dependency lockfilesは、ワークフローの依存をlockfileで固定する仕組みです。npmやpnpmのlockfileと同じ発想で、.github/workflows/actions.lockに各アクションのcommitを記録しておき、実行時はその記録どおりのcommitが使われます。2026年10月14日にパブリックプレビュー、10月28日にGAになりました。

この記事では、Freeプランのアカウントで次の3点を確かめます。

  • gh actions-lockで何が生成され、ワークフローはどう書き換わるか
  • lockfileを更新せずにアクションを追加すると、何が起きるか
  • 参照先のタグが動いたとき、実行されるcommitはどうなるか

Require lockfileポリシー、Dependabotによるlockfileの更新は、この記事では扱わず、追記で紹介した記事で試しています。reusable workflowの呼び出しは、lockfileの対象外です(次の節)。

対象と提供状況

  • 提供状況: 2026年10月14日にパブリックプレビュー、2026年10月28日にGA
  • 対象: GAのChangelogでは、GitHub Enterprise Cloud、GitHub Enterprise Cloud with data residency、Team、Freeが対象です。GitHub Enterprise Serverは、gh actions-lockのREADMEで非対応とされています
  • lockfileの場所: .github/workflows/actions.lock。GitHub CLIの拡張gh actions-lockが生成・更新し、手で編集しない前提です
  • 記録される内容: 直接参照しているアクションと、推移的依存のcommit(詳細は次の節)。ドキュメントによると、reusable workflowの呼び出し(jobs.<job_id>.uses)は固定されないので、固定したい場合は完全なcommit SHAで参照します
  • オンボードはワークフロー単位: ワークフローをlockfileの管理対象に入れることをオンボードと呼びます。オンボードしたワークフローでは、使う依存すべてにlockfileのエントリが必要になります。Actionsは記録されたcommitを実行します
  • 周辺機能: Dependabotがアクションのバージョン更新PRで該当するlockfileエントリも更新します。lockfileを必須にするRequire lockfileポリシーもあります

actions.lockは何を記録し、SHA固定と何が違うか

公式ドキュメントによると、lockfileはworkflowsとdependenciesの2つのセクションを持ちます。workflowsはオンボードしたワークフローごとに使っている依存の一覧、dependenciesは参照ごとの解決結果です。各依存には次の項目が記録されます。

項目 内容
ref ワークフローが参照しているタグまたはブランチ
commit その参照を解決したcommit SHA
owner_id 参照先リポジトリの所有者の数値ID
repo_id 参照先リポジトリの数値ID。owner_idとともに実行時にGitHub Actionsが照合します

推移的依存を持つ依存には、呼び出している依存の一覧もuses:として付きます。

SHA固定との違いは2つあります。1つは推移的依存まで固定されることです。composite actionが内部でuses:しているアクションもdependenciesに入り、親子関係が記録されます。もう1つはリポジトリの識別子が残ることです。公式ドキュメントでは、GitHub Actionsが実行時にowner_idとrepo_idを使って、名前の裏にあるリポジトリが固定したときと同じかを確かめるとされています。公式ドキュメントは、lockfileを使うリポジトリではワークフロー内のSHA固定は不要になるとしています。

試してみる

環境

  • 2026年10月16日: macOS 26.6.1、GitHub CLI 2.101.0、gh actions-lock v0.2.0。Freeプランのアカウントに作った検証用リポジトリで、GitHub Actionsの実行まで確認(検証用リポジトリは現在は削除済み)
  • 2026年11月2日: macOS 26.7.2、GitHub CLI 2.103.2、gh actions-lock v0.4.0(2026年11月2日時点の最新)。手元のフォルダで同じ構成をオンボードし直し、gh actions-lockの出力と書き換えを確認。実行画面は、同じ日に別の記事で使った検証用リポジトリのもの

拡張は次のコマンドでインストールできます。すでに入れている場合はgh extension upgrade actions-lockで更新します。

gh extension install github/gh-actions-lock
gh actions-lock --version

1. 導入前のワークフロー

比較の起点として、タグ参照のアクション3つとローカルのcomposite action1つを使うワークフローを用意しました。aquasecurity/trivy-actionは内部で別のアクションを呼ぶcomposite actionなので、推移的依存の確認に使います。

.github/workflows/ci.yml
name: ci
on:
  push:
    branches: [main]
  workflow_dispatch:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 24
      - run: node --version
      - uses: ./.github/actions/hello
      - uses: aquasecurity/trivy-action@v0.36.0
        with:
          scan-type: fs
          scan-ref: .
          exit-code: 0

2026年10月16日にこの状態でpushすると、実行は成功し、ログの「Set up job」にはタグを解決した結果が出ました。setup-trivyがさらに呼ぶactions/cacheとactions/checkoutの2行は省略しています。

Download action repository 'actions/checkout@v5' (SHA:fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09)
Download action repository 'actions/setup-node@v5' (SHA:a0853c24544627f65ddf259abe73b1d18a591444)
Download action repository 'aquasecurity/trivy-action@v0.36.0' (SHA:ed142fd0673e97e23eac54620cfb913e5ce36c25)
Download action repository 'aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514' (SHA:3fb12ec12f41e471780db15c232d5dd185dcb514)
Download action repository 'actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae' (SHA:27d5ce7f107fe9357f9df03efb73ab90386fccae)

trivy-actionの内側でsetup-trivyとactions/cacheが取得されています。ワークフローには書いていない推移的依存で、setup-trivyの分も含めると4つあります。

2. lockfileを生成する

リポジトリのルートで引数なしで実行すると、.github/workflows/以下のワークフローをすべて走査します。

gh actions-lock

次はv0.4.0での出力です。赤枠は追記です。

gh actions-lock v0.4.0の出力。冒頭の「Cannot follow 1 workspace-local action」の警告が赤枠で囲まれ、続いて直接依存3つと推移的依存4つを固定したと表示されている

直接依存3つに加えて、推移的依存4つ(trivy-actionからsetup-trivyとactions/cache、setup-trivyからactions/cacheとactions/checkout)が固定されました。ここはv0.2.0と同じです。変更はlockfileの追加だけではなく、ワークフロー本体にも入ります。生成後はワークフロー側のdiffも含めて確認してからcommitします。

.github/workflows/ci.yml
-      - uses: actions/checkout@v5
-      - uses: actions/setup-node@v5
+      - uses: actions/checkout@v5.1.0
+      - uses: actions/setup-node@v5.0.0
         with:
           node-version: 24
       - run: node --version
       - uses: ./.github/actions/hello
       - uses: aquasecurity/trivy-action@v0.36.0

@v5のようなメジャーバージョンだけの参照は、解決したcommitを指す完全なタグ(@v5.1.0)に書き換わります。完全なバージョンタグは公開後に動くことがほとんどないため、固定したSHAが有効な期間を長くする狙いだとgh actions-lock --helpの説明に書かれています。@v0.36.0のように最初から完全なタグはそのままです。--no-narrowで無効にできます。

一方、ローカルのアクション./.github/actions/helloは書き換えられず、出力の冒頭に「Cannot follow 1 workspace-local action」という警告が出ました。2026年10月16日のv0.2.0では、これが自動で$/.github/actions/helloに書き換わっていました。v0.3.0のリリースノートで、./のアクションはたどらないことになり、ドキュメントでも、書き換えるのは--migrate-local-actionsを付けたときだけとされています。また、リモートのアクションを使う./のアクションがあると、デフォルトではエラーで止まります(--ignore-local-actionsで警告に変えられます)。

--migrate-local-actionsを付けて実行すると、v0.2.0と同じく$/に書き換わりました。

gh actions-lock --migrate-local-actions
.github/workflows/ci.yml
-      - uses: ./.github/actions/hello
+      - uses: $/.github/actions/hello

$/は「このワークフローと同じリポジトリの、実行中のcommit」を指す参照で、常に実行中のSHAに解決されるため、lockfileのエントリは要りません。ドキュメントでは、ほかのアクションを使わない./のアクション(今回のhelloのようにrun:だけのもの)なら、./のままでもワークフローはそのまま動くとされています。./のままでの実行は試していません。推奨されているのは--migrate-local-actionsでの書き換えなので、警告が出たら書き換えておくのが良さそうです。

生成されたactions.lockは次のとおりです。actions/setup-node@v5.0.0と、setup-trivy配下のactions/cache・actions/checkoutの3エントリは省略しています。v0.2.0とv0.4.0で、記録されたcommitと構造は同じでした。

.github/workflows/actions.lock
# This file is machine-generated by `gh actions-lock`.
# Do not edit by hand; run `gh actions-lock` to update.
# Docs: https://gh.io/actions-lockfile
version: 'v0.0.3'
workflows:
    '.github/workflows/ci.yml':
        - 'actions/checkout@v5.1.0'
        - 'actions/setup-node@v5.0.0'
        - 'aquasecurity/trivy-action@v0.36.0'
dependencies:
    'actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae':
        ref: 'v5.0.5'
        commit: 'sha1-27d5ce7f107fe9357f9df03efb73ab90386fccae'
        owner_id: 44036562
        repo_id: 215566462
    'actions/checkout@v5.1.0':
        ref: 'v5.1.0'
        commit: 'sha1-fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09'
        owner_id: 44036562
        repo_id: 197814629
    'aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514':
        ref: 'v0.2.6'
        commit: 'sha1-3fb12ec12f41e471780db15c232d5dd185dcb514'
        owner_id: 12783832
        repo_id: 869952525
        uses:
            - 'actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb'
            - 'actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8'
    'aquasecurity/trivy-action@v0.36.0':
        ref: 'v0.36.0'
        commit: 'sha1-ed142fd0673e97e23eac54620cfb913e5ce36c25'
        owner_id: 12783832
        repo_id: 268833180
        uses:
            - 'actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae'
            - 'aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514'

trivy-actionのエントリにuses:としてsetup-trivyとactions/cacheが並び、setup-trivyのエントリにはさらにその依存が続きます。推移的依存はSHAで参照されていても、refにv5.0.5のような元のタグ名が残るので、何のバージョンが使われているかをlockfileだけで追えます。

2026年10月16日にこの変更をcommitしてpushすると、実行は成功しました。「Set up job」の取得ログでは、actions/checkout@v5.1.0のようにタグ名が変わった以外、SHAは導入前と同じでした。$/にしたローカルのアクションは、<owner>/<repo>@<実行中のcommit>として取得されていました。

3. lockfileを更新せずにアクションを追加する

2026年10月16日に、オンボード後のワークフローで、lockfileを更新しないままactions/cache@v4のステップを足してpushしました。

.github/workflows/ci.yml
      - run: node --version
      - uses: actions/cache@v4
        with:
          path: ~/.npm
          key: npm-${{ runner.os }}

結果はジョブが1つも始まらないstartup_failureでした。次は、2026年11月2日に別の記事の検証用リポジトリで、同じくactions/cache@v4をlockfileに入れずに足した実行の画面です。赤枠は追記です。

lockfileを更新せずにactions/cache@v4を足した実行の画面。StatusがStartup failureで、Annotationsに「Invalid lockfile: .github/workflows/actions.lock#L1」と「The lockfile is missing . Regenerate it by running .」が表示され、どちらも赤枠で囲まれている

注釈では、lockfileに足りない参照(actions/cache@v4)が名指しされ、gh actions-lockで作り直すよう案内されています。2026年10月16日の時点では「The lockfile could not be validated.」という文面で、足りない参照までは示されていませんでした。どちらの場合も、固定し忘れたアクションが混ざったワークフローは、ジョブが始まる前に止まります。

同じ状態は手元でも検出できます。--verifyは何も書き換えずに検査するモードです。

gh actions-lock --verify

gh actions-lock --verify v0.4.0の出力。「1 of 1 workflow failed」に続いて、actions/cache@v4がlockfileに固定されていないとして失敗する

「Not pinned actions/cache@v4」に続けて、ワークフローで使われているのにlockfileに固定されていない旨が出ます。ネットワークを使わない--verify-localも「1 of 1 workflow failed: 1 not-pinned」と失敗しました。こちらは各参照にエントリがあるかだけを見るので、エントリの中身が正しいかを確認するには--verifyを使う必要があります。

修正はワークフローを指定して再実行するだけです。

gh actions-lock .github/workflows/ci.yml
gh actions-lock --verify

v0.4.0でも、actions/cache@v4が@v4.3.0に書き換わり、lockfileにエントリが1つ追加され、--verifyは「All 1 workflow valid」になりました。2026年10月16日にpushした実行も成功し、取得ログはactions/cache@v4.3.0 (SHA:0057852b...)でした。

4. 参照先のタグが動いたとき

この節は2026年10月16日にv0.2.0で試した結果です。検証用リポジトリを削除したため、v0.4.0では確かめ直していません。

lockfileの本来の目的は「タグが動いても、固定したcommitを実行する」ことです。他人のリポジトリのタグは動かせないので、検証用リポジトリ自身のcomposite actionをowner/repo/path@v1の形でリモート参照するステップを追加し、タグv1を自分で動かしました。

.github/workflows/ci.yml
      - uses: <owner>/<repo>/.github/actions/hello@v1

手順は次のとおりです。

  1. タグv1を打ち、ワークフローに上のuses:を追加してgh actions-lockでロックする。lockfileのcommitは607ea0a
  2. 別のcommitをpushし、v1をそのcommit(24c8add)へgit push -fで移動する
  3. lockfileは更新せずに、workflow_dispatchでワークフローを実行する

実行ログは次のようになりました(リポジトリ名は伏せています)。

Download action repository '<owner>/<repo>@v1' (SHA:607ea0a6f16c076321a582ebb583afa0d3eac3ee)

リモートのv1は24c8addを指していますが、実行されたのはlockfileに記録された607ea0aです。タグが動いただけでは実行内容は変わりません。

このとき、手元のgh actions-lock --verifyと引数なしのgh actions-lockはどちらも「All 1 workflow valid」で、ファイルは変わりませんでした。v0.2.0のリリースノートにあるとおり、固定済みのピンは「sticky」で、通常のgh actions-lock実行では再解決されません。現行のドキュメントでは、参照の種類で扱いが分かれます。mainやv3のようなブランチや部分バージョンは、固定したcommitのままref-movedの警告が出ます。v3.1.0のような完全なバージョンタグが動いた場合はエラーになり、--relockかuses:の変更が必要です。今回のv1は前者に当たりますが、v0.4.0では確かめていません。

新しいcommitに追従したい場合は--relockを使います。

gh actions-lock --relock

lockfileのcommitが607ea0aから24c8addに変わるdiffが出ました。force pushなどで固定したcommitが参照の履歴から消えた場合は、--relockでは直りません。ドキュメントでは、上流の履歴を確認したうえでgh actions-lock --accept-movedを実行し、自動化では使わないようにとされています。その状況は試していません。

運用に組み込むときの要点

実測した範囲と公式ドキュメントから、運用の形は次のようになりそうです。CI、Dependabot、Require lockfileを実際に組み合わせた結果は、GA後の運用を試した記事にまとめています。

  • PRでlockfileを検証する: PRでgh actions-lock --verifyを実行するジョブを置き、lockfileが古ければ失敗させます。gh actions-lockのリポジトリに公式サンプルのverify-lockfile.ymlがありますが、2026年11月2日時点ではgh actions-lockをv0.2.0に固定しているので、バージョンを上げて使うのが良さそうです
  • lockfileのdiffをレビューする: commitの変化は別のコードが動くことを意味するので、依存のバージョン更新と同じ扱いでレビューします。owner_idやrepo_idの変化はリポジトリの置き換わりを意味するので、マージ前に調べます
  • 更新のタイミング: uses:を足したり外したりしたときにgh actions-lockを再実行します。タグの移動に追従したいときは--relockです。Dependabotは、オンボード済みワークフローのバージョン更新PRで、該当するlockfileエントリも一緒に更新します。新しいワークフローのオンボードは行わないので、自分で実行します
  • lockfileを必須にする: 「Settings」→「Actions」→「Policies」の「Require lockfile」で、オンボードしていないワークフローの実行をブロックできます。ドキュメントでは、使えるのはパブリックリポジトリと、GitHub TeamかGitHub Enterpriseのプライベートリポジトリとされています。結果だけを記録する「Evaluate」はGitHub Enterprise Cloudのみです

導入時の注意点

  • 拡張はまだ0.x: lockfile自体はGAになりましたが、gh actions-lockは2026年11月2日時点でv0.4.0です。v0.3.0では、ローカルのアクションの扱いや--verifyの判定が変わりました。v0.2.0で作ったlockfileは--verifyでincomplete-lockfileになることがあり、その場合はgh actions-lock --relockで作り直します。また、完全なSHAで書いた参照を、フォークにしかないcommit(impostor commit)に固定することを拒否するようになりました
  • allowlistとの相性: 公式ドキュメントによると、オンボード後のallowlist(Allow select actions)は固定したcommit SHAに対して照合されるため、actions/checkout@v5のようにタグで書いた許可エントリは一致しなくなります。ワイルドカードか完全なcommit SHAに直す必要があるとされています。今回は試していません
  • ローカルのアクションの扱い: v0.4.0では、./のアクションは書き換えずに警告を出します。$/に書き換えるには--migrate-local-actionsを付けます。リモートのアクションを使う./のアクションがあると、デフォルトではエラーで止まります
  • エラーがあれば書き込まない: v0.3.0のリリースノートによると、自分の--verifyで通らないlockfileは書き込まれません。v0.2.0のREADMEでは、解決できない参照が1つでもあると、他のワークフローの分も含めて何も書き込まないと説明されていました。参照先のタグやcommitが存在しないときは、先にワークフロー側を直す必要があります

まとめ

GitHub Actionsのworkflow lockfileは、gh actions-lockで.github/workflows/actions.lockを生成し、直接依存と推移的依存のcommitとリポジトリIDを記録する仕組みでした。オンボードしたワークフローがlockfileにないアクションを使っていると、ジョブが始まる前にstartup_failureで止まり、手元でも--verifyで同じ状態を検出できます。参照先のタグが動いても実行されるのは固定したcommitのままで、追従したいときだけ--relockで更新します。

GAになった今も、gh actions-lockの動作はバージョンで変わっています。v0.4.0では、ローカルのアクションを$/に書き換えるには--migrate-local-actionsが要ります。v0.2.0のころに作ったlockfileは--verifyで確かめて、必要なら--relockで作り直すのが良さそうです。SHA固定を手で管理している場合は、推移的依存まで固定でき、ワークフローもタグ名のまま読めるので、lockfileに置き換える価値があります。

参考リンク:

この記事をシェアする

関連記事