What Is the `bump-plugin-shas` GitHub Action? A Deep Dive into Automated SHA Management for Claude Plugins

The bump-plugin-shas GitHub Action automatically updates pinned SHA commits for external Claude plugins in the marketplace manifest, validates the new code, and opens pull requests for maintainer review.

This custom action in the anthropics/claude-plugins-community repository solves a critical maintenance problem: keeping third-party plugin references current without manual intervention. When upstream repositories move forward, this action detects changes, ensures plugin integrity through validation, and creates properly signed commits for security-conscious merging.

How bump-plugin-shas Discovers Outdated Plugin SHAs

The action begins by scanning .claude-plugin/marketplace.json for every external plugin entry that contains a source object. These entries point to remote Git repositories that require SHA pinning for reproducible builds.

For each discovered plugin, the action determines the target reference:

  • Default tracking: Compares against the repository's current HEAD
  • Releases-only tracking: Checks the latest published GitHub release (configured via tracking-config)

This dual-mode approach lets maintainers choose stability (releases) or bleeding-edge updates (HEAD) on a per-plugin basis.

Validation and Safety Guards in bump-plugin-shas

Before any SHA advances, the action enforces a multi-layer protection system:

Validation Pipeline

When a newer commit exists, the action clones the repository, checks out the candidate SHA, and runs claude plugin validate against the plugin manifest. For plugins using "strict": false, it synthesizes a minimal manifest to ensure basic structural compliance. Failed validations abort the bump for that plugin—no broken code enters the manifest.

Policy Enforcement Rules

Guard Purpose Location
sha-exempt Lists plugins deliberately without SHA pins; completely ignored Configurable list
freeze-shas Plugins frozen at current SHA; logged warning, never bumped .github/freeze-shas.txt
tracking-config JSON file specifying "releases-only" plugins Repository config
owner-baseline Verifies repository owner account ID matches recorded value .github/owner-baseline.json

The owner baseline check prevents a subtle attack vector: if a repository transfers ownership, the action detects the mismatch and stops automatic pinning to the new owner's code.

PR Creation Modes: Batch vs. Per-Entry

The pr-mode input controls how changes reach maintainers:

batch mode creates a single signed commit on bump/plugin-shas (configurable) containing all successful bumps—efficient for routine maintenance with trusted plugins.

per-entry mode isolates each bump on its own branch (bump/<sanitized-name>) with individual PRs. This prevents one validation failure from blocking ten healthy updates. The repository's default workflow uses this safer approach.

Both modes use GitHub's GraphQL createCommitOnBranch mutation for server-side signed commits, satisfying the organization's required_signatures rule without exposing private keys to runners.

Using bump-plugin-shas in Your Workflow

Nightly Automated Run


# .github/workflows/bump-plugin-shas.yml (excerpt)

- uses: ./.github/actions/bump-plugin-shas
  id: bump
  with:
    marketplace-path: .claude-plugin/marketplace.json
    max-bumps: ${{ inputs.max_bumps || '30' }}
    freeze-shas: ${{ steps.freeze.outputs.list }}
    only: ${{ inputs.plugin }}
    pr-mode: per-entry
    claude-cli-version: latest

The workflow triggers on cron schedule and manual dispatch, loading frozen pins before execution.

Single-Plugin Manual Trigger

workflow_dispatch:
  inputs:
    max_bumps:
      description: 'Cap on plugins bumped this run'
      default: '30'
    plugin:
      description: 'Bump ONLY this plugin name (empty = all stale)'
      default: ''

Supply a specific plugin name through the Actions UI for targeted updates—useful for urgent security patches or debugging.

Core Implementation in bump.sh

The discovery and validation logic lives in scripts/bump.sh:


# Simplified discovery loop from bump.sh lines 67-108

while IFS= read -r entry; do
  name=$(jq -r '.name' <<<"$entry")
  # Skip guards: sha-exempt, frozen, owner mismatch...

  
  new_sha=$(git ls-remote "$full_url" HEAD | awk '{print $1}')
  [[ "$new_sha" == "$old_sha" ]] && continue
  
  # Validate before accepting

  claude plugin validate "$manifest"
  
  # Record for commit/PR creation

  bumps+=("$name:$old_sha:$new_sha")
done < <(jq -c '.plugins[] | select(.source|type=="object")' "$MARKETPLACE_PATH")

This loop handles HEAD checks, release-only overrides, subtree suppression, validation gating, and finally delegates to the commit signing logic at lines 35-44.

Action Outputs and Observability

After execution, bump-plugin-shas exposes structured data:

  • bumped: JSON array of successful upgrades with name, old_sha, new_sha
  • skipped: Array of rejected bumps with explanatory reason
  • pr-url / pr-urls: Direct links to created pull request(s)

Downstream jobs can consume these outputs for notifications, metrics dashboards, or additional validation pipelines.

Summary

  • bump-plugin-shas automates SHA pin maintenance for external Claude plugins through discovery, validation, and policy-guarded PR creation
  • Two tracking modes support both HEAD-following and release-only update strategies
  • Four safety guards (sha-exempt, freeze-shas, tracking-config, owner-baseline) prevent unwanted or malicious updates
  • Server-side signed commits via createCommitOnBranch maintain GPG verification without key exposure
  • Per-entry PR mode isolates failures; batch mode optimizes for trusted plugins
  • Primary implementation spans .github/actions/bump-plugin-shas/action.yml and scripts/bump.sh

Frequently Asked Questions

What triggers the bump-plugin-shas action to run?

The action runs on a scheduled cron (nightly by default) and via workflow_dispatch for manual execution. The triggering workflow at .github/workflows/bump-plugin-shas.yml loads configuration, prepares the freeze list, then invokes the action with appropriate inputs.

How does bump-plugin-shas handle plugin validation failures?

Validation failures skip the individual bump without aborting the entire run. The plugin name and failure reason populate the skipped output array. In per-entry PR mode, other plugins still receive their own PRs; in batch mode, the failing plugin is simply omitted from the collective commit.

Why does the action use server-side commit signing instead of GPG keys on the runner?

The createCommitOnBranch GraphQL mutation generates commits with verified signatures directly through GitHub's API. This satisfies the required_signatures branch protection rule while eliminating the security risk of private signing keys in CI environments—no key material ever touches the action runner.

Can I prevent bump-plugin-shas from updating specific plugins?

Yes. Add plugin names to .github/freeze-shas.txt to freeze them at current SHAs, or to the sha-exempt list to ignore them entirely. For release stability, add plugins to the "releases-only" array in your tracking configuration file.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →