dependabot / dependabot/dependabot-core
GitHub Actions: SHA-pinned actions updated to untagged branch HEAD commit when current SHA lacks a direct tag, leaving version comment stale
- Dominant language
- Ruby
- Stars
- 5.8k
- Forks
- 1.5k
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 149
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Package ecosystem
github-actions
### Package manager version
N/A
### Language version
N/A
### Manifest location and content before the Dependabot update
Example from [awslabs/mcp](https://github.com/awslabs/mcp/blob/main/.github/workflows/cfn_nag.yml) before the update:
```yaml
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@c0fc915677567258ee3c194d03ffe7ae3dc8d741 # v4.31.9
```
### dependabot.yml content
```yaml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
```
### Updated dependency
`github/codeql-action` — SHA updated from `c0fc915677567258ee3c194d03ffe7ae3dc8d741` to `76a687e1d810ec603951c060d5afa98f121364a7`, but version comment remains `# v4.31.9`.
### What you expected to see, versus what you actually saw
**Expected:** Dependabot should update the SHA to the commit corresponding to the latest tagged release (`v4.35.1` = `c10b8064de6f491fea524254123dbe5e09572f13`, which is the HEAD of `releases/v4`) and update the version comment to `# v4.35.1`.
**Actual:** Dependabot updates the SHA to `76a687e1d810ec603951c060d5afa98f121364a7` — the HEAD of the `main` branch — which is **not** a tagged release. The version comment is left unchanged at `# v4.31.9`, which is now factually incorrect and actively misleading.
This is visible in [awslabs/mcp#2932](https://github.com/awslabs/mcp/pull/2932). In the same PR, actions where the SHA **does** correspond to a tagged release get their comments updated correctly. For example, `astral-sh/setup-uv` is correctly updated from `# v7.3.0` to `# v8.0.0`. But all `github/codeql-action` entries get a new SHA with a stale comment.
**Verification of the tag/SHA discrepancy:**
```
$ git ls-remote --tags https://github.com/github/codeql-action.git | grep v4.35.1
0e9f55954318745b37b7933c693bc093f7336125 refs/tags/v4.35.1
c10b8064de6f491fea524254123dbe5e09572f13 refs/tags/v4.35.1^{}
$ git ls-remote --heads https://github.com/github/codeql-action.git | grep releases/v4
c10b8064de6f491fea524254123dbe5e09572f13 refs/heads/releases/v4
```
The `v4.35.1` tag points to commit `c10b8064...` on the `releases/v4` branch. But Dependabot chose `76a687e1...` (HEAD of `main`), which has no tag.
### Root cause
The issue is in [`update_checker.rb:latest_commit_sha`](https://github.com/dependabot/dependabot-core/blob/main/github_actions/lib/dependabot/github_actions/update_checker.rb#L170-L178):
```ruby
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) # ✅ Correct: use the tagged release commit
else
latest_commit_for_pinned_ref # ❌ Bug: gets HEAD of containing branch
end
end
```
When `local_tag_for_pinned_sha` returns nil (the current SHA has no tag pointing to it), the code falls through to `latest_commit_for_pinned_ref`, which clones the repo, finds the branch containing the current SHA, and returns that branch's HEAD commit. This completely ignores the `new_tag` that was already resolved.
This happens with action repositories that use a **release branch workflow** (e.g., `github/codeql-action` where tags point to commits on `releases/v4` but development happens on `main`). Once a SHA ends up on `main` (either through this bug or manual error), subsequent updates will perpetually resolve to the HEAD of `main` — never a tagged release — creating a self-perpetuating cycle of stale comments and untagged SHAs.
The same `latest_commit_for_pinned_ref` / `find_container_branch` pattern exists in [`package_details_fetcher.rb`](https://github.com/dependabot/dependabot-core/blob/main/github_actions/lib/dependabot/github_actions/package/package_details_fetcher.rb#L212-L236) with the same issue.
### Native package manager behavior
N/A — GitHub Actions has no native package manager for version resolution.
### Images of the diff or a link to the PR, issue, or logs
- **PR exhibiting the bug:** [awslabs/mcp#2932](https://github.com/awslabs/mcp/pull/2932)
- Correctly updated (tag has matching SHA): [`aws-api-mcp-upgrade-version.yml` line 43](https://github.com/awslabs/mcp/blob/33f9e80f56f72d1b35d8a53d4ea78b0bb510fcd5/.github/workflows/aws-api-mcp-upgrade-version.yml#L43) — `astral-sh/setup-uv` comment updated from `# v7.3.0` → `# v8.0.0`
- **Not** updated (SHA on wrong branch): [`cfn_nag.yml` line 38](https://github.com/awslabs/mcp/blob/33f9e80f56f72d1b35d8a53d4ea78b0bb510fcd5/.github/workflows/cfn_nag.yml#L38) — `github/codeql-action` comment stuck at `# v4.31.9`
### Related issues
- #7912 — Version comment not updated if existing comment is already incorrect (open, 21 upvotes)
- #8011 — Hash-pinned `actions/checkout` v3→v4 doesn't always update version comments (open)
- #13466 — Hash pinned actions updated to latest commit instead of released version (closed by #14349, but fix only addressed mixed tag/SHA ref downgrade — not the branch-resolution fallback)
- #14685 — Dependabot puts incorrect version info into GHA update PRs (open)
PR #14349 fixed the narrow case where mixed tag/SHA refs caused downgrade via the shared `git_commit_checker`, but did not address the underlying `latest_commit_for_pinned_ref` fallback that resolves to untagged branch HEAD commits.
### Smallest manifest that reproduces the issue
Any workflow file SHA-pinned to a commit on `main` for an action that publishes releases on a separate branch (e.g., `releases/v4`):
```yaml
name: Reproduce
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
# Pin to a main-branch commit for codeql-action (tags are on releases/v4)
- uses: github/codeql-action/upload-sarif@76a687e1d810ec603951c060d5afa98f121364a7 # v4.31.9
```
Contributor guide
Research direction
Start in github_actions/lib/dependabot/github_actions/update_checker.rb at latest_commit_sha and trace the latest_commit_for_pinned_ref fallback. Then inspect package_details_fetcher.rb around the corresponding latest_commit_for_pinned_ref and find_container_branch logic. Reproduce with the minimal SHA-pinned workflow described in the issue; done means updates use the tagged release commit and keep the version comment accurate in both paths.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, ruby
- Domain
- ci-cd, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100