How the bump-plugin-shas Workflow Detects and Updates Stale Plugin SHAs in the Claude Plugins Community
The bump-plugin-shas GitHub Workflow detects stale plugin SHAs by comparing pinned commits in marketplace.json against live upstream references, then validates and opens signed pull requests to update them.
The anthropics/claude-plugins-community repository maintains a curated marketplace of external Claude plugins. To ensure security and stability, each plugin entry pins a specific Git commit SHA rather than floating on a branch. The bump-plugin-shas workflow automates the tedious work of detecting when upstream repositories advance and safely updating those pins.
How the Workflow Discovers Stale SHA Pins
The core detection logic lives in .github/actions/bump-plugin-shas/scripts/bump.sh. This script iterates over every external plugin entry in .claude-plugin/marketplace.json and performs a three-step staleness check.
Resolving the Live Upstream Reference
For each marketplace entry, the script extracts:
source_url: The Git repository URLsha: The currently pinned commitsubdirectory: Optional path if the plugin lives in a sub-foldertracking: Optional config to track latest GitHub Release instead of HEAD
The script resolves the target reference using git ls-remote:
- Default mode: HEAD of the default branch
- Releases-only mode: The commit associated with the latest GitHub Release (fetched via API)
# Example: resolving HEAD for a GitHub repository
git ls-remote https://github.com/owner/repo.git HEAD
The Staleness Comparison
An entry is flagged as stale when new_sha != old_sha. However, the script applies several granular safety checks before treating this as a genuine update candidate.
Safety Checks and Guardrails
Before any SHA update proceeds, the workflow enforces multiple security layers defined in bump.sh.
Host Allow-List Enforcement
Only URLs whose host appears in the ALLOWED_HOSTS environment variable are processed. This prevents accidental processing of internal or untrusted repositories.
Source-Owner Verification via GitHub API
The script queries the GitHub API to confirm the live repository still belongs to the same owner as the listed URL. This catches:
- Repository transfers to new owners
- Username changes that redirect to different accounts
- Typosquatting attempts through renamed repositories
Identity Baseline Matching
When .github/owner-baseline.json exists, the script verifies the repository's account ID matches the recorded baseline. This detects cases where a login name has been reassigned to a completely different user or organization.
Sub-Tree Suppression
For plugins in subdirectories, the script compares the actual tree objects:
# Compare subtree content between old and new commits
git rev-parse old_sha:subdirectory/
git rev-parse new_sha:subdirectory/
If the subdirectory bytes are identical, the bump is suppressed as a no-op—the parent repository moved but the plugin code did not change.
Existing PR Guard
In per-entry mode, the script queries open PRs and skips plugins that already have a pending bump PR, preventing duplicate work.
Freeze Lists and Exemption Config
The workflow respects intentional pinning through two mechanisms:
.github/freeze-shas.txt: Lists plugins whose SHAs are intentionally frozen, typically due to security concerns or known-breaking changes- SHA-exempt plugins: Configured directly in the action inputs for plugins that should never auto-update
Validation Before Commit
For each candidate that passes all checks, the workflow performs rigorous validation:
- Clone the external repository at
new_sha - Checkout the target commit
- Run
claude plugin validateagainst the plugin manifest - For
strict: falseplugins, synthesize a minimal manifest to enable validation
Only validated plugins proceed to the update phase.
Creating Signed Commits and Pull Requests
The workflow uses GitHub's GraphQL API to create commits that satisfy the organization's required_signatures rule:
mutation createCommitOnBranch {
createCommitOnBranch(input: {
branch: {id: $branchId},
message: {headline: "bump(plugin): example-plugin to b7c8d9e"},
fileChanges: {additions: [{path: ".claude-plugin/marketplace.json", contents: $encodedContent}]},
expectedHeadOid: $currentOid
}) {
commit {oid}
}
}
Per-Entry vs. Batch Modes
| Mode | Branch Pattern | Use Case |
|---|---|---|
| per-entry | bump/<sanitized-plugin-name> |
Isolated review, granular rollback |
| batch | bump |
Bulk updates, reduced noise |
Each mode creates appropriately scoped PRs with descriptive titles and summary tables.
Post-PR Validation Dispatch
After opening bump PRs, the workflow automatically dispatches the validate-plugins.yml workflow on each branch. This satisfies the required "Validate Plugins" status check before human review.
Running Locally for Debugging
You can execute the bump logic outside GitHub Actions for troubleshooting:
# Clone and enter the repository
git clone https://github.com/anthropics/claude-plugins-community.git
cd claude-plugins-community/.github/actions/bump-plugin-shas
# Configure environment
export MARKETPLACE_PATH=../../.claude-plugin/marketplace.json
export MAX_BUMPS=10
export ALLOWED_HOSTS="github.com"
export GH_TOKEN=$GITHUB_TOKEN
export PR_MODE=per-entry
export BASE_BRANCH=main
# Dry-run: preview what would change without making commits
MAX_BUMPS=0 ./scripts/bump.sh
Manual Workflow Dispatch
Trigger the workflow with custom parameters via the GitHub CLI:
gh workflow run bump-plugin-shas.yml \
--ref main \
-f max_bumps=5 \
-f plugin=my-plugin-name
This targets a single plugin or limits the batch size for controlled updates.
Key Files in the bump-plugin-shas System
| File | Purpose |
|---|---|
.github/workflows/bump-plugin-shas.yml |
Orchestrates scheduled and manual runs |
.github/actions/bump-plugin-shas/action.yml |
Action interface and input definitions |
.github/actions/bump-plugin-shas/scripts/bump.sh |
Core detection, validation, and PR creation logic |
.github/freeze-shas.txt |
Intentionally frozen plugin list |
.github/owner-baseline.json |
Optional owner identity verification data |
.claude-plugin/marketplace.json |
Source of truth for all plugin SHAs |
.github/actions/validate-plugins/action.yml |
Post-bump validation workflow |
Summary
- The bump-plugin-shas workflow scans
.claude-plugin/marketplace.jsonnightly to detect SHA pins that lag behind upstream repositories - Staleness detection compares pinned commits against
git ls-remote HEADor latest GitHub Releases - Multiple safety checks—host allow-list, owner verification, identity baseline, sub-tree comparison, and duplicate PR detection—filter out invalid or risky updates
- Validation via
claude plugin validateensures only working plugin code enters the marketplace - GraphQL-signed commits satisfy organizational signature requirements
- Per-entry and batch modes offer flexibility between isolated review and operational efficiency
Frequently Asked Questions
How does the workflow prevent updating plugins from compromised repositories?
The workflow combines source-owner verification via GitHub API with optional identity baseline matching against .github/owner-baseline.json. These checks ensure the repository still belongs to the expected account before accepting any new SHA, catching transfers or username reassignments that could indicate compromise.
What happens if a plugin's upstream repository hasn't changed but its subdirectory has identical content?
The sub-tree suppression logic in bump.sh compares the actual tree object hashes of the subdirectory between old and new commits. If they match byte-for-byte, the update is suppressed as a no-op, avoiding unnecessary churn when only unrelated parent repository files changed.
Can I prevent specific plugins from auto-updating?
Yes. Add plugin identifiers to .github/freeze-shas.txt for repository-wide freezes, or configure SHA-exempt plugins in the action inputs for workflow-scoped exemptions. Both mechanisms are respected during the discovery phase before any staleness checks run.
Why does the workflow use GraphQL instead of standard git commits for creating updates?
The anthropics/claude-plugins-community repository enforces required_signatures at the organization level, mandating GPG-signed commits. The GitHub GraphQL createCommitOnBranch mutation automatically signs commits with GitHub's web-flow GPG key, enabling automated commits that satisfy this policy without managing external signing keys in CI.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →