Repository navigation
Docs: adoption guides for repository and enterprise lockfile rollout #136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2453893
98935c4
7641e52
711b513
ac3962a
b7b7bfb
5658b31
e3b6f54
2466833
7c8f0e4
7f590f3
69f80d1
6639a0d
40f4154
eabf882
d3b2885
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| # Dependabot and the Actions lockfile | ||
|
|
||
| Dependabot updates action references in workflow YAML and invokes the CLI to | ||
| regenerate the corresponding lockfile entries in the same pull request. | ||
|
|
||
| > [!NOTE] | ||
| > gh-actions-lock is in public preview. Flags, findings JSON, and lockfile | ||
| > schema may change between releases, and Dependabot pins a specific CLI version | ||
| > and lockfile schema. See [RELEASING.md](../RELEASING.md). | ||
|
|
||
| ## Lockfile updates | ||
|
|
||
| When Dependabot opens a version update for a GitHub Actions dependency in a | ||
| workflow that is **already onboarded** to lockfile pinning, it also regenerates | ||
| the corresponding lockfile entry, so the pinned commit SHA always matches the | ||
| updated ref in your workflow YAML. | ||
|
|
||
| The two tools have separate responsibilities: | ||
|
|
||
| - **Dependabot owns the workflow YAML.** It decides the new ref, exactly as it | ||
| does today. | ||
| - **The `gh-actions-lock` CLI owns the lockfile, exclusively.** Dependabot | ||
| invokes the CLI rather than writing lockfile entries itself, so pinning has a | ||
| single implementation. | ||
|
|
||
| If you already use Dependabot for GitHub Actions and you have onboarded | ||
| workflows, this needs no configuration. | ||
|
|
||
| ## Onboarding | ||
|
|
||
| Dependabot invokes the CLI with `--no-onboard`, which refuses to add lockfile | ||
| entries for workflows or actions that do not already have them. A dependency | ||
| Dependabot bumps in a workflow you never locked produces a non-blocking | ||
| `onboarding-required` finding and no lockfile write: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't surfaced to the user from the Dependabot flow. Silently skipped. The user would see this if they inspected output locally. |
||
|
|
||
| ```json | ||
| { | ||
| "category": "onboarding-required", | ||
| "severity": "info", | ||
| "detail": "actions/checkout@v6 has no lockfile entry; --no-onboard refuses to add new workflows or actions" | ||
| } | ||
| ``` | ||
|
|
||
| Onboard workflows with the CLI before relying on Dependabot to maintain their | ||
| lockfile entries: | ||
|
|
||
| ```bash | ||
| gh actions-lock | ||
| ``` | ||
|
|
||
| Dependabot also passes `--no-narrow`, so the CLI does not rewrite the ref | ||
| Dependabot just chose. Dependabot picked `v7`; the lockfile records `v7` and its | ||
| commit, and the YAML is left alone. | ||
|
|
||
| ## Reading the update | ||
|
|
||
| A Dependabot pull request touching an onboarded workflow changes two files. The | ||
| lockfile diff is the security-relevant half: | ||
|
|
||
| ```diff | ||
| workflows: | ||
| '.github/workflows/ci.yml': | ||
| - - 'actions/checkout@v6.1.0' | ||
| + - 'actions/checkout@v7' | ||
| dependencies: | ||
| - 'actions/checkout@v6.1.0': | ||
| - ref: 'v6.1.0' | ||
| - commit: 'sha1-d23441a48e516b6c34aea4fa41551a30e30af803' | ||
| + 'actions/checkout@v7': | ||
| + ref: 'v7' | ||
| + commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1' | ||
| owner_id: 44036562 | ||
| repo_id: 197814629 | ||
| ``` | ||
|
|
||
| Review the changed commit SHA the way you would review any dependency change. A | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. repo_id move suggests a transfer, owner_id change suggests namespace squatting attack. The CLI isn't aware of the transfers being okay yet. There's a draft PR that I'm getting to for that here #118 but owner_id change will raise a message to the operator as this is really something that should not happen ever. This will also continue to fail at runtime, whereas repo transfers will not fail. |
||
| moved `owner_id` or `repo_id` is a stronger signal still: it means the | ||
| repository behind that name is not the one you locked. | ||
|
|
||
| Review it, but do not edit it. The lockfile is generated, and the CLI is the | ||
| only thing that writes it. If a Dependabot pull request's lockfile looks wrong, | ||
| close it or fix the workflow and let the lockfile be regenerated. | ||
|
|
||
| ## Cooldowns | ||
|
|
||
| Dependabot's [`cooldown` | ||
| option](https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference#cooldown) | ||
| delays updates until a release has had time to settle. | ||
|
|
||
| ```yaml | ||
| # .github/dependabot.yml | ||
| version: 2 | ||
| updates: | ||
| - package-ecosystem: "github-actions" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" | ||
| cooldown: | ||
| default-days: 7 | ||
| ``` | ||
|
|
||
| `gh actions-lock` reads this file too, so one setting governs both tools. | ||
|
|
||
| ### What the CLI actually uses it for | ||
|
|
||
| Cooldown does **not** hold back ref narrowing. When the CLI narrows | ||
| `actions/checkout@v6` to `v6.1.0`, it only considers tags that already point at | ||
| the commit `v6` resolves to. Narrowing renames the commit you already have; it | ||
| never moves you to a newer release. There is nothing for a cooldown to delay. | ||
|
|
||
| What cooldown does control: | ||
|
|
||
| - **The fresh-tag nudge.** With no cooldown configured, pinning a tag released | ||
| within the last 3 days emits an informational finding suggesting you configure | ||
| one. Any positive cooldown skips that check for the action. | ||
| - **The interactive tag picker**, which hides tags younger than the cooldown | ||
| unless one matches your current pin. | ||
|
|
||
| Precedence is Dependabot config first, then | ||
| `~/.config/gh-actions-lock/config.yml`. A Dependabot `default-days: 0` does not | ||
| count as configured, so it cannot silently downgrade a stricter setting in your | ||
| own config file. | ||
|
|
||
| ### Only `default-days` is honored today | ||
|
|
||
| The CLI parses the rest of the cooldown block and reports the keys it ignores: | ||
|
|
||
| ``` | ||
| Dependabot cooldown semver-major/minor/patch-days are not supported and were ignored | ||
| Dependabot cooldown include/exclude filters are not supported and were ignored | ||
| ``` | ||
|
|
||
| These are non-blocking `cooldown-config-ignored` findings. Dependabot still | ||
| honors those keys for its own scheduling — the gap is only in what the CLI reads | ||
| when deciding whether to nudge you about a fresh tag. | ||
|
|
||
| ## Automation interaction | ||
|
|
||
| If you also run the [lockfile automation | ||
| workflow](./repository-developer-experience.md), its `verify` job checks | ||
| Dependabot's pull requests like any other. When the lockfile entry is present | ||
| and correct, the check passes and nothing else happens. | ||
|
|
||
| The `update` job needs more thought. It only runs on `push` to a branch in your | ||
| repository, and Dependabot branches live in your repository, so a Dependabot | ||
| pull request whose lockfile is stale gets a bot commit fixing it. That means a | ||
| Dependabot pull request can gain a second commit. To prevent that, scope the | ||
| update job away from Dependabot branches: | ||
|
|
||
| ```yaml | ||
| if: github.event_name == 'push' && github.ref_type == 'branch' && !startsWith(github.ref_name, 'dependabot/') | ||
| ``` | ||
|
|
||
| ## A note on exit codes | ||
|
|
||
| On a fix run the findings JSON reports the state the CLI *diagnosed*, before it | ||
| fixed anything. A stale lockfile that the CLI then repaired reports | ||
| `"valid": false` with `ref-changed` findings and still exits `0`, because the | ||
| run succeeded in fixing it. Re-running reports `"valid": true` with no findings. | ||
|
|
||
| Use `--verify` for a read-only answer that writes nothing and exits non-zero if | ||
| the lockfile is stale. That is the form to use in a required check. | ||
|
|
||
| ## Related | ||
|
|
||
| - [Setting up lockfile pinning](../README.md) | ||
| - [Keeping a repository's Actions lockfile current](./repository-developer-experience.md) | ||
| - [Dependabot cooldown options reference](https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference#cooldown) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| --- | ||
| name: actions-lock | ||
| description: Keep GitHub Actions dependencies locked whenever workflows or local actions are created, modified, upgraded, or removed. | ||
| --- | ||
|
|
||
| <!-- | ||
| Example skill. Install as .github/skills/actions-lock/SKILL.md. | ||
| See docs/repository-developer-experience.md for the rationale. | ||
| --> | ||
|
|
||
| When changing files under `.github/workflows/`, or changing an `action.yml` or | ||
| `action.yaml` used by those workflows: | ||
|
|
||
| 1. Generate `.github/workflows/actions.lock` only with the CLI; do not create or | ||
| edit it manually. Manual changes bypass dependency resolution and can leave | ||
| refs, commits, or repository IDs inconsistent. Verification or workflow | ||
| startup can fail, and a later CLI run may overwrite the edits. | ||
| 2. Ensure the `github/gh-actions-lock` CLI extension is installed. This is safe | ||
| to run when it is already present: | ||
|
|
||
| ```bash | ||
| gh extension install github/gh-actions-lock | ||
| ``` | ||
|
|
||
| 3. After editing workflows or local actions, update the lockfile: | ||
|
|
||
| ```bash | ||
| gh actions-lock --no-interactive | ||
| ``` | ||
|
|
||
| 4. Expect the command to edit source files, not just the lockfile. It narrows | ||
| `uses:` refs to a full semver tag and rewrites same-repo `./…` action | ||
| references to `$/…`. Both are intended; do not revert them. | ||
| 5. Include every generated workflow, local action, and | ||
| `.github/workflows/actions.lock` change in the resulting change set. | ||
| 6. Verify the result without modifying files: | ||
|
|
||
| ```bash | ||
| gh actions-lock --verify | ||
| ``` | ||
|
|
||
| Do not consider the task complete unless verification succeeds. If locking | ||
|
Steve-Glass marked this conversation as resolved.
|
||
| fails, report the exact finding instead of leaving a stale or incomplete | ||
| lockfile. Use the finding's detail and remediation to identify the next step; | ||
| do not delete lockfile entries or accept moved pins just to make a check pass. | ||
|
Comment on lines
+44
to
+45
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point, escalate it to the human. AI can suggest a path forward, but this is a human decision IMO. |
||
|
|
||
| For `local path actions are not yet supported`, check that each `./…` path | ||
| resolves from the repository root to an `action.yml` or `action.yaml`. Fix an | ||
| incorrect path and re-run the CLI. If the action is generated, checked out from | ||
| another repository, or otherwise unavailable for inspection, defer onboarding | ||
| that workflow and report the limitation. Other workflows can still be locked. | ||
| If the affected workflow is already onboarded, report the blocking finding | ||
| rather than removing its lockfile entry. | ||
|
Comment on lines
+47
to
+53
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can use this skill to attempt to migrate to $/. |
||
|
|
||
| Other failures include missing or changed refs, invalid `$/…` paths, unreachable | ||
| pins, misleading SHA-shaped refs, and API or authentication failures. See | ||
| [Troubleshooting](https://github.com/github/gh-actions-lock/blob/main/docs/repository-developer-experience.md#troubleshooting) | ||
| for common findings and recovery steps. | ||
|
|
||
| Handling of job-level reusable workflow calls | ||
| (`jobs.<id>.uses: owner/repo/.github/workflows/x.yml@ref`) is still under | ||
| review. If this repository calls remote reusable workflows, review `git diff` on | ||
| the lockfile and report anything that looks wrong. Do not hand-edit the lockfile | ||
| to correct it. | ||
|
|
||
| Background on how locking is automated in this repository: | ||
| `docs/repository-developer-experience.md`. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| # Example: install this as `.github/workflows/actions-lock.yml` | ||
| # | ||
| # Regenerates the Actions lockfile on push and verifies it on pull requests. | ||
| # See docs/repository-developer-experience.md for the rationale. | ||
| # | ||
| # NOTE: handling of job-level reusable workflow calls | ||
| # (jobs.<id>.uses: owner/repo/.github/workflows/x.yml@ref) is still under | ||
| # review. Until that is settled, if this repository calls remote reusable | ||
| # workflows, delete the `update` job below and keep only `verify`. | ||
|
|
||
| name: Maintain Actions lockfile | ||
|
|
||
| on: | ||
| push: | ||
| paths: | ||
| - ".github/workflows/**" | ||
| - "**/action.yml" | ||
| - "**/action.yaml" | ||
| pull_request: | ||
| paths: | ||
| - ".github/workflows/**" | ||
| - "**/action.yml" | ||
| - "**/action.yaml" | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: actions-lock-${{ github.event_name }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| update: | ||
| name: Update lockfile | ||
| # Tag pushes are excluded: the commit step pushes back to a branch. | ||
| if: github.event_name == 'push' && github.ref_type == 'branch' | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| actions: write | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't the same as the workflow scope permission. And the workflow scope permission is not one that we'll issue to a job. The options there are a PAT with the workflow scope, or to just have this be CI that doesn't auto-fix things for you, and just blocks bad changes from merging. |
||
| contents: write | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v7.0.1 | ||
|
|
||
| - name: Install gh-actions-lock | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| # During public preview, add --pin <tag> to hold a tested release: | ||
| # gh extension install github/gh-actions-lock --pin v0.1.6 | ||
| run: gh extension install github/gh-actions-lock | ||
|
|
||
| # Also rewrites workflow refs and migrates same-repo `./…` actions to | ||
| # `$/…`, so the commit step stages more than just the lockfile. | ||
| - name: Update lockfile | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: gh actions-lock --no-interactive | ||
|
|
||
| - name: Commit lockfile updates | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: | | ||
| if [ -z "$(git status --porcelain)" ]; then | ||
| echo "Lockfile is already up to date." | ||
| exit 0 | ||
| fi | ||
|
|
||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
| git add --all | ||
| git commit -m "Update GitHub Actions lockfile" | ||
| git push origin "HEAD:${GITHUB_REF_NAME}" | ||
| # GITHUB_TOKEN pushes do not retrigger workflows, so verify the bot's | ||
| # own commit explicitly. | ||
| gh workflow run actions-lock.yml --ref "${GITHUB_REF_NAME}" | ||
|
|
||
| verify: | ||
| name: Verify lockfile | ||
| if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v7.0.1 | ||
|
|
||
| - name: Install gh-actions-lock | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: gh extension install github/gh-actions-lock | ||
|
|
||
| - name: Verify lockfile | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: gh actions-lock --verify | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.