Skip to content

Fix GitHub Actions SHA-pinned refs being downgraded when mixed with tag refs#14349

Merged
jurre merged 1 commit intomainfrom
jurre/fix-github-actions-sha-downgrade
Mar 3, 2026
Merged

Fix GitHub Actions SHA-pinned refs being downgraded when mixed with tag refs#14349
jurre merged 1 commit intomainfrom
jurre/fix-github-actions-sha-downgrade

Conversation

@jurre
Copy link
Member

@jurre jurre commented Mar 3, 2026

Problem

When a repository references the same GitHub Action with a mix of tag refs (@v4) and SHA-pinned refs (@<sha> # v6), the SHA-pinned refs get downgraded instead of upgraded.

For example, given three workflow files:

File Reference Expected update
codeql-rust.yml actions/checkout@v4 @v6
rust.yml actions/checkout@<sha> # v6.0.1 @<sha> # v6.0.2
security-workflow.yml actions/checkout@<sha> # v6.0.2 no change (already latest)

Dependabot was updating the SHA-pinned v6 refs to the v4 branch HEAD SHA (v4.3.1), effectively downgrading them.

Root cause

DependencySet.combined_version picks the lowest version across all requirements, so the combined dependency version becomes "4" rather than "6.0.1". The UpdateChecker creates a source-specific git_commit_checker per requirement (correct), but latest_commit_sha used the shared git_commit_checker which gets its ref from the first requirement's source: ref: "v4" (a tag, not a SHA).

Since "v4" is not a SHA, local_tag_for_pinned_sha returns nil, and the code falls through to latest_commit_for_pinned_ref, which follows the v4 ref and returns the v4.3.1 SHA. That wrong SHA then gets applied to all SHA-pinned requirements.

Fix

Pass the source-specific git_commit_checker (which has the actual SHA ref for each requirement) to latest_commit_sha, so local_tag_for_pinned_sha correctly resolves the tag from the SHA and returns the right commit.

4 lines changed in production code.

Fixes #13677.

…ag refs

When a dependency has mixed tag-based (e.g., @v4) and SHA-pinned
(e.g., @abc123 # v6.0.1) requirements across workflow files,
the SHA-pinned refs were being incorrectly downgraded.

Root cause: latest_commit_sha used the shared git_commit_checker
(which picks the first requirement's source ref, e.g., 'v4'). Since
'v4' is not a SHA, local_tag_for_pinned_sha returned nil, causing
the code to follow the v4 branch and return v4's latest SHA instead
of the target version's SHA.

Fix: Pass the source-specific git_commit_checker to latest_commit_sha
so it checks local_tag_for_pinned_sha against the actual SHA-pinned
ref, correctly taking the path that returns the target version's
commit SHA.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions bot added the L: github:actions GitHub Actions label Mar 3, 2026
@jurre jurre marked this pull request as ready for review March 3, 2026 11:09
@jurre jurre requested a review from a team as a code owner March 3, 2026 11:09
Copilot AI review requested due to automatic review settings March 3, 2026 11:09
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a GitHub Actions update-checking bug where dependencies with mixed tag refs and SHA-pinned refs across workflow files could incorrectly apply the tag ref’s commit SHA to SHA-pinned requirements (effectively downgrading them).

Changes:

  • Update the GitHub Actions UpdateChecker to pass a source-specific GitCommitChecker into latest_commit_sha when resolving updates for SHA-pinned requirements.
  • Add an RSpec regression test covering mixed tag + SHA requirements across multiple workflow files.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
github_actions/lib/dependabot/github_actions/update_checker.rb Uses the per-requirement GitCommitChecker when computing the latest commit SHA for SHA-pinned refs.
github_actions/spec/dependabot/github_actions/update_checker_spec.rb Adds coverage for mixed tag and SHA requirements to prevent SHA-pinned refs being updated via the tag ref’s source.
Comments suppressed due to low confidence (1)

github_actions/lib/dependabot/github_actions/update_checker.rb:178

  • latest_commit_sha now checks source_checker.local_tag_for_pinned_sha, but the fallback still calls latest_commit_for_pinned_ref, which is memoized and computed via the shared git_commit_checker (based on dependency.source_details, i.e., typically the first requirement’s ref). In mixed-requirement dependencies, this can still yield the wrong commit (e.g., for a SHA requirement where local_tag_for_pinned_sha is nil, the fallback may follow the first requirement’s tag/branch instead). Consider making the fallback source-specific as well (e.g., pass source_checker through and memoize per ref) so mixed refs can’t influence each other.
      sig { params(source_checker: Dependabot::GitCommitChecker).returns(T.nilable(String)) }
      def latest_commit_sha(source_checker)
        new_tag = T.must(latest_version_finder).latest_version_tag
        return unless new_tag

        if source_checker.local_tag_for_pinned_sha
          new_tag.fetch(:commit_sha)
        else
          latest_commit_for_pinned_ref
        end

Copy link
Contributor

@thavaahariharangit thavaahariharangit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jurre
Copy link
Member Author

jurre commented Mar 3, 2026

Verification

Tested end-to-end using the Dependabot CLI against a local reproduction repo.

Repo setup

Three workflow files referencing actions/checkout at different versions and pinning styles:

.github/workflows/codeql-rust.yml (tag ref, v4):

uses: actions/checkout@v4

.github/workflows/rust.yml (SHA-pinned, v6.0.1):

uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1

.github/workflows/security-workflow.yml (SHA-pinned, v6.0.2):

uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

Before fix

actions/checkout@v4                    → actions/checkout@v6                    ✅
actions/checkout@8e8c483... # v6.0.1   → actions/checkout@34e1148... # v4.3.1   ❌ downgrade
actions/checkout@de0fac2... # v6.0.2   → actions/checkout@34e1148... # v4.3.1   ❌ downgrade

After fix

actions/checkout@v4                    → actions/checkout@v6                    ✅
actions/checkout@8e8c483... # v6.0.1   → actions/checkout@de0fac2... # v6.0.2   ✅
actions/checkout@de0fac2... # v6.0.2   → (no change, already latest)            ✅

Built the Docker image locally with script/build github_actions and ran the CLI with --updater-image pointing to it.

@jurre jurre merged commit 7eb12fa into main Mar 3, 2026
88 checks passed
@jurre jurre deleted the jurre/fix-github-actions-sha-downgrade branch March 3, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L: github:actions GitHub Actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dependabot GHA dependency update PR downgrades a pinned version

3 participants